Skip to content

Commit ac2c130

Browse files
committed
Extensive audio formats: opus, mp3, flac, aac, coreaudio, wmf (#86)
1 parent ddf9b84 commit ac2c130

File tree

117 files changed

+8954
-39532
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+8954
-39532
lines changed

AGENTS.md

Lines changed: 407 additions & 0 deletions
Large diffs are not rendered by default.

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ option (YUP_BUILD_JAVA_SUPPORT "Build the Java support" OFF)
4444
option (YUP_BUILD_EXAMPLES "Build the examples" ${PROJECT_IS_TOP_LEVEL})
4545
option (YUP_BUILD_TESTS "Build the tests" ${PROJECT_IS_TOP_LEVEL})
4646
option (YUP_BUILD_WHEEL "Build the wheel" OFF)
47+
option (YUP_FETCH_UPSTREAM_MODULES "Fetch missing upstream sources for modules" ON)
4748

4849
# Dependencies modules
4950
if (YUP_EXPORT_MODULES)

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
<a href="./examples/graphics/source/examples/CrossoverDemo.h"><img src="./docs/images/yup_dsp_crossover.png" style="width:43.5%;" /></a>
2525
</div>
2626

27+
<div style="display: flex; width: 100%; flex-wrap: nowrap;">
28+
<a href="./examples/graphics/source/examples/AudioFileDemo.h"><img src="./docs/images/yup_audio_scope.png" style="width:99%;" /></a>
29+
</p>
30+
2731
<div style="display: flex; width: 100%; flex-wrap: nowrap;">
2832
<a href="./examples/graphics/source/examples/SpectrumAnalyzer.h"><img src="./docs/images/yup_dsp_spectrum_fill.png" style="width:99%;" /></a>
2933
<a href="./examples/graphics/source/examples/SpectrumAnalyzer.h"><img src="./docs/images/yup_dsp_spectrum_line.png" style="width:99%;" /></a>
@@ -102,6 +106,23 @@ YUP brings a suite of powerful features, including:
102106
| **Linux** | :construction: | :construction: | | | | | |
103107

104108

109+
## Supported Sound Formats
110+
111+
| | **Wav** | **Wav64** | **Mp3** | **OGG** | **Flac** | **Opus** | **AAC** | **WMF** |
112+
|-------------------|:------------------:|:------------------:|:------------------:|:--------------:|:------------------:|:------------------:|:------------------:|:--------------:|
113+
| **Windows** (enc) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :construction: | :white_check_mark: | :white_check_mark: | :construction: | :construction: |
114+
| **Windows** (dec) | :white_check_mark: | :white_check_mark: | :construction: | :construction: | :white_check_mark: | :white_check_mark: | :construction: | :construction: |
115+
| **macOS** (enc) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :construction: | :white_check_mark: | :white_check_mark: | :white_check_mark: | |
116+
| **macOS** (dec) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :construction: | :white_check_mark: | :white_check_mark: | :white_check_mark: | |
117+
| **Linux** (enc) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :construction: | :white_check_mark: | :white_check_mark: | | |
118+
| **Linux** (dec) | :white_check_mark: | :white_check_mark: | :construction: | :construction: | :white_check_mark: | :white_check_mark: | | |
119+
| **WASM** (enc) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :construction: | :white_check_mark: | :white_check_mark: | | |
120+
| **WASM** (dec) | :white_check_mark: | :white_check_mark: | :construction: | :construction: | :white_check_mark: | :white_check_mark: | | |
121+
| **Android** (enc) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :construction: | :white_check_mark: | :white_check_mark: | | |
122+
| **Android** (dec) | :white_check_mark: | :white_check_mark: | :construction: | :construction: | :white_check_mark: | :white_check_mark: | | |
123+
| **iOS** (enc) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :construction: | :white_check_mark: | :white_check_mark: | :white_check_mark: | |
124+
| **iOS** (dec) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :construction: | :white_check_mark: | :white_check_mark: | :white_check_mark: | |
125+
105126
## Prerequisites
106127
Before building, ensure you have a:
107128
- C++20-compliant compiler

cmake/yup_modules.cmake

Lines changed: 218 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
#
1818
# ==============================================================================
1919

20-
#==============================================================================
21-
2220
function (_yup_module_parse_config module_header output_module_configs output_module_user_configs)
2321
set (module_configs "")
2422
set (module_user_configs "")
@@ -58,6 +56,181 @@ endfunction()
5856

5957
#==============================================================================
6058

59+
function (_yup_module_upstream_has_content module_name module_path output_variable)
60+
_yup_collect_upstream_candidate_paths ("${module_name}" "${module_path}" candidate_paths)
61+
foreach (candidate_path IN LISTS candidate_paths)
62+
if (EXISTS "${candidate_path}")
63+
file (GLOB upstream_items "${candidate_path}/*")
64+
list (LENGTH upstream_items upstream_items_len)
65+
if (upstream_items_len GREATER 0)
66+
set (${output_variable} ON PARENT_SCOPE)
67+
return()
68+
endif()
69+
endif()
70+
endforeach()
71+
72+
set (${output_variable} OFF PARENT_SCOPE)
73+
endfunction()
74+
75+
#==============================================================================
76+
77+
function (_yup_module_get_upstream_path module_name module_path output_variable)
78+
_yup_collect_upstream_candidate_paths ("${module_name}" "${module_path}" candidate_paths)
79+
foreach (candidate_path IN LISTS candidate_paths)
80+
if (EXISTS "${candidate_path}")
81+
set (${output_variable} "${candidate_path}" PARENT_SCOPE)
82+
return()
83+
endif()
84+
endforeach()
85+
86+
set (${output_variable} "" PARENT_SCOPE)
87+
endfunction()
88+
89+
#==============================================================================
90+
91+
function (_yup_module_fetch_upstream module_name module_path module_upstream module_sha256 module_repository module_branch module_submodules output_target_variable)
92+
if (NOT YUP_FETCH_UPSTREAM_MODULES)
93+
return()
94+
endif()
95+
96+
if (module_upstream AND module_repository)
97+
_yup_message (FATAL_ERROR "Module ${module_name} defines both upstream and repository sources")
98+
endif()
99+
100+
if (NOT module_upstream AND NOT module_repository)
101+
return()
102+
endif()
103+
104+
_yup_module_upstream_has_content ("${module_name}" "${module_path}" upstream_has_content)
105+
if (upstream_has_content)
106+
return()
107+
endif()
108+
109+
_yup_message (STATUS "Fetching upstream sources for ${module_name}")
110+
111+
if (module_upstream)
112+
set (download_dir "${CMAKE_BINARY_DIR}/_yup_upstream_downloads")
113+
file (MAKE_DIRECTORY "${download_dir}")
114+
get_filename_component (archive_name "${module_upstream}" NAME)
115+
if ("${archive_name}" STREQUAL "")
116+
set (archive_name "${module_name}.archive")
117+
endif()
118+
set (archive_path "${download_dir}/${archive_name}")
119+
120+
# SHOW_PROGRESS
121+
if (module_sha256)
122+
file (DOWNLOAD "${module_upstream}" "${archive_path}" EXPECTED_HASH SHA256=${module_sha256})
123+
else()
124+
file (DOWNLOAD "${module_upstream}" "${archive_path}")
125+
endif()
126+
127+
set (extract_dir "${CMAKE_BINARY_DIR}/_yup_upstream_extract/${module_name}")
128+
file (REMOVE_RECURSE "${extract_dir}")
129+
file (MAKE_DIRECTORY "${extract_dir}")
130+
file (ARCHIVE_EXTRACT INPUT "${archive_path}" DESTINATION "${extract_dir}")
131+
132+
file (GLOB extracted_entries RELATIVE "${extract_dir}" "${extract_dir}/*")
133+
list (LENGTH extracted_entries extracted_entries_len)
134+
set (source_dir "${extract_dir}")
135+
if (extracted_entries_len EQUAL 1)
136+
list (GET extracted_entries 0 single_entry)
137+
if (IS_DIRECTORY "${extract_dir}/${single_entry}")
138+
set (source_dir "${extract_dir}/${single_entry}")
139+
endif()
140+
endif()
141+
142+
set (upstream_target_dir "${CMAKE_BINARY_DIR}/externals/${module_name}/upstream")
143+
file (REMOVE_RECURSE "${upstream_target_dir}")
144+
file (MAKE_DIRECTORY "${upstream_target_dir}")
145+
file (GLOB extracted_items "${source_dir}/*")
146+
if (extracted_items)
147+
file (COPY ${extracted_items} DESTINATION "${upstream_target_dir}")
148+
endif()
149+
else()
150+
if (NOT module_branch)
151+
set (module_branch "HEAD")
152+
endif()
153+
154+
set (upstream_target_dir "${CMAKE_BINARY_DIR}/externals/${module_name}/upstream")
155+
if (module_submodules)
156+
set (module_submodules_recurse ON)
157+
else()
158+
set (module_submodules_recurse OFF)
159+
endif()
160+
161+
file (MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/externals/${module_name}")
162+
163+
file (REMOVE_RECURSE "${upstream_target_dir}")
164+
set (module_branch_value "${module_branch}")
165+
string (STRIP "${module_branch_value}" module_branch_value)
166+
string (REGEX REPLACE "^\"(.*)\"$" "\\1" module_branch_value "${module_branch_value}")
167+
string (REGEX REPLACE "^'(.*)'$" "\\1" module_branch_value "${module_branch_value}")
168+
169+
if (module_branch_value AND NOT module_branch_value STREQUAL "HEAD")
170+
string (REGEX MATCH "^[0-9a-fA-F]+$" module_branch_is_hex "${module_branch_value}")
171+
string (LENGTH "${module_branch_value}" module_branch_length)
172+
if (module_branch_is_hex AND module_branch_length GREATER_EQUAL 7 AND module_branch_length LESS_EQUAL 40)
173+
set (module_branch_is_commit ON)
174+
else()
175+
set (module_branch_is_commit "")
176+
endif()
177+
else()
178+
set (module_branch_is_commit "")
179+
endif()
180+
181+
if (module_branch_is_commit)
182+
execute_process (
183+
COMMAND git clone -q --no-checkout "${module_repository}" "${upstream_target_dir}"
184+
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals/${module_name}"
185+
RESULT_VARIABLE clone_result)
186+
if (clone_result EQUAL 0)
187+
execute_process (
188+
COMMAND git -c advice.detachedHead=false -C "${upstream_target_dir}" fetch -q --depth=1 origin "${module_branch_value}"
189+
RESULT_VARIABLE fetch_result)
190+
execute_process (
191+
COMMAND git -c advice.detachedHead=false -C "${upstream_target_dir}" checkout -q "${module_branch_value}"
192+
RESULT_VARIABLE checkout_result)
193+
if (module_submodules_recurse AND fetch_result EQUAL 0 AND checkout_result EQUAL 0)
194+
execute_process (
195+
COMMAND git -c advice.detachedHead=false -C "${upstream_target_dir}" submodule update --init --recursive --depth=1
196+
RESULT_VARIABLE submodule_result)
197+
endif()
198+
endif()
199+
else()
200+
set (clone_args git clone)
201+
if (module_submodules_recurse)
202+
list (APPEND clone_args --recurse-submodules --shallow-submodules)
203+
endif()
204+
list (APPEND clone_args -q --depth=1)
205+
if (module_branch_value AND NOT module_branch_value STREQUAL "HEAD")
206+
list (APPEND clone_args --branch "${module_branch_value}")
207+
endif()
208+
list (APPEND clone_args "${module_repository}" "${upstream_target_dir}")
209+
execute_process (
210+
COMMAND ${clone_args}
211+
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals/${module_name}"
212+
RESULT_VARIABLE clone_result)
213+
endif()
214+
215+
if (module_branch_is_commit)
216+
if (NOT clone_result EQUAL 0 OR NOT fetch_result EQUAL 0 OR NOT checkout_result EQUAL 0)
217+
_yup_message (FATAL_ERROR "Failed to clone ${module_repository} at commit ${module_branch} for ${module_name}")
218+
endif()
219+
if (module_submodules_recurse AND NOT submodule_result EQUAL 0)
220+
_yup_message (FATAL_ERROR "Failed to update submodules for ${module_repository} at commit ${module_branch}")
221+
endif()
222+
else()
223+
if (NOT clone_result EQUAL 0)
224+
_yup_message (FATAL_ERROR "Failed to clone ${module_repository} for ${module_name}")
225+
endif()
226+
endif()
227+
228+
set (${output_target_variable} "" PARENT_SCOPE)
229+
endif()
230+
endfunction()
231+
232+
#==============================================================================
233+
61234
function (_yup_module_collect_sources folder output_variable)
62235
set(source_extensions ".c;.cc;.cxx;.cpp;.h;.hh;.hxx;.hpp")
63236
if (APPLE)
@@ -363,14 +536,37 @@ function (yup_add_module module_path modules_definitions module_group)
363536
_yup_boolean_property ("${value}" module_arc_enabled)
364537
elseif (${key} MATCHES "^needsPython$")
365538
_yup_boolean_property ("${value}" module_needs_python)
539+
elseif (${key} MATCHES "^upstream$")
540+
set (module_upstream "${value}")
541+
elseif (${key} MATCHES "^sha256$")
542+
set (module_sha256 "${value}")
543+
elseif (${key} MATCHES "^repository$")
544+
set (module_repository "${value}")
545+
elseif (${key} MATCHES "^branch$")
546+
set (module_branch "${value}")
547+
elseif (${key} MATCHES "^submodules$")
548+
_yup_boolean_property ("${value}" module_submodules)
366549
endif()
367550
endforeach()
368551

369552
_yup_set_default (module_cpp_standard "20")
370553
_yup_set_default (module_arc_enabled OFF)
371554
_yup_set_default (module_needs_python OFF)
555+
_yup_set_default (module_submodules ON)
372556
_yup_resolve_variable_paths ("${module_searchpaths}" module_searchpaths)
373557

558+
set (module_upstream_target "")
559+
if (module_upstream OR module_repository)
560+
_yup_module_upstream_has_content ("${module_name}" "${module_path}" upstream_has_content)
561+
if (NOT upstream_has_content)
562+
if (YUP_FETCH_UPSTREAM_MODULES)
563+
_yup_module_fetch_upstream ("${module_name}" "${module_path}" "${module_upstream}" "${module_sha256}" "${module_repository}" "${module_branch}" "${module_submodules}" module_upstream_target)
564+
else()
565+
_yup_message (WARNING "Upstream sources for ${module_name} are missing and YUP_FETCH_UPSTREAM_MODULES is OFF")
566+
endif()
567+
endif()
568+
endif()
569+
374570
# ==== Setup Platform-Specific Configurations
375571
if (YUP_PLATFORM_IOS)
376572
if (module_appleCppStandard)
@@ -513,11 +709,24 @@ function (yup_add_module module_path modules_definitions module_group)
513709
get_filename_component (module_include_path ${module_path} DIRECTORY)
514710
list (APPEND module_include_paths "${module_include_path}")
515711

712+
if (module_upstream OR module_repository)
713+
_yup_module_get_upstream_path ("${module_name}" "${module_path}" module_upstream_path)
714+
if (module_upstream_path)
715+
list (APPEND module_include_paths "${module_upstream_path}")
716+
else()
717+
list (APPEND module_include_paths "${CMAKE_BINARY_DIR}/externals/${module_name}/upstream")
718+
endif()
719+
endif()
720+
516721
foreach (searchpath IN LISTS module_searchpaths)
517722
if (EXISTS "${searchpath}")
518723
list (APPEND module_include_paths "${searchpath}")
519724
elseif (EXISTS "${module_path}/${searchpath}")
520725
list (APPEND module_include_paths "${module_path}/${searchpath}")
726+
elseif (module_upstream_path AND EXISTS "${module_upstream_path}/${searchpath}")
727+
list (APPEND module_include_paths "${module_upstream_path}/${searchpath}")
728+
elseif (module_upstream OR module_repository)
729+
list (APPEND module_include_paths "${CMAKE_BINARY_DIR}/externals/${module_name}/upstream/${searchpath}")
521730
endif()
522731
endforeach()
523732

@@ -558,6 +767,10 @@ function (yup_add_module module_path modules_definitions module_group)
558767
"${module_dependencies}"
559768
"${module_arc_enabled}")
560769

770+
if (module_upstream_target)
771+
add_dependencies (${module_name} "${module_upstream_target}")
772+
endif()
773+
561774
#set (${module_name}_Configs "${module_user_configs}")
562775
#set (${module_name}_Configs ${${module_name}_Configs} PARENT_SCOPE)
563776

@@ -621,6 +834,9 @@ macro (yup_add_default_modules modules_path)
621834
yup_add_module (${modules_path}/thirdparty/oboe_library "${modules_definitions}" ${thirdparty_group})
622835
yup_add_module (${modules_path}/thirdparty/pffft_library "${modules_definitions}" ${thirdparty_group})
623836
yup_add_module (${modules_path}/thirdparty/dr_libs "${modules_definitions}" ${thirdparty_group})
837+
yup_add_module (${modules_path}/thirdparty/opus_library "${modules_definitions}" ${thirdparty_group})
838+
yup_add_module (${modules_path}/thirdparty/flac_library "${modules_definitions}" ${thirdparty_group})
839+
yup_add_module (${modules_path}/thirdparty/hmp3_library "${modules_definitions}" ${thirdparty_group})
624840

625841
# ==== Yup modules
626842
set (modules_group "Modules")

cmake/yup_utilities.cmake

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,37 @@ function (_yup_resolve_variable_path input_path output_variable)
203203
set (${output_variable} "${input_path}" PARENT_SCOPE)
204204
endfunction()
205205

206+
#==============================================================================
207+
208+
function (_yup_collect_upstream_candidate_paths module_name module_path output_variable)
209+
set (candidate_paths "${module_path}/upstream")
210+
211+
if (DEFINED YUP_UPSTREAM_ROOT AND NOT "${YUP_UPSTREAM_ROOT}" STREQUAL "")
212+
list (APPEND candidate_paths "${YUP_UPSTREAM_ROOT}/${module_name}/upstream")
213+
endif()
214+
215+
if (CMAKE_SOURCE_DIR)
216+
list (APPEND candidate_paths "${CMAKE_SOURCE_DIR}/build/externals/${module_name}/upstream")
217+
list (APPEND candidate_paths "${CMAKE_SOURCE_DIR}/../build/externals/${module_name}/upstream")
218+
endif()
219+
220+
set (candidate_root "${CMAKE_BINARY_DIR}")
221+
set (max_depth 10)
222+
while (max_depth GREATER 0)
223+
list (APPEND candidate_paths "${candidate_root}/externals/${module_name}/upstream")
224+
225+
get_filename_component (candidate_parent "${candidate_root}" DIRECTORY)
226+
if ("${candidate_parent}" STREQUAL "${candidate_root}")
227+
break()
228+
endif()
229+
230+
set (candidate_root "${candidate_parent}")
231+
math (EXPR max_depth "${max_depth} - 1")
232+
endwhile()
233+
234+
set (${output_variable} "${candidate_paths}" PARENT_SCOPE)
235+
endfunction()
236+
206237
function (_yup_resolve_variable_paths input_list output_list)
207238
set (resolved_list "")
208239

docs/YUP Module Format.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ Possible values:
135135
- (Optional) A list (space or comma-separated) of macro defines needed by this module.
136136

137137
- searchpaths
138-
- (Optional) A space-separated list of internal include paths, relative to the module's parent folder, which need to be added to a project's header search path.
138+
- (Optional) A space-separated list of internal include paths, relative to the module's parent folder or the upstream checkout folder, which need to be added to a project's header search path.
139139

140140
- [android|apple|ios|linux|mobile|msft|osx|wasm|win32|windows]CppStandard
141141
- (Optional) A number indicating the minimum C++ language standard that is required for this module and this platform exclusively. This must be just the standard number with no prefix e.g. 20 for C++20.
@@ -156,7 +156,7 @@ Possible values:
156156
- (Optional) A list (space or comma-separated) of link options needed by this module in a build.
157157

158158
- [android|apple|ios|linux|mobile|msft|osx|wasm|win32|windows]Searchpaths
159-
- (Optional) A space-separated list of internal include paths, relative to the module's parent folder, which need to be added to a project's header search path.
159+
- (Optional) A space-separated list of internal include paths, relative to the module's parent folder or the upstream checkout folder, which need to be added to a project's header search path.
160160

161161
- [ios|osx|apple]Frameworks
162162
- (Optional) A list (space or comma-separated) of iOS/macOS/Apple frameworks that are needed by this module.

docs/images/yup_audio_scope.png

183 KB
Loading

examples/graphics/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ yup_standalone_app (
7474
yup::yup_audio_processors
7575
yup::yup_audio_formats
7676
pffft_library
77+
opus_library
78+
flac_library
79+
hmp3_library
7780
dr_libs
7881
libpng
7982
libwebp
577 KB
Binary file not shown.
164 KB
Binary file not shown.

0 commit comments

Comments
 (0)