@libraz/libsonare 1.7.2 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/NOTICE +178 -0
  2. package/README.md +26 -203
  3. package/dist/_chain_config.d.ts +14 -0
  4. package/dist/_chain_config.d.ts.map +1 -0
  5. package/dist/_effects_common.d.ts +6 -0
  6. package/dist/_effects_common.d.ts.map +1 -0
  7. package/dist/_feature_validation.d.ts +8 -0
  8. package/dist/_feature_validation.d.ts.map +1 -0
  9. package/dist/_fft_options.d.ts +24 -0
  10. package/dist/_fft_options.d.ts.map +1 -0
  11. package/dist/align_take.d.ts +50 -0
  12. package/dist/align_take.d.ts.map +1 -0
  13. package/dist/analysis.d.ts +29 -5840
  14. package/dist/analysis.d.ts.map +1 -0
  15. package/dist/analysis.js +873 -722
  16. package/dist/analysis.js.map +1 -1
  17. package/dist/analysis_helpers.d.ts +9 -0
  18. package/dist/analysis_helpers.d.ts.map +1 -0
  19. package/dist/audio.d.ts +163 -0
  20. package/dist/audio.d.ts.map +1 -0
  21. package/dist/clip_page_streamer.d.ts +133 -0
  22. package/dist/clip_page_streamer.d.ts.map +1 -0
  23. package/dist/codes.d.ts +44 -0
  24. package/dist/codes.d.ts.map +1 -0
  25. package/dist/effects_mastering.d.ts +23 -0
  26. package/dist/effects_mastering.d.ts.map +1 -0
  27. package/dist/effects_note_ops.d.ts +477 -0
  28. package/dist/effects_note_ops.d.ts.map +1 -0
  29. package/dist/effects_percussive.d.ts +185 -0
  30. package/dist/effects_percussive.d.ts.map +1 -0
  31. package/dist/effects_separation.d.ts +65 -0
  32. package/dist/effects_separation.d.ts.map +1 -0
  33. package/dist/effects_spectral.d.ts +28 -0
  34. package/dist/effects_spectral.d.ts.map +1 -0
  35. package/dist/effects_timepitch.d.ts +129 -0
  36. package/dist/effects_timepitch.d.ts.map +1 -0
  37. package/dist/effects_voice_change.d.ts +53 -0
  38. package/dist/effects_voice_change.d.ts.map +1 -0
  39. package/dist/errors.d.ts +51 -0
  40. package/dist/errors.d.ts.map +1 -0
  41. package/dist/feature_core.d.ts +341 -0
  42. package/dist/feature_core.d.ts.map +1 -0
  43. package/dist/feature_decompose.d.ts +278 -0
  44. package/dist/feature_decompose.d.ts.map +1 -0
  45. package/dist/feature_inverse.d.ts +128 -0
  46. package/dist/feature_inverse.d.ts.map +1 -0
  47. package/dist/feature_loudness.d.ts +66 -0
  48. package/dist/feature_loudness.d.ts.map +1 -0
  49. package/dist/feature_music.d.ts +307 -0
  50. package/dist/feature_music.d.ts.map +1 -0
  51. package/dist/feature_pitch.d.ts +108 -0
  52. package/dist/feature_pitch.d.ts.map +1 -0
  53. package/dist/feature_resample.d.ts +16 -0
  54. package/dist/feature_resample.d.ts.map +1 -0
  55. package/dist/feature_spectral.d.ts +137 -0
  56. package/dist/feature_spectral.d.ts.map +1 -0
  57. package/dist/feature_spectrogram.d.ts +198 -0
  58. package/dist/feature_spectrogram.d.ts.map +1 -0
  59. package/dist/features.d.ts +10 -0
  60. package/dist/features.d.ts.map +1 -0
  61. package/dist/hrtf/default.shrf +0 -0
  62. package/dist/index.d.ts +74 -7431
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +3758 -1362
  65. package/dist/index.js.map +1 -1
  66. package/dist/instrument_types.d.ts +517 -0
  67. package/dist/instrument_types.d.ts.map +1 -0
  68. package/dist/live_audio.d.ts +35 -0
  69. package/dist/live_audio.d.ts.map +1 -0
  70. package/dist/mastering_chain.d.ts +213 -0
  71. package/dist/mastering_chain.d.ts.map +1 -0
  72. package/dist/mastering_core.d.ts +457 -0
  73. package/dist/mastering_core.d.ts.map +1 -0
  74. package/dist/mastering_dynamics.d.ts +80 -0
  75. package/dist/mastering_dynamics.d.ts.map +1 -0
  76. package/dist/metering.d.ts +287 -0
  77. package/dist/metering.d.ts.map +1 -0
  78. package/dist/mixer.d.ts +464 -0
  79. package/dist/mixer.d.ts.map +1 -0
  80. package/dist/mixing_assistant.d.ts +62 -0
  81. package/dist/mixing_assistant.d.ts.map +1 -0
  82. package/dist/mixing_oneshot.d.ts +40 -0
  83. package/dist/mixing_oneshot.d.ts.map +1 -0
  84. package/dist/module_state.d.ts +15 -0
  85. package/dist/module_state.d.ts.map +1 -0
  86. package/dist/opfs_clip_pages.d.ts +28 -0
  87. package/dist/opfs_clip_pages.d.ts.map +1 -0
  88. package/dist/playback_renderer.d.ts +128 -0
  89. package/dist/playback_renderer.d.ts.map +1 -0
  90. package/dist/polyphony.d.ts +202 -0
  91. package/dist/polyphony.d.ts.map +1 -0
  92. package/dist/project.d.ts +8 -0
  93. package/dist/project.d.ts.map +1 -0
  94. package/dist/project_class.d.ts +562 -0
  95. package/dist/project_class.d.ts.map +1 -0
  96. package/dist/project_internal.d.ts +194 -0
  97. package/dist/project_internal.d.ts.map +1 -0
  98. package/dist/project_synth.d.ts +74 -0
  99. package/dist/project_synth.d.ts.map +1 -0
  100. package/dist/project_types.d.ts +652 -0
  101. package/dist/project_types.d.ts.map +1 -0
  102. package/dist/public_types.d.ts +185 -0
  103. package/dist/public_types.d.ts.map +1 -0
  104. package/dist/public_types_acoustic.d.ts +215 -0
  105. package/dist/public_types_acoustic.d.ts.map +1 -0
  106. package/dist/public_types_mastering.d.ts +510 -0
  107. package/dist/public_types_mastering.d.ts.map +1 -0
  108. package/dist/public_types_mixing.d.ts +436 -0
  109. package/dist/public_types_mixing.d.ts.map +1 -0
  110. package/dist/public_types_music.d.ts +619 -0
  111. package/dist/public_types_music.d.ts.map +1 -0
  112. package/dist/public_types_playback.d.ts +164 -0
  113. package/dist/public_types_playback.d.ts.map +1 -0
  114. package/dist/public_types_realtime.d.ts +174 -0
  115. package/dist/public_types_realtime.d.ts.map +1 -0
  116. package/dist/public_types_repair.d.ts +424 -0
  117. package/dist/public_types_repair.d.ts.map +1 -0
  118. package/dist/public_types_spectral.d.ts +697 -0
  119. package/dist/public_types_spectral.d.ts.map +1 -0
  120. package/dist/quick_analysis.d.ts +445 -0
  121. package/dist/quick_analysis.d.ts.map +1 -0
  122. package/dist/realtime_engine.d.ts +850 -0
  123. package/dist/realtime_engine.d.ts.map +1 -0
  124. package/dist/realtime_voice_changer.d.ts +158 -0
  125. package/dist/realtime_voice_changer.d.ts.map +1 -0
  126. package/dist/repair_dereverb.d.ts +187 -0
  127. package/dist/repair_dereverb.d.ts.map +1 -0
  128. package/dist/repair_impulsive.d.ts +186 -0
  129. package/dist/repair_impulsive.d.ts.map +1 -0
  130. package/dist/repair_noise.d.ts +239 -0
  131. package/dist/repair_noise.d.ts.map +1 -0
  132. package/dist/repair_trim.d.ts +123 -0
  133. package/dist/repair_trim.d.ts.map +1 -0
  134. package/dist/sample_bank.d.ts +84 -0
  135. package/dist/sample_bank.d.ts.map +1 -0
  136. package/dist/scale.d.ts +10 -0
  137. package/dist/scale.d.ts.map +1 -0
  138. package/dist/schemas/mixer-scene.schema.json +393 -0
  139. package/dist/schemas/playback-renderer-config.schema.json +392 -0
  140. package/dist/sonare-analysis.d.ts +8 -0
  141. package/dist/sonare-analysis.js +2 -2
  142. package/dist/sonare-analysis.wasm +0 -0
  143. package/dist/sonare.d.ts +3909 -0
  144. package/dist/sonare.js +2 -2
  145. package/dist/sonare.wasm +0 -0
  146. package/dist/stream_analyzer.d.ts +163 -0
  147. package/dist/stream_analyzer.d.ts.map +1 -0
  148. package/dist/stream_types.d.ts +214 -0
  149. package/dist/stream_types.d.ts.map +1 -0
  150. package/dist/streaming_mixing.d.ts +6 -0
  151. package/dist/streaming_mixing.d.ts.map +1 -0
  152. package/dist/streaming_processors.d.ts +335 -0
  153. package/dist/streaming_processors.d.ts.map +1 -0
  154. package/dist/transcribe.d.ts +77 -0
  155. package/dist/transcribe.d.ts.map +1 -0
  156. package/dist/validation.d.ts +140 -0
  157. package/dist/validation.d.ts.map +1 -0
  158. package/dist/web_midi.d.ts +77 -0
  159. package/dist/web_midi.d.ts.map +1 -0
  160. package/dist/worker.d.ts +5 -48
  161. package/dist/worker.d.ts.map +1 -0
  162. package/dist/worker.js +94 -41
  163. package/dist/worker.js.map +1 -1
  164. package/dist/worker_client.d.ts +96 -0
  165. package/dist/worker_client.d.ts.map +1 -0
  166. package/dist/worker_protocol.d.ts +43 -0
  167. package/dist/worker_protocol.d.ts.map +1 -0
  168. package/dist/worklet/audio_types.d.ts +21 -0
  169. package/dist/worklet/audio_types.d.ts.map +1 -0
  170. package/dist/worklet/engine-automation.d.ts +29 -0
  171. package/dist/worklet/engine-automation.d.ts.map +1 -0
  172. package/dist/worklet/engine-capture-facade.d.ts +35 -0
  173. package/dist/worklet/engine-capture-facade.d.ts.map +1 -0
  174. package/dist/worklet/engine-clips.d.ts +23 -0
  175. package/dist/worklet/engine-clips.d.ts.map +1 -0
  176. package/dist/worklet/engine-markers.d.ts +40 -0
  177. package/dist/worklet/engine-markers.d.ts.map +1 -0
  178. package/dist/worklet/engine-mixer-facade.d.ts +128 -0
  179. package/dist/worklet/engine-mixer-facade.d.ts.map +1 -0
  180. package/dist/worklet/engine-node.d.ts +81 -0
  181. package/dist/worklet/engine-node.d.ts.map +1 -0
  182. package/dist/worklet/engine-offline.d.ts +81 -0
  183. package/dist/worklet/engine-offline.d.ts.map +1 -0
  184. package/dist/worklet/engine-options.d.ts +12 -0
  185. package/dist/worklet/engine-options.d.ts.map +1 -0
  186. package/dist/worklet/engine-parameter-facade.d.ts +106 -0
  187. package/dist/worklet/engine-parameter-facade.d.ts.map +1 -0
  188. package/dist/worklet/engine-processor.d.ts +68 -0
  189. package/dist/worklet/engine-processor.d.ts.map +1 -0
  190. package/dist/worklet/engine-register.d.ts +2 -0
  191. package/dist/worklet/engine-register.d.ts.map +1 -0
  192. package/dist/worklet/engine-strips.d.ts +73 -0
  193. package/dist/worklet/engine-strips.d.ts.map +1 -0
  194. package/dist/worklet/engine-sync.d.ts +37 -0
  195. package/dist/worklet/engine-sync.d.ts.map +1 -0
  196. package/dist/worklet/engine-tempo-facade.d.ts +48 -0
  197. package/dist/worklet/engine-tempo-facade.d.ts.map +1 -0
  198. package/dist/worklet/engine.d.ts +397 -0
  199. package/dist/worklet/engine.d.ts.map +1 -0
  200. package/dist/worklet/guards.d.ts +47 -0
  201. package/dist/worklet/guards.d.ts.map +1 -0
  202. package/dist/worklet/messages.d.ts +710 -0
  203. package/dist/worklet/messages.d.ts.map +1 -0
  204. package/dist/worklet/mixer-processor.d.ts +46 -0
  205. package/dist/worklet/mixer-processor.d.ts.map +1 -0
  206. package/dist/worklet/playback-processor.d.ts +62 -0
  207. package/dist/worklet/playback-processor.d.ts.map +1 -0
  208. package/dist/worklet/protocol.d.ts +323 -0
  209. package/dist/worklet/protocol.d.ts.map +1 -0
  210. package/dist/worklet/voice-changer-processor.d.ts +41 -0
  211. package/dist/worklet/voice-changer-processor.d.ts.map +1 -0
  212. package/dist/worklet.d.ts +16 -2515
  213. package/dist/worklet.d.ts.map +1 -0
  214. package/dist/worklet.js +2763 -501
  215. package/dist/worklet.js.map +1 -1
  216. package/package.json +23 -12
  217. package/src/_effects_common.ts +17 -0
  218. package/src/_feature_validation.ts +34 -0
  219. package/src/_fft_options.ts +39 -0
  220. package/src/align_take.ts +64 -0
  221. package/src/analysis.ts +56 -3
  222. package/src/analysis_helpers.ts +7 -0
  223. package/src/audio.ts +106 -3
  224. package/src/codes.ts +39 -2
  225. package/src/effects_mastering.ts +97 -22
  226. package/src/effects_note_ops.ts +635 -0
  227. package/src/effects_percussive.ts +217 -0
  228. package/src/effects_separation.ts +150 -0
  229. package/src/effects_spectral.ts +60 -0
  230. package/src/effects_timepitch.ts +377 -0
  231. package/src/errors.ts +23 -1
  232. package/src/feature_core.ts +127 -2
  233. package/src/feature_decompose.ts +633 -0
  234. package/src/feature_inverse.ts +454 -0
  235. package/src/feature_loudness.ts +125 -0
  236. package/src/feature_music.ts +107 -14
  237. package/src/feature_pitch.ts +96 -1
  238. package/src/feature_spectral.ts +16 -611
  239. package/src/feature_spectrogram.ts +63 -450
  240. package/src/features.ts +36 -22
  241. package/src/index.ts +282 -30
  242. package/src/instrument_types.ts +645 -0
  243. package/src/live_audio.ts +27 -1
  244. package/src/mastering_chain.ts +184 -0
  245. package/src/mastering_core.ts +346 -32
  246. package/src/mastering_dynamics.ts +22 -11
  247. package/src/metering.ts +67 -24
  248. package/src/mixer.ts +212 -3
  249. package/src/mixing_assistant.ts +138 -0
  250. package/src/mixing_oneshot.ts +10 -5
  251. package/src/module_state.ts +24 -2
  252. package/src/playback_renderer.ts +252 -0
  253. package/src/polyphony.ts +279 -0
  254. package/src/project.ts +61 -24
  255. package/src/project_class.ts +450 -27
  256. package/src/project_internal.ts +149 -42
  257. package/src/project_synth.ts +67 -1
  258. package/src/project_types.ts +268 -270
  259. package/src/public_types.ts +122 -3
  260. package/src/public_types_acoustic.ts +112 -3
  261. package/src/public_types_mastering.ts +254 -73
  262. package/src/public_types_mixing.ts +363 -1
  263. package/src/public_types_music.ts +312 -2
  264. package/src/public_types_playback.ts +195 -0
  265. package/src/public_types_realtime.ts +39 -7
  266. package/src/public_types_repair.ts +446 -0
  267. package/src/public_types_spectral.ts +487 -1
  268. package/src/quick_analysis.ts +203 -26
  269. package/src/realtime_engine.ts +711 -28
  270. package/src/realtime_voice_changer.ts +55 -1
  271. package/src/repair_dereverb.ts +299 -0
  272. package/src/repair_impulsive.ts +395 -0
  273. package/src/repair_noise.ts +425 -0
  274. package/src/repair_trim.ts +226 -0
  275. package/src/sample_bank.ts +113 -0
  276. package/src/sonare.js.d.ts +1122 -30
  277. package/src/stream_analyzer.ts +36 -4
  278. package/src/stream_types.ts +37 -0
  279. package/src/streaming_mixing.ts +1 -1
  280. package/src/streaming_processors.ts +194 -10
  281. package/src/transcribe.ts +89 -0
  282. package/src/validation.ts +285 -11
  283. package/src/web_midi.ts +1 -6
  284. package/src/worker.ts +18 -2
  285. package/src/worklet/audio_types.ts +37 -0
  286. package/src/worklet/engine-mixer-facade.ts +444 -10
  287. package/src/worklet/engine-node.ts +78 -26
  288. package/src/worklet/engine-offline.ts +14 -8
  289. package/src/worklet/engine-parameter-facade.ts +21 -0
  290. package/src/worklet/engine-processor.ts +272 -83
  291. package/src/worklet/engine-register.ts +32 -18
  292. package/src/worklet/engine-strips.ts +280 -9
  293. package/src/worklet/engine-sync.ts +14 -6
  294. package/src/worklet/engine.ts +365 -31
  295. package/src/worklet/guards.ts +140 -44
  296. package/src/worklet/messages.ts +227 -2
  297. package/src/worklet/mixer-processor.ts +109 -47
  298. package/src/worklet/playback-processor.ts +300 -0
  299. package/src/worklet/protocol.ts +53 -3
  300. package/src/worklet/voice-changer-processor.ts +17 -11
  301. package/src/worklet.ts +17 -0
  302. package/src/effects_transform.ts +0 -718
  303. package/src/mastering_repair.ts +0 -273
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@libraz/libsonare",
3
- "version": "1.7.2",
3
+ "version": "1.8.0",
4
4
  "type": "module",
