@siteed/audio-studio 3.0.2 → 3.0.3

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 (86) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/android/src/main/java/net/siteed/audiostudio/AudioStudioModule.kt +7 -1
  3. package/build/cjs/AudioAnalysis/AudioAnalysis.types.js.map +1 -1
  4. package/build/cjs/AudioAnalysis/audioFeaturesWasm.js +10 -7
  5. package/build/cjs/AudioAnalysis/audioFeaturesWasm.js.map +1 -1
  6. package/build/cjs/AudioAnalysis/audioFeaturesWasm.web.js +78 -97
  7. package/build/cjs/AudioAnalysis/audioFeaturesWasm.web.js.map +1 -1
  8. package/build/cjs/AudioAnalysis/extractAudioAnalysis.js +15 -12
  9. package/build/cjs/AudioAnalysis/extractAudioAnalysis.js.map +1 -1
  10. package/build/cjs/AudioAnalysis/extractAudioData.js +144 -2
  11. package/build/cjs/AudioAnalysis/extractAudioData.js.map +1 -1
  12. package/build/cjs/AudioAnalysis/melSpectrogramWasm.web.js +9 -56
  13. package/build/cjs/AudioAnalysis/melSpectrogramWasm.web.js.map +1 -1
  14. package/build/cjs/AudioAnalysis/wasmConfig.js +4 -4
  15. package/build/cjs/AudioAnalysis/wasmConfig.js.map +1 -1
  16. package/build/cjs/AudioAnalysis/wasmLoader.web.js +78 -0
  17. package/build/cjs/AudioAnalysis/wasmLoader.web.js.map +1 -0
  18. package/build/cjs/AudioStudioModule.js +4 -599
  19. package/build/cjs/AudioStudioModule.js.map +1 -1
  20. package/build/cjs/trimAudio.js +227 -0
  21. package/build/cjs/trimAudio.js.map +1 -1
  22. package/build/cjs/utils/encodeCompressedAudio.web.js +65 -0
  23. package/build/cjs/utils/encodeCompressedAudio.web.js.map +1 -0
  24. package/build/cjs/utils/resampleAudioBuffer.web.js +25 -0
  25. package/build/cjs/utils/resampleAudioBuffer.web.js.map +1 -0
  26. package/build/esm/AudioAnalysis/AudioAnalysis.types.js.map +1 -1
  27. package/build/esm/AudioAnalysis/audioFeaturesWasm.js +8 -5
  28. package/build/esm/AudioAnalysis/audioFeaturesWasm.js.map +1 -1
  29. package/build/esm/AudioAnalysis/audioFeaturesWasm.web.js +76 -62
  30. package/build/esm/AudioAnalysis/audioFeaturesWasm.web.js.map +1 -1
  31. package/build/esm/AudioAnalysis/extractAudioAnalysis.js +15 -12
  32. package/build/esm/AudioAnalysis/extractAudioAnalysis.js.map +1 -1
  33. package/build/esm/AudioAnalysis/extractAudioData.js +144 -2
  34. package/build/esm/AudioAnalysis/extractAudioData.js.map +1 -1
  35. package/build/esm/AudioAnalysis/melSpectrogramWasm.web.js +9 -23
  36. package/build/esm/AudioAnalysis/melSpectrogramWasm.web.js.map +1 -1
  37. package/build/esm/AudioAnalysis/wasmConfig.js +4 -4
  38. package/build/esm/AudioAnalysis/wasmConfig.js.map +1 -1
  39. package/build/esm/AudioAnalysis/wasmLoader.web.js +42 -0
  40. package/build/esm/AudioAnalysis/wasmLoader.web.js.map +1 -0
  41. package/build/esm/AudioStudioModule.js +4 -596
  42. package/build/esm/AudioStudioModule.js.map +1 -1
  43. package/build/esm/trimAudio.js +227 -0
  44. package/build/esm/trimAudio.js.map +1 -1
  45. package/build/esm/utils/encodeCompressedAudio.web.js +62 -0
  46. package/build/esm/utils/encodeCompressedAudio.web.js.map +1 -0
  47. package/build/esm/utils/resampleAudioBuffer.web.js +22 -0
  48. package/build/esm/utils/resampleAudioBuffer.web.js.map +1 -0
  49. package/build/types/AudioAnalysis/AudioAnalysis.types.d.ts +11 -0
  50. package/build/types/AudioAnalysis/AudioAnalysis.types.d.ts.map +1 -1
  51. package/build/types/AudioAnalysis/audioFeaturesWasm.d.ts +5 -9
  52. package/build/types/AudioAnalysis/audioFeaturesWasm.d.ts.map +1 -1
  53. package/build/types/AudioAnalysis/audioFeaturesWasm.web.d.ts +35 -16
  54. package/build/types/AudioAnalysis/audioFeaturesWasm.web.d.ts.map +1 -1
  55. package/build/types/AudioAnalysis/extractAudioAnalysis.d.ts.map +1 -1
  56. package/build/types/AudioAnalysis/extractAudioData.d.ts +2 -2
  57. package/build/types/AudioAnalysis/extractAudioData.d.ts.map +1 -1
  58. package/build/types/AudioAnalysis/melSpectrogramWasm.web.d.ts.map +1 -1
  59. package/build/types/AudioAnalysis/wasmLoader.web.d.ts +3 -0
  60. package/build/types/AudioAnalysis/wasmLoader.web.d.ts.map +1 -0
  61. package/build/types/AudioStudioModule.d.ts.map +1 -1
  62. package/build/types/trimAudio.d.ts.map +1 -1
  63. package/build/types/utils/encodeCompressedAudio.web.d.ts +10 -0
  64. package/build/types/utils/encodeCompressedAudio.web.d.ts.map +1 -0
  65. package/build/types/utils/resampleAudioBuffer.web.d.ts +2 -0
  66. package/build/types/utils/resampleAudioBuffer.web.d.ts.map +1 -0
  67. package/package.json +1 -1
  68. package/src/AudioAnalysis/AudioAnalysis.types.ts +12 -0
  69. package/src/AudioAnalysis/audioFeaturesWasm.ts +17 -22
  70. package/src/AudioAnalysis/audioFeaturesWasm.web.ts +102 -94
  71. package/src/AudioAnalysis/extractAudioAnalysis.ts +23 -20
  72. package/src/AudioAnalysis/extractAudioData.ts +186 -4
  73. package/src/AudioAnalysis/melSpectrogramWasm.web.ts +10 -27
  74. package/src/AudioAnalysis/wasmConfig.ts +4 -4
  75. package/src/AudioAnalysis/wasmLoader.web.ts +48 -0
  76. package/src/AudioStudioModule.ts +6 -854
  77. package/src/trimAudio.ts +337 -0
  78. package/src/utils/encodeCompressedAudio.web.ts +78 -0
  79. package/src/utils/resampleAudioBuffer.web.ts +39 -0
  80. package/build/cjs/AudioAnalysis/extractWaveform.js +0 -18
  81. package/build/cjs/AudioAnalysis/extractWaveform.js.map +0 -1
  82. package/build/esm/AudioAnalysis/extractWaveform.js +0 -11
  83. package/build/esm/AudioAnalysis/extractWaveform.js.map +0 -1
  84. package/build/types/AudioAnalysis/extractWaveform.d.ts +0 -8
  85. package/build/types/AudioAnalysis/extractWaveform.d.ts.map +0 -1
  86. package/src/AudioAnalysis/extractWaveform.ts +0 -22
