@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,75 @@
1
+ import Foundation
2
+ import AVFoundation
3
+ import Accelerate
4
+
5
+ class TestAudioGenerator {
6
+
7
+ /// Generate a sine wave tone
8
+ static func generateTone(frequency: Double, duration: TimeInterval, sampleRate: Double = 44100) -> AVAudioPCMBuffer? {
9
+ let frameCount = AVAudioFrameCount(duration * sampleRate)
10
+
11
+ guard let buffer = AVAudioPCMBuffer(pcmFormat: AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: 1)!, frameCapacity: frameCount) else {
12
+ return nil
13
+ }
14
+
15
+ buffer.frameLength = frameCount
16
+
17
+ let channelData = buffer.floatChannelData![0]
18
+ let angleIncrement = 2.0 * .pi * frequency / sampleRate
19
+
20
+ for frame in 0..<Int(frameCount) {
21
+ channelData[frame] = Float(sin(Double(frame) * angleIncrement))
22
+ }
23
+
24
+ return buffer
25
+ }
26
+
27
+ /// Generate white noise
28
+ static func generateWhiteNoise(duration: TimeInterval, sampleRate: Double = 44100) -> AVAudioPCMBuffer? {
29
+ let frameCount = AVAudioFrameCount(duration * sampleRate)
30
+
31
+ guard let buffer = AVAudioPCMBuffer(pcmFormat: AVAudioFormat(standardFormatWithSampleRate: sampleRate, channels: 1)!, frameCapacity: frameCount) else {
32
+ return nil
33
+ }
34
+
35
+ buffer.frameLength = frameCount
36
+
37
+ let channelData = buffer.floatChannelData![0]
38
+
39
+ for frame in 0..<Int(frameCount) {
40
+ channelData[frame] = Float.random(in: -1...1)
41
+ }
42
+
43
+ return buffer
44
+ }
45
+
46
+ /// Load test asset from bundle
47
+ static func loadTestAsset(named name: String) -> AVAudioFile? {
48
+ guard let url = Bundle(for: TestAudioGenerator.self).url(forResource: name, withExtension: "wav") else {
49
+ return nil
50
+ }
51
+
52
+ return try? AVAudioFile(forReading: url)
53
+ }
54
+
55
+ /// Convert AVAudioPCMBuffer to Data
56
+ static func bufferToData(_ buffer: AVAudioPCMBuffer) -> Data? {
57
+ guard let channelData = buffer.floatChannelData else { return nil }
58
+
59
+ let channelCount = Int(buffer.format.channelCount)
60
+ let frameLength = Int(buffer.frameLength)
61
+ let bytesPerFrame = 2 * channelCount // 16-bit audio
62
+
63
+ var data = Data(capacity: frameLength * bytesPerFrame)
64
+
65
+ for frame in 0..<frameLength {
66
+ for channel in 0..<channelCount {
67
+ let sample = channelData[channel][frame]
68
+ let int16Sample = Int16(max(-32768, min(32767, sample * 32767)))
69
+ data.append(contentsOf: withUnsafeBytes(of: int16Sample) { Array($0) })
70
+ }
71
+ }
72
+
73
+ return data
74
+ }
75
+ }
@@ -0,0 +1,54 @@
1
+ //
2
+ // DataPoint.swift
3
+ // AudioStudio
4
+ //
5
+ // Created by Arthur Breton on 23/6/2024.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ public struct SpeechFeatures {
11
+ public var isActive: Bool
12
+ public var speakerId: Int?
13
+
14
+ func toDictionary() -> [String: Any] {
15
+ return [
16
+ "isActive": isActive,
17
+ "speakerId": speakerId as Any
18
+ ]
19
+ }
20
+ }
21
+
22
+ public struct DataPoint {
23
+ public var id: Int
24
+ public var amplitude: Float
25
+ public var rms: Float
26
+ public var dB: Float
27
+ public var silent: Bool
28
+ public var features: Features?
29
+ public var speech: SpeechFeatures?
30
+ public let startTime: Float // in seconds
31
+ public let endTime: Float // in seconds
32
+ public let startPosition: Int // byte position in audio file
33
+ public let endPosition: Int // byte position in audio file
34
+ public let samples: Int // number of samples in segment
35
+ }
36
+
37
+ extension DataPoint {
38
+ func toDictionary() -> [String: Any] {
39
+ return [
40
+ "id": id,
41
+ "amplitude": amplitude,
42
+ "rms": rms,
43
+ "dB": dB,
44
+ "silent": silent,
45
+ "features": features?.toDictionary() ?? [:],
46
+ "speech": speech?.toDictionary() ?? [:],
47
+ "startTime": startTime,
48
+ "endTime": endTime,
49
+ "startPosition": startPosition,
50
+ "endPosition": endPosition,
51
+ "samples": samples
52
+ ]
53
+ }
54
+ }
@@ -0,0 +1,59 @@
1
+ //
2
+ // DecodingConfig.swift
3
+ // Pods
4
+ //
5
+ // Created by Arthur Breton on 24/2/2025.
6
+ //
7
+
8
+ import AVFoundation
9
+
10
+ public struct DecodingConfig {
11
+ public let targetSampleRate: Double?
12
+ public let targetChannels: Int?
13
+ public let targetBitDepth: Int?
14
+ public let normalizeAudio: Bool
15
+
16
+ public init(
17
+ targetSampleRate: Double?,
18
+ targetChannels: Int?,
19
+ targetBitDepth: Int?,
20
+ normalizeAudio: Bool = false
21
+ ) {
22
+ self.targetSampleRate = targetSampleRate
23
+ self.targetChannels = targetChannels
24
+ self.targetBitDepth = targetBitDepth
25
+ self.normalizeAudio = normalizeAudio
26
+ }
27
+
28
+ public static func fromDictionary(_ dict: [String: Any]?) -> DecodingConfig {
29
+ guard let dict = dict else {
30
+ return DecodingConfig.default
31
+ }
32
+
33
+ return DecodingConfig(
34
+ targetSampleRate: dict["targetSampleRate"] as? Double,
35
+ targetChannels: dict["targetChannels"] as? Int,
36
+ targetBitDepth: dict["targetBitDepth"] as? Int,
37
+ normalizeAudio: dict["normalizeAudio"] as? Bool ?? false
38
+ )
39
+ }
40
+
41
+ public static var `default`: DecodingConfig {
42
+ return DecodingConfig(
43
+ targetSampleRate: nil,
44
+ targetChannels: nil,
45
+ targetBitDepth: nil,
46
+ normalizeAudio: false
47
+ )
48
+ }
49
+
50
+ public func toAudioFormat(baseFormat: AVAudioFormat) -> AVAudioFormat {
51
+ let sampleRate = targetSampleRate ?? baseFormat.sampleRate
52
+ let channels = targetChannels ?? Int(baseFormat.channelCount)
53
+
54
+ return AVAudioFormat(
55
+ standardFormatWithSampleRate: sampleRate,
56
+ channels: AVAudioChannelCount(channels)
57
+ )!
58
+ }
59
+ }
package/ios/FFT.swift ADDED
@@ -0,0 +1,62 @@
1
+ //
2
+ // FFT.swift
3
+ // Pods
4
+ //
5
+ // Created by Arthur Breton on 20/2/2025.
6
+ //
7
+
8
+ import Accelerate
9
+
10
+ class FFT {
11
+ private let length: Int
12
+ private var setup: vDSP_DFT_Setup?
13
+
14
+ init(_ length: Int) {
15
+ self.length = length
16
+ self.setup = vDSP_DFT_zop_CreateSetup(
17
+ nil,
18
+ vDSP_Length(length),
19
+ vDSP_DFT_Direction.FORWARD
20
+ )
21
+ }
22
+
23
+ deinit {
24
+ if let setup = setup {
25
+ vDSP_DFT_DestroySetup(setup)
26
+ }
27
+ }
28
+
29
+ func realForward(_ data: inout [Float]) {
30
+ var realIn = data
31
+ var imagIn = [Float](repeating: 0.0, count: length)
32
+ var realOut = [Float](repeating: 0.0, count: length)
33
+ var imagOut = [Float](repeating: 0.0, count: length)
34
+
35
+ // Perform FFT
36
+ vDSP_DFT_Execute(setup!,
37
+ &realIn,
38
+ &imagIn,
39
+ &realOut,
40
+ &imagOut)
41
+
42
+ // Ensure data array has enough space for both real and imaginary parts
43
+ if data.count < 2 * length {
44
+ data.append(contentsOf: [Float](repeating: 0.0, count: 2 * length - data.count))
45
+ }
46
+
47
+ // Combine real and imaginary parts
48
+ for i in 0..<length {
49
+ let j = i * 2
50
+ data[j] = realOut[i]
51
+ data[j + 1] = imagOut[i]
52
+ }
53
+ }
54
+
55
+ func processSegment(_ segment: [Float]) -> [Float] {
56
+ var fftData = segment.count < length ?
57
+ segment + [Float](repeating: 0, count: length - segment.count) :
58
+ Array(segment.prefix(length))
59
+ realForward(&fftData)
60
+ return fftData
61
+ }
62
+ }
@@ -0,0 +1,95 @@
1
+ //
2
+ // Features.swift
3
+ // AudioStudio
4
+ //
5
+ // Created by Arthur Breton on 23/6/2024.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ public struct Features {
11
+ var energy: Float
12
+ var mfcc: [Float]
13
+ var rms: Float
14
+ var minAmplitude: Float
15
+ var maxAmplitude: Float
16
+ var zcr: Float
17
+ var spectralCentroid: Float
18
+ var spectralFlatness: Float
19
+ var spectralRolloff: Float?
20
+ var spectralBandwidth: Float?
21
+ var chromagram: [Float]?
22
+ var tempo: Float?
23
+ var hnr: Float?
24
+ var melSpectrogram: [Float]?
25
+ var spectralContrast: [Float]?
26
+ var tonnetz: [Float]?
27
+ var pitch: Float?
28
+ var crc32: UInt32?
29
+
30
+ init(
31
+ energy: Float = 0,
32
+ mfcc: [Float] = [],
33
+ rms: Float = 0,
34
+ minAmplitude: Float = 0,
35
+ maxAmplitude: Float = 0,
36
+ zcr: Float = 0,
37
+ spectralCentroid: Float = 0,
38
+ spectralFlatness: Float = 0,
39
+ spectralRolloff: Float? = nil,
40
+ spectralBandwidth: Float? = nil,
41
+ chromagram: [Float]? = nil,
42
+ tempo: Float? = nil,
43
+ hnr: Float? = nil,
44
+ melSpectrogram: [Float]? = nil,
45
+ spectralContrast: [Float]? = nil,
46
+ tonnetz: [Float]? = nil,
47
+ pitch: Float? = nil,
48
+ crc32: UInt32? = nil
49
+ ) {
50
+ self.energy = energy
51
+ self.mfcc = mfcc
52
+ self.rms = rms
53
+ self.minAmplitude = minAmplitude
54
+ self.maxAmplitude = maxAmplitude
55
+ self.zcr = zcr
56
+ self.spectralCentroid = spectralCentroid
57
+ self.spectralFlatness = spectralFlatness
58
+ self.spectralRolloff = spectralRolloff
59
+ self.spectralBandwidth = spectralBandwidth
60
+ self.chromagram = chromagram
61
+ self.tempo = tempo
62
+ self.hnr = hnr
63
+ self.melSpectrogram = melSpectrogram
64
+ self.spectralContrast = spectralContrast
65
+ self.tonnetz = tonnetz
66
+ self.pitch = pitch
67
+ self.crc32 = crc32
68
+ }
69
+ }
70
+
71
+ extension Features {
72
+ func toDictionary() -> [String: Any] {
73
+ let dict: [String: Any] = [
74
+ "energy": energy,
75
+ "mfcc": mfcc,
76
+ "rms": rms,
77
+ "minAmplitude": minAmplitude,
78
+ "maxAmplitude": maxAmplitude,
79
+ "zcr": zcr,
80
+ "spectralCentroid": spectralCentroid,
81
+ "spectralFlatness": spectralFlatness,
82
+ "spectralRolloff": spectralRolloff ?? 0,
83
+ "spectralBandwidth": spectralBandwidth ?? 0,
84
+ "chromagram": chromagram ?? [],
85
+ "tempo": tempo ?? 0,
86
+ "hnr": hnr ?? 0,
87
+ "melSpectrogram": melSpectrogram ?? [],
88
+ "spectralContrast": spectralContrast ?? [],
89
+ "tonnetz": tonnetz ?? [],
90
+ "pitch": pitch ?? 0,
91
+ "crc32": crc32 ?? 0
92
+ ]
93
+ return dict
94
+ }
95
+ }
@@ -0,0 +1,68 @@
1
+ # iOS Recording Issue: No WAV Data/Analysis When Resampling (e.g., 16kHz) - RESOLVED
2
+
3
+ ## Problem Summary
4
+
5
+ Initially, the iOS implementation failed to record WAV audio data or perform real-time analysis when the requested `sampleRate` (e.g., 16,000 Hz) differed from the hardware's native sample rate (e.g., 48,000 Hz), requiring resampling. Recording at the native hardware sample rate worked correctly.
6
+
7
+ The primary symptom was that the tap installed on the `audioEngine.inputNode` using `installTap(onBus:bufferSize:format:)` was **not receiving any audio buffers** when resampling was required (i.e., requested rate != hardware rate). This resulted in:
8
+
9
+ * An empty WAV file (only the initial 44-byte header).
10
+ * No data being sent to the `AudioProcessor` for real-time analysis.
11
+ * No `AudioData` or `AudioAnalysis` events being emitted for the WAV stream.
12
+
13
+ Parallel compressed recording (e.g., AAC) functioned correctly even when the WAV stream failed, indicating the audio engine *was* capturing audio but not delivering it to the tap.
14
+
15
+ ## Debugging History & Findings
16
+
17
+ 1. **Initial State:** Empty WAV file at 16kHz, working AAC at 16kHz. Confirmed 48kHz WAV worked.
18
+ 2. **Tap Installation Format:** Early attempts tried setting the tap format to the *requested* sample rate (16kHz), leading to `AVAudioIONodeImpl.mm:1334 Format mismatch` crashes because the tap format didn't match the actual hardware input format (often 48kHz).
19
+ 3. **Using `inputNode.outputFormat`:** Switched to installing the tap using the format reported by `inputNode.outputFormat(forBus: 0)`, assuming this reflected the actual hardware format. Resampling was handled later in `processAudioBuffer`. This fixed the crash but **did not** fix the original issue – the tap still received no buffers at 16kHz.
20
+ 4. **Race Condition:** Identified and fixed a race condition where `audioEngine.start()` was called before `isRecording` was set to `true`, causing the tap's initial guard check to fail. This allowed buffers to be processed *after* the flag was set, but the WAV file writing was still faulty (only the first buffer was written).
21
+ 5. **Background File I/O Refactor:** Improved WAV file writing by keeping the `FileHandle` open during recording instead of opening/closing for each buffer in the background queue. This fixed the partial file writing issue but didn't solve the core "no buffers received at 16kHz" problem.
22
+ 6. **Removing `setPreferredSampleRate`:** Tried removing the `session.setPreferredSampleRate` call, hoping the session would default to the hardware rate, allowing the 48kHz tap (based on `inputNode.outputFormat`) to receive buffers. This **worked** for the internal microphone but caused crashes with Bluetooth headsets, as the Bluetooth hardware *actually* operated at 16kHz, creating a new format mismatch.
23
+ 7. **Using `session.sampleRate`:** Attempted to use `session.sampleRate` *after* session activation to determine the tap format. This also proved unreliable, sometimes reporting 16kHz for the session while `inputNode.outputFormat` still reported 48kHz, leading back to the format mismatch crash.
24
+ 8. **Using `inputNode.inputFormat`:** After further analysis, discovered that `inputNode.inputFormat(forBus: 0)` gives the actual hardware input format, which may differ from the output format. This is the format that iOS strictly requires for a tap.
25
+
26
+ ## Root Cause
27
+
28
+ The core issue stems from the unreliability and potential inconsistency between:
29
+
30
+ * `AVAudioSession.sampleRate` (especially after `setPreferredSampleRate` or device changes).
31
+ * `audioEngine.inputNode.outputFormat(forBus: 0)` (which might not immediately reflect the true hardware format).
32
+ * `audioEngine.inputNode.inputFormat(forBus: 0)` (which provides the hardware's actual input format).
33
+ * The actual sample rate the hardware is delivering to the audio engine.
34
+
35
+ Attempting to force a specific sample rate via `setPreferredSampleRate` or relying solely on `session.sampleRate` post-activation can lead to situations where the format used to install the tap does not match the format the audio engine expects/receives from the hardware input, causing either a crash (`Format mismatch`) or the tap simply not receiving any buffers.
36
+
37
+ ## Final Solution
38
+
39
+ The most robust solution was found to be:
40
+
41
+ 1. **Configure Session:** Set up the `AVAudioSession` category, mode, and options as required. **Do not** call `setPreferredSampleRate`. Let the session negotiate the rate with the hardware.
42
+ 2. **Activate Session:** Activate the audio session.
43
+ 3. **Query Hardware Input Format (Just-In-Time):** Immediately **before** calling `installTap`, query the hardware's input format using `audioEngine.inputNode.inputFormat(forBus: 0)`. This provides the actual format that the hardware is delivering and that iOS requires for the tap.
44
+ 4. **Install Tap:** Install the tap using the exact `AVAudioFormat` obtained from `inputNode.inputFormat(forBus: 0)` in the previous step.
45
+ 5. **Resample in Tap:** Inside the tap's processing closure (`processAudioBuffer`), check if the received `buffer.format.sampleRate` differs from the `settings.sampleRate` requested by the user. If they differ, perform the resampling explicitly using `AVAudioConverter` (or a similar method) before writing the WAV data or performing analysis.
46
+
47
+ This approach ensures the tap format always matches what the hardware requires, regardless of the device (internal mic, Bluetooth) or the requested output sample rate. Subsequent resampling handles the conversion to the user's desired format.
48
+
49
+ ## Additional Findings: Device Disconnection Handling
50
+
51
+ During testing, we discovered an issue with device disconnection (particularly Bluetooth headsets):
52
+
53
+ 1. When a recording device disconnects, iOS reports a route change notification.
54
+ 2. If we attempt to resume recording after the device disconnection or switch to a new device, the app would crash with `Format mismatch: input hw <AVAudioFormat: 1 ch, 16000 Hz, Float32>, client format <AVAudioFormat: 1 ch, 48000 Hz, Float32>`.
55
+
56
+ We implemented a robust solution with the following components:
57
+
58
+ 1. **Hardware Format Detection:** Created a shared `installTapWithHardwareFormat` method that always queries the current hardware input format using `inputNode.inputFormat(forBus: 0)` before installing a tap.
59
+
60
+ 2. **Format Verification on Resume:** When resuming recording after a pause (potentially due to device disconnect), we reinstall the tap with the current hardware format.
61
+
62
+ 3. **Fallback Device Handling:** Implemented a configurable device disconnection behavior:
63
+ - `pause`: Pause recording when the current device disconnects (default)
64
+ - `fallback`: Automatically switch to the default device (built-in mic) and continue recording
65
+
66
+ 4. **Size Tracking Preservation:** Ensured that during device transitions, the total audio data size is preserved to maintain continuity in the recording.
67
+
68
+ These improvements ensure that when audio devices change during a recording session, the app can either pause gracefully or continue recording with a fallback device, without data loss or crashes due to format mismatches.
@@ -0,0 +1,39 @@
1
+ class Logger {
2
+ // Similar to Android's TAG_PREFIX for consistent cross-platform logging
3
+ private static let TAG_PREFIX = "AudioStudio"
4
+
5
+ static func debug(_ className: String, _ message: @autoclosure () -> String) {
6
+ #if DEBUG
7
+ print("[\(TAG_PREFIX):\(className)] [DEBUG] \(message())")
8
+ #endif
9
+ }
10
+
11
+ static func info(_ className: String, _ message: @autoclosure () -> String) {
12
+ print("[\(TAG_PREFIX):\(className)] [INFO] \(message())")
13
+ }
14
+
15
+ static func warn(_ className: String, _ message: @autoclosure () -> String) {
16
+ print("[\(TAG_PREFIX):\(className)] [WARN] ⚠️ \(message())")
17
+ }
18
+
19
+ static func error(_ className: String, _ message: @autoclosure () -> String) {
20
+ print("[\(TAG_PREFIX):\(className)] [ERROR] 🛑 \(message())")
21
+ }
22
+
23
+ // For backward compatibility with code that doesn't specify a class name
24
+ static func debug(_ message: @autoclosure () -> String) {
25
+ debug("General", message())
26
+ }
27
+
28
+ static func info(_ message: @autoclosure () -> String) {
29
+ info("General", message())
30
+ }
31
+
32
+ static func warn(_ message: @autoclosure () -> String) {
33
+ warn("General", message())
34
+ }
35
+
36
+ static func error(_ message: @autoclosure () -> String) {
37
+ error("General", message())
38
+ }
39
+ }
@@ -0,0 +1,30 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ @interface MelSpectrogramWrapper : NSObject
4
+
5
+ + (nullable NSDictionary *)computeWithSamples:(const float *)samples
6
+ numSamples:(int)numSamples
7
+ sampleRate:(int)sampleRate
8
+ fftLength:(int)fftLength
9
+ windowSizeSamples:(int)windowSizeSamples
10
+ hopLengthSamples:(int)hopLengthSamples
11
+ nMels:(int)nMels
12
+ fMin:(float)fMin
13
+ fMax:(float)fMax
14
+ windowType:(int)windowType
15
+ logScale:(BOOL)logScale
16
+ normalize:(BOOL)normalize;
17
+
18
+ + (void)initWithSampleRate:(int)sampleRate
19
+ fftLength:(int)fftLength
20
+ windowSizeSamples:(int)windowSizeSamples
21
+ hopLengthSamples:(int)hopLengthSamples
22
+ nMels:(int)nMels
23
+ fMin:(float)fMin
24
+ fMax:(float)fMax
25
+ windowType:(int)windowType;
26
+
27
+ + (nullable NSArray<NSNumber *> *)computeFrameWithSamples:(const float *)samples
28
+ frameSize:(int)frameSize;
29
+
30
+ @end
@@ -0,0 +1,97 @@
1
+ #import "MelSpectrogramWrapper.h"
2
+
3
+ // Include C++ implementation directly since CocoaPods doesn't compile
4
+ // source files from outside the pod's root directory (../cpp/)
5
+ #include "kiss_fft/kiss_fft.c"
6
+ #include "kiss_fft/kiss_fftr.c"
7
+ #include "MelSpectrogram.cpp"
8
+ #include "MelSpectrogramBridge.cpp"
9
+
10
+ @implementation MelSpectrogramWrapper
11
+
12
+ + (nullable NSDictionary *)computeWithSamples:(const float *)samples
13
+ numSamples:(int)numSamples
14
+ sampleRate:(int)sampleRate
15
+ fftLength:(int)fftLength
16
+ windowSizeSamples:(int)windowSizeSamples
17
+ hopLengthSamples:(int)hopLengthSamples
18
+ nMels:(int)nMels
19
+ fMin:(float)fMin
20
+ fMax:(float)fMax
21
+ windowType:(int)windowType
22
+ logScale:(BOOL)logScale
23
+ normalize:(BOOL)normalize
24
+ {
25
+ CMelSpectrogramResult* result = mel_spectrogram_compute(
26
+ samples, numSamples, sampleRate,
27
+ fftLength, windowSizeSamples, hopLengthSamples,
28
+ nMels, fMin, fMax,
29
+ windowType, logScale ? 1 : 0, normalize ? 1 : 0);
30
+
31
+ if (!result) {
32
+ return nil;
33
+ }
34
+
35
+ // Convert flat float array to NSArray of NSArray<NSNumber>
36
+ NSMutableArray *spectrogram = [NSMutableArray arrayWithCapacity:result->timeSteps];
37
+ for (int i = 0; i < result->timeSteps; i++) {
38
+ NSMutableArray *row = [NSMutableArray arrayWithCapacity:result->nMels];
39
+ for (int j = 0; j < result->nMels; j++) {
40
+ [row addObject:@(result->data[i * result->nMels + j])];
41
+ }
42
+ [spectrogram addObject:row];
43
+ }
44
+
45
+ NSDictionary *dict = @{
46
+ @"spectrogram": spectrogram,
47
+ @"timeSteps": @(result->timeSteps),
48
+ @"nMels": @(result->nMels)
49
+ };
50
+
51
+ mel_spectrogram_free(result);
52
+
53
+ return dict;
54
+ }
55
+
56
+ + (void)initWithSampleRate:(int)sampleRate
57
+ fftLength:(int)fftLength
58
+ windowSizeSamples:(int)windowSizeSamples
59
+ hopLengthSamples:(int)hopLengthSamples
60
+ nMels:(int)nMels
61
+ fMin:(float)fMin
62
+ fMax:(float)fMax
63
+ windowType:(int)windowType
64
+ {
65
+ mel_spectrogram_init(sampleRate, fftLength, windowSizeSamples,
66
+ hopLengthSamples, nMels, fMin, fMax, windowType);
67
+ }
68
+
69
+ + (nullable NSArray<NSNumber *> *)computeFrameWithSamples:(const float *)samples
70
+ frameSize:(int)frameSize
71
+ {
72
+ int nMels = mel_spectrogram_get_n_mels();
73
+ if (nMels <= 0) {
74
+ return nil;
75
+ }
76
+
77
+ float* melOutput = (float*)malloc(nMels * sizeof(float));
78
+ if (!melOutput) {
79
+ return nil;
80
+ }
81
+
82
+ int success = mel_spectrogram_compute_frame(samples, frameSize, melOutput);
83
+ if (!success) {
84
+ free(melOutput);
85
+ return nil;
86
+ }
87
+
88
+ NSMutableArray<NSNumber *> *result = [NSMutableArray arrayWithCapacity:nMels];
89
+ for (int i = 0; i < nMels; i++) {
90
+ [result addObject:@(melOutput[i])];
91
+ }
92
+
93
+ free(melOutput);
94
+ return result;
95
+ }
96
+
97
+ @end
@@ -0,0 +1,15 @@
1
+ //
2
+ // NotificationExtension.swift
3
+ // Pods
4
+ //
5
+ // Created by Arthur Breton on 27/10/2024.
6
+ //
7
+
8
+
9
+ import Foundation
10
+
11
+ extension Notification.Name {
12
+ static let pauseRecording = Notification.Name("PAUSE_RECORDING")
13
+ static let resumeRecording = Notification.Name("RESUME_RECORDING")
14
+ static let notificationActionTriggered = Notification.Name("notificationActionTriggered")
15
+ }
@@ -0,0 +1,22 @@
1
+ // RecordingResult.swift
2
+
3
+ struct RecordingResult {
4
+ var fileUri: String
5
+ var filename: String
6
+ var mimeType: String
7
+ var duration: Int64
8
+ var size: Int64
9
+ var channels: Int
10
+ var bitDepth: Int
11
+ var sampleRate: Double
12
+ var compression: CompressedRecordingInfo?
13
+ }
14
+
15
+ struct StartRecordingResult {
16
+ var fileUri: String
17
+ var mimeType: String
18
+ var channels: Int
19
+ var bitDepth: Int
20
+ var sampleRate: Double
21
+ var compression: CompressedRecordingInfo?
22
+ }