5
5
  "packageManager": "yarn@4.18.0",
6
6
  "description": "Audio analysis, mastering, mixing, and MIDI synthesis in WebAssembly",
@@ -26,33 +26,42 @@
26
26
  "./wasm": "./dist/sonare.wasm",
27
27
  "./schemas/realtime-voice-changer-preset.schema.json": "./dist/schemas/realtime-voice-changer-preset.schema.json",
28
28
  "./schemas/realtime-voice-changer-preset-pack.schema.json": "./dist/schemas/realtime-voice-changer-preset-pack.schema.json",
29
+ "./schemas/mixer-scene.schema.json": "./dist/schemas/mixer-scene.schema.json",
30
+ "./schemas/playback-renderer-config.schema.json": "./dist/schemas/playback-renderer-config.schema.json",
31
+ "./hrtf/default.shrf": "./dist/hrtf/default.shrf",
29
32
  "./package.json": "./package.json"
30
33
  },
31
34
  "files": [
32
35
  "dist",
33
- "src"
36
+ "src",
37
+ "NOTICE",
38
+ "!dist/*.sources.json"
34
39
  ],
35
40
  "sideEffects": false,
36
41
  "scripts": {
37
42
  "build": "yarn build:wasm && yarn build:js",
38
43
  "build:wasm": "yarn build:wasm:full && yarn build:wasm:analysis",
39
- "build:wasm:full": "mkdir -p build-wasm/em-cache && EM_NODE_JS=\"$(mise which node 2>/dev/null || command -v node)\" EM_CACHE=$PWD/build-wasm/em-cache emcmake cmake -S ../.. -B build-wasm -DBUILD_WASM=ON -DSONARE_WASM_ANALYSIS_ONLY=OFF -DSONARE_WASM_OUTPUT_NAME=sonare -DBUILD_MASTERING=ON -DBUILD_MIXING=ON -DBUILD_GRAPH=ON -DBUILD_FX=ON -DBUILD_ACOUSTIC_SIM=ON -DBUILD_PITCH_EDITOR=ON -DBUILD_VOICE_CHANGER=ON -DBUILD_ARRANGEMENT=ON -DBUILD_ASSIST=ON -DCMAKE_BUILD_TYPE=Release && EM_NODE_JS=\"$(mise which node 2>/dev/null || command -v node)\" EM_CACHE=$PWD/build-wasm/em-cache cmake --build build-wasm",
40
- "build:wasm:analysis": "mkdir -p build-wasm-analysis/em-cache && EM_NODE_JS=\"$(mise which node 2>/dev/null || command -v node)\" EM_CACHE=$PWD/build-wasm-analysis/em-cache emcmake cmake -S ../.. -B build-wasm-analysis -DBUILD_WASM=ON -DSONARE_WASM_ANALYSIS_ONLY=ON -DSONARE_WASM_OUTPUT_NAME=sonare-analysis -DBUILD_MASTERING=OFF -DBUILD_MIXING=OFF -DBUILD_GRAPH=OFF -DBUILD_FX=OFF -DBUILD_ACOUSTIC_SIM=OFF -DBUILD_VOICE_CHANGER=OFF -DBUILD_ARRANGEMENT=OFF -DBUILD_ASSIST=OFF -DCMAKE_BUILD_TYPE=Release && EM_NODE_JS=\"$(mise which node 2>/dev/null || command -v node)\" EM_CACHE=$PWD/build-wasm-analysis/em-cache cmake --build build-wasm-analysis --target sonare",
44
+ "build:wasm:full": "mkdir -p build-wasm/em-cache && EM_NODE_JS=\"$(mise which node 2>/dev/null || command -v node)\" EM_CACHE=$PWD/build-wasm/em-cache emcmake cmake -S ../.. -B build-wasm -DBUILD_WASM=ON -DSONARE_WASM_ANALYSIS_ONLY=OFF -DSONARE_WASM_OUTPUT_NAME=sonare -DBUILD_MASTERING=ON -DBUILD_MIXING=ON -DBUILD_MIXING_ASSISTANT=ON -DBUILD_GRAPH=ON -DBUILD_FX=ON -DBUILD_ACOUSTIC_SIM=ON -DBUILD_PITCH_EDITOR=ON -DBUILD_VOICE_CHANGER=ON -DBUILD_ARRANGEMENT=ON -DBUILD_ASSIST=ON -DCMAKE_BUILD_TYPE=Release && EM_NODE_JS=\"$(mise which node 2>/dev/null || command -v node)\" EM_CACHE=$PWD/build-wasm/em-cache cmake --build build-wasm && node scripts/dist-source-manifest.mjs --write sonare",
45
+ "build:wasm:analysis": "mkdir -p build-wasm-analysis/em-cache && EM_NODE_JS=\"$(mise which node 2>/dev/null || command -v node)\" EM_CACHE=$PWD/build-wasm-analysis/em-cache emcmake cmake -S ../.. -B build-wasm-analysis -DBUILD_WASM=ON -DSONARE_WASM_ANALYSIS_ONLY=ON -DSONARE_WASM_OUTPUT_NAME=sonare-analysis -DBUILD_MASTERING=OFF -DBUILD_MIXING=OFF -DBUILD_MIXING_ASSISTANT=OFF -DBUILD_GRAPH=OFF -DBUILD_FX=OFF -DBUILD_ACOUSTIC_SIM=OFF -DBUILD_VOICE_CHANGER=OFF -DBUILD_ARRANGEMENT=OFF -DBUILD_ASSIST=OFF -DCMAKE_BUILD_TYPE=Release && EM_NODE_JS=\"$(mise which node 2>/dev/null || command -v node)\" EM_CACHE=$PWD/build-wasm-analysis/em-cache cmake --build build-wasm-analysis --target sonare && node scripts/dist-source-manifest.mjs --write sonare-analysis",
46
+ "check:dist-freshness": "node scripts/dist-source-manifest.mjs",
41
47
  "check:wasm-size": "python3 ../../tools/check_wasm_size.py --baseline wasm-size-budget.json --artifact sonare.wasm=dist/sonare.wasm --artifact sonare-analysis.wasm=dist/sonare-analysis.wasm",
48
+ "check:wasm-size:record": "python3 ../../tools/check_wasm_size.py --baseline wasm-size-baseline.json --artifact sonare.wasm=dist/sonare.wasm --artifact sonare-analysis.wasm=dist/sonare-analysis.wasm --write-baseline",
42
49
  "bench:wasm:isp": "mkdir -p build-wasm-bench/em-cache /tmp/libsonare-wasm-bench && EM_CACHE=$PWD/build-wasm-bench/em-cache emcmake cmake -S ../.. -B build-wasm-bench -DBUILD_WASM=ON -DBUILD_MASTERING=ON -DBUILD_BENCH=ON -DBUILD_TESTING=OFF -DBUILD_CLI=OFF -DCMAKE_BUILD_TYPE=Release && EM_CACHE=$PWD/build-wasm-bench/em-cache cmake --build build-wasm-bench --target sonare_mastering_isp_bench && cp build-wasm-bench/bin/sonare_mastering_isp_bench.js /tmp/libsonare-wasm-bench/sonare_mastering_isp_bench.cjs && cp build-wasm-bench/bin/sonare_mastering_isp_bench.wasm /tmp/libsonare-wasm-bench/sonare_mastering_isp_bench.wasm && node /tmp/libsonare-wasm-bench/sonare_mastering_isp_bench.cjs",
50
+ "bench:wasm:playback": "mkdir -p build-wasm-bench/em-cache /tmp/libsonare-wasm-bench && EM_CACHE=$PWD/build-wasm-bench/em-cache emcmake cmake -S ../.. -B build-wasm-bench -DBUILD_WASM=ON -DBUILD_MASTERING=ON -DBUILD_MIXING=ON -DBUILD_ACOUSTIC_SIM=ON -DBUILD_PLAYBACK=ON -DBUILD_BENCH=ON -DBUILD_TESTING=OFF -DBUILD_CLI=OFF -DCMAKE_BUILD_TYPE=Release && EM_CACHE=$PWD/build-wasm-bench/em-cache cmake --build build-wasm-bench --target sonare_playback_binaural_bench && cp build-wasm-bench/bin/sonare_playback_binaural_bench.js /tmp/libsonare-wasm-bench/sonare_playback_binaural_bench.cjs && cp build-wasm-bench/bin/sonare_playback_binaural_bench.wasm /tmp/libsonare-wasm-bench/sonare_playback_binaural_bench.wasm && node /tmp/libsonare-wasm-bench/sonare_playback_binaural_bench.cjs",
43
51
  "bench:wasm:phase-vocoder": "mkdir -p build-wasm-bench/em-cache /tmp/libsonare-wasm-bench && EM_CACHE=$PWD/build-wasm-bench/em-cache emcmake cmake -S ../.. -B build-wasm-bench -DBUILD_WASM=ON -DBUILD_BENCH=ON -DBUILD_TESTING=OFF -DBUILD_CLI=OFF -DCMAKE_BUILD_TYPE=Release && EM_CACHE=$PWD/build-wasm-bench/em-cache cmake --build build-wasm-bench --target sonare_phase_vocoder_streaming_bench && cp build-wasm-bench/bin/sonare_phase_vocoder_streaming_bench.js /tmp/libsonare-wasm-bench/sonare_phase_vocoder_streaming_bench.cjs && cp build-wasm-bench/bin/sonare_phase_vocoder_streaming_bench.wasm /tmp/libsonare-wasm-bench/sonare_phase_vocoder_streaming_bench.wasm && node /tmp/libsonare-wasm-bench/sonare_phase_vocoder_streaming_bench.cjs",
44
- "build:js": "tsup && node scripts/copy-schemas.mjs",
52
+ "build:js": "tsup && yarn build:types && node scripts/copy-schemas.mjs && node scripts/copy-hrtf.mjs && node scripts/copy-module-types.mjs && node scripts/dist-source-manifest.mjs --write bundle",
53
+ "build:types": "node scripts/prune-dist-declarations.mjs && tsc -p tsconfig.json --emitDeclarationOnly",
45
54
  "clean": "rm -rf dist build-wasm build-wasm-analysis LICENSE",
46
55
  "lint": "biome check src/ tests/",
47
- "lint:fix": "biome check --write src/ tests/",
48
- "format": "biome format --write src/ tests/",
56
+ "lint:fix": "git ls-files -z -- 'src/**' 'tests/**' | xargs -0 biome check --write",
57
+ "format": "git ls-files -z -- 'src/**' 'tests/**' | xargs -0 biome format --write",
49
58
  "test": "vitest run",
50
- "test:types": "tsc --noEmit --ignoreConfig --strict --module ESNext --moduleResolution bundler --target ES2020 tests/typing/analysis-entry.ts tests/typing/worklet-capture-response.ts",
59
+ "test:types": "tsc --noEmit --ignoreConfig --strict --module ESNext --moduleResolution bundler --target ES2020 tests/typing/analysis-entry.ts tests/typing/dist-entry-shared-types.ts tests/typing/worklet-capture-response.ts && tsc --noEmit -p tsconfig.json && tsc -p tsconfig.test.json",
51
60
  "test:browser": "node scripts/audio-worklet-smoke.mjs",
52
61
  "test:browser:worker": "node scripts/offline-worker-smoke.mjs",
53
62
  "test:browser:boundary": "node scripts/boundary-smoke.mjs",
54
63
  "test:watch": "vitest",
55
- "prepublishOnly": "yarn clean && cp ../../LICENSE LICENSE && yarn build && yarn lint && yarn test && yarn test:types"
64
+ "prepublishOnly": "yarn clean && cp ../../LICENSE LICENSE && cp ../../NOTICE NOTICE && yarn build && yarn lint && yarn test && yarn test:types"
56
65
  },
