@siteed/audio-studio 3.0.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 (375) hide show
  1. package/CHANGELOG.md +535 -0
  2. package/LICENSE +21 -0
  3. package/README.md +167 -0
  4. package/android/build.gradle +143 -0
  5. package/android/src/androidTest/assets/chorus.wav +0 -0
  6. package/android/src/androidTest/assets/jfk.wav +0 -0
  7. package/android/src/androidTest/assets/osr_us_000_0010_8k.wav +0 -0
  8. package/android/src/androidTest/assets/recorder_hello_world.wav +0 -0
  9. package/android/src/androidTest/java/net/siteed/audiostudio/AudioProcessorInstrumentedTest.kt +197 -0
  10. package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderInstrumentedTest.kt +541 -0
  11. package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderPerformanceInstrumentedTest.kt +234 -0
  12. package/android/src/androidTest/java/net/siteed/audiostudio/integration/AudioFocusStrategyIntegrationTest.kt +332 -0
  13. package/android/src/androidTest/java/net/siteed/audiostudio/integration/BufferDurationIntegrationTest.kt +324 -0
  14. package/android/src/androidTest/java/net/siteed/audiostudio/integration/CompressedOnlyOutputTest.kt +253 -0
  15. package/android/src/androidTest/java/net/siteed/audiostudio/integration/DeviceDisconnectionFallbackTest.kt +218 -0
  16. package/android/src/androidTest/java/net/siteed/audiostudio/integration/EventEmissionIntervalTest.kt +120 -0
  17. package/android/src/androidTest/java/net/siteed/audiostudio/integration/M4aFormatTest.kt +345 -0
  18. package/android/src/androidTest/java/net/siteed/audiostudio/integration/OutputControlIntegrationTest.kt +340 -0
  19. package/android/src/androidTest/java/net/siteed/audiostudio/integration/PcmStreamingDurationTest.kt +252 -0
  20. package/android/src/androidTest/java/net/siteed/audiostudio/integration/README.md +95 -0
  21. package/android/src/androidTest/java/net/siteed/audiostudio/integration/run_integration_tests.sh +43 -0
  22. package/android/src/main/AndroidManifest.xml +30 -0
  23. package/android/src/main/CMakeLists.txt +29 -0
  24. package/android/src/main/java/net/siteed/audiostudio/AudioAnalysisData.kt +188 -0
  25. package/android/src/main/java/net/siteed/audiostudio/AudioDataEncoder.kt +9 -0
  26. package/android/src/main/java/net/siteed/audiostudio/AudioDeviceManager.kt +1741 -0
  27. package/android/src/main/java/net/siteed/audiostudio/AudioFeaturesNative.kt +26 -0
  28. package/android/src/main/java/net/siteed/audiostudio/AudioFileHandler.kt +136 -0
  29. package/android/src/main/java/net/siteed/audiostudio/AudioFormatUtils.kt +354 -0
  30. package/android/src/main/java/net/siteed/audiostudio/AudioNotificationsManager.kt +439 -0
  31. package/android/src/main/java/net/siteed/audiostudio/AudioProcessor.kt +2237 -0
  32. package/android/src/main/java/net/siteed/audiostudio/AudioRecorderManager.kt +2163 -0
  33. package/android/src/main/java/net/siteed/audiostudio/AudioRecordingService.kt +167 -0
  34. package/android/src/main/java/net/siteed/audiostudio/AudioStudioModule.kt +1112 -0
  35. package/android/src/main/java/net/siteed/audiostudio/AudioTrimmer.kt +1099 -0
  36. package/android/src/main/java/net/siteed/audiostudio/Constants.kt +37 -0
  37. package/android/src/main/java/net/siteed/audiostudio/EventSender.kt +7 -0
  38. package/android/src/main/java/net/siteed/audiostudio/FFT.kt +100 -0
  39. package/android/src/main/java/net/siteed/audiostudio/Features.kt +98 -0
  40. package/android/src/main/java/net/siteed/audiostudio/LogUtils.kt +93 -0
  41. package/android/src/main/java/net/siteed/audiostudio/MelSpectrogramNative.kt +36 -0
  42. package/android/src/main/java/net/siteed/audiostudio/NotificationConfig.kt +72 -0
  43. package/android/src/main/java/net/siteed/audiostudio/PermissionUtils.kt +68 -0
  44. package/android/src/main/java/net/siteed/audiostudio/RecordingActionReceiver.kt +59 -0
  45. package/android/src/main/java/net/siteed/audiostudio/RecordingConfig.kt +259 -0
  46. package/android/src/main/java/net/siteed/audiostudio/WaveformConfig.kt +19 -0
  47. package/android/src/main/java/net/siteed/audiostudio/WaveformRenderer.kt +159 -0
  48. package/android/src/main/jni/AudioFeaturesJNI.cpp +152 -0
  49. package/android/src/main/jni/MelSpectrogramJNI.cpp +165 -0
  50. package/android/src/main/res/drawable/ic_default_action_icon.xml +16 -0
  51. package/android/src/main/res/drawable/ic_microphone.xml +13 -0
  52. package/android/src/main/res/drawable/ic_pause.xml +10 -0
  53. package/android/src/main/res/drawable/ic_play.xml +10 -0
  54. package/android/src/main/res/drawable/ic_stop.xml +10 -0
  55. package/android/src/main/res/layout/notification_recording.xml +37 -0
  56. package/android/src/test/java/net/siteed/audiostudio/AudioFileHandlerTest.kt +279 -0
  57. package/android/src/test/java/net/siteed/audiostudio/AudioFocusStrategyTest.kt +249 -0
  58. package/android/src/test/java/net/siteed/audiostudio/AudioFormatTest.kt +151 -0
  59. package/android/src/test/java/net/siteed/audiostudio/AudioFormatUtilsTest.kt +273 -0
  60. package/android/src/test/java/net/siteed/audiostudio/DeviceDisconnectionFallbackUnitTest.kt +140 -0
  61. package/android/src/test/resources/chorus.wav +0 -0
  62. package/android/src/test/resources/generate_test_audio.py +94 -0
  63. package/android/src/test/resources/jfk.wav +0 -0
  64. package/android/src/test/resources/osr_us_000_0010_8k.wav +0 -0
  65. package/android/src/test/resources/recorder_hello_world.wav +0 -0
  66. package/app.plugin.js +3 -0
  67. package/build/cjs/AudioAnalysis/AudioAnalysis.types.js +4 -0
  68. package/build/cjs/AudioAnalysis/AudioAnalysis.types.js.map +1 -0
  69. package/build/cjs/AudioAnalysis/audioFeaturesWasm.js +164 -0
  70. package/build/cjs/AudioAnalysis/audioFeaturesWasm.js.map +1 -0
  71. package/build/cjs/AudioAnalysis/extractAudioAnalysis.js +213 -0
  72. package/build/cjs/AudioAnalysis/extractAudioAnalysis.js.map +1 -0
  73. package/build/cjs/AudioAnalysis/extractAudioData.js +21 -0
  74. package/build/cjs/AudioAnalysis/extractAudioData.js.map +1 -0
  75. package/build/cjs/AudioAnalysis/extractMelSpectrogram.js +90 -0
  76. package/build/cjs/AudioAnalysis/extractMelSpectrogram.js.map +1 -0
  77. package/build/cjs/AudioAnalysis/extractPreview.js +28 -0
  78. package/build/cjs/AudioAnalysis/extractPreview.js.map +1 -0
  79. package/build/cjs/AudioAnalysis/extractWaveform.js +18 -0
  80. package/build/cjs/AudioAnalysis/extractWaveform.js.map +1 -0
  81. package/build/cjs/AudioAnalysis/melSpectrogramWasm.js +149 -0
  82. package/build/cjs/AudioAnalysis/melSpectrogramWasm.js.map +1 -0
  83. package/build/cjs/AudioDeviceManager.js +688 -0
  84. package/build/cjs/AudioDeviceManager.js.map +1 -0
  85. package/build/cjs/AudioRecorder.provider.js +78 -0
  86. package/build/cjs/AudioRecorder.provider.js.map +1 -0
  87. package/build/cjs/AudioStudio.native.js +8 -0
  88. package/build/cjs/AudioStudio.native.js.map +1 -0
  89. package/build/cjs/AudioStudio.types.js +11 -0
  90. package/build/cjs/AudioStudio.types.js.map +1 -0
  91. package/build/cjs/AudioStudio.web.js +708 -0
  92. package/build/cjs/AudioStudio.web.js.map +1 -0
  93. package/build/cjs/AudioStudioModule.js +718 -0
  94. package/build/cjs/AudioStudioModule.js.map +1 -0
  95. package/build/cjs/WebRecorder.web.js +865 -0
  96. package/build/cjs/WebRecorder.web.js.map +1 -0
  97. package/build/cjs/constants/platformLimitations.js +99 -0
  98. package/build/cjs/constants/platformLimitations.js.map +1 -0
  99. package/build/cjs/constants.js +20 -0
  100. package/build/cjs/constants.js.map +1 -0
  101. package/build/cjs/events.js +29 -0
  102. package/build/cjs/events.js.map +1 -0
  103. package/build/cjs/hooks/useAudioDevices.js +179 -0
  104. package/build/cjs/hooks/useAudioDevices.js.map +1 -0
  105. package/build/cjs/index.js +64 -0
  106. package/build/cjs/index.js.map +1 -0
  107. package/build/cjs/trimAudio.js +76 -0
  108. package/build/cjs/trimAudio.js.map +1 -0
  109. package/build/cjs/useAudioRecorder.js +535 -0
  110. package/build/cjs/useAudioRecorder.js.map +1 -0
  111. package/build/cjs/utils/BlobFix.js +502 -0
  112. package/build/cjs/utils/BlobFix.js.map +1 -0
  113. package/build/cjs/utils/audioProcessing.js +136 -0
  114. package/build/cjs/utils/audioProcessing.js.map +1 -0
  115. package/build/cjs/utils/cleanNativeOptions.js +22 -0
  116. package/build/cjs/utils/cleanNativeOptions.js.map +1 -0
  117. package/build/cjs/utils/concatenateBuffers.js +25 -0
  118. package/build/cjs/utils/concatenateBuffers.js.map +1 -0
  119. package/build/cjs/utils/convertPCMToFloat32.js +124 -0
  120. package/build/cjs/utils/convertPCMToFloat32.js.map +1 -0
  121. package/build/cjs/utils/crc32.js +52 -0
  122. package/build/cjs/utils/crc32.js.map +1 -0
  123. package/build/cjs/utils/encodingToBitDepth.js +17 -0
  124. package/build/cjs/utils/encodingToBitDepth.js.map +1 -0
  125. package/build/cjs/utils/getWavFileInfo.js +96 -0
  126. package/build/cjs/utils/getWavFileInfo.js.map +1 -0
  127. package/build/cjs/utils/writeWavHeader.js +88 -0
  128. package/build/cjs/utils/writeWavHeader.js.map +1 -0
  129. package/build/cjs/workers/InlineFeaturesExtractor.web.js +294 -0
  130. package/build/cjs/workers/InlineFeaturesExtractor.web.js.map +1 -0
  131. package/build/cjs/workers/inlineAudioWebWorker.web.js +190 -0
  132. package/build/cjs/workers/inlineAudioWebWorker.web.js.map +1 -0
  133. package/build/cjs/workers/wasmGlueString.web.js +27 -0
  134. package/build/cjs/workers/wasmGlueString.web.js.map +1 -0
  135. package/build/esm/AudioAnalysis/AudioAnalysis.types.js +3 -0
  136. package/build/esm/AudioAnalysis/AudioAnalysis.types.js.map +1 -0
  137. package/build/esm/AudioAnalysis/audioFeaturesWasm.js +126 -0
  138. package/build/esm/AudioAnalysis/audioFeaturesWasm.js.map +1 -0
  139. package/build/esm/AudioAnalysis/extractAudioAnalysis.js +205 -0
  140. package/build/esm/AudioAnalysis/extractAudioAnalysis.js.map +1 -0
  141. package/build/esm/AudioAnalysis/extractAudioData.js +14 -0
  142. package/build/esm/AudioAnalysis/extractAudioData.js.map +1 -0
  143. package/build/esm/AudioAnalysis/extractMelSpectrogram.js +86 -0
  144. package/build/esm/AudioAnalysis/extractMelSpectrogram.js.map +1 -0
  145. package/build/esm/AudioAnalysis/extractPreview.js +25 -0
  146. package/build/esm/AudioAnalysis/extractPreview.js.map +1 -0
  147. package/build/esm/AudioAnalysis/extractWaveform.js +11 -0
  148. package/build/esm/AudioAnalysis/extractWaveform.js.map +1 -0
  149. package/build/esm/AudioAnalysis/melSpectrogramWasm.js +111 -0
  150. package/build/esm/AudioAnalysis/melSpectrogramWasm.js.map +1 -0
  151. package/build/esm/AudioDeviceManager.js +681 -0
  152. package/build/esm/AudioDeviceManager.js.map +1 -0
  153. package/build/esm/AudioRecorder.provider.js +40 -0
  154. package/build/esm/AudioRecorder.provider.js.map +1 -0
  155. package/build/esm/AudioStudio.native.js +6 -0
  156. package/build/esm/AudioStudio.native.js.map +1 -0
  157. package/build/esm/AudioStudio.types.js +8 -0
  158. package/build/esm/AudioStudio.types.js.map +1 -0
  159. package/build/esm/AudioStudio.web.js +704 -0
  160. package/build/esm/AudioStudio.web.js.map +1 -0
  161. package/build/esm/AudioStudioModule.js +713 -0
  162. package/build/esm/AudioStudioModule.js.map +1 -0
  163. package/build/esm/WebRecorder.web.js +861 -0
  164. package/build/esm/WebRecorder.web.js.map +1 -0
  165. package/build/esm/constants/platformLimitations.js +90 -0
  166. package/build/esm/constants/platformLimitations.js.map +1 -0
  167. package/build/esm/constants.js +17 -0
  168. package/build/esm/constants.js.map +1 -0
  169. package/build/esm/events.js +21 -0
  170. package/build/esm/events.js.map +1 -0
  171. package/build/esm/hooks/useAudioDevices.js +176 -0
  172. package/build/esm/hooks/useAudioDevices.js.map +1 -0
  173. package/build/esm/index.js +23 -0
  174. package/build/esm/index.js.map +1 -0
  175. package/build/esm/trimAudio.js +69 -0
  176. package/build/esm/trimAudio.js.map +1 -0
  177. package/build/esm/useAudioRecorder.js +529 -0
  178. package/build/esm/useAudioRecorder.js.map +1 -0
  179. package/build/esm/utils/BlobFix.js +498 -0
  180. package/build/esm/utils/BlobFix.js.map +1 -0
  181. package/build/esm/utils/audioProcessing.js +133 -0
  182. package/build/esm/utils/audioProcessing.js.map +1 -0
  183. package/build/esm/utils/cleanNativeOptions.js +19 -0
  184. package/build/esm/utils/cleanNativeOptions.js.map +1 -0
  185. package/build/esm/utils/concatenateBuffers.js +21 -0
  186. package/build/esm/utils/concatenateBuffers.js.map +1 -0
  187. package/build/esm/utils/convertPCMToFloat32.js +120 -0
  188. package/build/esm/utils/convertPCMToFloat32.js.map +1 -0
  189. package/build/esm/utils/crc32.js +50 -0
  190. package/build/esm/utils/crc32.js.map +1 -0
  191. package/build/esm/utils/encodingToBitDepth.js +13 -0
  192. package/build/esm/utils/encodingToBitDepth.js.map +1 -0
  193. package/build/esm/utils/getWavFileInfo.js +92 -0
  194. package/build/esm/utils/getWavFileInfo.js.map +1 -0
  195. package/build/esm/utils/writeWavHeader.js +84 -0
  196. package/build/esm/utils/writeWavHeader.js.map +1 -0
  197. package/build/esm/workers/InlineFeaturesExtractor.web.js +291 -0
  198. package/build/esm/workers/InlineFeaturesExtractor.web.js.map +1 -0
  199. package/build/esm/workers/inlineAudioWebWorker.web.js +187 -0
  200. package/build/esm/workers/inlineAudioWebWorker.web.js.map +1 -0
  201. package/build/esm/workers/wasmGlueString.web.js +24 -0
  202. package/build/esm/workers/wasmGlueString.web.js.map +1 -0
  203. package/build/types/AudioAnalysis/AudioAnalysis.types.d.ts +198 -0
  204. package/build/types/AudioAnalysis/AudioAnalysis.types.d.ts.map +1 -0
  205. package/build/types/AudioAnalysis/audioFeaturesWasm.d.ts +24 -0
  206. package/build/types/AudioAnalysis/audioFeaturesWasm.d.ts.map +1 -0
  207. package/build/types/AudioAnalysis/extractAudioAnalysis.d.ts +74 -0
  208. package/build/types/AudioAnalysis/extractAudioAnalysis.d.ts.map +1 -0
  209. package/build/types/AudioAnalysis/extractAudioData.d.ts +3 -0
  210. package/build/types/AudioAnalysis/extractAudioData.d.ts.map +1 -0
  211. package/build/types/AudioAnalysis/extractMelSpectrogram.d.ts +20 -0
  212. package/build/types/AudioAnalysis/extractMelSpectrogram.d.ts.map +1 -0
  213. package/build/types/AudioAnalysis/extractPreview.d.ts +11 -0
  214. package/build/types/AudioAnalysis/extractPreview.d.ts.map +1 -0
  215. package/build/types/AudioAnalysis/extractWaveform.d.ts +8 -0
  216. package/build/types/AudioAnalysis/extractWaveform.d.ts.map +1 -0
  217. package/build/types/AudioAnalysis/melSpectrogramWasm.d.ts +16 -0
  218. package/build/types/AudioAnalysis/melSpectrogramWasm.d.ts.map +1 -0
  219. package/build/types/AudioDeviceManager.d.ts +187 -0
  220. package/build/types/AudioDeviceManager.d.ts.map +1 -0
  221. package/build/types/AudioRecorder.provider.d.ts +11 -0
  222. package/build/types/AudioRecorder.provider.d.ts.map +1 -0
  223. package/build/types/AudioStudio.native.d.ts +3 -0
  224. package/build/types/AudioStudio.native.d.ts.map +1 -0
  225. package/build/types/AudioStudio.types.d.ts +760 -0
  226. package/build/types/AudioStudio.types.d.ts.map +1 -0
  227. package/build/types/AudioStudio.web.d.ts +96 -0
  228. package/build/types/AudioStudio.web.d.ts.map +1 -0
  229. package/build/types/AudioStudioModule.d.ts +3 -0
  230. package/build/types/AudioStudioModule.d.ts.map +1 -0
  231. package/build/types/WebRecorder.web.d.ts +208 -0
  232. package/build/types/WebRecorder.web.d.ts.map +1 -0
  233. package/build/types/constants/platformLimitations.d.ts +40 -0
  234. package/build/types/constants/platformLimitations.d.ts.map +1 -0
  235. package/build/types/constants.d.ts +14 -0
  236. package/build/types/constants.d.ts.map +1 -0
  237. package/build/types/events.d.ts +29 -0
  238. package/build/types/events.d.ts.map +1 -0
  239. package/build/types/hooks/useAudioDevices.d.ts +15 -0
  240. package/build/types/hooks/useAudioDevices.d.ts.map +1 -0
  241. package/build/types/index.d.ts +21 -0
  242. package/build/types/index.d.ts.map +1 -0
  243. package/build/types/trimAudio.d.ts +25 -0
  244. package/build/types/trimAudio.d.ts.map +1 -0
  245. package/build/types/useAudioRecorder.d.ts +22 -0
  246. package/build/types/useAudioRecorder.d.ts.map +1 -0
  247. package/build/types/utils/BlobFix.d.ts +9 -0
  248. package/build/types/utils/BlobFix.d.ts.map +1 -0
  249. package/build/types/utils/audioProcessing.d.ts +24 -0
  250. package/build/types/utils/audioProcessing.d.ts.map +1 -0
  251. package/build/types/utils/cleanNativeOptions.d.ts +15 -0
  252. package/build/types/utils/cleanNativeOptions.d.ts.map +1 -0
  253. package/build/types/utils/concatenateBuffers.d.ts +8 -0
  254. package/build/types/utils/concatenateBuffers.d.ts.map +1 -0
  255. package/build/types/utils/convertPCMToFloat32.d.ts +13 -0
  256. package/build/types/utils/convertPCMToFloat32.d.ts.map +1 -0
  257. package/build/types/utils/crc32.d.ts +7 -0
  258. package/build/types/utils/crc32.d.ts.map +1 -0
  259. package/build/types/utils/encodingToBitDepth.d.ts +5 -0
  260. package/build/types/utils/encodingToBitDepth.d.ts.map +1 -0
  261. package/build/types/utils/getWavFileInfo.d.ts +26 -0
  262. package/build/types/utils/getWavFileInfo.d.ts.map +1 -0
  263. package/build/types/utils/writeWavHeader.d.ts +34 -0
  264. package/build/types/utils/writeWavHeader.d.ts.map +1 -0
  265. package/build/types/workers/InlineFeaturesExtractor.web.d.ts +2 -0
  266. package/build/types/workers/InlineFeaturesExtractor.web.d.ts.map +1 -0
  267. package/build/types/workers/inlineAudioWebWorker.web.d.ts +2 -0
  268. package/build/types/workers/inlineAudioWebWorker.web.d.ts.map +1 -0
  269. package/build/types/workers/wasmGlueString.web.d.ts +2 -0
  270. package/build/types/workers/wasmGlueString.web.d.ts.map +1 -0
  271. package/cpp/AudioFeatures.cpp +274 -0
  272. package/cpp/AudioFeatures.h +85 -0
  273. package/cpp/AudioFeaturesBridge.cpp +146 -0
  274. package/cpp/AudioFeaturesBridge.h +47 -0
  275. package/cpp/MelSpectrogram.cpp +227 -0
  276. package/cpp/MelSpectrogram.h +82 -0
  277. package/cpp/MelSpectrogramBridge.cpp +112 -0
  278. package/cpp/MelSpectrogramBridge.h +33 -0
  279. package/cpp/kiss_fft/COPYING +11 -0
  280. package/cpp/kiss_fft/_kiss_fft_guts.h +167 -0
  281. package/cpp/kiss_fft/kiss_fft.c +424 -0
  282. package/cpp/kiss_fft/kiss_fft.h +160 -0
  283. package/cpp/kiss_fft/kiss_fft_log.h +36 -0
  284. package/cpp/kiss_fft/kiss_fftr.c +155 -0
  285. package/cpp/kiss_fft/kiss_fftr.h +54 -0
  286. package/expo-module.config.json +10 -0
  287. package/ios/AudioAnalysisData.swift +74 -0
  288. package/ios/AudioDeviceManager.swift +670 -0
  289. package/ios/AudioFeaturesWrapper.h +21 -0
  290. package/ios/AudioFeaturesWrapper.mm +63 -0
  291. package/ios/AudioNotificationManager.swift +154 -0
  292. package/ios/AudioProcessingHelpers.swift +797 -0
  293. package/ios/AudioProcessor.swift +1191 -0
  294. package/ios/AudioStreamError.swift +7 -0
  295. package/ios/AudioStreamManager.swift +2369 -0
  296. package/ios/AudioStreamManagerDelegate.swift +16 -0
  297. package/ios/AudioStudio.podspec +39 -0
  298. package/ios/AudioStudioModule.swift +1111 -0
  299. package/ios/AudioStudioTests/AudioFileHandlerTests.swift +338 -0
  300. package/ios/AudioStudioTests/AudioFormatUtilsTests.swift +331 -0
  301. package/ios/AudioStudioTests/AudioTestHelpers.swift +130 -0
  302. package/ios/AudioStudioTests/CompressedOnlyOutputTests.swift +294 -0
  303. package/ios/AudioStudioTests/EventEmissionIntervalTests.swift +105 -0
  304. package/ios/AudioStudioTests/Info.plist +22 -0
  305. package/ios/AudioStudioTests/README.md +39 -0
  306. package/ios/AudioStudioTests/SimpleAudioTest.swift +98 -0
  307. package/ios/AudioStudioTests/TestAudioGenerator.swift +75 -0
  308. package/ios/DataPoint.swift +54 -0
  309. package/ios/DecodingConfig.swift +59 -0
  310. package/ios/FFT.swift +62 -0
  311. package/ios/Features.swift +95 -0
  312. package/ios/ISSUE_IOS.md +68 -0
  313. package/ios/Logger.swift +39 -0
  314. package/ios/MelSpectrogramWrapper.h +30 -0
  315. package/ios/MelSpectrogramWrapper.mm +97 -0
  316. package/ios/NotificationExtension.swift +15 -0
  317. package/ios/RecordingResult.swift +22 -0
  318. package/ios/RecordingSettings.swift +311 -0
  319. package/ios/WaveformExtractor.swift +105 -0
  320. package/ios/tests/README.md +41 -0
  321. package/ios/tests/integration/buffer_and_fallback_test.swift +178 -0
  322. package/ios/tests/integration/buffer_duration_test.swift +185 -0
  323. package/ios/tests/integration/compressed_only_output_test.swift +271 -0
  324. package/ios/tests/integration/output_control_test.swift +322 -0
  325. package/ios/tests/integration/run_integration_tests.sh +37 -0
  326. package/ios/tests/opus_support_test_macos.swift +154 -0
  327. package/ios/tests/standalone/audio_processing_test.swift +144 -0
  328. package/ios/tests/standalone/audio_recording_test.swift +277 -0
  329. package/ios/tests/standalone/audio_streaming_test.swift +249 -0
  330. package/ios/tests/standalone/standalone_test.swift +144 -0
  331. package/package.json +146 -0
  332. package/plugin/build/index.cjs +194 -0
  333. package/plugin/build/index.d.cts +22 -0
  334. package/plugin/build/index.js +194 -0
  335. package/plugin/src/index.ts +285 -0
  336. package/plugin/tsconfig.json +10 -0
  337. package/plugin/tsconfig.tsbuildinfo +1 -0
  338. package/prebuilt/wasm/mel-spectrogram.js +18 -0
  339. package/src/AudioAnalysis/AudioAnalysis.types.ts +226 -0
  340. package/src/AudioAnalysis/audio-features-wasm.d.ts +37 -0
  341. package/src/AudioAnalysis/audioFeaturesWasm.ts +200 -0
  342. package/src/AudioAnalysis/extractAudioAnalysis.ts +350 -0
  343. package/src/AudioAnalysis/extractAudioData.ts +17 -0
  344. package/src/AudioAnalysis/extractMelSpectrogram.ts +140 -0
  345. package/src/AudioAnalysis/extractPreview.ts +34 -0
  346. package/src/AudioAnalysis/extractWaveform.ts +22 -0
  347. package/src/AudioAnalysis/mel-spectrogram-wasm.d.ts +48 -0
  348. package/src/AudioAnalysis/melSpectrogramWasm.ts +179 -0
  349. package/src/AudioDeviceManager.ts +800 -0
  350. package/src/AudioRecorder.provider.tsx +57 -0
  351. package/src/AudioStudio.native.ts +6 -0
  352. package/src/AudioStudio.types.ts +899 -0
  353. package/src/AudioStudio.web.ts +911 -0
  354. package/src/AudioStudioModule.ts +984 -0
  355. package/src/WebRecorder.web.ts +1114 -0
  356. package/src/constants/platformLimitations.ts +118 -0
  357. package/src/constants.ts +21 -0
  358. package/src/events.ts +63 -0
  359. package/src/hooks/useAudioDevices.ts +213 -0
  360. package/src/index.ts +67 -0
  361. package/src/trimAudio.ts +94 -0
  362. package/src/types/crc-32.d.ts +9 -0
  363. package/src/useAudioRecorder.tsx +784 -0
  364. package/src/utils/BlobFix.ts +561 -0
  365. package/src/utils/audioProcessing.ts +205 -0
  366. package/src/utils/cleanNativeOptions.ts +18 -0
  367. package/src/utils/concatenateBuffers.ts +24 -0
  368. package/src/utils/convertPCMToFloat32.ts +170 -0
  369. package/src/utils/crc32.ts +59 -0
  370. package/src/utils/encodingToBitDepth.ts +18 -0
  371. package/src/utils/getWavFileInfo.ts +132 -0
  372. package/src/utils/writeWavHeader.ts +115 -0
  373. package/src/workers/InlineFeaturesExtractor.web.tsx +291 -0
  374. package/src/workers/inlineAudioWebWorker.web.tsx +186 -0
  375. package/src/workers/wasmGlueString.web.ts +23 -0
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.extractRawWavAnalysis = void 0;
7
+ exports.extractAudioAnalysis = extractAudioAnalysis;
8
+ const AudioStudioModule_1 = __importDefault(require("../AudioStudioModule"));
9
+ const constants_1 = require("../constants");
10
+ const audioProcessing_1 = require("../utils/audioProcessing");
11
+ const cleanNativeOptions_1 = require("../utils/cleanNativeOptions");
12
+ const convertPCMToFloat32_1 = require("../utils/convertPCMToFloat32");
13
+ const crc32_1 = __importDefault(require("../utils/crc32"));
14
+ const getWavFileInfo_1 = require("../utils/getWavFileInfo");
15
+ const InlineFeaturesExtractor_web_1 = require("../workers/InlineFeaturesExtractor.web");
16
+ const wasmGlueString_web_1 = require("../workers/wasmGlueString.web");
17
+ function calculateCRC32ForDataPoint(data) {
18
+ // Convert float array to byte array for CRC32
19
+ const byteArray = new Uint8Array(data.length * 4);
20
+ const dataView = new DataView(byteArray.buffer);
21
+ for (let i = 0; i < data.length; i++) {
22
+ dataView.setFloat32(i * 4, data[i], true);
23
+ }
24
+ return crc32_1.default.buf(byteArray);
25
+ }
26
+ /**
27
+ * Extracts detailed audio analysis from the specified audio file or buffer.
28
+ * Supports either time-based or byte-based ranges for flexibility in analysis.
29
+ *
30
+ * @param props - The options for extraction, including file URI, ranges, and decoding settings.
31
+ * @returns A promise that resolves to the audio analysis data.
32
+ * @throws {Error} If both time and byte ranges are provided or if required parameters are missing.
33
+ */
34
+ async function extractAudioAnalysis(props) {
35
+ const { fileUri, arrayBuffer, decodingOptions, logger, segmentDurationMs = 100, features, } = props;
36
+ if (constants_1.isWeb) {
37
+ try {
38
+ // Create AudioContext here
39
+ const audioContext = new (window.AudioContext ||
40
+ window.webkitAudioContext)({
41
+ sampleRate: decodingOptions?.targetSampleRate ?? 16000,
42
+ });
43
+ try {
44
+ const processedBuffer = await (0, audioProcessing_1.processAudioBuffer)({
45
+ arrayBuffer,
46
+ fileUri,
47
+ targetSampleRate: decodingOptions?.targetSampleRate ?? 16000,
48
+ targetChannels: decodingOptions?.targetChannels ?? 1,
49
+ normalizeAudio: decodingOptions?.normalizeAudio ?? false,
50
+ startTimeMs: 'startTimeMs' in props ? props.startTimeMs : undefined,
51
+ endTimeMs: 'endTimeMs' in props ? props.endTimeMs : undefined,
52
+ position: 'position' in props ? props.position : undefined,
53
+ length: 'length' in props ? props.length : undefined,
54
+ audioContext, // Pass the context we created
55
+ logger,
56
+ });
57
+ const channelData = processedBuffer.buffer.getChannelData(0);
58
+ // Create worker blob: WASM glue (defines createMelSpectrogramModule) + worker code
59
+ const blob = new Blob([wasmGlueString_web_1.wasmGlueJs, '\n', InlineFeaturesExtractor_web_1.InlineFeaturesExtractor], { type: 'application/javascript' });
60
+ const workerUrl = URL.createObjectURL(blob);
61
+ const worker = new Worker(workerUrl);
62
+ return new Promise((resolve, reject) => {
63
+ worker.onmessage = (event) => {
64
+ if (event.data.error) {
65
+ reject(new Error(event.data.error));
66
+ return;
67
+ }
68
+ const result = event.data.result;
69
+ // Calculate CRC32 after worker completes if requested
70
+ if (features?.crc32) {
71
+ const samplesPerSegment = Math.floor((processedBuffer.sampleRate *
72
+ segmentDurationMs) /
73
+ 1000);
74
+ result.dataPoints = result.dataPoints.map((point, index) => {
75
+ const startSample = index * samplesPerSegment;
76
+ const segmentData = channelData.slice(startSample, startSample + samplesPerSegment);
77
+ return {
78
+ ...point,
79
+ features: {
80
+ ...point.features,
81
+ crc32: calculateCRC32ForDataPoint(segmentData),
82
+ },
83
+ };
84
+ });
85
+ }
86
+ URL.revokeObjectURL(workerUrl);
87
+ worker.terminate();
88
+ resolve(result);
89
+ };
90
+ worker.onerror = (error) => {
91
+ URL.revokeObjectURL(workerUrl);
92
+ worker.terminate();
93
+ reject(error);
94
+ };
95
+ worker.postMessage({
96
+ channelData,
97
+ sampleRate: processedBuffer.sampleRate,
98
+ segmentDurationMs,
99
+ bitDepth: decodingOptions?.targetBitDepth ?? 32,
100
+ numberOfChannels: processedBuffer.channels,
101
+ fullAudioDurationMs: processedBuffer.durationMs,
102
+ // enableLogging: !!logger,
103
+ features,
104
+ });
105
+ });
106
+ }
107
+ finally {
108
+ await audioContext.close();
109
+ }
110
+ }
111
+ catch (error) {
112
+ logger?.error('Failed to process audio:', error);
113
+ throw error;
114
+ }
115
+ }
116
+ else {
117
+ // Strip non-serializable fields — logger and arrayBuffer cause
118
+ // "Cannot convert '[object Object]' to a Kotlin type" on Android.
119
+ const { logger: _logger, arrayBuffer: _arrayBuffer, ...nativeOptions } = props;
120
+ // Clean undefined values to avoid Android Kotlin bridge crash
121
+ return await AudioStudioModule_1.default.extractAudioAnalysis((0, cleanNativeOptions_1.cleanNativeOptions)(nativeOptions));
122
+ }
123
+ }
124
+ /**
125
+ * Analyzes WAV files without decoding, preserving original PCM values.
126
+ * Use this function when you need to ensure the analysis matches other software by avoiding any transformations.
127
+ *
128
+ * @param props - The options for WAV analysis, including file URI and range.
129
+ * @returns A promise that resolves to the audio analysis data.
130
+ */
131
+ const extractRawWavAnalysis = async ({ fileUri, segmentDurationMs = 100, // Default to 100ms
132
+ arrayBuffer, bitDepth, durationMs, sampleRate, numberOfChannels, features, logger, position = 0, length, }) => {
133
+ if (constants_1.isWeb) {
134
+ if (!arrayBuffer && !fileUri) {
135
+ throw new Error('Either arrayBuffer or fileUri must be provided');
136
+ }
137
+ if (!arrayBuffer) {
138
+ logger?.log(`fetching fileUri`, fileUri);
139
+ const response = await fetch(fileUri);
140
+ if (!response.ok) {
141
+ throw new Error(`Failed to fetch fileUri: ${response.statusText}`);
142
+ }
143
+ arrayBuffer = await response.arrayBuffer();
144
+ logger?.log(`fetched fileUri`, arrayBuffer.byteLength, arrayBuffer);
145
+ }
146
+ // Create a new copy of the ArrayBuffer to avoid detachment issues
147
+ const bufferCopy = arrayBuffer.slice(0);
148
+ logger?.log(`extractAudioAnalysis bitDepth=${bitDepth} len=${bufferCopy.byteLength}`, bufferCopy.slice(0, 100));
149
+ let actualBitDepth = bitDepth;
150
+ if (!actualBitDepth) {
151
+ logger?.log(`extractAudioAnalysis bitDepth not provided -- getting wav file info`);
152
+ const fileInfo = await (0, getWavFileInfo_1.getWavFileInfo)(bufferCopy);
153
+ actualBitDepth = fileInfo.bitDepth;
154
+ }
155
+ logger?.log(`extractAudioAnalysis actualBitDepth=${actualBitDepth}`);
156
+ const { pcmValues: channelData, min, max, } = await (0, convertPCMToFloat32_1.convertPCMToFloat32)({
157
+ buffer: arrayBuffer,
158
+ bitDepth: actualBitDepth,
159
+ });
160
+ logger?.log(`extractAudioAnalysis convertPCMToFloat32 length=${channelData.length} range: [ ${min} :: ${max} ]`);
161
+ // Apply position and length constraints to channelData if specified
162
+ const startIndex = position;
163
+ const endIndex = length ? startIndex + length : channelData.length;
164
+ const constrainedChannelData = channelData.slice(startIndex, endIndex);
165
+ return new Promise((resolve, reject) => {
166
+ const blob = new Blob([wasmGlueString_web_1.wasmGlueJs, '\n', InlineFeaturesExtractor_web_1.InlineFeaturesExtractor], {
167
+ type: 'application/javascript',
168
+ });
169
+ const url = URL.createObjectURL(blob);
170
+ const worker = new Worker(url);
171
+ worker.onmessage = (event) => {
172
+ URL.revokeObjectURL(url);
173
+ worker.terminate();
174
+ resolve(event.data.result);
175
+ };
176
+ worker.onerror = (error) => {
177
+ URL.revokeObjectURL(url);
178
+ worker.terminate();
179
+ reject(error);
180
+ };
181
+ worker.postMessage({
182
+ command: 'process',
183
+ channelData: constrainedChannelData,
184
+ sampleRate,
185
+ segmentDurationMs,
186
+ logger,
187
+ bitDepth,
188
+ fullAudioDurationMs: durationMs,
189
+ numberOfChannels,
190
+ });
191
+ });
192
+ }
193
+ else {
194
+ if (!fileUri) {
195
+ throw new Error('fileUri is required');
196
+ }
197
+ logger?.log(`extractAudioAnalysis`, {
198
+ fileUri,
199
+ segmentDurationMs,
200
+ });
201
+ const res = await AudioStudioModule_1.default.extractAudioAnalysis({
202
+ fileUri,
203
+ segmentDurationMs,
204
+ features,
205
+ position,
206
+ length,
207
+ });
208
+ logger?.log(`extractAudioAnalysis`, res);
209
+ return res;
210
+ }
211
+ };
212
+ exports.extractRawWavAnalysis = extractRawWavAnalysis;
213
+ //# sourceMappingURL=extractAudioAnalysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractAudioAnalysis.js","sourceRoot":"","sources":["../../../src/AudioAnalysis/extractAudioAnalysis.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/audio-studio/src/AudioAnalysis/extractAudioAnalysis.ts\n/**\n * This module provides functions for extracting and analyzing audio data.\n * - `extractAudioAnalysis`: For detailed analysis with customizable ranges and decoding options.\n * - `extractWavAudioAnalysis`: For analyzing WAV files without decoding, preserving original PCM values.\n * - `extractPreview`: For generating quick previews of audio waveforms, optimized for UI rendering.\n */\nimport { ConsoleLike } from '../AudioStudio.types'\nimport AudioStudioModule from '../AudioStudioModule'\nimport { isWeb } from '../constants'\nimport {\n AudioAnalysis,\n AudioFeaturesOptions,\n DataPoint,\n DecodingConfig,\n} from './AudioAnalysis.types'\nimport { processAudioBuffer } from '../utils/audioProcessing'\nimport { cleanNativeOptions } from '../utils/cleanNativeOptions'\nimport { convertPCMToFloat32 } from '../utils/convertPCMToFloat32'\nimport crc32 from '../utils/crc32'\nimport { getWavFileInfo, WavFileInfo } from '../utils/getWavFileInfo'\nimport { InlineFeaturesExtractor } from '../workers/InlineFeaturesExtractor.web'\nimport { wasmGlueJs } from '../workers/wasmGlueString.web'\n\nfunction calculateCRC32ForDataPoint(data: Float32Array): number {\n // Convert float array to byte array for CRC32\n const byteArray = new Uint8Array(data.length * 4)\n const dataView = new DataView(byteArray.buffer)\n\n for (let i = 0; i < data.length; i++) {\n dataView.setFloat32(i * 4, data[i], true)\n }\n\n return crc32.buf(byteArray)\n}\n\nexport interface ExtractWavAudioAnalysisProps {\n fileUri?: string // should provide either fileUri or arrayBuffer\n wavMetadata?: WavFileInfo\n arrayBuffer?: ArrayBuffer\n bitDepth?: number\n durationMs?: number\n sampleRate?: number\n numberOfChannels?: number\n position?: number // Optional number of bytes to skip. Default is 0\n length?: number // Optional number of bytes to read.\n segmentDurationMs?: number // Optional number of points per second. Use to reduce the number of points and compute the number of datapoints to return.\n features?: AudioFeaturesOptions\n featuresExtratorUrl?: string\n logger?: ConsoleLike\n decodingOptions?: DecodingConfig\n}\n\n// Define base options interface with common properties\ninterface BaseExtractOptions {\n fileUri?: string\n arrayBuffer?: ArrayBuffer\n /**\n * Duration of each analysis segment in milliseconds. Defaults to 100ms if not specified.\n */\n segmentDurationMs?: number\n features?: AudioFeaturesOptions\n decodingOptions?: DecodingConfig\n logger?: ConsoleLike\n}\n\n// Time-based range options\ninterface TimeRangeOptions extends BaseExtractOptions {\n startTimeMs?: number\n endTimeMs?: number\n position?: never\n length?: never\n}\n\n// Byte-based range options\ninterface ByteRangeOptions extends BaseExtractOptions {\n position?: number\n length?: number\n startTimeMs?: never\n endTimeMs?: never\n}\n\n/**\n * Options for extracting audio analysis.\n * - For time-based analysis, provide `startTimeMs` and `endTimeMs`.\n * - For byte-based analysis, provide `position` and `length`.\n * - Do not mix time and byte ranges.\n */\nexport type ExtractAudioAnalysisProps = TimeRangeOptions | ByteRangeOptions\n\n/**\n * Extracts detailed audio analysis from the specified audio file or buffer.\n * Supports either time-based or byte-based ranges for flexibility in analysis.\n *\n * @param props - The options for extraction, including file URI, ranges, and decoding settings.\n * @returns A promise that resolves to the audio analysis data.\n * @throws {Error} If both time and byte ranges are provided or if required parameters are missing.\n */\nexport async function extractAudioAnalysis(\n props: ExtractAudioAnalysisProps\n): Promise<AudioAnalysis> {\n const {\n fileUri,\n arrayBuffer,\n decodingOptions,\n logger,\n segmentDurationMs = 100,\n features,\n } = props\n\n if (isWeb) {\n try {\n // Create AudioContext here\n const audioContext = new (window.AudioContext ||\n (window as any).webkitAudioContext)({\n sampleRate: decodingOptions?.targetSampleRate ?? 16000,\n })\n\n try {\n const processedBuffer = await processAudioBuffer({\n arrayBuffer,\n fileUri,\n targetSampleRate:\n decodingOptions?.targetSampleRate ?? 16000,\n targetChannels: decodingOptions?.targetChannels ?? 1,\n normalizeAudio: decodingOptions?.normalizeAudio ?? false,\n startTimeMs:\n 'startTimeMs' in props ? props.startTimeMs : undefined,\n endTimeMs:\n 'endTimeMs' in props ? props.endTimeMs : undefined,\n position: 'position' in props ? props.position : undefined,\n length: 'length' in props ? props.length : undefined,\n audioContext, // Pass the context we created\n logger,\n })\n\n const channelData = processedBuffer.buffer.getChannelData(0)\n\n // Create worker blob: WASM glue (defines createMelSpectrogramModule) + worker code\n const blob = new Blob(\n [wasmGlueJs, '\\n', InlineFeaturesExtractor],\n { type: 'application/javascript' }\n )\n const workerUrl = URL.createObjectURL(blob)\n const worker = new Worker(workerUrl)\n\n return new Promise((resolve, reject) => {\n worker.onmessage = (event) => {\n if (event.data.error) {\n reject(new Error(event.data.error))\n return\n }\n\n const result: AudioAnalysis = event.data.result\n // Calculate CRC32 after worker completes if requested\n if (features?.crc32) {\n const samplesPerSegment = Math.floor(\n (processedBuffer.sampleRate *\n segmentDurationMs) /\n 1000\n )\n\n result.dataPoints = result.dataPoints.map(\n (point: DataPoint, index: number) => {\n const startSample =\n index * samplesPerSegment\n const segmentData = channelData.slice(\n startSample,\n startSample + samplesPerSegment\n )\n\n return {\n ...point,\n features: {\n ...point.features,\n crc32: calculateCRC32ForDataPoint(\n segmentData\n ),\n },\n }\n }\n )\n }\n\n URL.revokeObjectURL(workerUrl)\n worker.terminate()\n resolve(result)\n }\n\n worker.onerror = (error) => {\n URL.revokeObjectURL(workerUrl)\n worker.terminate()\n reject(error)\n }\n\n worker.postMessage({\n channelData,\n sampleRate: processedBuffer.sampleRate,\n segmentDurationMs,\n bitDepth: decodingOptions?.targetBitDepth ?? 32,\n numberOfChannels: processedBuffer.channels,\n fullAudioDurationMs: processedBuffer.durationMs,\n // enableLogging: !!logger,\n features,\n })\n })\n } finally {\n await audioContext.close()\n }\n } catch (error) {\n logger?.error('Failed to process audio:', error)\n throw error\n }\n } else {\n // Strip non-serializable fields — logger and arrayBuffer cause\n // \"Cannot convert '[object Object]' to a Kotlin type\" on Android.\n const {\n logger: _logger,\n arrayBuffer: _arrayBuffer,\n ...nativeOptions\n } = props\n // Clean undefined values to avoid Android Kotlin bridge crash\n return await AudioStudioModule.extractAudioAnalysis(\n cleanNativeOptions(nativeOptions)\n )\n }\n}\n\n/**\n * Analyzes WAV files without decoding, preserving original PCM values.\n * Use this function when you need to ensure the analysis matches other software by avoiding any transformations.\n *\n * @param props - The options for WAV analysis, including file URI and range.\n * @returns A promise that resolves to the audio analysis data.\n */\nexport const extractRawWavAnalysis = async ({\n fileUri,\n segmentDurationMs = 100, // Default to 100ms\n arrayBuffer,\n bitDepth,\n durationMs,\n sampleRate,\n numberOfChannels,\n features,\n logger,\n position = 0,\n length,\n}: ExtractWavAudioAnalysisProps): Promise<AudioAnalysis> => {\n if (isWeb) {\n if (!arrayBuffer && !fileUri) {\n throw new Error('Either arrayBuffer or fileUri must be provided')\n }\n\n if (!arrayBuffer) {\n logger?.log(`fetching fileUri`, fileUri)\n const response = await fetch(fileUri!)\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch fileUri: ${response.statusText}`\n )\n }\n\n arrayBuffer = await response.arrayBuffer()\n logger?.log(`fetched fileUri`, arrayBuffer.byteLength, arrayBuffer)\n }\n\n // Create a new copy of the ArrayBuffer to avoid detachment issues\n const bufferCopy = arrayBuffer.slice(0)\n logger?.log(\n `extractAudioAnalysis bitDepth=${bitDepth} len=${bufferCopy.byteLength}`,\n bufferCopy.slice(0, 100)\n )\n\n let actualBitDepth = bitDepth\n if (!actualBitDepth) {\n logger?.log(\n `extractAudioAnalysis bitDepth not provided -- getting wav file info`\n )\n const fileInfo = await getWavFileInfo(bufferCopy)\n actualBitDepth = fileInfo.bitDepth\n }\n logger?.log(`extractAudioAnalysis actualBitDepth=${actualBitDepth}`)\n\n const {\n pcmValues: channelData,\n min,\n max,\n } = await convertPCMToFloat32({\n buffer: arrayBuffer,\n bitDepth: actualBitDepth,\n })\n logger?.log(\n `extractAudioAnalysis convertPCMToFloat32 length=${channelData.length} range: [ ${min} :: ${max} ]`\n )\n\n // Apply position and length constraints to channelData if specified\n const startIndex = position\n const endIndex = length ? startIndex + length : channelData.length\n const constrainedChannelData = channelData.slice(startIndex, endIndex)\n\n return new Promise((resolve, reject) => {\n const blob = new Blob([wasmGlueJs, '\\n', InlineFeaturesExtractor], {\n type: 'application/javascript',\n })\n const url = URL.createObjectURL(blob)\n const worker = new Worker(url)\n\n worker.onmessage = (event) => {\n URL.revokeObjectURL(url)\n worker.terminate()\n resolve(event.data.result)\n }\n\n worker.onerror = (error) => {\n URL.revokeObjectURL(url)\n worker.terminate()\n reject(error)\n }\n\n worker.postMessage({\n command: 'process',\n channelData: constrainedChannelData,\n sampleRate,\n segmentDurationMs,\n logger,\n bitDepth,\n fullAudioDurationMs: durationMs,\n numberOfChannels,\n })\n })\n } else {\n if (!fileUri) {\n throw new Error('fileUri is required')\n }\n logger?.log(`extractAudioAnalysis`, {\n fileUri,\n segmentDurationMs,\n })\n const res = await AudioStudioModule.extractAudioAnalysis({\n fileUri,\n segmentDurationMs,\n features,\n position,\n length,\n })\n logger?.log(`extractAudioAnalysis`, res)\n return res\n }\n}\n"]}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.extractAudioData = void 0;
7
+ const AudioStudioModule_1 = __importDefault(require("../AudioStudioModule"));
8
+ const constants_1 = require("../constants");
9
+ const cleanNativeOptions_1 = require("../utils/cleanNativeOptions");
10
+ const extractAudioData = async (props) => {
11
+ if (constants_1.isWeb) {
12
+ // Web implementation handles logger natively in AudioStudioModule.ts
13
+ return await AudioStudioModule_1.default.extractAudioData(props);
14
+ }
15
+ // Native: only pass serializable fields — logger causes crash on Android
16
+ const { logger: _logger, ...nativeOptions } = props;
17
+ // Clean undefined values to avoid Android Kotlin bridge crash
18
+ return await AudioStudioModule_1.default.extractAudioData((0, cleanNativeOptions_1.cleanNativeOptions)(nativeOptions));
19
+ };
20
+ exports.extractAudioData = extractAudioData;
21
+ //# sourceMappingURL=extractAudioData.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractAudioData.js","sourceRoot":"","sources":["../../../src/AudioAnalysis/extractAudioData.ts"],"names":[],"mappings":";;;;;;AACA,6EAAoD;AACpD,4CAAoC;AACpC,oEAAgE;AAEzD,MAAM,gBAAgB,GAAG,KAAK,EAAE,KAA8B,EAAE,EAAE;IACrE,IAAI,iBAAK,EAAE,CAAC;QACR,qEAAqE;QACrE,OAAO,MAAM,2BAAiB,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAA;IAC1D,CAAC;IACD,yEAAyE;IACzE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,aAAa,EAAE,GAAG,KAAK,CAAA;IACnD,8DAA8D;IAC9D,OAAO,MAAM,2BAAiB,CAAC,gBAAgB,CAC3C,IAAA,uCAAkB,EAAC,aAAa,CAAC,CACpC,CAAA;AACL,CAAC,CAAA;AAXY,QAAA,gBAAgB,oBAW5B","sourcesContent":["import { ExtractAudioDataOptions } from '../AudioStudio.types'\nimport AudioStudioModule from '../AudioStudioModule'\nimport { isWeb } from '../constants'\nimport { cleanNativeOptions } from '../utils/cleanNativeOptions'\n\nexport const extractAudioData = async (props: ExtractAudioDataOptions) => {\n if (isWeb) {\n // Web implementation handles logger natively in AudioStudioModule.ts\n return await AudioStudioModule.extractAudioData(props)\n }\n // Native: only pass serializable fields — logger causes crash on Android\n const { logger: _logger, ...nativeOptions } = props\n // Clean undefined values to avoid Android Kotlin bridge crash\n return await AudioStudioModule.extractAudioData(\n cleanNativeOptions(nativeOptions)\n )\n}\n"]}
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ /**
3
+ * @experimental This feature is experimental and currently only available on Android.
4
+ * The API may change in future versions.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.MAX_DURATION_MS = void 0;
8
+ exports.extractMelSpectrogram = extractMelSpectrogram;
9
+ const __1 = require("..");
10
+ const constants_1 = require("../constants");
11
+ const melSpectrogramWasm_1 = require("./melSpectrogramWasm");
12
+ const audioProcessing_1 = require("../utils/audioProcessing");
13
+ const cleanNativeOptions_1 = require("../utils/cleanNativeOptions");
14
+ /**
15
+ * Maximum duration in milliseconds that extractMelSpectrogram will process in a single call.
16
+ * The C++ core requires the entire trimmed range as a contiguous float array in memory,
17
+ * so this bound prevents OOM on all platforms. Callers needing longer ranges can iterate
18
+ * in windows of this size using startTimeMs/endTimeMs.
19
+ */
20
+ exports.MAX_DURATION_MS = 30_000;
21
+ /**
22
+ * Extracts a mel spectrogram from audio data
23
+ *
24
+ * @experimental This feature is experimental.
25
+ * Uses shared C++ implementation on all platforms (native on iOS/Android, WASM on web).
26
+ */
27
+ async function extractMelSpectrogram(options) {
28
+ let { fileUri, arrayBuffer, windowSizeMs, hopLengthMs, nMels, fMin = 0, fMax, windowType = 'hann', normalize = false, logScale = true, decodingOptions, startTimeMs, endTimeMs, logger, } = options;
29
+ // Apply max duration guard
30
+ if (startTimeMs == null && endTimeMs == null) {
31
+ startTimeMs = 0;
32
+ endTimeMs = exports.MAX_DURATION_MS;
33
+ logger?.warn?.(`extractMelSpectrogram: no time range specified, defaulting to 0–${exports.MAX_DURATION_MS}ms`);
34
+ }
35
+ else {
36
+ const start = startTimeMs ?? 0;
37
+ const end = endTimeMs ?? start + exports.MAX_DURATION_MS;
38
+ if (end - start > exports.MAX_DURATION_MS) {
39
+ endTimeMs = start + exports.MAX_DURATION_MS;
40
+ logger?.warn?.(`extractMelSpectrogram: requested range ${end - start}ms exceeds max ${exports.MAX_DURATION_MS}ms, clamping endTimeMs to ${endTimeMs}`);
41
+ }
42
+ }
43
+ if (constants_1.isWeb) {
44
+ // Create audio context
45
+ const audioContext = new (window.AudioContext ||
46
+ window.webkitAudioContext)();
47
+ try {
48
+ // Process audio data using the existing utility
49
+ const processedAudio = await (0, audioProcessing_1.processAudioBuffer)({
50
+ arrayBuffer,
51
+ fileUri,
52
+ targetSampleRate: decodingOptions?.targetSampleRate || 16000,
53
+ targetChannels: decodingOptions?.targetChannels || 1,
54
+ normalizeAudio: decodingOptions?.normalizeAudio ?? false,
55
+ startTimeMs,
56
+ endTimeMs,
57
+ audioContext,
58
+ logger: options.logger,
59
+ });
60
+ // Calculate window and hop size in samples
61
+ const sampleRate = processedAudio.sampleRate;
62
+ const windowSize = Math.floor((windowSizeMs * sampleRate) / 1000);
63
+ const hopLength = Math.floor((hopLengthMs * sampleRate) / 1000);
64
+ const maxFreq = fMax || sampleRate / 2;
65
+ // Extract the mel spectrogram via WASM (same C++ as native)
66
+ const spectrogram = await (0, melSpectrogramWasm_1.computeMelSpectrogramWasm)(processedAudio.channelData, sampleRate, nMels, windowSize, hopLength, fMin, maxFreq, windowType, normalize, logScale);
67
+ const timeSteps = spectrogram.length;
68
+ return {
69
+ spectrogram,
70
+ sampleRate,
71
+ nMels,
72
+ timeSteps,
73
+ durationMs: processedAudio.durationMs,
74
+ };
75
+ }
76
+ catch (error) {
77
+ logger?.error('Error extracting mel spectrogram:', error);
78
+ throw error;
79
+ }
80
+ finally {
81
+ // Close the audio context
82
+ await audioContext.close();
83
+ }
84
+ }
85
+ // Strip logger/arrayBuffer (non-serializable) then clean undefined values
86
+ // to avoid Android "Cannot convert '[object Object]' to Kotlin type" crash
87
+ const { logger: _logger, arrayBuffer: _arrayBuffer, ...nativeOptions } = options;
88
+ return __1.AudioStudioModule.extractMelSpectrogram((0, cleanNativeOptions_1.cleanNativeOptions)(nativeOptions));
89
+ }
90
+ //# sourceMappingURL=extractMelSpectrogram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractMelSpectrogram.js","sourceRoot":"","sources":["../../../src/AudioAnalysis/extractMelSpectrogram.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @experimental This feature is experimental and currently only available on Android.\n * The API may change in future versions.\n */\n\nimport { AudioStudioModule } from '..'\nimport { isWeb } from '../constants'\nimport {\n ExtractMelSpectrogramOptions,\n MelSpectrogram,\n} from './AudioAnalysis.types'\nimport { computeMelSpectrogramWasm } from './melSpectrogramWasm'\nimport {\n processAudioBuffer,\n ProcessedAudioData,\n} from '../utils/audioProcessing'\nimport { cleanNativeOptions } from '../utils/cleanNativeOptions'\n\n/**\n * Maximum duration in milliseconds that extractMelSpectrogram will process in a single call.\n * The C++ core requires the entire trimmed range as a contiguous float array in memory,\n * so this bound prevents OOM on all platforms. Callers needing longer ranges can iterate\n * in windows of this size using startTimeMs/endTimeMs.\n */\nexport const MAX_DURATION_MS = 30_000\n\n/**\n * Extracts a mel spectrogram from audio data\n *\n * @experimental This feature is experimental.\n * Uses shared C++ implementation on all platforms (native on iOS/Android, WASM on web).\n */\nexport async function extractMelSpectrogram(\n options: ExtractMelSpectrogramOptions\n): Promise<MelSpectrogram> {\n let {\n fileUri,\n arrayBuffer,\n windowSizeMs,\n hopLengthMs,\n nMels,\n fMin = 0,\n fMax,\n windowType = 'hann',\n normalize = false,\n logScale = true,\n decodingOptions,\n startTimeMs,\n endTimeMs,\n logger,\n } = options\n\n // Apply max duration guard\n if (startTimeMs == null && endTimeMs == null) {\n startTimeMs = 0\n endTimeMs = MAX_DURATION_MS\n logger?.warn?.(\n `extractMelSpectrogram: no time range specified, defaulting to 0–${MAX_DURATION_MS}ms`\n )\n } else {\n const start = startTimeMs ?? 0\n const end = endTimeMs ?? start + MAX_DURATION_MS\n if (end - start > MAX_DURATION_MS) {\n endTimeMs = start + MAX_DURATION_MS\n logger?.warn?.(\n `extractMelSpectrogram: requested range ${end - start}ms exceeds max ${MAX_DURATION_MS}ms, clamping endTimeMs to ${endTimeMs}`\n )\n }\n }\n\n if (isWeb) {\n // Create audio context\n const audioContext = new (window.AudioContext ||\n (window as any).webkitAudioContext)()\n\n try {\n // Process audio data using the existing utility\n const processedAudio: ProcessedAudioData = await processAudioBuffer(\n {\n arrayBuffer,\n fileUri,\n targetSampleRate:\n decodingOptions?.targetSampleRate || 16000,\n targetChannels: decodingOptions?.targetChannels || 1,\n normalizeAudio: decodingOptions?.normalizeAudio ?? false,\n startTimeMs,\n endTimeMs,\n audioContext,\n logger: options.logger,\n }\n )\n\n // Calculate window and hop size in samples\n const sampleRate = processedAudio.sampleRate\n const windowSize = Math.floor((windowSizeMs * sampleRate) / 1000)\n const hopLength = Math.floor((hopLengthMs * sampleRate) / 1000)\n const maxFreq = fMax || sampleRate / 2\n\n // Extract the mel spectrogram via WASM (same C++ as native)\n const spectrogram = await computeMelSpectrogramWasm(\n processedAudio.channelData,\n sampleRate,\n nMels,\n windowSize,\n hopLength,\n fMin,\n maxFreq,\n windowType,\n normalize,\n logScale\n )\n\n const timeSteps = spectrogram.length\n\n return {\n spectrogram,\n sampleRate,\n nMels,\n timeSteps,\n durationMs: processedAudio.durationMs,\n }\n } catch (error) {\n logger?.error('Error extracting mel spectrogram:', error)\n throw error\n } finally {\n // Close the audio context\n await audioContext.close()\n }\n }\n // Strip logger/arrayBuffer (non-serializable) then clean undefined values\n // to avoid Android \"Cannot convert '[object Object]' to Kotlin type\" crash\n const {\n logger: _logger,\n arrayBuffer: _arrayBuffer,\n ...nativeOptions\n } = options\n return AudioStudioModule.extractMelSpectrogram(\n cleanNativeOptions(nativeOptions)\n )\n}\n"]}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractPreview = extractPreview;
4
+ const extractAudioAnalysis_1 = require("./extractAudioAnalysis");
5
+ /**
6
+ * Generates a simplified preview of the audio waveform for quick visualization.
7
+ * Ideal for UI rendering with a specified number of points.
8
+ *
9
+ * @param options - The options for the preview, including file URI and time range.
10
+ * @returns A promise that resolves to the audio preview data.
11
+ */
12
+ async function extractPreview({ fileUri, numberOfPoints = 100, startTimeMs = 0, endTimeMs = 30000, // First 30 seconds
13
+ decodingOptions, logger, }) {
14
+ const durationMs = endTimeMs - startTimeMs;
15
+ const segmentDurationMs = Math.floor(durationMs / numberOfPoints);
16
+ // Call extractAudioAnalysis with calculated parameters
17
+ const analysis = await (0, extractAudioAnalysis_1.extractAudioAnalysis)({
18
+ fileUri,
19
+ startTimeMs,
20
+ endTimeMs,
21
+ logger,
22
+ segmentDurationMs,
23
+ decodingOptions,
24
+ });
25
+ // Transform the result into AudioPreview format
26
+ return analysis;
27
+ }
28
+ //# sourceMappingURL=extractPreview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractPreview.js","sourceRoot":"","sources":["../../../src/AudioAnalysis/extractPreview.ts"],"names":[],"mappings":";;AAUA,wCAuBC;AAhCD,iEAA6D;AAE7D;;;;;;GAMG;AACI,KAAK,UAAU,cAAc,CAAC,EACjC,OAAO,EACP,cAAc,GAAG,GAAG,EACpB,WAAW,GAAG,CAAC,EACf,SAAS,GAAG,KAAK,EAAE,mBAAmB;AACtC,eAAe,EACf,MAAM,GACO;IACb,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,CAAA;IAC1C,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,cAAc,CAAC,CAAA;IAEjE,uDAAuD;IACvD,MAAM,QAAQ,GAAG,MAAM,IAAA,2CAAoB,EAAC;QACxC,OAAO;QACP,WAAW;QACX,SAAS;QACT,MAAM;QACN,iBAAiB;QACjB,eAAe;KAClB,CAAC,CAAA;IAEF,gDAAgD;IAChD,OAAO,QAAQ,CAAA;AACnB,CAAC","sourcesContent":["import { PreviewOptions, AudioAnalysis } from './AudioAnalysis.types'\nimport { extractAudioAnalysis } from './extractAudioAnalysis'\n\n/**\n * Generates a simplified preview of the audio waveform for quick visualization.\n * Ideal for UI rendering with a specified number of points.\n *\n * @param options - The options for the preview, including file URI and time range.\n * @returns A promise that resolves to the audio preview data.\n */\nexport async function extractPreview({\n fileUri,\n numberOfPoints = 100,\n startTimeMs = 0,\n endTimeMs = 30000, // First 30 seconds\n decodingOptions,\n logger,\n}: PreviewOptions): Promise<AudioAnalysis> {\n const durationMs = endTimeMs - startTimeMs\n const segmentDurationMs = Math.floor(durationMs / numberOfPoints)\n\n // Call extractAudioAnalysis with calculated parameters\n const analysis = await extractAudioAnalysis({\n fileUri,\n startTimeMs,\n endTimeMs,\n logger,\n segmentDurationMs,\n decodingOptions,\n })\n\n // Transform the result into AudioPreview format\n return analysis\n}\n"]}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.extractWaveform = void 0;
7
+ const AudioStudioModule_1 = __importDefault(require("../AudioStudioModule"));
8
+ const extractWaveform = async ({ fileUri, numberOfSamples, offset = 0, length, }) => {
9
+ const res = await AudioStudioModule_1.default.extractAudioAnalysis({
10
+ fileUri,
11
+ numberOfSamples,
12
+ offset,
13
+ length,
14
+ });
15
+ return res;
16
+ };
17
+ exports.extractWaveform = extractWaveform;
18
+ //# sourceMappingURL=extractWaveform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractWaveform.js","sourceRoot":"","sources":["../../../src/AudioAnalysis/extractWaveform.ts"],"names":[],"mappings":";;;;;;AAAA,6EAAoD;AAQ7C,MAAM,eAAe,GAAG,KAAK,EAAE,EAClC,OAAO,EACP,eAAe,EACf,MAAM,GAAG,CAAC,EACV,MAAM,GACa,EAAoB,EAAE;IACzC,MAAM,GAAG,GAAG,MAAM,2BAAiB,CAAC,oBAAoB,CAAC;QACrD,OAAO;QACP,eAAe;QACf,MAAM;QACN,MAAM;KACT,CAAC,CAAA;IACF,OAAO,GAAG,CAAA;AACd,CAAC,CAAA;AAbY,QAAA,eAAe,mBAa3B","sourcesContent":["import AudioStudioModule from '../AudioStudioModule'\n\nexport interface ExtractWaveformProps {\n fileUri: string\n numberOfSamples: number\n offset?: number\n length?: number\n}\nexport const extractWaveform = async ({\n fileUri,\n numberOfSamples,\n offset = 0,\n length,\n}: ExtractWaveformProps): Promise<unknown> => {\n const res = await AudioStudioModule.extractAudioAnalysis({\n fileUri,\n numberOfSamples,\n offset,\n length,\n })\n return res\n}\n"]}
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.initMelStreamingWasm = initMelStreamingWasm;
37
+ exports.computeMelFrameWasm = computeMelFrameWasm;
38
+ exports.computeMelSpectrogramWasm = computeMelSpectrogramWasm;
39
+ let modulePromise = null;
40
+ function getModule() {
41
+ if (!modulePromise) {
42
+ modulePromise = (async () => {
43
+ // Dynamic import of the prebuilt SINGLE_FILE Emscripten module
44
+ // @ts-expect-error -- prebuilt Emscripten JS glue has no .d.ts
45
+ const mod = await Promise.resolve().then(() => __importStar(require('../../prebuilt/wasm/mel-spectrogram.js')));
46
+ const factory = mod.default ?? mod;
47
+ return factory();
48
+ })().catch((err) => {
49
+ modulePromise = null;
50
+ throw err;
51
+ });
52
+ }
53
+ return modulePromise;
54
+ }
55
+ // --- Streaming (per-frame) API for live mel spectrogram ---
56
+ let streamingModule = null;
57
+ let streamingNMels = 0;
58
+ let streamingFramePtr = 0;
59
+ let streamingMelPtr = 0;
60
+ let streamingFrameCapacity = 0;
61
+ /**
62
+ * Initialise the WASM streaming processor. Call once before computeMelFrame().
63
+ * Re-initialises only when config changes.
64
+ */
65
+ async function initMelStreamingWasm(sampleRate, nMels = 128, fftLength = 2048, windowSizeSamples = 400, hopLengthSamples = 160, fMin = 0, fMax = 0) {
66
+ const Module = await getModule();
67
+ streamingModule = Module;
68
+ const actualFMax = fMax > 0 ? fMax : sampleRate / 2;
69
+ Module._mel_spectrogram_init(sampleRate, fftLength, windowSizeSamples, hopLengthSamples, nMels, fMin, actualFMax, 0 /* hann */);
70
+ streamingNMels = nMels;
71
+ // Pre-allocate output buffer (fixed size)
72
+ if (streamingMelPtr)
73
+ Module._free(streamingMelPtr);
74
+ streamingMelPtr = Module._malloc(nMels * 4);
75
+ // Frame input buffer allocated on demand in computeMelFrame
76
+ streamingFrameCapacity = 0;
77
+ streamingFramePtr = 0;
78
+ }
79
+ /**
80
+ * Compute a single mel spectrogram frame from raw PCM samples via WASM C++.
81
+ * Returns null if not initialised or on error.
82
+ */
83
+ function computeMelFrameWasm(samples) {
84
+ if (!streamingModule || !streamingMelPtr)
85
+ return null;
86
+ const Module = streamingModule;
87
+ // (Re-)allocate frame input buffer if needed
88
+ if (samples.length > streamingFrameCapacity) {
89
+ if (streamingFramePtr)
90
+ Module._free(streamingFramePtr);
91
+ streamingFramePtr = Module._malloc(samples.length * 4);
92
+ streamingFrameCapacity = samples.length;
93
+ }
94
+ // Copy samples to WASM heap
95
+ Module.HEAPF32.set(samples, streamingFramePtr >> 2);
96
+ const ok = Module._mel_spectrogram_compute_frame(streamingFramePtr, samples.length, streamingMelPtr);
97
+ if (!ok)
98
+ return null;
99
+ // Read mel output from WASM heap
100
+ const offset = streamingMelPtr >> 2;
101
+ const result = new Array(streamingNMels);
102
+ for (let i = 0; i < streamingNMels; i++) {
103
+ result[i] = Module.HEAPF32[offset + i];
104
+ }
105
+ return result;
106
+ }
107
+ /**
108
+ * Computes a mel spectrogram via the WASM-compiled C++ implementation.
109
+ * Lazy-loads the WASM module on first call.
110
+ */
111
+ async function computeMelSpectrogramWasm(audioData, sampleRate, nMels, windowSizeSamples, hopLengthSamples, fMin, fMax, windowType, normalize, logScale) {
112
+ const Module = await getModule();
113
+ const fftLength = 2048;
114
+ const windowTypeInt = windowType === 'hamming' ? 1 : 0;
115
+ // Allocate input buffer on WASM heap
116
+ const numSamples = audioData.length;
117
+ const inputPtr = Module._malloc(numSamples * 4); // 4 bytes per float
118
+ Module.HEAPF32.set(audioData, inputPtr >> 2);
119
+ // Call the C bridge
120
+ const resultPtr = Module._mel_spectrogram_compute(inputPtr, numSamples, sampleRate, fftLength, windowSizeSamples, hopLengthSamples, nMels, fMin, fMax, windowTypeInt, logScale ? 1 : 0, normalize ? 1 : 0);
121
+ // Free input buffer
122
+ Module._free(inputPtr);
123
+ if (resultPtr === 0) {
124
+ throw new Error('mel_spectrogram_compute returned null (too few samples?)');
125
+ }
126
+ // Read CMelSpectrogramResult struct (wasm32 pointers are 4 bytes)
127
+ // struct layout: { float* data (offset 0), int timeSteps (offset 4), int nMels (offset 8) }
128
+ const dataPtr = Module.getValue(resultPtr, 'i32');
129
+ const timeSteps = Module.getValue(resultPtr + 4, 'i32');
130
+ const resultNMels = Module.getValue(resultPtr + 8, 'i32');
131
+ if (!dataPtr || timeSteps <= 0 || resultNMels <= 0) {
132
+ Module._mel_spectrogram_free(resultPtr);
133
+ throw new Error('mel_spectrogram_compute returned invalid result struct');
134
+ }
135
+ // Copy spectrogram data to JS arrays
136
+ const spectrogram = [];
137
+ const heapOffset = dataPtr >> 2; // float32 offset into HEAPF32
138
+ for (let t = 0; t < timeSteps; t++) {
139
+ const row = new Array(resultNMels);
140
+ for (let m = 0; m < resultNMels; m++) {
141
+ row[m] = Module.HEAPF32[heapOffset + t * resultNMels + m];
142
+ }
143
+ spectrogram.push(row);
144
+ }
145
+ // Free the C result
146
+ Module._mel_spectrogram_free(resultPtr);
147
+ return spectrogram;
148
+ }
149
+ //# sourceMappingURL=melSpectrogramWasm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"melSpectrogramWasm.js","sourceRoot":"","sources":["../../../src/AudioAnalysis/melSpectrogramWasm.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MelSpectrogramWasmModule } from './mel-spectrogram-wasm'\n\nlet modulePromise: Promise<MelSpectrogramWasmModule> | null = null\n\nfunction getModule(): Promise<MelSpectrogramWasmModule> {\n if (!modulePromise) {\n modulePromise = (async () => {\n // Dynamic import of the prebuilt SINGLE_FILE Emscripten module\n // @ts-expect-error -- prebuilt Emscripten JS glue has no .d.ts\n const mod = await import('../../prebuilt/wasm/mel-spectrogram.js')\n const factory = mod.default ?? mod\n return factory() as Promise<MelSpectrogramWasmModule>\n })().catch((err) => {\n modulePromise = null\n throw err\n })\n }\n return modulePromise\n}\n\n// --- Streaming (per-frame) API for live mel spectrogram ---\n\nlet streamingModule: MelSpectrogramWasmModule | null = null\nlet streamingNMels = 0\nlet streamingFramePtr = 0\nlet streamingMelPtr = 0\nlet streamingFrameCapacity = 0\n\n/**\n * Initialise the WASM streaming processor. Call once before computeMelFrame().\n * Re-initialises only when config changes.\n */\nexport async function initMelStreamingWasm(\n sampleRate: number,\n nMels = 128,\n fftLength = 2048,\n windowSizeSamples = 400,\n hopLengthSamples = 160,\n fMin = 0,\n fMax = 0\n): Promise<void> {\n const Module = await getModule()\n streamingModule = Module\n const actualFMax = fMax > 0 ? fMax : sampleRate / 2\n Module._mel_spectrogram_init(\n sampleRate,\n fftLength,\n windowSizeSamples,\n hopLengthSamples,\n nMels,\n fMin,\n actualFMax,\n 0 /* hann */\n )\n streamingNMels = nMels\n\n // Pre-allocate output buffer (fixed size)\n if (streamingMelPtr) Module._free(streamingMelPtr)\n streamingMelPtr = Module._malloc(nMels * 4)\n\n // Frame input buffer allocated on demand in computeMelFrame\n streamingFrameCapacity = 0\n streamingFramePtr = 0\n}\n\n/**\n * Compute a single mel spectrogram frame from raw PCM samples via WASM C++.\n * Returns null if not initialised or on error.\n */\nexport function computeMelFrameWasm(samples: Float32Array): number[] | null {\n if (!streamingModule || !streamingMelPtr) return null\n const Module = streamingModule\n\n // (Re-)allocate frame input buffer if needed\n if (samples.length > streamingFrameCapacity) {\n if (streamingFramePtr) Module._free(streamingFramePtr)\n streamingFramePtr = Module._malloc(samples.length * 4)\n streamingFrameCapacity = samples.length\n }\n\n // Copy samples to WASM heap\n Module.HEAPF32.set(samples, streamingFramePtr >> 2)\n\n const ok = Module._mel_spectrogram_compute_frame(\n streamingFramePtr,\n samples.length,\n streamingMelPtr\n )\n if (!ok) return null\n\n // Read mel output from WASM heap\n const offset = streamingMelPtr >> 2\n const result = new Array(streamingNMels)\n for (let i = 0; i < streamingNMels; i++) {\n result[i] = Module.HEAPF32[offset + i]\n }\n return result\n}\n\n/**\n * Computes a mel spectrogram via the WASM-compiled C++ implementation.\n * Lazy-loads the WASM module on first call.\n */\nexport async function computeMelSpectrogramWasm(\n audioData: Float32Array,\n sampleRate: number,\n nMels: number,\n windowSizeSamples: number,\n hopLengthSamples: number,\n fMin: number,\n fMax: number,\n windowType: 'hann' | 'hamming',\n normalize: boolean,\n logScale: boolean\n): Promise<number[][]> {\n const Module = await getModule()\n\n const fftLength = 2048\n const windowTypeInt = windowType === 'hamming' ? 1 : 0\n\n // Allocate input buffer on WASM heap\n const numSamples = audioData.length\n const inputPtr = Module._malloc(numSamples * 4) // 4 bytes per float\n Module.HEAPF32.set(audioData, inputPtr >> 2)\n\n // Call the C bridge\n const resultPtr = Module._mel_spectrogram_compute(\n inputPtr,\n numSamples,\n sampleRate,\n fftLength,\n windowSizeSamples,\n hopLengthSamples,\n nMels,\n fMin,\n fMax,\n windowTypeInt,\n logScale ? 1 : 0,\n normalize ? 1 : 0\n )\n\n // Free input buffer\n Module._free(inputPtr)\n\n if (resultPtr === 0) {\n throw new Error(\n 'mel_spectrogram_compute returned null (too few samples?)'\n )\n }\n\n // Read CMelSpectrogramResult struct (wasm32 pointers are 4 bytes)\n // struct layout: { float* data (offset 0), int timeSteps (offset 4), int nMels (offset 8) }\n const dataPtr = Module.getValue(resultPtr, 'i32')\n const timeSteps = Module.getValue(resultPtr + 4, 'i32')\n const resultNMels = Module.getValue(resultPtr + 8, 'i32')\n\n if (!dataPtr || timeSteps <= 0 || resultNMels <= 0) {\n Module._mel_spectrogram_free(resultPtr)\n throw new Error(\n 'mel_spectrogram_compute returned invalid result struct'\n )\n }\n\n // Copy spectrogram data to JS arrays\n const spectrogram: number[][] = []\n const heapOffset = dataPtr >> 2 // float32 offset into HEAPF32\n for (let t = 0; t < timeSteps; t++) {\n const row = new Array(resultNMels)\n for (let m = 0; m < resultNMels; m++) {\n row[m] = Module.HEAPF32[heapOffset + t * resultNMels + m]\n }\n spectrogram.push(row)\n }\n\n // Free the C result\n Module._mel_spectrogram_free(resultPtr)\n\n return spectrogram\n}\n"]}