@@ -1 +1 @@
1
- {"version":3,"file":"AudioStudioModule.js","sourceRoot":"","sources":["../../src/AudioStudioModule.ts"],"names":[],"mappings":"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","sourcesContent":["import { requireNativeModule } from 'expo-modules-core'\nimport { Platform } from 'react-native'\n\nimport {\n ExtractAudioDataOptions,\n ExtractedAudioData,\n BitDepth,\n TrimAudioOptions,\n TrimAudioResult,\n} from './AudioStudio.types'\nimport { AudioStudioWeb, AudioStudioWebProps } from './AudioStudio.web'\nimport { processAudioBuffer } from './utils/audioProcessing'\nimport crc32 from './utils/crc32'\nimport { writeWavHeader } from './utils/writeWavHeader'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet AudioStudioModule: any\n\nif (Platform.OS === 'web') {\n let instance: AudioStudioWeb | null = null\n\n AudioStudioModule = (webProps: AudioStudioWebProps) => {\n if (!instance) {\n instance = new AudioStudioWeb(webProps)\n }\n return instance\n }\n AudioStudioModule.requestPermissionsAsync = async () => {\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n })\n stream.getTracks().forEach((track) => track.stop())\n return {\n status: 'granted',\n expires: 'never',\n canAskAgain: true,\n granted: true,\n }\n } catch {\n return {\n status: 'denied',\n expires: 'never',\n canAskAgain: true,\n granted: false,\n }\n }\n }\n AudioStudioModule.getPermissionsAsync = async () => {\n let maybeStatus: string | null = null\n\n if (navigator?.permissions?.query) {\n try {\n const { state } = await navigator.permissions.query({\n name: 'microphone' as PermissionName,\n })\n maybeStatus = state\n } catch {\n maybeStatus = null\n }\n }\n\n switch (maybeStatus) {\n case 'granted':\n return {\n status: 'granted',\n expires: 'never',\n canAskAgain: true,\n granted: true,\n }\n case 'denied':\n return {\n status: 'denied',\n expires: 'never',\n canAskAgain: true,\n granted: false,\n }\n default:\n return await AudioStudioModule.requestPermissionsAsync()\n }\n }\n AudioStudioModule.extractAudioData = async (\n options: ExtractAudioDataOptions\n ): Promise<ExtractedAudioData> => {\n try {\n const {\n fileUri,\n position,\n length,\n startTimeMs,\n endTimeMs,\n decodingOptions,\n includeNormalizedData,\n includeBase64Data,\n includeWavHeader = false,\n logger,\n } = options\n\n logger?.debug('EXTRACT AUDIO - Step 1: Initial request', {\n fileUri,\n extractionParams: {\n position,\n length,\n startTimeMs,\n endTimeMs,\n },\n decodingOptions: {\n targetSampleRate:\n decodingOptions?.targetSampleRate ?? 16000,\n targetChannels: decodingOptions?.targetChannels ?? 1,\n targetBitDepth: decodingOptions?.targetBitDepth ?? 16,\n normalizeAudio: decodingOptions?.normalizeAudio ?? false,\n },\n outputOptions: {\n includeNormalizedData,\n includeBase64Data,\n includeWavHeader,\n },\n })\n\n // Process the audio using shared helper function\n const processedBuffer = await processAudioBuffer({\n fileUri,\n targetSampleRate: decodingOptions?.targetSampleRate ?? 16000,\n targetChannels: decodingOptions?.targetChannels ?? 1,\n normalizeAudio: decodingOptions?.normalizeAudio ?? false,\n position,\n length,\n startTimeMs,\n endTimeMs,\n logger,\n })\n\n logger?.debug('EXTRACT AUDIO - Step 2: Audio processing complete', {\n processedData: {\n samples: processedBuffer.samples,\n sampleRate: processedBuffer.sampleRate,\n channels: processedBuffer.channels,\n durationMs: processedBuffer.durationMs,\n },\n })\n\n const channelData = processedBuffer.channelData\n const bitDepth = (decodingOptions?.targetBitDepth ?? 16) as BitDepth\n const bytesPerSample = bitDepth / 8\n const numSamples = processedBuffer.samples\n\n logger?.debug('EXTRACT AUDIO - Step 3: PCM conversion setup', {\n channelData: {\n length: channelData.length,\n first: channelData[0],\n last: channelData[channelData.length - 1],\n },\n calculation: {\n bitDepth,\n bytesPerSample,\n numSamples,\n expectedBytes: numSamples * bytesPerSample,\n },\n })\n\n // Create PCM data with correct length based on original byte length\n const pcmData = new Uint8Array(numSamples * bytesPerSample)\n let offset = 0\n\n // Convert Float32 samples to PCM format\n for (let i = 0; i < numSamples; i++) {\n const sample = channelData[i]\n const value = Math.max(-1, Math.min(1, sample))\n // Convert to 16-bit signed integer\n let intValue = Math.round(value * 32767)\n\n // Handle negative values correctly\n if (intValue < 0) {\n intValue = 65536 + intValue\n }\n\n // Write as little-endian\n pcmData[offset++] = intValue & 255 // Low byte\n pcmData[offset++] = (intValue >> 8) & 255 // High byte\n }\n\n const durationMs = Math.round(\n (numSamples / processedBuffer.sampleRate) * 1000\n )\n\n logger?.debug('EXTRACT AUDIO - Step 4: Final output', {\n pcmData: {\n length: pcmData.length,\n first: pcmData[0],\n last: pcmData[pcmData.length - 1],\n },\n timing: {\n numSamples,\n sampleRate: processedBuffer.sampleRate,\n durationMs,\n shouldBe3000ms: endTimeMs\n ? endTimeMs - (startTimeMs ?? 0) === 3000\n : undefined,\n },\n })\n\n const result: ExtractedAudioData = {\n pcmData: new Uint8Array(pcmData.buffer),\n sampleRate: processedBuffer.sampleRate,\n channels: processedBuffer.channels,\n bitDepth,\n durationMs,\n format: `pcm_${bitDepth}bit` as const,\n samples: numSamples,\n }\n\n // Add WAV header if requested\n if (includeWavHeader) {\n logger?.debug('EXTRACT AUDIO - Step 4: Adding WAV header', {\n originalLength: pcmData.length,\n newLength: result.pcmData.length,\n firstBytes: Array.from(result.pcmData.slice(0, 44)), // WAV header is 44 bytes\n })\n const wavBuffer = writeWavHeader({\n buffer: pcmData.buffer.slice(0, pcmData.length),\n sampleRate: processedBuffer.sampleRate,\n numChannels: processedBuffer.channels,\n bitDepth,\n })\n result.pcmData = new Uint8Array(wavBuffer)\n result.hasWavHeader = true\n }\n\n if (includeNormalizedData) {\n // // Simple approach: Create normalized data directly from the PCM data\n // // Just convert to -1 to 1 range without any amplification\n // const normalizedData = new Float32Array(numSamples)\n\n // // Convert the PCM data to float values\n // for (let i = 0; i < numSamples; i++) {\n // // Get the 16-bit PCM value (little endian)\n // const lowByte = pcmData[i * 2]\n // const highByte = pcmData[i * 2 + 1]\n // const pcmValue = (highByte << 8) | lowByte\n\n // // Convert to signed 16-bit value\n // const signedValue =\n // pcmValue > 32767 ? pcmValue - 65536 : pcmValue\n\n // // Normalize to float between -1 and 1\n // normalizedData[i] = signedValue / 32768.0\n // }\n // Store the normalized data in the result\n result.normalizedData = channelData\n }\n\n if (includeBase64Data) {\n // Convert the PCM data to a base64 string\n const binary = Array.from(new Uint8Array(pcmData.buffer))\n .map((b) => String.fromCharCode(b))\n .join('')\n result.base64Data = btoa(binary)\n }\n\n if (options.computeChecksum) {\n result.checksum = crc32.buf(pcmData)\n }\n\n logger?.debug('EXTRACT AUDIO - Step 3: PCM conversion complete', {\n pcmStats: {\n length: pcmData.length,\n bytesPerSample,\n totalSamples: numSamples,\n firstBytes: Array.from(pcmData.slice(0, 16)),\n lastBytes: Array.from(pcmData.slice(-16)),\n },\n })\n\n return result\n } catch (error) {\n options.logger?.error('EXTRACT AUDIO - Error:', error)\n throw error\n }\n }\n\n AudioStudioModule.trimAudio = async (\n options: TrimAudioOptions\n ): Promise<TrimAudioResult> => {\n try {\n const startTime = performance.now()\n const {\n fileUri,\n mode = 'single',\n startTimeMs,\n endTimeMs,\n ranges,\n outputFileName,\n outputFormat,\n } = options\n\n // Validate inputs\n if (!fileUri) {\n throw new Error('fileUri is required')\n }\n\n if (\n mode === 'single' &&\n startTimeMs === undefined &&\n endTimeMs === undefined\n ) {\n throw new Error(\n 'At least one of startTimeMs or endTimeMs must be provided in single mode'\n )\n }\n\n if (\n (mode === 'keep' || mode === 'remove') &&\n (!ranges || ranges.length === 0)\n ) {\n throw new Error(\n 'ranges must be provided and non-empty for keep or remove modes'\n )\n }\n\n // Create AudioContext\n const audioContext = new (window.AudioContext ||\n (window as any).webkitAudioContext)()\n\n // First, load the entire audio file to get its properties\n const response = await fetch(fileUri)\n const arrayBuffer = await response.arrayBuffer()\n const originalAudioBuffer =\n await audioContext.decodeAudioData(arrayBuffer)\n\n // Get original audio properties\n const originalSampleRate = originalAudioBuffer.sampleRate\n const originalChannels = originalAudioBuffer.numberOfChannels\n\n // Add more detailed logging\n console.log(`Original audio details:`, {\n sampleRate: originalSampleRate,\n channels: originalChannels,\n duration: originalAudioBuffer.duration,\n length: originalAudioBuffer.length,\n // Log a few samples to verify content\n firstSamples: Array.from(\n originalAudioBuffer.getChannelData(0).slice(0, 5)\n ),\n })\n\n // Determine output format - use original values as defaults if not specified\n let format = outputFormat?.format || 'wav'\n const targetSampleRate =\n outputFormat?.sampleRate || originalSampleRate\n const targetChannels = outputFormat?.channels || originalChannels\n const targetBitDepth = outputFormat?.bitDepth || 16\n\n // Get file info from the URL\n const filename =\n outputFileName ||\n fileUri.split('/').pop() ||\n 'trimmed-audio.wav'\n\n // Process based on mode\n let resultBuffer: AudioBuffer\n\n // Report initial progress\n AudioStudioModule.sendEvent('TrimProgress', {\n progress: 10,\n })\n\n if (mode === 'single') {\n // Single mode: extract a single range\n // Use original sample rate and channels for extraction to preserve quality\n const { buffer } = await processAudioBuffer({\n fileUri,\n targetSampleRate, // Use the requested sample rate\n targetChannels,\n normalizeAudio: false,\n startTimeMs,\n endTimeMs,\n audioContext,\n })\n\n console.log(`Processed buffer details:`, {\n sampleRate: buffer.sampleRate,\n channels: buffer.numberOfChannels,\n duration: buffer.duration,\n length: buffer.length,\n // Log a few samples to verify content\n firstSamples: Array.from(\n buffer.getChannelData(0).slice(0, 5)\n ),\n })\n\n resultBuffer = buffer\n\n // If we need to change sample rate or channels, do it after extraction\n if (\n targetSampleRate !== originalSampleRate ||\n targetChannels !== originalChannels\n ) {\n console.log(\n `Resampling from ${originalSampleRate}Hz to ${targetSampleRate}Hz`\n )\n resultBuffer = await resampleAudioBuffer(\n audioContext,\n buffer,\n targetSampleRate,\n targetChannels\n )\n }\n } else {\n // For keep or remove modes\n const fullDuration = originalAudioBuffer.duration * 1000 // in ms\n\n type ProcessSegment = {\n startTimeMs: number\n endTimeMs: number\n }\n\n let segmentsToProcess: ProcessSegment[] = []\n\n if (mode === 'keep') {\n // For keep mode, use the ranges directly\n segmentsToProcess = ranges!\n } else {\n // mode === 'remove'\n // For remove mode, invert the ranges\n const sortedRanges = [...ranges!].sort(\n (a, b) => a.startTimeMs - b.startTimeMs\n )\n\n // Add segment from start to first range if needed\n if (\n sortedRanges.length > 0 &&\n sortedRanges[0].startTimeMs > 0\n ) {\n segmentsToProcess.push({\n startTimeMs: 0,\n endTimeMs: sortedRanges[0].startTimeMs,\n })\n }\n\n // Add segments between ranges\n for (let i = 0; i < sortedRanges.length - 1; i++) {\n segmentsToProcess.push({\n startTimeMs: sortedRanges[i].endTimeMs,\n endTimeMs: sortedRanges[i + 1].startTimeMs,\n })\n }\n\n // Add segment from last range to end if needed\n if (\n sortedRanges.length > 0 &&\n sortedRanges[sortedRanges.length - 1].endTimeMs <\n fullDuration\n ) {\n segmentsToProcess.push({\n startTimeMs:\n sortedRanges[sortedRanges.length - 1].endTimeMs,\n endTimeMs: fullDuration,\n })\n }\n }\n\n // Filter out empty or invalid segments\n segmentsToProcess = segmentsToProcess.filter(\n (segment) =>\n segment.startTimeMs < segment.endTimeMs &&\n segment.endTimeMs - segment.startTimeMs > 1\n ) // 1ms minimum\n\n if (segmentsToProcess.length === 0) {\n throw new Error(\n 'No valid segments to process after filtering ranges'\n )\n }\n\n // Process each segment using original sample rate and channels\n const segmentBuffers: AudioBuffer[] = []\n\n for (let i = 0; i < segmentsToProcess.length; i++) {\n const segment = segmentsToProcess[i]\n\n // Report progress for each segment\n AudioStudioModule.sendEvent('TrimProgress', {\n progress:\n 10 +\n Math.round((i / segmentsToProcess.length) * 40),\n })\n\n // Use processAudioBuffer to extract this segment\n const { buffer: segmentBuffer } = await processAudioBuffer({\n fileUri,\n targetSampleRate: originalSampleRate, // Use original sample rate\n targetChannels: originalChannels, // Use original channels\n normalizeAudio: false,\n startTimeMs: segment.startTimeMs,\n endTimeMs: segment.endTimeMs,\n audioContext,\n })\n\n segmentBuffers.push(segmentBuffer)\n }\n\n // Concatenate all segments\n const totalSamples = segmentBuffers.reduce(\n (sum, buffer) => sum + buffer.length,\n 0\n )\n\n // Create buffer with original properties first\n const concatenatedBuffer = audioContext.createBuffer(\n originalChannels,\n totalSamples,\n originalSampleRate\n )\n\n let offset = 0\n for (const segmentBuffer of segmentBuffers) {\n for (\n let channel = 0;\n channel < originalChannels;\n channel++\n ) {\n const outputData =\n concatenatedBuffer.getChannelData(channel)\n const segmentData =\n segmentBuffer.getChannelData(channel)\n\n for (let i = 0; i < segmentBuffer.length; i++) {\n outputData[offset + i] = segmentData[i]\n }\n }\n offset += segmentBuffer.length\n }\n\n resultBuffer = concatenatedBuffer\n\n // If we need to change sample rate or channels, do it after concatenation\n if (\n targetSampleRate !== originalSampleRate ||\n targetChannels !== originalChannels\n ) {\n console.log(\n `Resampling concatenated buffer from ${originalSampleRate}Hz to ${targetSampleRate}Hz`\n )\n resultBuffer = await resampleAudioBuffer(\n audioContext,\n concatenatedBuffer,\n targetSampleRate,\n targetChannels\n )\n }\n }\n\n // Report progress (50% - processing complete)\n AudioStudioModule.sendEvent('TrimProgress', {\n progress: 50,\n })\n\n // Encode the result based on the requested format\n let outputData: ArrayBuffer\n let outputMimeType: string\n let compressionInfo: any = null\n\n // Check if AAC was requested on web and show a warning\n if (format === 'aac' && Platform.OS === 'web') {\n console.warn(\n 'AAC format is not supported on web platforms. Falling back to OPUS format.'\n )\n format = 'opus'\n }\n\n if (format === 'wav') {\n // Create a properly interleaved buffer for WAV format\n // For WAV, we need to convert Float32Array to Int16Array (for 16-bit audio)\n const numSamples =\n resultBuffer.length * resultBuffer.numberOfChannels\n const interleavedData = new Int16Array(numSamples)\n\n // Log detailed information about the buffer before encoding\n console.log(`Creating WAV file:`, {\n bufferSampleRate: resultBuffer.sampleRate,\n bufferChannels: resultBuffer.numberOfChannels,\n bufferLength: resultBuffer.length,\n targetSampleRate,\n targetChannels,\n targetBitDepth,\n // Log a few samples to verify content\n firstSamples: Array.from(\n resultBuffer.getChannelData(0).slice(0, 5)\n ),\n })\n\n // Interleave channels properly\n for (let i = 0; i < resultBuffer.length; i++) {\n for (\n let channel = 0;\n channel < resultBuffer.numberOfChannels;\n channel++\n ) {\n // Convert float (-1.0 to 1.0) to int16 (-32768 to 32767)\n const floatSample =\n resultBuffer.getChannelData(channel)[i]\n // Clamp the value to -1.0 to 1.0\n const clampedSample = Math.max(\n -1.0,\n Math.min(1.0, floatSample)\n )\n // Convert to int16\n const intSample = Math.round(clampedSample * 32767)\n // Store in interleaved buffer\n interleavedData[\n i * resultBuffer.numberOfChannels + channel\n ] = intSample\n }\n }\n\n // Convert Int16Array to ArrayBuffer for WAV header\n const rawBuffer = interleavedData.buffer\n\n // IMPORTANT: Make sure we're using the ACTUAL sample rate of the buffer\n // not just what was requested in the options\n console.log(\n `Creating WAV with ${resultBuffer.numberOfChannels} channels at ${resultBuffer.sampleRate}Hz`\n )\n\n outputData = writeWavHeader({\n buffer: rawBuffer as ArrayBuffer,\n sampleRate: resultBuffer.sampleRate, // Use the actual buffer's sample rate\n numChannels: resultBuffer.numberOfChannels,\n bitDepth: targetBitDepth as BitDepth,\n })\n outputMimeType = 'audio/wav'\n } else if (format === 'opus' || format === 'aac') {\n try {\n // Try to use MediaRecorder for compressed formats\n const { data, bitrate } = await encodeCompressedAudio(\n resultBuffer,\n format,\n outputFormat?.bitrate\n )\n\n outputData = data\n outputMimeType =\n format === 'opus' ? 'audio/webm' : 'audio/aac'\n compressionInfo = {\n format,\n bitrate,\n size: data.byteLength,\n }\n } catch (error) {\n console.warn(\n `Failed to encode to ${format}, falling back to WAV: ${error}`\n )\n\n // Same WAV encoding as above\n const wavData = new Float32Array(\n resultBuffer.length * resultBuffer.numberOfChannels\n )\n\n for (let i = 0; i < resultBuffer.length; i++) {\n for (\n let channel = 0;\n channel < resultBuffer.numberOfChannels;\n channel++\n ) {\n wavData[\n i * resultBuffer.numberOfChannels + channel\n ] = resultBuffer.getChannelData(channel)[i]\n }\n }\n\n outputData = writeWavHeader({\n buffer: wavData.buffer as ArrayBuffer,\n sampleRate: resultBuffer.sampleRate,\n numChannels: resultBuffer.numberOfChannels,\n bitDepth: targetBitDepth as BitDepth,\n })\n outputMimeType = 'audio/wav'\n }\n } else {\n // Default to WAV for unsupported formats\n console.warn(\n `Format ${format} not supported on web, using WAV instead`\n )\n\n // Same WAV encoding as above\n const wavData = new Float32Array(\n resultBuffer.length * resultBuffer.numberOfChannels\n )\n\n for (let i = 0; i < resultBuffer.length; i++) {\n for (\n let channel = 0;\n channel < resultBuffer.numberOfChannels;\n channel++\n ) {\n wavData[i * resultBuffer.numberOfChannels + channel] =\n resultBuffer.getChannelData(channel)[i]\n }\n }\n\n outputData = writeWavHeader({\n buffer: wavData.buffer as ArrayBuffer,\n sampleRate: resultBuffer.sampleRate,\n numChannels: resultBuffer.numberOfChannels,\n bitDepth: targetBitDepth as BitDepth,\n })\n outputMimeType = 'audio/wav'\n }\n\n // Report progress (90% - encoding complete)\n AudioStudioModule.sendEvent('TrimProgress', {\n progress: 90,\n })\n\n // Create a blob and URL for the result\n const blob = new Blob([outputData], { type: outputMimeType })\n const outputUri = URL.createObjectURL(blob)\n\n // Calculate processing time\n const processingTimeMs = performance.now() - startTime\n\n // Report progress (100% - complete)\n AudioStudioModule.sendEvent('TrimProgress', {\n progress: 100,\n })\n\n // Create result object\n const result: TrimAudioResult = {\n uri: outputUri,\n filename,\n durationMs: Math.round(resultBuffer.duration * 1000),\n size: outputData.byteLength,\n sampleRate: resultBuffer.sampleRate,\n channels: resultBuffer.numberOfChannels,\n bitDepth: targetBitDepth,\n mimeType: outputMimeType,\n processingInfo: {\n durationMs: processingTimeMs,\n },\n }\n\n // Add compression info if available\n if (compressionInfo) {\n result.compression = compressionInfo\n }\n\n return result\n } catch (error) {\n console.error('Error in trimAudio:', error)\n throw error\n }\n }\n\n // Add a sendEvent method for web\n AudioStudioModule.sendEvent = (eventName: string, params: any) => {\n // This will be picked up by the LegacyEventEmitter in trimAudio.ts\n if (\n AudioStudioModule.listeners &&\n AudioStudioModule.listeners[eventName]\n ) {\n AudioStudioModule.listeners[eventName].forEach(\n (listener: Function) => {\n listener(params)\n }\n )\n }\n }\n\n // Initialize listeners object\n AudioStudioModule.listeners = {}\n\n // Add methods for event listeners that LegacyEventEmitter will use\n AudioStudioModule.addListener = (eventName: string, listener: Function) => {\n if (!AudioStudioModule.listeners[eventName]) {\n AudioStudioModule.listeners[eventName] = []\n }\n AudioStudioModule.listeners[eventName].push(listener)\n\n // Return an object with a remove method\n return {\n remove: () => {\n const index =\n AudioStudioModule.listeners[eventName].indexOf(listener)\n if (index !== -1) {\n AudioStudioModule.listeners[eventName].splice(index, 1)\n }\n },\n }\n }\n\n AudioStudioModule.removeAllListeners = (eventName: string) => {\n if (AudioStudioModule.listeners[eventName]) {\n delete AudioStudioModule.listeners[eventName]\n }\n }\n\n AudioStudioModule.prepareRecording = async (options: any) => {\n // For web platform, we'll implement a simplified version that just checks permissions\n // and does minimal setup. The actual recording setup will still happen in startRecording.\n try {\n // Check for microphone permissions\n const permissionsResult =\n await AudioStudioModule.getPermissionsAsync()\n if (!permissionsResult.granted) {\n throw new Error('Microphone permission not granted')\n }\n\n // If using a web instance, call its prepareRecording method\n if (instance) {\n return await instance.prepareRecording(options)\n }\n\n return true\n } catch (error) {\n console.error('Error preparing recording:', error)\n throw error\n }\n }\n}\n\n// Move the encodeCompressedAudio function outside the if block to fix the ESLint error\nasync function encodeCompressedAudio(\n buffer: AudioBuffer,\n format: 'opus' | 'aac',\n bitrate?: number\n): Promise<{ data: ArrayBuffer; bitrate: number }> {\n return new Promise((resolve, reject) => {\n try {\n // On web, always use opus if aac is requested\n const actualFormat =\n Platform.OS === 'web' && format === 'aac' ? 'opus' : format\n\n // Check if MediaRecorder supports the requested format\n const mimeType =\n actualFormat === 'opus' ? 'audio/webm;codecs=opus' : 'audio/aac'\n if (!MediaRecorder.isTypeSupported(mimeType)) {\n throw new Error(`MediaRecorder does not support ${mimeType}`)\n }\n\n // Create a new AudioContext and source\n const ctx = new (window.AudioContext ||\n (window as any).webkitAudioContext)()\n const source = ctx.createBufferSource()\n source.buffer = buffer\n\n // Create a MediaStreamDestination to capture the audio\n const destination = ctx.createMediaStreamDestination()\n source.connect(destination)\n\n // Create a MediaRecorder with the requested format\n const recorder = new MediaRecorder(destination.stream, {\n mimeType,\n audioBitsPerSecond:\n bitrate || (actualFormat === 'opus' ? 32000 : 64000),\n })\n\n const chunks: Blob[] = []\n\n recorder.ondataavailable = (e) => {\n if (e.data.size > 0) {\n chunks.push(e.data)\n }\n }\n\n recorder.onstop = async () => {\n try {\n const blob = new Blob(chunks, { type: mimeType })\n const arrayBuffer = await blob.arrayBuffer()\n\n // Get the actual bitrate used\n const actualBitrate = Math.round(\n (arrayBuffer.byteLength * 8) / buffer.duration\n )\n\n resolve({\n data: arrayBuffer,\n bitrate: actualBitrate / 1000, // Convert to kbps\n })\n\n // Clean up\n ctx.close()\n } catch (error) {\n reject(error)\n }\n }\n\n // Start recording and playback\n recorder.start()\n source.start(0)\n\n // Stop recording when the buffer finishes playing\n setTimeout(() => {\n recorder.stop()\n source.stop()\n }, buffer.duration * 1000)\n } catch (error) {\n reject(error)\n }\n })\n}\n\n// Improved resampleAudioBuffer function\nasync function resampleAudioBuffer(\n context: AudioContext,\n buffer: AudioBuffer,\n targetSampleRate: number,\n targetChannels: number\n): Promise<AudioBuffer> {\n // If no change needed, return the original buffer\n if (\n buffer.sampleRate === targetSampleRate &&\n buffer.numberOfChannels === targetChannels\n ) {\n return buffer\n }\n\n console.log(\n `Resampling: ${buffer.sampleRate}Hz → ${targetSampleRate}Hz, ${buffer.numberOfChannels} → ${targetChannels} channels`\n )\n\n // Calculate the new length based on the sample rate change\n const newLength = Math.round(\n (buffer.length * targetSampleRate) / buffer.sampleRate\n )\n\n // Create an offline context for resampling\n const offlineContext = new OfflineAudioContext(\n targetChannels,\n newLength,\n targetSampleRate\n )\n\n // Create a source node\n const source = offlineContext.createBufferSource()\n source.buffer = buffer\n\n // If we need to change channel count\n if (buffer.numberOfChannels !== targetChannels) {\n if (targetChannels === 1 && buffer.numberOfChannels > 1) {\n // Downmix to mono\n const merger = offlineContext.createChannelMerger(1)\n\n // Create a gain node to reduce volume when downmixing to prevent clipping\n const gainNode = offlineContext.createGain()\n gainNode.gain.value = 1.0 / buffer.numberOfChannels\n\n source.connect(gainNode)\n gainNode.connect(merger)\n merger.connect(offlineContext.destination)\n } else if (targetChannels === 2 && buffer.numberOfChannels === 1) {\n // Upmix mono to stereo (duplicate the channel)\n const splitter = offlineContext.createChannelSplitter(1)\n const merger = offlineContext.createChannelMerger(2)\n\n source.connect(splitter)\n splitter.connect(merger, 0, 0)\n splitter.connect(merger, 0, 1)\n merger.connect(offlineContext.destination)\n } else {\n // For other cases, just connect and let the system handle it\n source.connect(offlineContext.destination)\n }\n } else {\n // No channel conversion needed\n source.connect(offlineContext.destination)\n }\n\n // Start rendering\n source.start(0)\n const resampledBuffer = await offlineContext.startRendering()\n\n console.log(\n `Resampling complete: ${resampledBuffer.length} samples at ${resampledBuffer.sampleRate}Hz`\n )\n\n return resampledBuffer\n}\n\nif (Platform.OS !== 'web') {\n AudioStudioModule = requireNativeModule('AudioStudio')\n}\n\nexport default AudioStudioModule\n"]}
1
+ {"version":3,"file":"AudioStudioModule.js","sourceRoot":"","sources":["../../src/AudioStudioModule.ts"],"names":[],"mappings":"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","sourcesContent":["import { requireNativeModule } from 'expo-modules-core'\nimport { Platform } from 'react-native'\n\nimport { AudioStudioWeb, AudioStudioWebProps } from './AudioStudio.web'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet AudioStudioModule: any\n\nif (Platform.OS === 'web') {\n let instance: AudioStudioWeb | null = null\n\n AudioStudioModule = (webProps: AudioStudioWebProps) => {\n instance ??= new AudioStudioWeb(webProps)\n return instance\n }\n AudioStudioModule.requestPermissionsAsync = async () => {\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n })\n stream.getTracks().forEach((track) => track.stop())\n return {\n status: 'granted',\n expires: 'never',\n canAskAgain: true,\n granted: true,\n }\n } catch {\n return {\n status: 'denied',\n expires: 'never',\n canAskAgain: true,\n granted: false,\n }\n }\n }\n AudioStudioModule.getPermissionsAsync = async () => {\n let maybeStatus: string | null = null\n\n if (navigator?.permissions?.query) {\n try {\n const { state } = await navigator.permissions.query({\n name: 'microphone' as PermissionName,\n })\n maybeStatus = state\n } catch {\n maybeStatus = null\n }\n }\n\n switch (maybeStatus) {\n case 'granted':\n return {\n status: 'granted',\n expires: 'never',\n canAskAgain: true,\n granted: true,\n }\n case 'denied':\n return {\n status: 'denied',\n expires: 'never',\n canAskAgain: true,\n granted: false,\n }\n default:\n return await AudioStudioModule.requestPermissionsAsync()\n }\n }\n // Add a sendEvent method for web\n AudioStudioModule.sendEvent = (eventName: string, params: any) => {\n // This will be picked up by the LegacyEventEmitter in trimAudio.ts\n AudioStudioModule.listeners?.[eventName]?.forEach(\n (listener: Function) => {\n listener(params)\n }\n )\n }\n\n // Initialize listeners object\n AudioStudioModule.listeners = {}\n\n // Add methods for event listeners that LegacyEventEmitter will use\n AudioStudioModule.addListener = (eventName: string, listener: Function) => {\n if (!AudioStudioModule.listeners[eventName]) {\n AudioStudioModule.listeners[eventName] = []\n }\n AudioStudioModule.listeners[eventName].push(listener)\n\n // Return an object with a remove method\n return {\n remove: () => {\n const index =\n AudioStudioModule.listeners[eventName].indexOf(listener)\n if (index !== -1) {\n AudioStudioModule.listeners[eventName].splice(index, 1)\n }\n },\n }\n }\n\n AudioStudioModule.removeAllListeners = (eventName: string) => {\n if (AudioStudioModule.listeners[eventName]) {\n delete AudioStudioModule.listeners[eventName]\n }\n }\n\n AudioStudioModule.prepareRecording = async (options: any) => {\n // For web platform, we'll implement a simplified version that just checks permissions\n // and does minimal setup. The actual recording setup will still happen in startRecording.\n try {\n // Check for microphone permissions\n const permissionsResult =\n await AudioStudioModule.getPermissionsAsync()\n if (!permissionsResult.granted) {\n throw new Error('Microphone permission not granted')\n }\n\n // If using a web instance, call its prepareRecording method\n if (instance) {\n return await instance.prepareRecording(options)\n }\n\n return true\n } catch (error) {\n console.error('Error preparing recording:', error)\n throw error\n }\n }\n}\n\nif (Platform.OS !== 'web') {\n AudioStudioModule = requireNativeModule('AudioStudio')\n}\n\nexport default AudioStudioModule\n"]}
@@ -1,8 +1,44 @@
1
1
  import { LegacyEventEmitter } from 'expo-modules-core';