57
66
  "keywords": [
58
67
  "audio",
@@ -90,10 +99,12 @@
90
99
  "node": ">=18.0.0"
91
100
  },
92
101
  "devDependencies": {
93
- "@biomejs/biome": "^2.4.16",
94
- "ajv": "^8.17.1",
102
+ "@biomejs/biome": "^2.5.13",
103
+ "@types/node": "^22.20.3",
104
+ "ajv": "^8.20.0",
95
105
  "tsup": "^8.5.1",
96
106
  "typescript": "^6.0.3",
97
- "vitest": "^4.1.8"
107
+ "vite": "^8.3.0",
108
+ "vitest": "^5.0.1"
98
109
  }
99
110
  }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Input conversion the effect families share.
3
+ */
4
+
5
+ import type { VoicedFlags } from './public_types';
6
+
7
+ // The embind layer reads the companion voicing array as Float32Array. A flag is
8
+ // a decision, not a magnitude: collapse to 1/0 on truthiness, which is the same
9
+ // reduction the Node facade applies, so both surfaces agree on every accepted
10
+ // input type.
11
+ export function toVoicedFloat32(voiced: VoicedFlags): Float32Array {
12
+ const out = new Float32Array(voiced.length);
13
+ for (let index = 0; index < voiced.length; index += 1) {
14
+ out[index] = voiced[index] ? 1 : 0;
15
+ }
16
+ return out;
17
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Input checks the spectrogram and inverse-transform entries share.
3
+ */
4
+
5
+ import type { ValidateOptions } from './validation';
6
+ import { assertFiniteScalar, assertPositiveInteger } from './validation';
7
+
8
+ export type GuardedOptions = ValidateOptions;
9
+
10
+ export function validatePositiveIntegers(fnName: string, values: Record<string, number>): void {
11
+ for (const [name, value] of Object.entries(values)) {
12
+ assertPositiveInteger(fnName, value, name);
13
+ }
14
+ }
15
+
16
+ export function validateMelFrequencyRange(
17
+ fnName: string,
18
+ fmin: number,
19
+ fmax: number,
20
+ sampleRate: number,
21
+ ): void {
22
+ assertFiniteScalar(fnName, fmin, 'fmin');
23
+ assertFiniteScalar(fnName, fmax, 'fmax');
24
+ if (fmin < 0) {
25
+ throw new RangeError(`${fnName}: fmin must be non-negative`);
26
+ }
27
+ if (fmax < 0) {
28
+ throw new RangeError(`${fnName}: fmax must be non-negative`);
29
+ }
30
+ const effectiveFmax = fmax === 0 ? sampleRate / 2 : fmax;
31
+ if (effectiveFmax <= fmin) {
32
+ throw new RangeError(`${fnName}: fmax must be greater than fmin`);
33
+ }
34
+ }
@@ -0,0 +1,39 @@
1
+ import {
2
+ assertEvenIntegerAtLeast,
3
+ assertIntegerValue,
4
+ assertPositiveInteger,
5
+ } from './validation.js';
6
+
7
+ /**
8
+ * The facade's single FFT-size/hop domain.
9
+ *
10
+ * This module is deliberately internal: sibling facade modules import it, but
11
+ * nothing re-exports it, so it stays out of the package entry point and out of
12
+ * the C-ABI parity surface (which is defined by the index's re-export closure).
13
+ */
14
+
15
+ /**
16
+ * Resolves and validates the `nFft` / `hopLength` pair every STFT-backed entry
17
+ * point takes.
18
+ *
19
+ * The core FFT is mixed-radix, so any even size transforms exactly; only the
20
+ * real one-sided spectrum's `n_fft / 2 + 1` bin layout needs the evenness. A
21
+ * power-of-two restriction rejects sizes the C ABI and the native CLI accept,
22
+ * which is what a second copy of this rule used to do: `hpss({ nFft: 1536 })`
23
+ * worked while `hpssWithResidual({ nFft: 1536 })` threw, with the message
24
+ * asserting a constraint this project had explicitly written down as untrue.
25
+ * One implementation, so the two cannot disagree again.
26
+ */
27
+ export function resolveFftOptions(
28
+ fnName: string,
29
+ nFft: unknown,
30
+ hopLength: unknown,
31
+ ): { nFft: number; hopLength: number } {
32
+ const resolvedNFft = nFft === undefined ? 2048 : nFft;
33
+ const resolvedHopLength = hopLength === undefined ? 512 : hopLength;
34
+ assertIntegerValue(fnName, resolvedNFft, 'nFft');
35
+ assertEvenIntegerAtLeast(fnName, resolvedNFft, 'nFft', 2, 2 ** 30);
36
+ assertIntegerValue(fnName, resolvedHopLength, 'hopLength');
37
+ assertPositiveInteger(fnName, resolvedHopLength, 'hopLength');
38
+ return { nFft: resolvedNFft, hopLength: resolvedHopLength };
39
+ }
@@ -0,0 +1,64 @@
1
+ import { projectModule } from './project_internal';
2
+ import type { AlignTakeToReferenceRequest, AlignTakeToReferenceResult } from './project_types';
3
+ import { assertSampleRate, assertSamples } from './validation';
4
+
5
+ /**
6
+ * Aligns one take to a reference timeline and returns the warp anchors that place
7
+ * the take under it.
8
+ *
9
+ * A chromagram is measured for each signal and the two are aligned, then the
10
+ * alignment is reduced to anchors {@link Project.setWarpMap} accepts: at least
11
+ * two finite, strictly increasing pairs. The reduction is needed rather than
12
+ * decorative — an alignment path advances one axis at a time, so the raw
13
+ * correspondence repeats a coordinate wherever one signal carries more frames
14
+ * than the other, and those pairs are refused as a warp map.
15
+ *
16
+ * **The anchors are oriented for the take's own clip.** `warpSample` is a
17
+ * position on the REFERENCE timeline and `sourceSample` the corresponding
18
+ * position in the TAKE, which is the direction a clip whose source is that take
19
+ * needs. This is why the entry point exists rather than the core alignment
20
+ * primitive being exposed directly: that one names its arguments the other way
21
+ * round, so passing the reference as its reference yields the inverse map and
22
+ * nothing reports it.
23
+ *
24
+ * Both signals are read at `sampleRate`; resample first if they differ, since
25
+ * the alignment does no I/O and no rate conversion.
26
+ *
27
+ * {@link AlignTakeToReferenceResult.alignment} is descriptive only — it says how
28
+ * far the path strayed from a constant rate, so a caller can tell a take the
29
+ * reference genuinely fits from one it does not, and supplies its own threshold.
30
+ *
31
+ * @param request - The two signals, their shared sample rate, and the chroma
32
+ * resolution
33
+ * @returns The anchors and how well the alignment was conditioned
34
+ * @throws {RangeError} on an empty buffer, a non-finite sample, or a `sampleRate`
35
+ * outside `[8000, 384000]`
36
+ * @throws {SonareError} `InvalidParameter` on a non-positive `hopLength` or
37
+ * `binsPerOctave`, on a `binsPerOctave` that is not a multiple of 12, on a
38
+ * signal too short to measure two chroma frames, or when the two signals produce
39
+ * no pair of distinct anchors — which is what an unalignable pair looks like,
40
+ * and is reported rather than answered with a map you cannot use
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * const { anchors } = alignTakeToReference({ reference: guide, take, sampleRate });
45
+ * const project = new Project();
46
+ * const trackId = project.addTrack({ kind: 'audio' });
47
+ * const clipId = project.addClip({ trackId, lengthPpq: 64, audio: take, audioSampleRate: sampleRate }); // 16 bars at 4/4, in quarter notes (PPQ)
48
+ * project.setWarpMap({ id: 1, anchors });
49
+ * project.setClipWarpRef(clipId, 1);
50
+ * ```
51
+ */
52
+ export function alignTakeToReference(
53
+ request: AlignTakeToReferenceRequest,
54
+ ): AlignTakeToReferenceResult {
55
+ assertSamples('alignTakeToReference', request.reference, true, 'reference');
56
+ assertSamples('alignTakeToReference', request.take, true, 'take');
57
+ assertSampleRate('alignTakeToReference', request.sampleRate);
58
+ return projectModule().alignTakeToReference(
59
+ request.reference,
60
+ request.take,
61
+ request.sampleRate,
62
+ request,
63
+ );
64
+ }
package/src/analysis.ts CHANGED
@@ -12,11 +12,61 @@ import type { SonareModule } from './sonare.js';
12
12
 
13
13
  export { ErrorCode, isSonareError, SonareError } from './errors';
14
14
  export * from './feature_core';
15
+ // Several modules here also hold functions the analysis-only embind source set
16
+ // never registers, so those are re-exported by name rather than wholesale:
17
+ // `export *` published symbols that imported fine and then threw
18
+ // "is not a function" at call time, on a binary that never had them. Types stay
19
+ // wholesale — a type cannot fail to resolve. `analysis-entry.test.ts` guards
20
+ // these lists in one direction: every function the entry exports must be
21
+ // registered by the module it loads, so a name the analysis binary lacks fails
22
+ // as a test rather than at a caller's first call. The other direction is not
23
+ // guarded and a strict form of it would be wrong — the module also registers
24
+ // enums, emscripten internals and raw `_` / `Ex` variants this entry withholds
25
+ // deliberately — so a name dropped from a list below shrinks the published
26
+ // surface silently.
27
+ export type * from './feature_decompose';
28
+ export {
29
+ segmentAgglomerative,
30
+ segmentCrossSimilarity,
31
+ segmentLagToRecurrence,
32
+ segmentPathEnhance,
33
+ segmentRecurrenceMatrix,
34
+ segmentRecurrenceToLag,
35
+ segmentSubsegment,
36
+ } from './feature_decompose';
37
+ export type * from './feature_inverse';
38
+ export { griffinLim, melToAudio, melToStft, mfccToAudio, mfccToMel } from './feature_inverse';
39
+ export type * from './feature_loudness';
40
+ export { ebur128LoudnessRange, lufsInterleaved, lufsSeriesInterleaved } from './feature_loudness';
15
41
  export * from './feature_music';
16
42
  export * from './feature_pitch';
17
- export * from './feature_resample';
18
- export * from './feature_spectral';
19
- export * from './feature_spectrogram';
43
+ export type * from './feature_resample';
44
+ export type * from './feature_spectral';
45
+ export {
46
+ polyFeatures,
47
+ rmsEnergy,
48
+ spectralBandwidth,
49
+ spectralCentroid,
50
+ spectralContrast,
51
+ spectralFlatness,
52
+ spectralFlux,
53
+ spectralRolloff,
54
+ zeroCrossingRate,
55
+ zeroCrossings,
56
+ } from './feature_spectral';
57
+ export type * from './feature_spectrogram';
58
+ export {
59
+ bassChroma,
60
+ chroma,
61
+ chromaCens,
62
+ chromaCqt,
63
+ melDelta,
64
+ melSpectrogram,
65
+ mfcc,
66
+ reassignedSpectrogram,
67
+ stft,
68
+ stftDb,
69
+ } from './feature_spectrogram';
20
70
  export * from './metering';
21
71
  export * from './public_types';
22
72
  export type {
@@ -33,6 +83,8 @@ export type {
33
83
  DetectChordsRequest,
34
84
  DetectKeyRequest,
35
85
  DynamicsAnalysisResult,
86
+ DynamicsResult,
87
+ EstimateMeterRequest,
36
88
  MusicAnalyzeOptions,
37
89
  MusicAnalyzeRequest,
38
90
  RhythmAnalysisResult,
@@ -57,6 +109,7 @@ export {
57
109
  detectKey,
58
110
  detectKeyCandidates,
59
111
  detectOnsets,
112
+ estimateMeter,
60
113
  hasFfmpegSupport,
61
114
  } from './quick_analysis';
62
115
 
@@ -118,6 +118,7 @@ export function convertChordAnalysisResult(wasm: WasmChordAnalysisResult): Chord
118
118
  quality: c.quality as ChordQuality,
119
119
  start: c.start,
120
120
  end: c.end,
121
+ duration: c.end - c.start,
121
122
  confidence: c.confidence,
122
123
  name: c.name,
123
124
  })),
