@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.
- package/CHANGELOG.md +535 -0
- package/LICENSE +21 -0
- package/README.md +167 -0
- package/android/build.gradle +143 -0
- package/android/src/androidTest/assets/chorus.wav +0 -0
- package/android/src/androidTest/assets/jfk.wav +0 -0
- package/android/src/androidTest/assets/osr_us_000_0010_8k.wav +0 -0
- package/android/src/androidTest/assets/recorder_hello_world.wav +0 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/AudioProcessorInstrumentedTest.kt +197 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderInstrumentedTest.kt +541 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderPerformanceInstrumentedTest.kt +234 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/AudioFocusStrategyIntegrationTest.kt +332 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/BufferDurationIntegrationTest.kt +324 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/CompressedOnlyOutputTest.kt +253 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/DeviceDisconnectionFallbackTest.kt +218 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/EventEmissionIntervalTest.kt +120 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/M4aFormatTest.kt +345 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/OutputControlIntegrationTest.kt +340 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/PcmStreamingDurationTest.kt +252 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/README.md +95 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/run_integration_tests.sh +43 -0
- package/android/src/main/AndroidManifest.xml +30 -0
- package/android/src/main/CMakeLists.txt +29 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioAnalysisData.kt +188 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioDataEncoder.kt +9 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioDeviceManager.kt +1741 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioFeaturesNative.kt +26 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioFileHandler.kt +136 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioFormatUtils.kt +354 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioNotificationsManager.kt +439 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioProcessor.kt +2237 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioRecorderManager.kt +2163 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioRecordingService.kt +167 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioStudioModule.kt +1112 -0
- package/android/src/main/java/net/siteed/audiostudio/AudioTrimmer.kt +1099 -0
- package/android/src/main/java/net/siteed/audiostudio/Constants.kt +37 -0
- package/android/src/main/java/net/siteed/audiostudio/EventSender.kt +7 -0
- package/android/src/main/java/net/siteed/audiostudio/FFT.kt +100 -0
- package/android/src/main/java/net/siteed/audiostudio/Features.kt +98 -0
- package/android/src/main/java/net/siteed/audiostudio/LogUtils.kt +93 -0
- package/android/src/main/java/net/siteed/audiostudio/MelSpectrogramNative.kt +36 -0
- package/android/src/main/java/net/siteed/audiostudio/NotificationConfig.kt +72 -0
- package/android/src/main/java/net/siteed/audiostudio/PermissionUtils.kt +68 -0
- package/android/src/main/java/net/siteed/audiostudio/RecordingActionReceiver.kt +59 -0
- package/android/src/main/java/net/siteed/audiostudio/RecordingConfig.kt +259 -0
- package/android/src/main/java/net/siteed/audiostudio/WaveformConfig.kt +19 -0
- package/android/src/main/java/net/siteed/audiostudio/WaveformRenderer.kt +159 -0
- package/android/src/main/jni/AudioFeaturesJNI.cpp +152 -0
- package/android/src/main/jni/MelSpectrogramJNI.cpp +165 -0
- package/android/src/main/res/drawable/ic_default_action_icon.xml +16 -0
- package/android/src/main/res/drawable/ic_microphone.xml +13 -0
- package/android/src/main/res/drawable/ic_pause.xml +10 -0
- package/android/src/main/res/drawable/ic_play.xml +10 -0
- package/android/src/main/res/drawable/ic_stop.xml +10 -0
- package/android/src/main/res/layout/notification_recording.xml +37 -0
- package/android/src/test/java/net/siteed/audiostudio/AudioFileHandlerTest.kt +279 -0
- package/android/src/test/java/net/siteed/audiostudio/AudioFocusStrategyTest.kt +249 -0
- package/android/src/test/java/net/siteed/audiostudio/AudioFormatTest.kt +151 -0
- package/android/src/test/java/net/siteed/audiostudio/AudioFormatUtilsTest.kt +273 -0
- package/android/src/test/java/net/siteed/audiostudio/DeviceDisconnectionFallbackUnitTest.kt +140 -0
- package/android/src/test/resources/chorus.wav +0 -0
- package/android/src/test/resources/generate_test_audio.py +94 -0
- package/android/src/test/resources/jfk.wav +0 -0
- package/android/src/test/resources/osr_us_000_0010_8k.wav +0 -0
- package/android/src/test/resources/recorder_hello_world.wav +0 -0
- package/app.plugin.js +3 -0
- package/build/cjs/AudioAnalysis/AudioAnalysis.types.js +4 -0
- package/build/cjs/AudioAnalysis/AudioAnalysis.types.js.map +1 -0
- package/build/cjs/AudioAnalysis/audioFeaturesWasm.js +164 -0
- package/build/cjs/AudioAnalysis/audioFeaturesWasm.js.map +1 -0
- package/build/cjs/AudioAnalysis/extractAudioAnalysis.js +213 -0
- package/build/cjs/AudioAnalysis/extractAudioAnalysis.js.map +1 -0
- package/build/cjs/AudioAnalysis/extractAudioData.js +21 -0
- package/build/cjs/AudioAnalysis/extractAudioData.js.map +1 -0
- package/build/cjs/AudioAnalysis/extractMelSpectrogram.js +90 -0
- package/build/cjs/AudioAnalysis/extractMelSpectrogram.js.map +1 -0
- package/build/cjs/AudioAnalysis/extractPreview.js +28 -0
- package/build/cjs/AudioAnalysis/extractPreview.js.map +1 -0
- package/build/cjs/AudioAnalysis/extractWaveform.js +18 -0
- package/build/cjs/AudioAnalysis/extractWaveform.js.map +1 -0
- package/build/cjs/AudioAnalysis/melSpectrogramWasm.js +149 -0
- package/build/cjs/AudioAnalysis/melSpectrogramWasm.js.map +1 -0
- package/build/cjs/AudioDeviceManager.js +688 -0
- package/build/cjs/AudioDeviceManager.js.map +1 -0
- package/build/cjs/AudioRecorder.provider.js +78 -0
- package/build/cjs/AudioRecorder.provider.js.map +1 -0
- package/build/cjs/AudioStudio.native.js +8 -0
- package/build/cjs/AudioStudio.native.js.map +1 -0
- package/build/cjs/AudioStudio.types.js +11 -0
- package/build/cjs/AudioStudio.types.js.map +1 -0
- package/build/cjs/AudioStudio.web.js +708 -0
- package/build/cjs/AudioStudio.web.js.map +1 -0
- package/build/cjs/AudioStudioModule.js +718 -0
- package/build/cjs/AudioStudioModule.js.map +1 -0
- package/build/cjs/WebRecorder.web.js +865 -0
- package/build/cjs/WebRecorder.web.js.map +1 -0
- package/build/cjs/constants/platformLimitations.js +99 -0
- package/build/cjs/constants/platformLimitations.js.map +1 -0
- package/build/cjs/constants.js +20 -0
- package/build/cjs/constants.js.map +1 -0
- package/build/cjs/events.js +29 -0
- package/build/cjs/events.js.map +1 -0
- package/build/cjs/hooks/useAudioDevices.js +179 -0
- package/build/cjs/hooks/useAudioDevices.js.map +1 -0
- package/build/cjs/index.js +64 -0
- package/build/cjs/index.js.map +1 -0
- package/build/cjs/trimAudio.js +76 -0
- package/build/cjs/trimAudio.js.map +1 -0
- package/build/cjs/useAudioRecorder.js +535 -0
- package/build/cjs/useAudioRecorder.js.map +1 -0
- package/build/cjs/utils/BlobFix.js +502 -0
- package/build/cjs/utils/BlobFix.js.map +1 -0
- package/build/cjs/utils/audioProcessing.js +136 -0
- package/build/cjs/utils/audioProcessing.js.map +1 -0
- package/build/cjs/utils/cleanNativeOptions.js +22 -0
- package/build/cjs/utils/cleanNativeOptions.js.map +1 -0
- package/build/cjs/utils/concatenateBuffers.js +25 -0
- package/build/cjs/utils/concatenateBuffers.js.map +1 -0
- package/build/cjs/utils/convertPCMToFloat32.js +124 -0
- package/build/cjs/utils/convertPCMToFloat32.js.map +1 -0
- package/build/cjs/utils/crc32.js +52 -0
- package/build/cjs/utils/crc32.js.map +1 -0
- package/build/cjs/utils/encodingToBitDepth.js +17 -0
- package/build/cjs/utils/encodingToBitDepth.js.map +1 -0
- package/build/cjs/utils/getWavFileInfo.js +96 -0
- package/build/cjs/utils/getWavFileInfo.js.map +1 -0
- package/build/cjs/utils/writeWavHeader.js +88 -0
- package/build/cjs/utils/writeWavHeader.js.map +1 -0
- package/build/cjs/workers/InlineFeaturesExtractor.web.js +294 -0
- package/build/cjs/workers/InlineFeaturesExtractor.web.js.map +1 -0
- package/build/cjs/workers/inlineAudioWebWorker.web.js +190 -0
- package/build/cjs/workers/inlineAudioWebWorker.web.js.map +1 -0
- package/build/cjs/workers/wasmGlueString.web.js +27 -0
- package/build/cjs/workers/wasmGlueString.web.js.map +1 -0
- package/build/esm/AudioAnalysis/AudioAnalysis.types.js +3 -0
- package/build/esm/AudioAnalysis/AudioAnalysis.types.js.map +1 -0
- package/build/esm/AudioAnalysis/audioFeaturesWasm.js +126 -0
- package/build/esm/AudioAnalysis/audioFeaturesWasm.js.map +1 -0
- package/build/esm/AudioAnalysis/extractAudioAnalysis.js +205 -0
- package/build/esm/AudioAnalysis/extractAudioAnalysis.js.map +1 -0
- package/build/esm/AudioAnalysis/extractAudioData.js +14 -0
- package/build/esm/AudioAnalysis/extractAudioData.js.map +1 -0
- package/build/esm/AudioAnalysis/extractMelSpectrogram.js +86 -0
- package/build/esm/AudioAnalysis/extractMelSpectrogram.js.map +1 -0
- package/build/esm/AudioAnalysis/extractPreview.js +25 -0
- package/build/esm/AudioAnalysis/extractPreview.js.map +1 -0
- package/build/esm/AudioAnalysis/extractWaveform.js +11 -0
- package/build/esm/AudioAnalysis/extractWaveform.js.map +1 -0
- package/build/esm/AudioAnalysis/melSpectrogramWasm.js +111 -0
- package/build/esm/AudioAnalysis/melSpectrogramWasm.js.map +1 -0
- package/build/esm/AudioDeviceManager.js +681 -0
- package/build/esm/AudioDeviceManager.js.map +1 -0
- package/build/esm/AudioRecorder.provider.js +40 -0
- package/build/esm/AudioRecorder.provider.js.map +1 -0
- package/build/esm/AudioStudio.native.js +6 -0
- package/build/esm/AudioStudio.native.js.map +1 -0
- package/build/esm/AudioStudio.types.js +8 -0
- package/build/esm/AudioStudio.types.js.map +1 -0
- package/build/esm/AudioStudio.web.js +704 -0
- package/build/esm/AudioStudio.web.js.map +1 -0
- package/build/esm/AudioStudioModule.js +713 -0
- package/build/esm/AudioStudioModule.js.map +1 -0
- package/build/esm/WebRecorder.web.js +861 -0
- package/build/esm/WebRecorder.web.js.map +1 -0
- package/build/esm/constants/platformLimitations.js +90 -0
- package/build/esm/constants/platformLimitations.js.map +1 -0
- package/build/esm/constants.js +17 -0
- package/build/esm/constants.js.map +1 -0
- package/build/esm/events.js +21 -0
- package/build/esm/events.js.map +1 -0
- package/build/esm/hooks/useAudioDevices.js +176 -0
- package/build/esm/hooks/useAudioDevices.js.map +1 -0
- package/build/esm/index.js +23 -0
- package/build/esm/index.js.map +1 -0
- package/build/esm/trimAudio.js +69 -0
- package/build/esm/trimAudio.js.map +1 -0
- package/build/esm/useAudioRecorder.js +529 -0
- package/build/esm/useAudioRecorder.js.map +1 -0
- package/build/esm/utils/BlobFix.js +498 -0
- package/build/esm/utils/BlobFix.js.map +1 -0
- package/build/esm/utils/audioProcessing.js +133 -0
- package/build/esm/utils/audioProcessing.js.map +1 -0
- package/build/esm/utils/cleanNativeOptions.js +19 -0
- package/build/esm/utils/cleanNativeOptions.js.map +1 -0
- package/build/esm/utils/concatenateBuffers.js +21 -0
- package/build/esm/utils/concatenateBuffers.js.map +1 -0
- package/build/esm/utils/convertPCMToFloat32.js +120 -0
- package/build/esm/utils/convertPCMToFloat32.js.map +1 -0
- package/build/esm/utils/crc32.js +50 -0
- package/build/esm/utils/crc32.js.map +1 -0
- package/build/esm/utils/encodingToBitDepth.js +13 -0
- package/build/esm/utils/encodingToBitDepth.js.map +1 -0
- package/build/esm/utils/getWavFileInfo.js +92 -0
- package/build/esm/utils/getWavFileInfo.js.map +1 -0
- package/build/esm/utils/writeWavHeader.js +84 -0
- package/build/esm/utils/writeWavHeader.js.map +1 -0
- package/build/esm/workers/InlineFeaturesExtractor.web.js +291 -0
- package/build/esm/workers/InlineFeaturesExtractor.web.js.map +1 -0
- package/build/esm/workers/inlineAudioWebWorker.web.js +187 -0
- package/build/esm/workers/inlineAudioWebWorker.web.js.map +1 -0
- package/build/esm/workers/wasmGlueString.web.js +24 -0
- package/build/esm/workers/wasmGlueString.web.js.map +1 -0
- package/build/types/AudioAnalysis/AudioAnalysis.types.d.ts +198 -0
- package/build/types/AudioAnalysis/AudioAnalysis.types.d.ts.map +1 -0
- package/build/types/AudioAnalysis/audioFeaturesWasm.d.ts +24 -0
- package/build/types/AudioAnalysis/audioFeaturesWasm.d.ts.map +1 -0
- package/build/types/AudioAnalysis/extractAudioAnalysis.d.ts +74 -0
- package/build/types/AudioAnalysis/extractAudioAnalysis.d.ts.map +1 -0
- package/build/types/AudioAnalysis/extractAudioData.d.ts +3 -0
- package/build/types/AudioAnalysis/extractAudioData.d.ts.map +1 -0
- package/build/types/AudioAnalysis/extractMelSpectrogram.d.ts +20 -0
- package/build/types/AudioAnalysis/extractMelSpectrogram.d.ts.map +1 -0
- package/build/types/AudioAnalysis/extractPreview.d.ts +11 -0
- package/build/types/AudioAnalysis/extractPreview.d.ts.map +1 -0
- package/build/types/AudioAnalysis/extractWaveform.d.ts +8 -0
- package/build/types/AudioAnalysis/extractWaveform.d.ts.map +1 -0
- package/build/types/AudioAnalysis/melSpectrogramWasm.d.ts +16 -0
- package/build/types/AudioAnalysis/melSpectrogramWasm.d.ts.map +1 -0
- package/build/types/AudioDeviceManager.d.ts +187 -0
- package/build/types/AudioDeviceManager.d.ts.map +1 -0
- package/build/types/AudioRecorder.provider.d.ts +11 -0
- package/build/types/AudioRecorder.provider.d.ts.map +1 -0
- package/build/types/AudioStudio.native.d.ts +3 -0
- package/build/types/AudioStudio.native.d.ts.map +1 -0
- package/build/types/AudioStudio.types.d.ts +760 -0
- package/build/types/AudioStudio.types.d.ts.map +1 -0
- package/build/types/AudioStudio.web.d.ts +96 -0
- package/build/types/AudioStudio.web.d.ts.map +1 -0
- package/build/types/AudioStudioModule.d.ts +3 -0
- package/build/types/AudioStudioModule.d.ts.map +1 -0
- package/build/types/WebRecorder.web.d.ts +208 -0
- package/build/types/WebRecorder.web.d.ts.map +1 -0
- package/build/types/constants/platformLimitations.d.ts +40 -0
- package/build/types/constants/platformLimitations.d.ts.map +1 -0
- package/build/types/constants.d.ts +14 -0
- package/build/types/constants.d.ts.map +1 -0
- package/build/types/events.d.ts +29 -0
- package/build/types/events.d.ts.map +1 -0
- package/build/types/hooks/useAudioDevices.d.ts +15 -0
- package/build/types/hooks/useAudioDevices.d.ts.map +1 -0
- package/build/types/index.d.ts +21 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/trimAudio.d.ts +25 -0
- package/build/types/trimAudio.d.ts.map +1 -0
- package/build/types/useAudioRecorder.d.ts +22 -0
- package/build/types/useAudioRecorder.d.ts.map +1 -0
- package/build/types/utils/BlobFix.d.ts +9 -0
- package/build/types/utils/BlobFix.d.ts.map +1 -0
- package/build/types/utils/audioProcessing.d.ts +24 -0
- package/build/types/utils/audioProcessing.d.ts.map +1 -0
- package/build/types/utils/cleanNativeOptions.d.ts +15 -0
- package/build/types/utils/cleanNativeOptions.d.ts.map +1 -0
- package/build/types/utils/concatenateBuffers.d.ts +8 -0
- package/build/types/utils/concatenateBuffers.d.ts.map +1 -0
- package/build/types/utils/convertPCMToFloat32.d.ts +13 -0
- package/build/types/utils/convertPCMToFloat32.d.ts.map +1 -0
- package/build/types/utils/crc32.d.ts +7 -0
- package/build/types/utils/crc32.d.ts.map +1 -0
- package/build/types/utils/encodingToBitDepth.d.ts +5 -0
- package/build/types/utils/encodingToBitDepth.d.ts.map +1 -0
- package/build/types/utils/getWavFileInfo.d.ts +26 -0
- package/build/types/utils/getWavFileInfo.d.ts.map +1 -0
- package/build/types/utils/writeWavHeader.d.ts +34 -0
- package/build/types/utils/writeWavHeader.d.ts.map +1 -0
- package/build/types/workers/InlineFeaturesExtractor.web.d.ts +2 -0
- package/build/types/workers/InlineFeaturesExtractor.web.d.ts.map +1 -0
- package/build/types/workers/inlineAudioWebWorker.web.d.ts +2 -0
- package/build/types/workers/inlineAudioWebWorker.web.d.ts.map +1 -0
- package/build/types/workers/wasmGlueString.web.d.ts +2 -0
- package/build/types/workers/wasmGlueString.web.d.ts.map +1 -0
- package/cpp/AudioFeatures.cpp +274 -0
- package/cpp/AudioFeatures.h +85 -0
- package/cpp/AudioFeaturesBridge.cpp +146 -0
- package/cpp/AudioFeaturesBridge.h +47 -0
- package/cpp/MelSpectrogram.cpp +227 -0
- package/cpp/MelSpectrogram.h +82 -0
- package/cpp/MelSpectrogramBridge.cpp +112 -0
- package/cpp/MelSpectrogramBridge.h +33 -0
- package/cpp/kiss_fft/COPYING +11 -0
- package/cpp/kiss_fft/_kiss_fft_guts.h +167 -0
- package/cpp/kiss_fft/kiss_fft.c +424 -0
- package/cpp/kiss_fft/kiss_fft.h +160 -0
- package/cpp/kiss_fft/kiss_fft_log.h +36 -0
- package/cpp/kiss_fft/kiss_fftr.c +155 -0
- package/cpp/kiss_fft/kiss_fftr.h +54 -0
- package/expo-module.config.json +10 -0
- package/ios/AudioAnalysisData.swift +74 -0
- package/ios/AudioDeviceManager.swift +670 -0
- package/ios/AudioFeaturesWrapper.h +21 -0
- package/ios/AudioFeaturesWrapper.mm +63 -0
- package/ios/AudioNotificationManager.swift +154 -0
- package/ios/AudioProcessingHelpers.swift +797 -0
- package/ios/AudioProcessor.swift +1191 -0
- package/ios/AudioStreamError.swift +7 -0
- package/ios/AudioStreamManager.swift +2369 -0
- package/ios/AudioStreamManagerDelegate.swift +16 -0
- package/ios/AudioStudio.podspec +39 -0
- package/ios/AudioStudioModule.swift +1111 -0
- package/ios/AudioStudioTests/AudioFileHandlerTests.swift +338 -0
- package/ios/AudioStudioTests/AudioFormatUtilsTests.swift +331 -0
- package/ios/AudioStudioTests/AudioTestHelpers.swift +130 -0
- package/ios/AudioStudioTests/CompressedOnlyOutputTests.swift +294 -0
- package/ios/AudioStudioTests/EventEmissionIntervalTests.swift +105 -0
- package/ios/AudioStudioTests/Info.plist +22 -0
- package/ios/AudioStudioTests/README.md +39 -0
- package/ios/AudioStudioTests/SimpleAudioTest.swift +98 -0
- package/ios/AudioStudioTests/TestAudioGenerator.swift +75 -0
- package/ios/DataPoint.swift +54 -0
- package/ios/DecodingConfig.swift +59 -0
- package/ios/FFT.swift +62 -0
- package/ios/Features.swift +95 -0
- package/ios/ISSUE_IOS.md +68 -0
- package/ios/Logger.swift +39 -0
- package/ios/MelSpectrogramWrapper.h +30 -0
- package/ios/MelSpectrogramWrapper.mm +97 -0
- package/ios/NotificationExtension.swift +15 -0
- package/ios/RecordingResult.swift +22 -0
- package/ios/RecordingSettings.swift +311 -0
- package/ios/WaveformExtractor.swift +105 -0
- package/ios/tests/README.md +41 -0
- package/ios/tests/integration/buffer_and_fallback_test.swift +178 -0
- package/ios/tests/integration/buffer_duration_test.swift +185 -0
- package/ios/tests/integration/compressed_only_output_test.swift +271 -0
- package/ios/tests/integration/output_control_test.swift +322 -0
- package/ios/tests/integration/run_integration_tests.sh +37 -0
- package/ios/tests/opus_support_test_macos.swift +154 -0
- package/ios/tests/standalone/audio_processing_test.swift +144 -0
- package/ios/tests/standalone/audio_recording_test.swift +277 -0
- package/ios/tests/standalone/audio_streaming_test.swift +249 -0
- package/ios/tests/standalone/standalone_test.swift +144 -0
- package/package.json +146 -0
- package/plugin/build/index.cjs +194 -0
- package/plugin/build/index.d.cts +22 -0
- package/plugin/build/index.js +194 -0
- package/plugin/src/index.ts +285 -0
- package/plugin/tsconfig.json +10 -0
- package/plugin/tsconfig.tsbuildinfo +1 -0
- package/prebuilt/wasm/mel-spectrogram.js +18 -0
- package/src/AudioAnalysis/AudioAnalysis.types.ts +226 -0
- package/src/AudioAnalysis/audio-features-wasm.d.ts +37 -0
- package/src/AudioAnalysis/audioFeaturesWasm.ts +200 -0
- package/src/AudioAnalysis/extractAudioAnalysis.ts +350 -0
- package/src/AudioAnalysis/extractAudioData.ts +17 -0
- package/src/AudioAnalysis/extractMelSpectrogram.ts +140 -0
- package/src/AudioAnalysis/extractPreview.ts +34 -0
- package/src/AudioAnalysis/extractWaveform.ts +22 -0
- package/src/AudioAnalysis/mel-spectrogram-wasm.d.ts +48 -0
- package/src/AudioAnalysis/melSpectrogramWasm.ts +179 -0
- package/src/AudioDeviceManager.ts +800 -0
- package/src/AudioRecorder.provider.tsx +57 -0
- package/src/AudioStudio.native.ts +6 -0
- package/src/AudioStudio.types.ts +899 -0
- package/src/AudioStudio.web.ts +911 -0
- package/src/AudioStudioModule.ts +984 -0
- package/src/WebRecorder.web.ts +1114 -0
- package/src/constants/platformLimitations.ts +118 -0
- package/src/constants.ts +21 -0
- package/src/events.ts +63 -0
- package/src/hooks/useAudioDevices.ts +213 -0
- package/src/index.ts +67 -0
- package/src/trimAudio.ts +94 -0
- package/src/types/crc-32.d.ts +9 -0
- package/src/useAudioRecorder.tsx +784 -0
- package/src/utils/BlobFix.ts +561 -0
- package/src/utils/audioProcessing.ts +205 -0
- package/src/utils/cleanNativeOptions.ts +18 -0
- package/src/utils/concatenateBuffers.ts +24 -0
- package/src/utils/convertPCMToFloat32.ts +170 -0
- package/src/utils/crc32.ts +59 -0
- package/src/utils/encodingToBitDepth.ts +18 -0
- package/src/utils/getWavFileInfo.ts +132 -0
- package/src/utils/writeWavHeader.ts +115 -0
- package/src/workers/InlineFeaturesExtractor.web.tsx +291 -0
- package/src/workers/inlineAudioWebWorker.web.tsx +186 -0
- package/src/workers/wasmGlueString.web.ts +23 -0
package/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# @siteed/audio-studio
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@siteed/audio-studio)
|
|
4
|
+
[](https://www.npmjs.com/package/@siteed/audio-studio)
|
|
5
|
+
[](https://www.npmjs.com/package/@siteed/audio-studio)
|
|
6
|
+
[](https://github.com/deeeed/audiolab)
|
|
7
|
+
|
|
8
|
+
**Give it a GitHub star, if you found this repo useful.**
|
|
9
|
+
|
|
10
|
+
Cross-platform audio recording, analysis, and processing for React Native and Expo. Mel spectrogram and spectral feature extraction run through a shared C++ layer on iOS, Android, and web (via WASM).
|
|
11
|
+
|
|
12
|
+
> Formerly `@siteed/expo-audio-studio`. See [MIGRATION.md](../../MIGRATION.md) for upgrade steps.
|
|
13
|
+
|
|
14
|
+
<div align="center">
|
|
15
|
+
<div style="display: flex; justify-content: center; gap: 20px; margin: 30px 0;">
|
|
16
|
+
<div>
|
|
17
|
+
<h3>iOS</h3>
|
|
18
|
+
<img src="../../docs/ios.gif" alt="iOS Demo" width="280" />
|
|
19
|
+
</div>
|
|
20
|
+
<div>
|
|
21
|
+
<h3>Android</h3>
|
|
22
|
+
<img src="../../docs/android.gif" alt="Android Demo" width="280" />
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<p>
|
|
27
|
+
<a href="https://apps.apple.com/app/audio-playground/id6739774966">
|
|
28
|
+
<img src="https://developer.apple.com/app-store/marketing/guidelines/images/badge-download-on-the-app-store.svg" alt="App Store" height="40" />
|
|
29
|
+
</a>
|
|
30
|
+
<a href="https://play.google.com/store/apps/details?id=net.siteed.audioplayground">
|
|
31
|
+
<img src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png" alt="Google Play" height="40" />
|
|
32
|
+
</a>
|
|
33
|
+
</p>
|
|
34
|
+
<p><a href="https://deeeed.github.io/audiolab/playground">Try the web demo</a></p>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- **Recording** — real-time streaming, dual-stream (raw PCM + compressed), background recording, zero-latency start via `prepareRecording`
|
|
40
|
+
- **Device management** — list/select input devices (Bluetooth, USB, wired), automatic fallback
|
|
41
|
+
- **Interruption handling** — auto pause/resume during phone calls
|
|
42
|
+
- **Audio analysis** — MFCC, spectral features, mel spectrogram, tempo, pitch, waveform preview
|
|
43
|
+
- **Native performance** — mel spectrogram and FFT-based features (MFCC, spectral centroid, etc.) computed in shared C++ on all platforms (JNI on Android, Obj-C++ bridge on iOS, WASM on web)
|
|
44
|
+
- **Trimming** — precision cut with multi-segment support (keep or remove ranges)
|
|
45
|
+
- **Notifications** — Android live waveform in notification, iOS media player integration
|
|
46
|
+
- **Consistent format** — WAV PCM output across all platforms
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
yarn add @siteed/audio-studio
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { useAudioRecorder } from '@siteed/audio-studio';
|
|
58
|
+
|
|
59
|
+
const { startRecording, stopRecording, isRecording } = useAudioRecorder();
|
|
60
|
+
|
|
61
|
+
// Record
|
|
62
|
+
await startRecording({
|
|
63
|
+
sampleRate: 44100,
|
|
64
|
+
channels: 1,
|
|
65
|
+
encoding: 'pcm_16bit',
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// ... later
|
|
69
|
+
const result = await stopRecording();
|
|
70
|
+
console.log('Saved to:', result.fileUri);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Zero-Latency Recording
|
|
74
|
+
|
|
75
|
+
Pre-initialize to eliminate startup delay:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
const { prepareRecording, startRecording, stopRecording } = useSharedAudioRecorder();
|
|
79
|
+
|
|
80
|
+
await prepareRecording({ sampleRate: 44100, channels: 1, encoding: 'pcm_16bit' });
|
|
81
|
+
|
|
82
|
+
// Later — starts instantly
|
|
83
|
+
await startRecording();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Shared State Across Components
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const AudioApp = () => (
|
|
90
|
+
<AudioRecorderProvider>
|
|
91
|
+
<RecordButton />
|
|
92
|
+
<AudioVisualizer />
|
|
93
|
+
</AudioRecorderProvider>
|
|
94
|
+
);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Float32 Streaming (for ML / DSP)
|
|
98
|
+
|
|
99
|
+
Set `streamFormat: 'float32'` to get `Float32Array` on all platforms instead of base64:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
await startRecording({
|
|
103
|
+
sampleRate: 16000,
|
|
104
|
+
channels: 1,
|
|
105
|
+
encoding: 'pcm_32bit',
|
|
106
|
+
streamFormat: 'float32',
|
|
107
|
+
onAudioStream: async (event) => {
|
|
108
|
+
const samples = event.data as Float32Array;
|
|
109
|
+
await myModel.feed(samples);
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Audio Analysis
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { extractAudioAnalysis, extractPreview, extractMelSpectrogram, trimAudio } from '@siteed/audio-studio';
|
|
118
|
+
|
|
119
|
+
// Feature extraction
|
|
120
|
+
const analysis = await extractAudioAnalysis({
|
|
121
|
+
fileUri: 'path/to/recording.wav',
|
|
122
|
+
features: { rms: true, zcr: true, mfcc: true, spectralCentroid: true }
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Lightweight waveform for visualization
|
|
126
|
+
const preview = await extractPreview({
|
|
127
|
+
fileUri: 'path/to/recording.wav',
|
|
128
|
+
pointsPerSecond: 50
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Mel spectrogram for ML
|
|
132
|
+
const mel = await extractMelSpectrogram({
|
|
133
|
+
fileUri: 'path/to/recording.wav',
|
|
134
|
+
nMels: 40, hopLengthMs: 10
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Trim audio
|
|
138
|
+
const trimmed = await trimAudio({
|
|
139
|
+
fileUri: 'path/to/recording.wav',
|
|
140
|
+
ranges: [{ startTimeMs: 1000, endTimeMs: 5000 }],
|
|
141
|
+
mode: 'keep'
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Which Method to Use
|
|
146
|
+
|
|
147
|
+
| Method | Cost | Use case |
|
|
148
|
+
|--------|------|----------|
|
|
149
|
+
| `extractPreview` | Light | Waveform visualization |
|
|
150
|
+
| `extractRawWavAnalysis` | Light | WAV metadata without decoding |
|
|
151
|
+
| `extractAudioData` | Medium | Raw PCM for custom processing |
|
|
152
|
+
| `extractAudioAnalysis` | Medium-Heavy | MFCC, spectral features, pitch, tempo |
|
|
153
|
+
| `extractMelSpectrogram` | Heavy | Frequency-domain for ML |
|
|
154
|
+
|
|
155
|
+
## Docs
|
|
156
|
+
|
|
157
|
+
- [Getting Started Guide](https://deeeed.github.io/audiolab/docs/)
|
|
158
|
+
- [Contributing](./CONTRIBUTE.md)
|
|
159
|
+
- [AudioPlayground](https://deeeed.github.io/audiolab/playground) — live demo of all features
|
|
160
|
+
- [@siteed/expo-audio-ui](https://github.com/deeeed/audiolab/tree/main/packages/expo-audio-ui) — waveform, spectrogram, and audio control components
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT — see [LICENSE](LICENSE).
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
<sub>Created by [Arthur Breton](https://siteed.net)</sub>
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
apply plugin: 'com.android.library'
|
|
2
|
+
apply plugin: 'kotlin-android'
|
|
3
|
+
apply plugin: 'maven-publish'
|
|
4
|
+
|
|
5
|
+
group = 'net.siteed.audiostudio'
|
|
6
|
+
version = '0.1.0'
|
|
7
|
+
|
|
8
|
+
// These properties prevent plugin conflicts in all Expo versions
|
|
9
|
+
project.ext.isLibrary = true
|
|
10
|
+
project.ext.preventPluginConflict = true
|
|
11
|
+
|
|
12
|
+
buildscript {
|
|
13
|
+
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
14
|
+
if (expoModulesCorePlugin.exists()) {
|
|
15
|
+
apply from: expoModulesCorePlugin
|
|
16
|
+
applyKotlinExpoModulesCorePlugin()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Simple helper that allows the root project to override versions declared by this library.
|
|
20
|
+
ext.safeExtGet = { prop, fallback ->
|
|
21
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Ensures backward compatibility
|
|
25
|
+
ext.getKotlinVersion = {
|
|
26
|
+
if (ext.has("kotlinVersion")) {
|
|
27
|
+
ext.kotlinVersion()
|
|
28
|
+
} else {
|
|
29
|
+
ext.safeExtGet("kotlinVersion", "1.8.10")
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
repositories {
|
|
34
|
+
mavenCentral()
|
|
35
|
+
google()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
dependencies {
|
|
39
|
+
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
afterEvaluate {
|
|
44
|
+
publishing {
|
|
45
|
+
publications {
|
|
46
|
+
release(MavenPublication) {
|
|
47
|
+
from components.release
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
repositories {
|
|
51
|
+
maven {
|
|
52
|
+
url = mavenLocal().url
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
android {
|
|
59
|
+
compileSdkVersion safeExtGet("compileSdkVersion", 34)
|
|
60
|
+
|
|
61
|
+
def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
|
|
62
|
+
if (agpVersion.tokenize('.')[0].toInteger() < 8) {
|
|
63
|
+
compileOptions {
|
|
64
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
65
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
|
69
|
+
kotlinOptions {
|
|
70
|
+
jvmTarget = '17'
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
ndkVersion safeExtGet("ndkVersion", "27.1.12297006")
|
|
76
|
+
|
|
77
|
+
namespace "net.siteed.audiostudio"
|
|
78
|
+
defaultConfig {
|
|
79
|
+
minSdkVersion safeExtGet("minSdkVersion", 21)
|
|
80
|
+
targetSdkVersion safeExtGet("targetSdkVersion", 34)
|
|
81
|
+
versionCode 1
|
|
82
|
+
versionName "0.1.0"
|
|
83
|
+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
84
|
+
externalNativeBuild {
|
|
85
|
+
cmake {
|
|
86
|
+
cppFlags "-frtti -fexceptions -Wall"
|
|
87
|
+
arguments "-DANDROID_STL=c++_shared"
|
|
88
|
+
abiFilters "x86", "x86_64", "arm64-v8a"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
externalNativeBuild {
|
|
93
|
+
cmake {
|
|
94
|
+
path "src/main/CMakeLists.txt"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
lintOptions {
|
|
98
|
+
abortOnError false
|
|
99
|
+
}
|
|
100
|
+
publishing {
|
|
101
|
+
singleVariant("release") {
|
|
102
|
+
withSourcesJar()
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
repositories {
|
|
108
|
+
mavenCentral()
|
|
109
|
+
google()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
dependencies {
|
|
113
|
+
implementation project(':expo-modules-core')
|
|
114
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
|
|
115
|
+
|
|
116
|
+
// Add AndroidX dependencies
|
|
117
|
+
implementation 'androidx.core:core-ktx:1.10.1'
|
|
118
|
+
implementation 'androidx.annotation:annotation:1.6.0'
|
|
119
|
+
implementation 'androidx.appcompat:appcompat:1.6.1'
|
|
120
|
+
|
|
121
|
+
// Add Kotlinx Coroutines for main code
|
|
122
|
+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
|
|
123
|
+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
|
|
124
|
+
|
|
125
|
+
// Add testing dependencies
|
|
126
|
+
testImplementation 'junit:junit:4.13.2'
|
|
127
|
+
testImplementation 'org.jetbrains.kotlin:kotlin-test:1.8.10'
|
|
128
|
+
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit:1.8.10'
|
|
129
|
+
|
|
130
|
+
// Add Android instrumented test dependencies
|
|
131
|
+
androidTestImplementation 'androidx.test:runner:1.5.2'
|
|
132
|
+
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
|
133
|
+
androidTestImplementation 'androidx.test:core:1.5.0'
|
|
134
|
+
androidTestImplementation 'junit:junit:4.13.2'
|
|
135
|
+
androidTestImplementation 'androidx.test:rules:1.5.0'
|
|
136
|
+
androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3'
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
kotlin {
|
|
140
|
+
jvmToolchain {
|
|
141
|
+
languageVersion.set(JavaLanguageVersion.of(17))
|
|
142
|
+
}
|
|
143
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
package net.siteed.audiostudio
|
|
2
|
+
|
|
3
|
+
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
4
|
+
import androidx.test.platform.app.InstrumentationRegistry
|
|
5
|
+
import org.junit.Test
|
|
6
|
+
import org.junit.Assert.*
|
|
7
|
+
import org.junit.Before
|
|
8
|
+
import org.junit.After
|
|
9
|
+
import org.junit.runner.RunWith
|
|
10
|
+
import java.io.File
|
|
11
|
+
import kotlin.math.abs
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Instrumented tests for AudioProcessor that require Android framework components.
|
|
15
|
+
* These tests run on an Android device/emulator and have access to MediaExtractor/MediaCodec.
|
|
16
|
+
*/
|
|
17
|
+
@RunWith(AndroidJUnit4::class)
|
|
18
|
+
class AudioProcessorInstrumentedTest {
|
|
19
|
+
private lateinit var context: android.content.Context
|
|
20
|
+
private lateinit var audioProcessor: AudioProcessor
|
|
21
|
+
private lateinit var testFilesDir: File
|
|
22
|
+
|
|
23
|
+
@Before
|
|
24
|
+
fun setUp() {
|
|
25
|
+
context = InstrumentationRegistry.getInstrumentation().targetContext
|
|
26
|
+
testFilesDir = context.filesDir
|
|
27
|
+
audioProcessor = AudioProcessor(testFilesDir)
|
|
28
|
+
|
|
29
|
+
// Copy test assets to files directory
|
|
30
|
+
copyTestAssets()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@After
|
|
34
|
+
fun tearDown() {
|
|
35
|
+
// Clean up test files
|
|
36
|
+
testFilesDir.listFiles()?.forEach { file ->
|
|
37
|
+
if (file.name.endsWith(".wav")) {
|
|
38
|
+
file.delete()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private fun copyTestAssets() {
|
|
44
|
+
val assetManager = context.assets
|
|
45
|
+
val testFiles = listOf("jfk.wav", "chorus.wav", "recorder_hello_world.wav")
|
|
46
|
+
|
|
47
|
+
testFiles.forEach { fileName ->
|
|
48
|
+
try {
|
|
49
|
+
assetManager.open(fileName).use { input ->
|
|
50
|
+
File(testFilesDir, fileName).outputStream().use { output ->
|
|
51
|
+
input.copyTo(output)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
} catch (e: Exception) {
|
|
55
|
+
// If asset doesn't exist, skip it
|
|
56
|
+
println("Warning: Test asset $fileName not found")
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ========== Audio Loading Tests ==========
|
|
62
|
+
|
|
63
|
+
@Test
|
|
64
|
+
fun testLoadAudioFromAnyFormat_loadsWavFile() {
|
|
65
|
+
// Given
|
|
66
|
+
val wavFile = File(testFilesDir, "jfk.wav")
|
|
67
|
+
assertTrue("Test file should exist", wavFile.exists())
|
|
68
|
+
|
|
69
|
+
// When
|
|
70
|
+
val audioData = audioProcessor.loadAudioFromAnyFormat(wavFile.absolutePath, null)
|
|
71
|
+
|
|
72
|
+
// Then
|
|
73
|
+
assertNotNull("Audio data should not be null", audioData)
|
|
74
|
+
assertEquals("Sample rate should be 16000", 16000, audioData!!.sampleRate)
|
|
75
|
+
assertEquals("Should be mono", 1, audioData.channels)
|
|
76
|
+
assertEquals("Should be 16-bit", 16, audioData.bitDepth)
|
|
77
|
+
assertTrue("Should have audio data", audioData.data.isNotEmpty())
|
|
78
|
+
assertTrue("Duration should be positive", audioData.durationMs > 0)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@Test
|
|
82
|
+
fun testLoadAudioFromAnyFormat_withDecodingConfig() {
|
|
83
|
+
// Given
|
|
84
|
+
val wavFile = File(testFilesDir, "jfk.wav")
|
|
85
|
+
val config = DecodingConfig(
|
|
86
|
+
targetSampleRate = 44100,
|
|
87
|
+
targetChannels = 2, // Test channel conversion - bug fixed
|
|
88
|
+
targetBitDepth = 16,
|
|
89
|
+
normalizeAudio = false
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
// When
|
|
93
|
+
val audioData = audioProcessor.loadAudioFromAnyFormat(wavFile.absolutePath, config)
|
|
94
|
+
|
|
95
|
+
// Then
|
|
96
|
+
assertNotNull("Audio data should not be null", audioData)
|
|
97
|
+
assertEquals("Sample rate should be converted to 44100", 44100, audioData!!.sampleRate)
|
|
98
|
+
assertEquals("Should be converted to stereo", 2, audioData.channels)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ========== Audio Trimming Tests ==========
|
|
102
|
+
|
|
103
|
+
@Test
|
|
104
|
+
fun testTrimAudio_basicTrimming() {
|
|
105
|
+
// Given
|
|
106
|
+
val wavFile = File(testFilesDir, "jfk.wav")
|
|
107
|
+
val startTimeMs = 1000L
|
|
108
|
+
val endTimeMs = 3000L
|
|
109
|
+
|
|
110
|
+
// When
|
|
111
|
+
val trimmedAudio = audioProcessor.trimAudio(
|
|
112
|
+
fileUri = wavFile.absolutePath,
|
|
113
|
+
startTimeMs = startTimeMs,
|
|
114
|
+
endTimeMs = endTimeMs,
|
|
115
|
+
config = null,
|
|
116
|
+
outputFileName = "trimmed_jfk.wav"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
// Then
|
|
120
|
+
assertNotNull("Trimmed audio should not be null", trimmedAudio)
|
|
121
|
+
|
|
122
|
+
// Verify the trimmed file was created
|
|
123
|
+
val trimmedFile = File(testFilesDir, "trimmed_jfk.wav")
|
|
124
|
+
assertTrue("Trimmed file should exist", trimmedFile.exists())
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ========== Mel Spectrogram Tests ==========
|
|
128
|
+
|
|
129
|
+
@Test
|
|
130
|
+
fun testExtractMelSpectrogram_basicGeneration() {
|
|
131
|
+
// Given
|
|
132
|
+
val wavFile = File(testFilesDir, "jfk.wav")
|
|
133
|
+
val audioData = audioProcessor.loadAudioFromAnyFormat(wavFile.absolutePath, null)
|
|
134
|
+
assertNotNull("Audio data should load", audioData)
|
|
135
|
+
|
|
136
|
+
// When
|
|
137
|
+
val melSpectrogram = audioProcessor.extractMelSpectrogram(
|
|
138
|
+
audioData = audioData!!,
|
|
139
|
+
windowSizeMs = 25f,
|
|
140
|
+
hopLengthMs = 10f,
|
|
141
|
+
nMels = 40,
|
|
142
|
+
fftLength = 512
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
// Then
|
|
146
|
+
assertNotNull("Mel spectrogram should not be null", melSpectrogram)
|
|
147
|
+
assertTrue("Should have time frames", melSpectrogram.spectrogram.isNotEmpty())
|
|
148
|
+
assertEquals("Should have 40 mel bins", 40, melSpectrogram.spectrogram[0].size)
|
|
149
|
+
|
|
150
|
+
// Verify timestamps
|
|
151
|
+
assertTrue("Should have timestamps", melSpectrogram.timeStamps.isNotEmpty())
|
|
152
|
+
assertEquals("Timestamps should match frames",
|
|
153
|
+
melSpectrogram.spectrogram.size, melSpectrogram.timeStamps.size)
|
|
154
|
+
|
|
155
|
+
// Verify frequencies
|
|
156
|
+
assertEquals("Should have 40 frequency bins", 40, melSpectrogram.frequencies.size)
|
|
157
|
+
assertTrue("Frequencies should be ascending",
|
|
158
|
+
melSpectrogram.frequencies.zip(melSpectrogram.frequencies.drop(1))
|
|
159
|
+
.all { (a, b) -> a < b })
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ========== Preview Generation Tests ==========
|
|
163
|
+
|
|
164
|
+
@Test
|
|
165
|
+
fun testGeneratePreview_basicPreview() {
|
|
166
|
+
// Given
|
|
167
|
+
val wavFile = File(testFilesDir, "chorus.wav")
|
|
168
|
+
val audioData = audioProcessor.loadAudioFromAnyFormat(wavFile.absolutePath, null)
|
|
169
|
+
assertNotNull("Audio data should load", audioData)
|
|
170
|
+
|
|
171
|
+
val config = RecordingConfig(
|
|
172
|
+
sampleRate = audioData!!.sampleRate,
|
|
173
|
+
channels = audioData.channels,
|
|
174
|
+
encoding = "pcm_16bit",
|
|
175
|
+
segmentDurationMs = 20 // 50 points per second
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
// When
|
|
179
|
+
val preview = audioProcessor.generatePreview(
|
|
180
|
+
audioData = audioData,
|
|
181
|
+
numberOfPoints = 100,
|
|
182
|
+
startTimeMs = null,
|
|
183
|
+
endTimeMs = null,
|
|
184
|
+
config = config
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
// Then
|
|
188
|
+
assertNotNull("Preview should not be null", preview)
|
|
189
|
+
assertEquals("Should have 100 data points", 100, preview.dataPoints.size)
|
|
190
|
+
|
|
191
|
+
// Verify amplitude range
|
|
192
|
+
assertTrue("Min amplitude should be reasonable", preview.amplitudeRange.min >= 0)
|
|
193
|
+
assertTrue("Max amplitude should be reasonable", preview.amplitudeRange.max <= 1)
|
|
194
|
+
assertTrue("Max should be greater than min",
|
|
195
|
+
preview.amplitudeRange.max > preview.amplitudeRange.min)
|
|
196
|
+
}
|
|
197
|
+
}
|