2
2
  import AudioStudioModule from './AudioStudioModule';
3
+ import { isWeb } from './constants';
4
+ import { processAudioBuffer } from './utils/audioProcessing';
3
5
  import { cleanNativeOptions } from './utils/cleanNativeOptions';
6
+ import { encodeCompressedAudio } from './utils/encodeCompressedAudio.web';
7
+ import { resampleAudioBuffer } from './utils/resampleAudioBuffer.web';
8
+ import { writeWavHeader } from './utils/writeWavHeader';
4
9
  // Create a single emitter instance
5
10
  const emitter = new LegacyEventEmitter(AudioStudioModule);
11
+ function sliceAudioBuffer(src, ctx, startMs, endMs) {
12
+ const sr = src.sampleRate;
13
+ const start = Math.floor((startMs / 1000) * sr);
14
+ const end = Math.min(Math.ceil((endMs / 1000) * sr), src.length);
15
+ const length = Math.max(0, end - start);
16
+ const out = ctx.createBuffer(src.numberOfChannels, length, sr);
17
+ for (let c = 0; c < src.numberOfChannels; c++) {
18
+ out.getChannelData(c).set(src.getChannelData(c).subarray(start, end));
19
+ }
20
+ return out;
21
+ }
22
+ function encodeBufferToWav(buffer, bitDepth) {
23
+ const { length, numberOfChannels, sampleRate } = buffer;
24
+ const channels = [];
25
+ for (let c = 0; c < numberOfChannels; c++) {
26
+ channels.push(buffer.getChannelData(c));
27
+ }
28
+ const interleavedData = new Int16Array(length * numberOfChannels);
29
+ for (let i = 0; i < length; i++) {
30
+ for (let c = 0; c < numberOfChannels; c++) {
31
+ const clamped = Math.max(-1, Math.min(1, channels[c][i]));
32
+ interleavedData[i * numberOfChannels + c] = Math.round(clamped * 32767);
33
+ }
34
+ }
35
+ return writeWavHeader({
36
+ buffer: interleavedData.buffer,
37
+ sampleRate,
38
+ numChannels: numberOfChannels,
39
+ bitDepth,
40
+ });
41
+ }
6
42
  /**
7
43
  * Trims an audio file based on the provided options.
8
44
  *
@@ -34,6 +70,197 @@ export async function trimAudio(options, progressCallback) {
34
70
  else {
35
71
  throw new Error(`Invalid mode: ${mode}. Must be 'single', 'keep', or 'remove'`);
36
72
  }
73
+ if (isWeb) {
74
+ try {
75
+ const startTime = performance.now();
76
+ const { fileUri, startTimeMs, endTimeMs, ranges, outputFileName, outputFormat, } = options;
77
+ // Create AudioContext
78
+ const audioContext = new (window.AudioContext ||
79
+ window.webkitAudioContext)();
80
+ // First, load the entire audio file to get its properties
81
+ const response = await fetch(fileUri);
82
+ const arrayBuffer = await response.arrayBuffer();
83
+ const originalAudioBuffer = await audioContext.decodeAudioData(arrayBuffer);
84
+ // Get original audio properties
85
+ const originalSampleRate = originalAudioBuffer.sampleRate;
86
+ const originalChannels = originalAudioBuffer.numberOfChannels;
87
+ // Determine output format - use original values as defaults if not specified
88
+ let format = outputFormat?.format || 'wav';
89
+ const targetSampleRate = outputFormat?.sampleRate || originalSampleRate;
90
+ const targetChannels = outputFormat?.channels || originalChannels;
91
+ const targetBitDepth = outputFormat?.bitDepth || 16;
92
+ // Get file info from the URL
93
+ const filename = outputFileName ||
94
+ fileUri.split('/').pop() ||
95
+ 'trimmed-audio.wav';
96
+ // Process based on mode
97
+ let resultBuffer;
98
+ // Report initial progress
99
+ progressCallback?.({ progress: 10 });
100
+ if (mode === 'single') {
101
+ // Single mode: extract a single range
102
+ // Use original sample rate and channels for extraction to preserve quality
103
+ const { buffer } = await processAudioBuffer({
104
+ fileUri,
105
+ targetSampleRate, // Use the requested sample rate
106
+ targetChannels,
107
+ normalizeAudio: false,
108
+ startTimeMs,
109
+ endTimeMs,
110
+ audioContext,
111
+ });
112
+ resultBuffer = buffer;
113
+ // If we need to change sample rate or channels, do it after extraction
114
+ if (targetSampleRate !== originalSampleRate ||
115
+ targetChannels !== originalChannels) {
116
+ resultBuffer = await resampleAudioBuffer(buffer, targetSampleRate, targetChannels);
117
+ }
118
+ }
119
+ else {
120
+ // For keep or remove modes
121
+ const fullDuration = originalAudioBuffer.duration * 1000; // in ms
122
+ let segmentsToProcess = [];
123
+ if (mode === 'keep') {
124
+ // For keep mode, use the ranges directly
125
+ segmentsToProcess = ranges;
126
+ }
127
+ else {
128
+ // mode === 'remove'
129
+ // For remove mode, invert the ranges
130
+ const sortedRanges = [...ranges].sort((a, b) => a.startTimeMs - b.startTimeMs);
131
+ // Add segment from start to first range if needed
132
+ if (sortedRanges.length > 0 &&
133
+ sortedRanges[0].startTimeMs > 0) {
134
+ segmentsToProcess.push({
135
+ startTimeMs: 0,
136
+ endTimeMs: sortedRanges[0].startTimeMs,
137
+ });
138
+ }
139
+ // Add segments between ranges
140
+ for (let i = 0; i < sortedRanges.length - 1; i++) {
141
+ segmentsToProcess.push({
142
+ startTimeMs: sortedRanges[i].endTimeMs,
143
+ endTimeMs: sortedRanges[i + 1].startTimeMs,
144
+ });
145
+ }
146
+ // Add segment from last range to end if needed
147
+ if (sortedRanges.length > 0 &&
148
+ sortedRanges[sortedRanges.length - 1].endTimeMs <
149
+ fullDuration) {
150
+ segmentsToProcess.push({
151
+ startTimeMs: sortedRanges[sortedRanges.length - 1].endTimeMs,
152
+ endTimeMs: fullDuration,
153
+ });
154
+ }
155
+ }
156
+ // Filter out empty or invalid segments
157
+ segmentsToProcess = segmentsToProcess.filter((segment) => segment.startTimeMs < segment.endTimeMs &&
158
+ segment.endTimeMs - segment.startTimeMs > 1); // 1ms minimum
159
+ if (segmentsToProcess.length === 0) {
160
+ throw new Error('No valid segments to process after filtering ranges');
161
+ }
162
+ // Process each segment using original sample rate and channels
163
+ const segmentBuffers = [];
164
+ for (let i = 0; i < segmentsToProcess.length; i++) {
165
+ const segment = segmentsToProcess[i];
166
+ // Report progress for each segment
167
+ progressCallback?.({
168
+ progress: 10 +
169
+ Math.round((i / segmentsToProcess.length) * 40),
170
+ });
171
+ // Slice from the already-decoded buffer (avoids N re-fetches)
172
+ const segmentBuffer = sliceAudioBuffer(originalAudioBuffer, audioContext, segment.startTimeMs, segment.endTimeMs);
173
+ segmentBuffers.push(segmentBuffer);
174
+ }
175
+ // Concatenate all segments
176
+ const totalSamples = segmentBuffers.reduce((sum, buffer) => sum + buffer.length, 0);
177
+ // Create buffer with original properties first
178
+ const concatenatedBuffer = audioContext.createBuffer(originalChannels, totalSamples, originalSampleRate);
179
+ let offset = 0;
180
+ for (const segmentBuffer of segmentBuffers) {
181
+ for (let channel = 0; channel < originalChannels; channel++) {
182
+ const outputData = concatenatedBuffer.getChannelData(channel);
183
+ const segmentData = segmentBuffer.getChannelData(channel);
184
+ for (let i = 0; i < segmentBuffer.length; i++) {
185
+ outputData[offset + i] = segmentData[i];
186
+ }
187
+ }
188
+ offset += segmentBuffer.length;
189
+ }
190
+ resultBuffer = concatenatedBuffer;
191
+ // If we need to change sample rate or channels, do it after concatenation
192
+ if (targetSampleRate !== originalSampleRate ||
193
+ targetChannels !== originalChannels) {
194
+ resultBuffer = await resampleAudioBuffer(concatenatedBuffer, targetSampleRate, targetChannels);
195
+ }
196
+ }
197
+ // Report progress (50% - processing complete)
198
+ progressCallback?.({ progress: 50 });
199
+ // Encode the result based on the requested format
200
+ let outputData;
201
+ let outputMimeType;
202
+ let compressionInfo = undefined;
203
+ // AAC is not reliably supported in browsers; fall back to opus
204
+ if (format === 'aac') {
205
+ console.warn('AAC format is not supported on web platforms. Falling back to OPUS format.');
206
+ format = 'opus';
207
+ }
208
+ if (format === 'wav') {
209
+ outputData = encodeBufferToWav(resultBuffer, targetBitDepth);
210
+ outputMimeType = 'audio/wav';
211
+ }
212
+ else if (format === 'opus') {
213
+ try {
214
+ const { data, bitrate } = await encodeCompressedAudio(resultBuffer, format, outputFormat?.bitrate);
215
+ outputData = data;
216
+ outputMimeType = 'audio/webm';
217
+ compressionInfo = { format, bitrate, size: data.byteLength };
218
+ }
219
+ catch (error) {
220
+ console.warn(`Failed to encode to ${format}, falling back to WAV: ${error}`);
221
+ outputData = encodeBufferToWav(resultBuffer, targetBitDepth);
222
+ outputMimeType = 'audio/wav';
223
+ }
224
+ }
225
+ else {
226
+ // Default to WAV for unsupported formats
227
+ console.warn(`Format ${format} not supported on web, using WAV instead`);
228
+ outputData = encodeBufferToWav(resultBuffer, targetBitDepth);
229
+ outputMimeType = 'audio/wav';
230
+ }
231
+ // Report progress (90% - encoding complete)
232
+ progressCallback?.({ progress: 90 });
233
+ // Create a blob and URL for the result
234
+ const blob = new Blob([outputData], { type: outputMimeType });
235
+ const outputUri = URL.createObjectURL(blob);
236
+ // Calculate processing time
237
+ const processingTimeMs = performance.now() - startTime;
238
+ // Report progress (100% - complete)
239
+ progressCallback?.({ progress: 100 });
240
+ // Create result object
241
+ const result = {
242
+ uri: outputUri,
243
+ filename,
244
+ durationMs: Math.round(resultBuffer.duration * 1000),
245
+ size: outputData.byteLength,
246
+ sampleRate: resultBuffer.sampleRate,
247
+ channels: resultBuffer.numberOfChannels,
248
+ bitDepth: targetBitDepth,
249
+ mimeType: outputMimeType,
250
+ processingInfo: {
251
+ durationMs: processingTimeMs,
252
+ },
253
+ };
254
+ if (compressionInfo) {
255
+ result.compression = compressionInfo;
256
+ }
257
+ return result;
258
+ }
259
+ catch (error) {
260
+ console.error('Error in trimAudio:', error);
261
+ throw error;
262
+ }
263
+ }
37
264
  // Set up progress event listener if callback is provided
38
265
  let subscription;
39
266
  if (progressCallback) {
@@ -1 +1 @@
1
- {"version":3,"file":"trimAudio.js","sourceRoot":"","sources":["../../src/trimAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAA0B,MAAM,mBAAmB,CAAA;AAO9E,OAAO,iBAAiB,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAE/D,mCAAmC;AACnC,MAAM,OAAO,GAAG,IAAI,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;AAEzD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC3B,OAAyB,EACzB,gBAAqD;IAErD,aAAa;IACb,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAA;IAC1C,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,QAAQ,CAAA;IACrC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACpB,IACI,OAAO,CAAC,WAAW,KAAK,SAAS;YACjC,OAAO,CAAC,SAAS,KAAK,SAAS,EACjC,CAAC;YACC,MAAM,IAAI,KAAK,CACX,0EAA0E,CAC7E,CAAA;QACL,CAAC;IACL,CAAC;SAAM,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9C,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CACX,gEAAgE,CACnE,CAAA;QACL,CAAC;IACL,CAAC;SAAM,CAAC;QACJ,MAAM,IAAI,KAAK,CACX,iBAAiB,IAAI,yCAAyC,CACjE,CAAA;IACL,CAAC;IAED,yDAAyD;IACzD,IAAI,YAA2C,CAAA;IAC/C,IAAI,gBAAgB,EAAE,CAAC;QACnB,YAAY,GAAG,OAAO,CAAC,WAAW,CAC9B,cAAc,EACd,CAAC,KAAwB,EAAE,EAAE;YACzB,gBAAgB,CAAC,KAAK,CAAC,CAAA;QAC3B,CAAC,CACJ,CAAA;IACL,CAAC;IAED,IAAI,CAAC;QACD,+EAA+E;QAC/E,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,SAAS,CAC5C,kBAAkB,CAAC,OAAO,CAAC,CAC9B,CAAA;QACD,OAAO,MAAM,CAAA;IACjB,CAAC;YAAS,CAAC;QACP,IAAI,YAAY,EAAE,CAAC;YACf,YAAY,CAAC,MAAM,EAAE,CAAA;QACzB,CAAC;IACL,CAAC;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACjC,OAAyB;IAEzB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,CAAA;IACvC,OAAO,MAAM,CAAC,GAAG,CAAA;AACrB,CAAC","sourcesContent":["import { LegacyEventEmitter, type EventSubscription } from 'expo-modules-core'\n\nimport {\n TrimAudioOptions,\n TrimAudioResult,\n TrimProgressEvent,\n} from './AudioStudio.types'\nimport AudioStudioModule from './AudioStudioModule'\nimport { cleanNativeOptions } from './utils/cleanNativeOptions'\n\n// Create a single emitter instance\nconst emitter = new LegacyEventEmitter(AudioStudioModule)\n\n/**\n * Trims an audio file based on the provided options.\n *\n * @experimental This API is experimental and not fully optimized for production use.\n * Performance may vary based on file size and device capabilities.\n * Future versions may include breaking changes.\n *\n * @param options Configuration options for the trimming operation\n * @param progressCallback Optional callback to receive progress updates\n * @returns Promise resolving to the trimmed audio file information, including processing time\n */\nexport async function trimAudio(\n options: TrimAudioOptions,\n progressCallback?: (event: TrimProgressEvent) => void\n): Promise<TrimAudioResult> {\n // Validation\n if (!options.fileUri) {\n throw new Error('fileUri is required')\n }\n const mode = options.mode ?? 'single'\n if (mode === 'single') {\n if (\n options.startTimeMs === undefined &&\n options.endTimeMs === undefined\n ) {\n throw new Error(\n 'At least one of startTimeMs or endTimeMs must be provided in single mode'\n )\n }\n } else if (mode === 'keep' || mode === 'remove') {\n if (!options.ranges || options.ranges.length === 0) {\n throw new Error(\n 'ranges must be provided and non-empty for keep or remove modes'\n )\n }\n } else {\n throw new Error(\n `Invalid mode: ${mode}. Must be 'single', 'keep', or 'remove'`\n )\n }\n\n // Set up progress event listener if callback is provided\n let subscription: EventSubscription | undefined\n if (progressCallback) {\n subscription = emitter.addListener(\n 'TrimProgress',\n (event: TrimProgressEvent) => {\n progressCallback(event)\n }\n )\n }\n\n try {\n // Clean non-serializable/undefined values to avoid Android Kotlin bridge crash\n const result = await AudioStudioModule.trimAudio(\n cleanNativeOptions(options)\n )\n return result\n } finally {\n if (subscription) {\n subscription.remove()\n }\n }\n}\n\n/**\n * Simplified version of trimAudio that returns only the URI of the trimmed file.\n *\n * @experimental This API is experimental and not fully optimized for production use.\n * Performance may vary based on file size and device capabilities.\n * Future versions may include breaking changes.\n *\n * @param options Configuration options for the trimming operation\n * @returns Promise resolving to the URI of the trimmed audio file\n */\nexport async function trimAudioSimple(\n options: TrimAudioOptions\n): Promise<string> {\n const result = await trimAudio(options)\n return result.uri\n}\n"]}
1
+ {"version":3,"file":"trimAudio.js","sourceRoot":"","sources":["../../src/trimAudio.ts"],"names":[],"mappings":"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","sourcesContent":["import { LegacyEventEmitter, type EventSubscription } from 'expo-modules-core'\n\nimport {\n BitDepth,\n TrimAudioOptions,\n TrimAudioResult,\n TrimProgressEvent,\n} from './AudioStudio.types'\nimport AudioStudioModule from './AudioStudioModule'\nimport { isWeb } from './constants'\nimport { processAudioBuffer } from './utils/audioProcessing'\nimport { cleanNativeOptions } from './utils/cleanNativeOptions'\nimport { encodeCompressedAudio } from './utils/encodeCompressedAudio.web'\nimport { resampleAudioBuffer } from './utils/resampleAudioBuffer.web'\nimport { writeWavHeader } from './utils/writeWavHeader'\n\n// Create a single emitter instance\nconst emitter = new LegacyEventEmitter(AudioStudioModule)\n\nfunction sliceAudioBuffer(\n src: AudioBuffer,\n ctx: AudioContext,\n startMs: number,\n endMs: number\n): AudioBuffer {\n const sr = src.sampleRate\n const start = Math.floor((startMs / 1000) * sr)\n const end = Math.min(Math.ceil((endMs / 1000) * sr), src.length)\n const length = Math.max(0, end - start)\n const out = ctx.createBuffer(src.numberOfChannels, length, sr)\n for (let c = 0; c < src.numberOfChannels; c++) {\n out.getChannelData(c).set(src.getChannelData(c).subarray(start, end))\n }\n return out\n}\n\nfunction encodeBufferToWav(buffer: AudioBuffer, bitDepth: BitDepth): ArrayBuffer {\n const { length, numberOfChannels, sampleRate } = buffer\n const channels: Float32Array[] = []\n for (let c = 0; c < numberOfChannels; c++) {\n channels.push(buffer.getChannelData(c))\n }\n const interleavedData = new Int16Array(length * numberOfChannels)\n for (let i = 0; i < length; i++) {\n for (let c = 0; c < numberOfChannels; c++) {\n const clamped = Math.max(-1, Math.min(1, channels[c][i]))\n interleavedData[i * numberOfChannels + c] = Math.round(clamped * 32767)\n }\n }\n return writeWavHeader({\n buffer: interleavedData.buffer as ArrayBuffer,\n sampleRate,\n numChannels: numberOfChannels,\n bitDepth,\n })\n}\n\n/**\n * Trims an audio file based on the provided options.\n *\n * @experimental This API is experimental and not fully optimized for production use.\n * Performance may vary based on file size and device capabilities.\n * Future versions may include breaking changes.\n *\n * @param options Configuration options for the trimming operation\n * @param progressCallback Optional callback to receive progress updates\n * @returns Promise resolving to the trimmed audio file information, including processing time\n */\nexport async function trimAudio(\n options: TrimAudioOptions,\n progressCallback?: (event: TrimProgressEvent) => void\n): Promise<TrimAudioResult> {\n // Validation\n if (!options.fileUri) {\n throw new Error('fileUri is required')\n }\n const mode = options.mode ?? 'single'\n if (mode === 'single') {\n if (\n options.startTimeMs === undefined &&\n options.endTimeMs === undefined\n ) {\n throw new Error(\n 'At least one of startTimeMs or endTimeMs must be provided in single mode'\n )\n }\n } else if (mode === 'keep' || mode === 'remove') {\n if (!options.ranges || options.ranges.length === 0) {\n throw new Error(\n 'ranges must be provided and non-empty for keep or remove modes'\n )\n }\n } else {\n throw new Error(\n `Invalid mode: ${mode}. Must be 'single', 'keep', or 'remove'`\n )\n }\n\n if (isWeb) {\n try {\n const startTime = performance.now()\n const {\n fileUri,\n startTimeMs,\n endTimeMs,\n ranges,\n outputFileName,\n outputFormat,\n } = options\n\n // Create AudioContext\n const audioContext = new (window.AudioContext ||\n (window as any).webkitAudioContext)()\n\n // First, load the entire audio file to get its properties\n const response = await fetch(fileUri)\n const arrayBuffer = await response.arrayBuffer()\n const originalAudioBuffer =\n await audioContext.decodeAudioData(arrayBuffer)\n\n // Get original audio properties\n const originalSampleRate = originalAudioBuffer.sampleRate\n const originalChannels = originalAudioBuffer.numberOfChannels\n\n // Determine output format - use original values as defaults if not specified\n let format = outputFormat?.format || 'wav'\n const targetSampleRate =\n outputFormat?.sampleRate || originalSampleRate\n const targetChannels = outputFormat?.channels || originalChannels\n const targetBitDepth = outputFormat?.bitDepth || 16\n\n // Get file info from the URL\n const filename =\n outputFileName ||\n fileUri.split('/').pop() ||\n 'trimmed-audio.wav'\n\n // Process based on mode\n let resultBuffer: AudioBuffer\n\n // Report initial progress\n progressCallback?.({ progress: 10 })\n\n if (mode === 'single') {\n // Single mode: extract a single range\n // Use original sample rate and channels for extraction to preserve quality\n const { buffer } = await processAudioBuffer({\n fileUri,\n targetSampleRate, // Use the requested sample rate\n targetChannels,\n normalizeAudio: false,\n startTimeMs,\n endTimeMs,\n audioContext,\n })\n\n resultBuffer = buffer\n\n // If we need to change sample rate or channels, do it after extraction\n if (\n targetSampleRate !== originalSampleRate ||\n targetChannels !== originalChannels\n ) {\n resultBuffer = await resampleAudioBuffer(\n buffer,\n targetSampleRate,\n targetChannels\n )\n }\n } else {\n // For keep or remove modes\n const fullDuration = originalAudioBuffer.duration * 1000 // in ms\n\n type ProcessSegment = {\n startTimeMs: number\n endTimeMs: number\n }\n\n let segmentsToProcess: ProcessSegment[] = []\n\n if (mode === 'keep') {\n // For keep mode, use the ranges directly\n segmentsToProcess = ranges!\n } else {\n // mode === 'remove'\n // For remove mode, invert the ranges\n const sortedRanges = [...ranges!].sort(\n (a, b) => a.startTimeMs - b.startTimeMs\n )\n\n // Add segment from start to first range if needed\n if (\n sortedRanges.length > 0 &&\n sortedRanges[0].startTimeMs > 0\n ) {\n segmentsToProcess.push({\n startTimeMs: 0,\n endTimeMs: sortedRanges[0].startTimeMs,\n })\n }\n\n // Add segments between ranges\n for (let i = 0; i < sortedRanges.length - 1; i++) {\n segmentsToProcess.push({\n startTimeMs: sortedRanges[i].endTimeMs,\n endTimeMs: sortedRanges[i + 1].startTimeMs,\n })\n }\n\n // Add segment from last range to end if needed\n if (\n sortedRanges.length > 0 &&\n sortedRanges[sortedRanges.length - 1].endTimeMs <\n fullDuration\n ) {\n segmentsToProcess.push({\n startTimeMs:\n sortedRanges[sortedRanges.length - 1].endTimeMs,\n endTimeMs: fullDuration,\n })\n }\n }\n\n // Filter out empty or invalid segments\n segmentsToProcess = segmentsToProcess.filter(\n (segment) =>\n segment.startTimeMs < segment.endTimeMs &&\n segment.endTimeMs - segment.startTimeMs > 1\n ) // 1ms minimum\n\n if (segmentsToProcess.length === 0) {\n throw new Error(\n 'No valid segments to process after filtering ranges'\n )\n }\n\n // Process each segment using original sample rate and channels\n const segmentBuffers: AudioBuffer[] = []\n\n for (let i = 0; i < segmentsToProcess.length; i++) {\n const segment = segmentsToProcess[i]\n\n // Report progress for each segment\n progressCallback?.({\n progress:\n 10 +\n Math.round((i / segmentsToProcess.length) * 40),\n })\n\n // Slice from the already-decoded buffer (avoids N re-fetches)\n const segmentBuffer = sliceAudioBuffer(\n originalAudioBuffer,\n audioContext,\n segment.startTimeMs,\n segment.endTimeMs\n )\n\n segmentBuffers.push(segmentBuffer)\n }\n\n // Concatenate all segments\n const totalSamples = segmentBuffers.reduce(\n (sum, buffer) => sum + buffer.length,\n 0\n )\n\n // Create buffer with original properties first\n const concatenatedBuffer = audioContext.createBuffer(\n originalChannels,\n totalSamples,\n originalSampleRate\n )\n\n let offset = 0\n for (const segmentBuffer of segmentBuffers) {\n for (\n let channel = 0;\n channel < originalChannels;\n channel++\n ) {\n const outputData =\n concatenatedBuffer.getChannelData(channel)\n const segmentData =\n segmentBuffer.getChannelData(channel)\n\n for (let i = 0; i < segmentBuffer.length; i++) {\n outputData[offset + i] = segmentData[i]\n }\n }\n offset += segmentBuffer.length\n }\n\n resultBuffer = concatenatedBuffer\n\n // If we need to change sample rate or channels, do it after concatenation\n if (\n targetSampleRate !== originalSampleRate ||\n targetChannels !== originalChannels\n ) {\n resultBuffer = await resampleAudioBuffer(\n concatenatedBuffer,\n targetSampleRate,\n targetChannels\n )\n }\n }\n\n // Report progress (50% - processing complete)\n progressCallback?.({ progress: 50 })\n\n // Encode the result based on the requested format\n let outputData: ArrayBuffer\n let outputMimeType: string\n let compressionInfo: TrimAudioResult['compression'] = undefined\n\n // AAC is not reliably supported in browsers; fall back to opus\n if (format === 'aac') {\n console.warn(\n 'AAC format is not supported on web platforms. Falling back to OPUS format.'\n )\n format = 'opus'\n }\n\n if (format === 'wav') {\n outputData = encodeBufferToWav(resultBuffer, targetBitDepth as BitDepth)\n outputMimeType = 'audio/wav'\n } else if (format === 'opus') {\n try {\n const { data, bitrate } = await encodeCompressedAudio(\n resultBuffer,\n format,\n outputFormat?.bitrate\n )\n outputData = data\n outputMimeType = 'audio/webm'\n compressionInfo = { format, bitrate, size: data.byteLength }\n } catch (error) {\n console.warn(\n `Failed to encode to ${format}, falling back to WAV: ${error}`\n )\n outputData = encodeBufferToWav(resultBuffer, targetBitDepth as BitDepth)\n outputMimeType = 'audio/wav'\n }\n } else {\n // Default to WAV for unsupported formats\n console.warn(\n `Format ${format} not supported on web, using WAV instead`\n )\n outputData = encodeBufferToWav(resultBuffer, targetBitDepth as BitDepth)\n outputMimeType = 'audio/wav'\n }\n\n // Report progress (90% - encoding complete)\n progressCallback?.({ progress: 90 })\n\n // Create a blob and URL for the result\n const blob = new Blob([outputData], { type: outputMimeType })\n const outputUri = URL.createObjectURL(blob)\n\n // Calculate processing time\n const processingTimeMs = performance.now() - startTime\n\n // Report progress (100% - complete)\n progressCallback?.({ progress: 100 })\n\n // Create result object\n const result: TrimAudioResult = {\n uri: outputUri,\n filename,\n durationMs: Math.round(resultBuffer.duration * 1000),\n size: outputData.byteLength,\n sampleRate: resultBuffer.sampleRate,\n channels: resultBuffer.numberOfChannels,\n bitDepth: targetBitDepth,\n mimeType: outputMimeType,\n processingInfo: {\n durationMs: processingTimeMs,\n },\n }\n\n if (compressionInfo) {\n result.compression = compressionInfo\n }\n\n return result\n } catch (error) {\n console.error('Error in trimAudio:', error)\n throw error\n }\n }\n\n // Set up progress event listener if callback is provided\n let subscription: EventSubscription | undefined\n if (progressCallback) {\n subscription = emitter.addListener(\n 'TrimProgress',\n (event: TrimProgressEvent) => {\n progressCallback(event)\n }\n )\n }\n\n try {\n // Clean non-serializable/undefined values to avoid Android Kotlin bridge crash\n const result = await AudioStudioModule.trimAudio(\n cleanNativeOptions(options)\n )\n return result\n } finally {\n if (subscription) {\n subscription.remove()\n }\n }\n}\n\n/**\n * Simplified version of trimAudio that returns only the URI of the trimmed file.\n *\n * @experimental This API is experimental and not fully optimized for production use.\n * Performance may vary based on file size and device capabilities.\n * Future versions may include breaking changes.\n *\n * @param options Configuration options for the trimming operation\n * @returns Promise resolving to the URI of the trimmed audio file\n */\nexport async function trimAudioSimple(\n options: TrimAudioOptions\n): Promise<string> {\n const result = await trimAudio(options)\n return result.uri\n}\n"]}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * NOTE: Encodes audio in real-time via AudioContext + MediaRecorder playback.
3
+ * A 60-second clip takes ~60 seconds to encode — this is a known Web Audio API
4
+ * limitation; there is no offline API for Opus/AAC encoding in browsers.
5
+ */
6
+ export function encodeCompressedAudio(buffer, format, bitrate) {
7
+ return new Promise((resolve, reject) => {
8
+ try {
9
+ // On web, always use opus if aac is requested (browser aac support is rare)
10
+ const actualFormat = format === 'aac' ? 'opus' : format;
11
+ // Check if MediaRecorder supports the requested format
12
+ const mimeType = actualFormat === 'opus' ? 'audio/webm;codecs=opus' : 'audio/aac';
13
+ if (!MediaRecorder.isTypeSupported(mimeType)) {
14
+ throw new Error(`MediaRecorder does not support ${mimeType}`);
15
+ }
16
+ // Create a new AudioContext and source
17
+ const ctx = new (window.AudioContext ||
18
+ window.webkitAudioContext)();
19
+ const source = ctx.createBufferSource();
20
+ source.buffer = buffer;
21
+ // Create a MediaStreamDestination to capture the audio
22
+ const destination = ctx.createMediaStreamDestination();
23
+ source.connect(destination);
24
+ // Create a MediaRecorder with the requested format
25
+ const recorder = new MediaRecorder(destination.stream, {
26
+ mimeType,
27
+ audioBitsPerSecond: bitrate || (actualFormat === 'opus' ? 32000 : 64000),
28
+ });
29
+ const chunks = [];
30
+ recorder.ondataavailable = (e) => {
31
+ if (e.data.size > 0) {
32
+ chunks.push(e.data);
33
+ }
34
+ };
35
+ recorder.onstop = async () => {
36
+ try {
37
+ const blob = new Blob(chunks, { type: mimeType });
38
+ const arrayBuffer = await blob.arrayBuffer();
39
+ // Get the actual bitrate used
40
+ const actualBitrate = Math.round((arrayBuffer.byteLength * 8) / buffer.duration);
41
+ resolve({
42
+ data: arrayBuffer,
43
+ bitrate: actualBitrate / 1000, // Convert to kbps
44
+ });
45
+ // Clean up
46
+ ctx.close();
47
+ }
48
+ catch (error) {
49
+ reject(error);
50
+ }
51
+ };
52
+ // Start recording and playback; stop recorder when playback ends
53
+ recorder.start();
54
+ source.onended = () => recorder.stop();
55
+ source.start(0);
56
+ }
57
+ catch (error) {
58
+ reject(error);
59
+ }
60
+ });
61
+ }
62
+ //# sourceMappingURL=encodeCompressedAudio.web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encodeCompressedAudio.web.js","sourceRoot":"","sources":["../../../src/utils/encodeCompressedAudio.web.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACjC,MAAmB,EACnB,MAAsB,EACtB,OAAgB;IAEhB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,IAAI,CAAC;YACD,4EAA4E;YAC5E,MAAM,YAAY,GAAG,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAA;YAEvD,uDAAuD;YACvD,MAAM,QAAQ,GACV,YAAY,KAAK,MAAM,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,WAAW,CAAA;YACpE,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC3C,MAAM,IAAI,KAAK,CAAC,kCAAkC,QAAQ,EAAE,CAAC,CAAA;YACjE,CAAC;YAED,uCAAuC;YACvC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY;gBAC/B,MAAc,CAAC,kBAAkB,CAAC,EAAE,CAAA;YACzC,MAAM,MAAM,GAAG,GAAG,CAAC,kBAAkB,EAAE,CAAA;YACvC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAA;YAEtB,uDAAuD;YACvD,MAAM,WAAW,GAAG,GAAG,CAAC,4BAA4B,EAAE,CAAA;YACtD,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;YAE3B,mDAAmD;YACnD,MAAM,QAAQ,GAAG,IAAI,aAAa,CAAC,WAAW,CAAC,MAAM,EAAE;gBACnD,QAAQ;gBACR,kBAAkB,EACd,OAAO,IAAI,CAAC,YAAY,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;aAC3D,CAAC,CAAA;YAEF,MAAM,MAAM,GAAW,EAAE,CAAA;YAEzB,QAAQ,CAAC,eAAe,GAAG,CAAC,CAAC,EAAE,EAAE;gBAC7B,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;oBAClB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;gBACvB,CAAC;YACL,CAAC,CAAA;YAED,QAAQ,CAAC,MAAM,GAAG,KAAK,IAAI,EAAE;gBACzB,IAAI,CAAC;oBACD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;oBACjD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;oBAE5C,8BAA8B;oBAC9B,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAC5B,CAAC,WAAW,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CACjD,CAAA;oBAED,OAAO,CAAC;wBACJ,IAAI,EAAE,WAAW;wBACjB,OAAO,EAAE,aAAa,GAAG,IAAI,EAAE,kBAAkB;qBACpD,CAAC,CAAA;oBAEF,WAAW;oBACX,GAAG,CAAC,KAAK,EAAE,CAAA;gBACf,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACb,MAAM,CAAC,KAAK,CAAC,CAAA;gBACjB,CAAC;YACL,CAAC,CAAA;YAED,iEAAiE;YACjE,QAAQ,CAAC,KAAK,EAAE,CAAA;YAChB,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAA;YACtC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,CAAA;QACjB,CAAC;IACL,CAAC,CAAC,CAAA;AACN,CAAC","sourcesContent":["/**\n * NOTE: Encodes audio in real-time via AudioContext + MediaRecorder playback.\n * A 60-second clip takes ~60 seconds to encode — this is a known Web Audio API\n * limitation; there is no offline API for Opus/AAC encoding in browsers.\n */\nexport function encodeCompressedAudio(\n buffer: AudioBuffer,\n format: 'opus' | 'aac',\n bitrate?: number\n): Promise<{ data: ArrayBuffer; bitrate: number }> {\n return new Promise((resolve, reject) => {\n try {\n // On web, always use opus if aac is requested (browser aac support is rare)\n const actualFormat = format === 'aac' ? 'opus' : format\n\n // Check if MediaRecorder supports the requested format\n const mimeType =\n actualFormat === 'opus' ? 'audio/webm;codecs=opus' : 'audio/aac'\n if (!MediaRecorder.isTypeSupported(mimeType)) {\n throw new Error(`MediaRecorder does not support ${mimeType}`)\n }\n\n // Create a new AudioContext and source\n const ctx = new (window.AudioContext ||\n (window as any).webkitAudioContext)()\n const source = ctx.createBufferSource()\n source.buffer = buffer\n\n // Create a MediaStreamDestination to capture the audio\n const destination = ctx.createMediaStreamDestination()\n source.connect(destination)\n\n // Create a MediaRecorder with the requested format\n const recorder = new MediaRecorder(destination.stream, {\n mimeType,\n audioBitsPerSecond:\n bitrate || (actualFormat === 'opus' ? 32000 : 64000),\n })\n\n const chunks: Blob[] = []\n\n recorder.ondataavailable = (e) => {\n if (e.data.size > 0) {\n chunks.push(e.data)\n }\n }\n\n recorder.onstop = async () => {\n try {\n const blob = new Blob(chunks, { type: mimeType })\n const arrayBuffer = await blob.arrayBuffer()\n\n // Get the actual bitrate used\n const actualBitrate = Math.round(\n (arrayBuffer.byteLength * 8) / buffer.duration\n )\n\n resolve({\n data: arrayBuffer,\n bitrate: actualBitrate / 1000, // Convert to kbps\n })\n\n // Clean up\n ctx.close()\n } catch (error) {\n reject(error)\n }\n }\n\n // Start recording and playback; stop recorder when playback ends\n recorder.start()\n source.onended = () => recorder.stop()\n source.start(0)\n } catch (error) {\n reject(error)\n }\n })\n}\n"]}
@@ -0,0 +1,22 @@
1
+ export async function resampleAudioBuffer(buffer, targetSampleRate, targetChannels) {
2
+ // If no change needed, return the original buffer
3
+ if (buffer.sampleRate === targetSampleRate &&
4
+ buffer.numberOfChannels === targetChannels) {
5
+ return buffer;
6
+ }
7
+ // Calculate the new length based on the sample rate change
8
+ const newLength = Math.round((buffer.length * targetSampleRate) / buffer.sampleRate);
9
+ // Create an offline context for resampling
10
+ const offlineContext = new OfflineAudioContext(targetChannels, newLength, targetSampleRate);
11
+ // Create a source node
12
+ const source = offlineContext.createBufferSource();
13
+ source.buffer = buffer;
14
+ // The OfflineAudioContext was created with targetChannels; the Web Audio API
15
+ // applies its built-in speaker downmix/upmix rules automatically.
16
+ source.connect(offlineContext.destination);
17
+ // Start rendering
18
+ source.start(0);
19
+ const resampledBuffer = await offlineContext.startRendering();
20
+ return resampledBuffer;
21
+ }
22
+ //# sourceMappingURL=resampleAudioBuffer.web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resampleAudioBuffer.web.js","sourceRoot":"","sources":["../../../src/utils/resampleAudioBuffer.web.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACrC,MAAmB,EACnB,gBAAwB,EACxB,cAAsB;IAEtB,kDAAkD;IAClD,IACI,MAAM,CAAC,UAAU,KAAK,gBAAgB;QACtC,MAAM,CAAC,gBAAgB,KAAK,cAAc,EAC5C,CAAC;QACC,OAAO,MAAM,CAAA;IACjB,CAAC;IAED,2DAA2D;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CACxB,CAAC,MAAM,CAAC,MAAM,GAAG,gBAAgB,CAAC,GAAG,MAAM,CAAC,UAAU,CACzD,CAAA;IAED,2CAA2C;IAC3C,MAAM,cAAc,GAAG,IAAI,mBAAmB,CAC1C,cAAc,EACd,SAAS,EACT,gBAAgB,CACnB,CAAA;IAED,uBAAuB;IACvB,MAAM,MAAM,GAAG,cAAc,CAAC,kBAAkB,EAAE,CAAA;IAClD,MAAM,CAAC,MAAM,GAAG,MAAM,CAAA;IAEtB,6EAA6E;IAC7E,kEAAkE;IAClE,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,CAAA;IAE1C,kBAAkB;IAClB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACf,MAAM,eAAe,GAAG,MAAM,cAAc,CAAC,cAAc,EAAE,CAAA;IAE7D,OAAO,eAAe,CAAA;AAC1B,CAAC","sourcesContent":["export async function resampleAudioBuffer(\n buffer: AudioBuffer,\n targetSampleRate: number,\n targetChannels: number\n): Promise<AudioBuffer> {\n // If no change needed, return the original buffer\n if (\n buffer.sampleRate === targetSampleRate &&\n buffer.numberOfChannels === targetChannels\n ) {\n return buffer\n }\n\n // Calculate the new length based on the sample rate change\n const newLength = Math.round(\n (buffer.length * targetSampleRate) / buffer.sampleRate\n )\n\n // Create an offline context for resampling\n const offlineContext = new OfflineAudioContext(\n targetChannels,\n newLength,\n targetSampleRate\n )\n\n // Create a source node\n const source = offlineContext.createBufferSource()\n source.buffer = buffer\n\n // The OfflineAudioContext was created with targetChannels; the Web Audio API\n // applies its built-in speaker downmix/upmix rules automatically.\n source.connect(offlineContext.destination)\n\n // Start rendering\n source.start(0)\n const resampledBuffer = await offlineContext.startRendering()\n\n return resampledBuffer\n}\n"]}
@@ -182,6 +182,17 @@ export interface ExtractMelSpectrogramOptions {
182
182
  endTimeMs?: number;
183
183
  logger?: ConsoleLike;
184
184
  }
185
+ /**
186
+ * Result type for WASM-based audio feature extraction.
187
+ */
188
+ export interface AudioFeaturesWasmResult {
189
+ spectralCentroid: number;
190
+ spectralFlatness: number;
191
+ spectralRolloff: number;
192
+ spectralBandwidth: number;
193
+ mfcc: number[];
194
+ chromagram: number[];
195
+ }
185
196
  /**
186
197
  * Return type for mel spectrogram extraction
187
198
  *