@@ -158,6 +159,10 @@ export function convertAnalysisResult(wasm: WasmAnalysisResult): AnalysisResult
158
159
  timeSignatureCandidates: wasm.timeSignatureCandidates,
159
160
  beatTimes,
160
161
  beats: wasm.beats,
162
+ downbeatIndices: wasm.downbeatIndices,
163
+ downbeatPhase: wasm.downbeatPhase,
164
+ beatObservations: wasm.beatObservations,
165
+ beatLocalBpm: wasm.beatLocalBpm,
161
166
  chords: wasm.chords.map((c) => ({
162
167
  root: c.root as PitchClass,
163
168
  bass: c.bass as PitchClass,
@@ -166,8 +171,10 @@ export function convertAnalysisResult(wasm: WasmAnalysisResult): AnalysisResult
166
171
  quality: c.quality as ChordQuality,
167
172
  start: c.start,
168
173
  end: c.end,
174
+ duration: c.end - c.start,
169
175
  confidence: c.confidence,
170
176
  name: c.name,
177
+ romanNumeral: c.romanNumeral,
171
178
  })),
172
179
  sections: wasm.sections.map((s) => ({
173
180
  type: s.type as SectionType,
package/src/audio.ts CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  } from './effects_mastering';
18
18
  import {
19
19
  chroma,
20
+ ebur128LoudnessRange,
20
21
  lufs,
21
22
  melSpectrogram,
22
23
  mfcc,
@@ -37,6 +38,26 @@ import {
37
38
  trim,
38
39
  zeroCrossingRate,
39
40
  } from './features';
41
+ import type {
42
+ ClippingReport,
43
+ DynamicRangeReport,
44
+ MeteringDetectClippingOptions,
45
+ MeteringDynamicRangeOptions,
46
+ SpectrumOptions,
47
+ SpectrumReport,
48
+ } from './metering';
49
+ import {
50
+ meteringCrestFactorDb,
51
+ meteringDcOffset,
52
+ meteringDetectClipping,
53
+ meteringDynamicRange,
54
+ meteringPeakDb,
55
+ meteringRmsDb,
56
+ meteringSilenceRatio,
57
+ meteringSpectrum,
58
+ meteringSpectrumFrame,
59
+ meteringTruePeakDb,
60
+ } from './metering';
40
61
  import { getSonareModule } from './module_state';
41
62
  import type {
42
63
  AnalysisResult,
@@ -63,6 +84,7 @@ import type {
63
84
  SoloProcessor,
64
85
  StftResult,
65
86
  } from './public_types';
87
+ import type { MusicAnalyzeOptions } from './quick_analysis';
66
88
  import {
67
89
  analyze,
68
90
  analyzeWithProgress,
@@ -76,6 +98,7 @@ import {
76
98
  detectOnsets,
77
99
  } from './quick_analysis';
78
100
  import type { ProgressCallback, WasmNnlsChromaResult } from './sonare.js';
101
+ import type { ValidateOptions } from './validation';
79
102
  import { validateAudioBuffer } from './validation';
80
103
 
81
104
  // ============================================================================
@@ -146,7 +169,14 @@ async function closeCreatedContext(context: BrowserDecodeContext): Promise<void>
146
169
  }
147
170
 
148
171
  /**
149
- * Wrapper around audio data that exposes all analysis and feature functions as instance methods.
172
+ * Wrapper around audio data that exposes analysis and feature functions as
173
+ * instance methods.
174
+ *
175
+ * Not every module-level function has a method here — `analyzeBpm`,
176
+ * `analyzeRhythm`, `analyzeDynamics`, `analyzeTimbre`, `analyzeImpulseResponse`
177
+ * and `detectAcoustic` are reachable as free functions only, and the Node
178
+ * facade exposes them as methods as well. Where a method does exist on both, it
179
+ * takes the same arguments.
150
180
  *
151
181
  * @example
152
182
  * ```typescript
@@ -302,8 +332,15 @@ export class Audio {
302
332
  return chordFunctionalAnalysis(this._samples, keyRoot, keyMode, this._sampleRate, options);
303
333
  }
304
334
 
305
- analyze(): AnalysisResult {
306
- return analyze(this._samples, this._sampleRate);
335
+ /**
336
+ * Full music analysis of the held buffer.
337
+ *
338
+ * Takes the same option bag as the module-level {@link analyze} and as the
339
+ * Node facade's `Audio.analyze`; this method used to drop it, so the same
340
+ * call was tunable on one binding and fixed at the defaults on the other.
341
+ */
342
+ analyze(options: MusicAnalyzeOptions = {}): AnalysisResult {
343
+ return analyze(this._samples, this._sampleRate, options);
307
344
  }
308
345
 
309
346
  analyzeWithProgress(onProgress: ProgressCallback): AnalysisResult {
@@ -517,4 +554,70 @@ export class Audio {
517
554
  resample(targetSr: number): Float32Array {
518
555
  return resample(this._samples, this._sampleRate, targetSr);
519
556
  }
557
+
558
+ // -- Metering --
559
+ //
560
+ // These delegate to the module-level buffer-form functions rather than a
561
+ // native handle: WASM's Audio is a plain JS wrapper around a Float32Array,
562
+ // not an embind class, so there is no cheaper path to reach the same
563
+ // measurement. The methods exist for call-shape parity with Node/Python,
564
+ // which do hold a native handle here.
565
+
566
+ peakDb(): number {
567
+ return meteringPeakDb(this._samples, this._sampleRate);
568
+ }
569
+
570
+ rmsDb(): number {
571
+ return meteringRmsDb(this._samples, this._sampleRate);
572
+ }
573
+
574
+ dcOffset(): number {
575
+ return meteringDcOffset(this._samples, this._sampleRate);
576
+ }
577
+
578
+ crestFactorDb(): number {
579
+ return meteringCrestFactorDb(this._samples, this._sampleRate);
580
+ }
581
+
582
+ silenceRatio(thresholdDb = -45, frameLength = 1024, hopLength = 256): number {
583
+ return meteringSilenceRatio(
584
+ this._samples,
585
+ this._sampleRate,
586
+ thresholdDb,
587
+ frameLength,
588
+ hopLength,
589
+ );
590
+ }
591
+
592
+ /**
593
+ * Inter-sample (true) peak in dBFS. `oversampleFactor` must be a power of two
594
+ * in [1, 16]; pass 0 to use the library default (4).
595
+ */
596
+ truePeakDb(oversampleFactor = 4): number {
597
+ return meteringTruePeakDb(this._samples, this._sampleRate, oversampleFactor);
598
+ }
599
+
600
+ detectClipping(options: MeteringDetectClippingOptions = {}): ClippingReport {
601
+ return meteringDetectClipping(this._samples, this._sampleRate, options);
602
+ }
603
+
604
+ dynamicRange(options: MeteringDynamicRangeOptions = {}): DynamicRangeReport {
605
+ return meteringDynamicRange(this._samples, this._sampleRate, options);
606
+ }
607
+
608
+ spectrum(options: SpectrumOptions & ValidateOptions = {}): SpectrumReport {
609
+ return meteringSpectrum(this._samples, this._sampleRate, options);
610
+ }
611
+
612
+ /**
613
+ * True single-frame magnitude / power / dB spectrum starting at `frameOffset`.
614
+ * See {@link meteringSpectrumFrame} for the frame-validation contract.
615
+ */
616
+ spectrumFrame(frameOffset = 0, options: SpectrumOptions & ValidateOptions = {}): SpectrumReport {
617
+ return meteringSpectrumFrame(this._samples, this._sampleRate, frameOffset, options);
618
+ }
619
+
620
+ ebur128LoudnessRange(): number {
621
+ return ebur128LoudnessRange(this._samples, this._sampleRate);
622
+ }
520
623
  }
package/src/codes.ts CHANGED
@@ -1,4 +1,12 @@
1
- import type { AutomationCurve, MeterTap, PanLawInput, PanMode, SendTiming } from './public_types';
1
+ import type { ProjectAutomationCurve } from './project_types';
2
+ import type {
3
+ AutomationCurve,
4
+ MeterTap,
5
+ PanLawInput,
6
+ PanMode,
7
+ SendTiming,
8
+ SidechainSourceKind,
9
+ } from './public_types';
2
10
 
3
11
  /** Resolve a numeric ordinal in an inclusive range without coercion. */
4
12
  export function resolveOrdinalInRange(
@@ -41,12 +49,30 @@ export function resolveEnumOrdinal(
41
49
  throw new RangeError(`Invalid ${enumName}: ${String(value)}`);
42
50
  }
43
51
 
44
- const AUTOMATION_CURVE_VALUES = {
52
+ /**
53
+ * Automation curve spellings and their `SonareAutomationCurve` ordinals.
54
+ *
55
+ * Single source of truth for the vocabulary: {@link AutomationCurve} and
56
+ * {@link ProjectAutomationCurve} are derived from these keys, so a spelling
57
+ * cannot be documented without resolving, or resolve without being documented.
58
+ */
59
+ export const AUTOMATION_CURVE_VALUES = {
45
60
  linear: 0,
46
61
  exponential: 1,
47
62
  hold: 2,
48
63
  's-curve': 3,
49
64
  } as const;
65
+
66
+ /**
67
+ * The Project facade additionally accepts the legacy `'scurve'` spelling for
68
+ * compatibility with project data written before `'s-curve'` was canonical.
69
+ * The Node package declares the same pair of tables, so a breakpoint accepted
70
+ * by one facade resolves to the same ordinal on the other.
71
+ */
72
+ export const PROJECT_AUTOMATION_CURVE_VALUES = {
73
+ ...AUTOMATION_CURVE_VALUES,
74
+ scurve: 3,
75
+ } as const;
50
76
  const PAN_LAW_VALUES: Readonly<Record<string, number>> = {
51
77
  const3db: 0,
52
78
  'const-3db': 0,
@@ -72,12 +98,18 @@ const PAN_MODE_VALUES = {
72
98
  } as const;
73
99
  const METER_TAP_VALUES = { preFader: 0, postFader: 1 } as const;
74
100
  const SEND_TIMING_VALUES = { postFader: 0, preFader: 1 } as const;
101
+ const SIDECHAIN_SOURCE_KIND_VALUES = { track: 0, bus: 1 } as const;
75
102
  const TRACK_MONITOR_MODE_VALUES = { off: 0, pfl: 1, afl: 2 } as const;
76
103
 
77
104
  export function automationCurveCode(curve: AutomationCurve): number {
78
105
  return resolveEnumOrdinal(curve, AUTOMATION_CURVE_VALUES, 'automation curve');
79
106
  }
80
107
 
108
+ /** Resolve a Project automation breakpoint curve, legacy spellings included. */
109
+ export function projectAutomationCurveCode(curve: ProjectAutomationCurve | undefined): number {
110
+ return resolveEnumOrdinal(curve ?? 'linear', PROJECT_AUTOMATION_CURVE_VALUES, 'automation curve');
111
+ }
112
+
81
113
  export function panLawCode(panLaw: PanLawInput): number {
82
114
  const normalized = typeof panLaw === 'string' ? panLaw.toLowerCase().replace(/_/g, '-') : panLaw;
83
115
  return resolveEnumOrdinal(normalized, PAN_LAW_VALUES, 'pan law');
@@ -101,6 +133,11 @@ export function sendTimingCode(timing: SendTiming | number): number {
101
133
  return resolveEnumOrdinal(timing, SEND_TIMING_VALUES, 'send timing');
102
134
  }
103
135
 
136
+ /** Resolve a sidechain source kind to its `SonareSidechainSourceKind` ordinal. */
137
+ export function sidechainSourceKindCode(kind: SidechainSourceKind | number): number {
138
+ return resolveEnumOrdinal(kind, SIDECHAIN_SOURCE_KIND_VALUES, 'sidechain source kind');
139
+ }
140
+
104
141
  /** Resolve a per-track PFL/AFL monitor mode to its C-ABI ordinal. */
105
142
  export function trackMonitorModeCode(mode: unknown): number {
106
143
  return resolveEnumOrdinal(mode, TRACK_MONITOR_MODE_VALUES, 'track monitor mode');