@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":";;AAAA,yDAAuD;AACvD,+CAAuC;AAEvC,uDAAuE;AAEvE,8DAA8D;AAC9D,IAAI,iBAAsB,CAAA;AAE1B,IAAI,uBAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;IACxB,IAAI,QAAQ,GAA0B,IAAI,CAAA;IAE1C,iBAAiB,GAAG,CAAC,QAA6B,EAAE,EAAE;QAClD,QAAQ,KAAK,IAAI,gCAAc,CAAC,QAAQ,CAAC,CAAA;QACzC,OAAO,QAAQ,CAAA;IACnB,CAAC,CAAA;IACD,iBAAiB,CAAC,uBAAuB,GAAG,KAAK,IAAI,EAAE;QACnD,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;gBACrD,KAAK,EAAE,IAAI;aACd,CAAC,CAAA;YACF,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;YACnD,OAAO;gBACH,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,OAAO;gBAChB,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,IAAI;aAChB,CAAA;QACL,CAAC;QAAC,MAAM,CAAC;YACL,OAAO;gBACH,MAAM,EAAE,QAAQ;gBAChB,OAAO,EAAE,OAAO;gBAChB,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,KAAK;aACjB,CAAA;QACL,CAAC;IACL,CAAC,CAAA;IACD,iBAAiB,CAAC,mBAAmB,GAAG,KAAK,IAAI,EAAE;QAC/C,IAAI,WAAW,GAAkB,IAAI,CAAA;QAErC,IAAI,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;YAChC,IAAI,CAAC;gBACD,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC;oBAChD,IAAI,EAAE,YAA8B;iBACvC,CAAC,CAAA;gBACF,WAAW,GAAG,KAAK,CAAA;YACvB,CAAC;YAAC,MAAM,CAAC;gBACL,WAAW,GAAG,IAAI,CAAA;YACtB,CAAC;QACL,CAAC;QAED,QAAQ,WAAW,EAAE,CAAC;YAClB,KAAK,SAAS;gBACV,OAAO;oBACH,MAAM,EAAE,SAAS;oBACjB,OAAO,EAAE,OAAO;oBAChB,WAAW,EAAE,IAAI;oBACjB,OAAO,EAAE,IAAI;iBAChB,CAAA;YACL,KAAK,QAAQ;gBACT,OAAO;oBACH,MAAM,EAAE,QAAQ;oBAChB,OAAO,EAAE,OAAO;oBAChB,WAAW,EAAE,IAAI;oBACjB,OAAO,EAAE,KAAK;iBACjB,CAAA;YACL;gBACI,OAAO,MAAM,iBAAiB,CAAC,uBAAuB,EAAE,CAAA;QAChE,CAAC;IACL,CAAC,CAAA;IACD,iCAAiC;IACjC,iBAAiB,CAAC,SAAS,GAAG,CAAC,SAAiB,EAAE,MAAW,EAAE,EAAE;QAC7D,mEAAmE;QACnE,iBAAiB,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,OAAO,CAC7C,CAAC,QAAkB,EAAE,EAAE;YACnB,QAAQ,CAAC,MAAM,CAAC,CAAA;QACpB,CAAC,CACJ,CAAA;IACL,CAAC,CAAA;IAED,8BAA8B;IAC9B,iBAAiB,CAAC,SAAS,GAAG,EAAE,CAAA;IAEhC,mEAAmE;IACnE,iBAAiB,CAAC,WAAW,GAAG,CAAC,SAAiB,EAAE,QAAkB,EAAE,EAAE;QACtE,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1C,iBAAiB,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,CAAA;QAC/C,CAAC;QACD,iBAAiB,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAErD,wCAAwC;QACxC,OAAO;YACH,MAAM,EAAE,GAAG,EAAE;gBACT,MAAM,KAAK,GACP,iBAAiB,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;gBAC5D,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;oBACf,iBAAiB,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;gBAC3D,CAAC;YACL,CAAC;SACJ,CAAA;IACL,CAAC,CAAA;IAED,iBAAiB,CAAC,kBAAkB,GAAG,CAAC,SAAiB,EAAE,EAAE;QACzD,IAAI,iBAAiB,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;YACzC,OAAO,iBAAiB,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;QACjD,CAAC;IACL,CAAC,CAAA;IAED,iBAAiB,CAAC,gBAAgB,GAAG,KAAK,EAAE,OAAY,EAAE,EAAE;QACxD,sFAAsF;QACtF,0FAA0F;QAC1F,IAAI,CAAC;YACD,mCAAmC;YACnC,MAAM,iBAAiB,GACnB,MAAM,iBAAiB,CAAC,mBAAmB,EAAE,CAAA;YACjD,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,CAAC;gBAC7B,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;YACxD,CAAC;YAED,4DAA4D;YAC5D,IAAI,QAAQ,EAAE,CAAC;gBACX,OAAO,MAAM,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAA;YACnD,CAAC;YAED,OAAO,IAAI,CAAA;QACf,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAA;YAClD,MAAM,KAAK,CAAA;QACf,CAAC;IACL,CAAC,CAAA;AACL,CAAC;AAED,IAAI,uBAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;IACxB,iBAAiB,GAAG,IAAA,uCAAmB,EAAC,aAAa,CAAC,CAAA;AAC1D,CAAC;AAED,kBAAe,iBAAiB,CAAA","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"]}
@@ -7,9 +7,45 @@ exports.trimAudio = trimAudio;
7
7
  exports.trimAudioSimple = trimAudioSimple;
8
8
  const expo_modules_core_1 = require("expo-modules-core");
9
9
  const AudioStudioModule_1 = __importDefault(require("./AudioStudioModule"));
10
+ const constants_1 = require("./constants");
11
+ const audioProcessing_1 = require("./utils/audioProcessing");
10
12
  const cleanNativeOptions_1 = require("./utils/cleanNativeOptions");
13
+ const encodeCompressedAudio_web_1 = require("./utils/encodeCompressedAudio.web");
14
+ const resampleAudioBuffer_web_1 = require("./utils/resampleAudioBuffer.web");
15
+ const writeWavHeader_1 = require("./utils/writeWavHeader");
11
16
  // Create a single emitter instance
12
17
  const emitter = new expo_modules_core_1.LegacyEventEmitter(AudioStudioModule_1.default);
18
+ function sliceAudioBuffer(src, ctx, startMs, endMs) {
19
+ const sr = src.sampleRate;
20
+ const start = Math.floor((startMs / 1000) * sr);
21
+ const end = Math.min(Math.ceil((endMs / 1000) * sr), src.length);
22
+ const length = Math.max(0, end - start);
23
+ const out = ctx.createBuffer(src.numberOfChannels, length, sr);
24
+ for (let c = 0; c < src.numberOfChannels; c++) {
25
+ out.getChannelData(c).set(src.getChannelData(c).subarray(start, end));
26
+ }
27
+ return out;
28
+ }
29
+ function encodeBufferToWav(buffer, bitDepth) {
30
+ const { length, numberOfChannels, sampleRate } = buffer;
31
+ const channels = [];
32
+ for (let c = 0; c < numberOfChannels; c++) {
33
+ channels.push(buffer.getChannelData(c));
34
+ }
35
+ const interleavedData = new Int16Array(length * numberOfChannels);
36
+ for (let i = 0; i < length; i++) {
37
+ for (let c = 0; c < numberOfChannels; c++) {
38
+ const clamped = Math.max(-1, Math.min(1, channels[c][i]));
39
+ interleavedData[i * numberOfChannels + c] = Math.round(clamped * 32767);
40
+ }
41
+ }
42
+ return (0, writeWavHeader_1.writeWavHeader)({
43
+ buffer: interleavedData.buffer,
44
+ sampleRate,
45
+ numChannels: numberOfChannels,
46
+ bitDepth,
47
+ });
48
+ }
13
49
  /**
14
50
  * Trims an audio file based on the provided options.
15
51
  *
@@ -41,6 +77,197 @@ async function trimAudio(options, progressCallback) {
41
77
  else {
42
78
  throw new Error(`Invalid mode: ${mode}. Must be 'single', 'keep', or 'remove'`);
43
79
  }
80
+ if (constants_1.isWeb) {
81
+ try {
82
+ const startTime = performance.now();
83
+ const { fileUri, startTimeMs, endTimeMs, ranges, outputFileName, outputFormat, } = options;
84
+ // Create AudioContext
85
+ const audioContext = new (window.AudioContext ||
86
+ window.webkitAudioContext)();
87
+ // First, load the entire audio file to get its properties
88
+ const response = await fetch(fileUri);
89
+ const arrayBuffer = await response.arrayBuffer();
90
+ const originalAudioBuffer = await audioContext.decodeAudioData(arrayBuffer);
91
+ // Get original audio properties
92
+ const originalSampleRate = originalAudioBuffer.sampleRate;
93
+ const originalChannels = originalAudioBuffer.numberOfChannels;
94
+ // Determine output format - use original values as defaults if not specified
95
+ let format = outputFormat?.format || 'wav';
96
+ const targetSampleRate = outputFormat?.sampleRate || originalSampleRate;
97
+ const targetChannels = outputFormat?.channels || originalChannels;
98
+ const targetBitDepth = outputFormat?.bitDepth || 16;
99
+ // Get file info from the URL
100
+ const filename = outputFileName ||
101
+ fileUri.split('/').pop() ||
102
+ 'trimmed-audio.wav';
103
+ // Process based on mode
104
+ let resultBuffer;
105
+ // Report initial progress
106
+ progressCallback?.({ progress: 10 });
107
+ if (mode === 'single') {
108
+ // Single mode: extract a single range
109
+ // Use original sample rate and channels for extraction to preserve quality
110
+ const { buffer } = await (0, audioProcessing_1.processAudioBuffer)({
111
+ fileUri,
112
+ targetSampleRate, // Use the requested sample rate
113
+ targetChannels,
114
+ normalizeAudio: false,
115
+ startTimeMs,
116
+ endTimeMs,
117
+ audioContext,
118
+ });
119
+ resultBuffer = buffer;
120
+ // If we need to change sample rate or channels, do it after extraction
121
+ if (targetSampleRate !== originalSampleRate ||
122
+ targetChannels !== originalChannels) {
123
+ resultBuffer = await (0, resampleAudioBuffer_web_1.resampleAudioBuffer)(buffer, targetSampleRate, targetChannels);
124
+ }
125
+ }
126
+ else {
127
+ // For keep or remove modes
128
+ const fullDuration = originalAudioBuffer.duration * 1000; // in ms
129
+ let segmentsToProcess = [];
130
+ if (mode === 'keep') {
131
+ // For keep mode, use the ranges directly
132
+ segmentsToProcess = ranges;
133
+ }
134
+ else {
135
+ // mode === 'remove'
136
+ // For remove mode, invert the ranges
137
+ const sortedRanges = [...ranges].sort((a, b) => a.startTimeMs - b.startTimeMs);
138
+ // Add segment from start to first range if needed
139
+ if (sortedRanges.length > 0 &&
140
+ sortedRanges[0].startTimeMs > 0) {
141
+ segmentsToProcess.push({
142
+ startTimeMs: 0,
143
+ endTimeMs: sortedRanges[0].startTimeMs,
144
+ });
145
+ }
146
+ // Add segments between ranges
147
+ for (let i = 0; i < sortedRanges.length - 1; i++) {
148
+ segmentsToProcess.push({
149
+ startTimeMs: sortedRanges[i].endTimeMs,
150
+ endTimeMs: sortedRanges[i + 1].startTimeMs,
151
+ });
152
+ }
153
+ // Add segment from last range to end if needed
154
+ if (sortedRanges.length > 0 &&
155
+ sortedRanges[sortedRanges.length - 1].endTimeMs <
156
+ fullDuration) {
157
+ segmentsToProcess.push({
158
+ startTimeMs: sortedRanges[sortedRanges.length - 1].endTimeMs,
159
+ endTimeMs: fullDuration,
160
+ });
161
+ }
162
+ }
163
+ // Filter out empty or invalid segments
164
+ segmentsToProcess = segmentsToProcess.filter((segment) => segment.startTimeMs < segment.endTimeMs &&
165
+ segment.endTimeMs - segment.startTimeMs > 1); // 1ms minimum
166
+ if (segmentsToProcess.length === 0) {
167
+ throw new Error('No valid segments to process after filtering ranges');
168
+ }
169
+ // Process each segment using original sample rate and channels
170
+ const segmentBuffers = [];
171
+ for (let i = 0; i < segmentsToProcess.length; i++) {
172
+ const segment = segmentsToProcess[i];
173
+ // Report progress for each segment
174
+ progressCallback?.({
175
+ progress: 10 +
176
+ Math.round((i / segmentsToProcess.length) * 40),
177
+ });
178
+ // Slice from the already-decoded buffer (avoids N re-fetches)
179
+ const segmentBuffer = sliceAudioBuffer(originalAudioBuffer, audioContext, segment.startTimeMs, segment.endTimeMs);
180
+ segmentBuffers.push(segmentBuffer);
181
+ }
182
+ // Concatenate all segments
183
+ const totalSamples = segmentBuffers.reduce((sum, buffer) => sum + buffer.length, 0);
184
+ // Create buffer with original properties first
185
+ const concatenatedBuffer = audioContext.createBuffer(originalChannels, totalSamples, originalSampleRate);
186
+ let offset = 0;
187
+ for (const segmentBuffer of segmentBuffers) {
188
+ for (let channel = 0; channel < originalChannels; channel++) {
189
+ const outputData = concatenatedBuffer.getChannelData(channel);
190
+ const segmentData = segmentBuffer.getChannelData(channel);
191
+ for (let i = 0; i < segmentBuffer.length; i++) {
192
+ outputData[offset + i] = segmentData[i];
193
+ }
194
+ }
195
+ offset += segmentBuffer.length;
196
+ }
197
+ resultBuffer = concatenatedBuffer;
198
+ // If we need to change sample rate or channels, do it after concatenation
199
+ if (targetSampleRate !== originalSampleRate ||
200
+ targetChannels !== originalChannels) {
201
+ resultBuffer = await (0, resampleAudioBuffer_web_1.resampleAudioBuffer)(concatenatedBuffer, targetSampleRate, targetChannels);
202
+ }
203
+ }
204
+ // Report progress (50% - processing complete)
205
+ progressCallback?.({ progress: 50 });
206
+ // Encode the result based on the requested format
207
+ let outputData;
208
+ let outputMimeType;
209
+ let compressionInfo = undefined;
210
+ // AAC is not reliably supported in browsers; fall back to opus
211
+ if (format === 'aac') {
212
+ console.warn('AAC format is not supported on web platforms. Falling back to OPUS format.');
213
+ format = 'opus';
214
+ }
215
+ if (format === 'wav') {
216
+ outputData = encodeBufferToWav(resultBuffer, targetBitDepth);
217
+ outputMimeType = 'audio/wav';
218
+ }
219
+ else if (format === 'opus') {
220
+ try {
221
+ const { data, bitrate } = await (0, encodeCompressedAudio_web_1.encodeCompressedAudio)(resultBuffer, format, outputFormat?.bitrate);
222
+ outputData = data;
223
+ outputMimeType = 'audio/webm';
224
+ compressionInfo = { format, bitrate, size: data.byteLength };
225
+ }
226
+ catch (error) {
227
+ console.warn(`Failed to encode to ${format}, falling back to WAV: ${error}`);
228
+ outputData = encodeBufferToWav(resultBuffer, targetBitDepth);
229
+ outputMimeType = 'audio/wav';
230
+ }
231
+ }
232
+ else {
233
+ // Default to WAV for unsupported formats
234
+ console.warn(`Format ${format} not supported on web, using WAV instead`);
235
+ outputData = encodeBufferToWav(resultBuffer, targetBitDepth);
236
+ outputMimeType = 'audio/wav';
237
+ }
238
+ // Report progress (90% - encoding complete)
239
+ progressCallback?.({ progress: 90 });
240
+ // Create a blob and URL for the result
241
+ const blob = new Blob([outputData], { type: outputMimeType });
242
+ const outputUri = URL.createObjectURL(blob);
243
+ // Calculate processing time
244
+ const processingTimeMs = performance.now() - startTime;
245
+ // Report progress (100% - complete)
246
+ progressCallback?.({ progress: 100 });
247
+ // Create result object
248
+ const result = {
249
+ uri: outputUri,
250
+ filename,
251
+ durationMs: Math.round(resultBuffer.duration * 1000),
252
+ size: outputData.byteLength,
253
+ sampleRate: resultBuffer.sampleRate,
254
+ channels: resultBuffer.numberOfChannels,
255
+ bitDepth: targetBitDepth,
256
+ mimeType: outputMimeType,
257
+ processingInfo: {
258
+ durationMs: processingTimeMs,
259
+ },
260
+ };
261
+ if (compressionInfo) {
262
+ result.compression = compressionInfo;
263
+ }
264
+ return result;
265
+ }
266
+ catch (error) {
267
+ console.error('Error in trimAudio:', error);
268
+ throw error;
269
+ }
270
+ }
44
271
  // Set up progress event listener if callback is provided
45
272
  let subscription;
46
273
  if (progressCallback) {
@@ -1 +1 @@
1
- {"version":3,"file":"trimAudio.js","sourceRoot":"","sources":["../../src/trimAudio.ts"],"names":[],"mappings":";;;;;AAwBA,8BAoDC;AAYD,0CAKC;AA7FD,yDAA8E;AAO9E,4EAAmD;AACnD,mEAA+D;AAE/D,mCAAmC;AACnC,MAAM,OAAO,GAAG,IAAI,sCAAkB,CAAC,2BAAiB,CAAC,CAAA;AAEzD;;;;;;;;;;GAUG;AACI,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,2BAAiB,CAAC,SAAS,CAC5C,IAAA,uCAAkB,EAAC,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;AACI,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,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encodeCompressedAudio = encodeCompressedAudio;
4
+ /**
5
+ * NOTE: Encodes audio in real-time via AudioContext + MediaRecorder playback.
6
+ * A 60-second clip takes ~60 seconds to encode — this is a known Web Audio API
7
+ * limitation; there is no offline API for Opus/AAC encoding in browsers.
8
+ */
9
+ function encodeCompressedAudio(buffer, format, bitrate) {
10
+ return new Promise((resolve, reject) => {
11
+ try {
12
+ // On web, always use opus if aac is requested (browser aac support is rare)
13
+ const actualFormat = format === 'aac' ? 'opus' : format;
14
+ // Check if MediaRecorder supports the requested format
15
+ const mimeType = actualFormat === 'opus' ? 'audio/webm;codecs=opus' : 'audio/aac';
16
+ if (!MediaRecorder.isTypeSupported(mimeType)) {
17
+ throw new Error(`MediaRecorder does not support ${mimeType}`);
18
+ }
19
+ // Create a new AudioContext and source
20
+ const ctx = new (window.AudioContext ||
21
+ window.webkitAudioContext)();
22
+ const source = ctx.createBufferSource();
23
+ source.buffer = buffer;
24
+ // Create a MediaStreamDestination to capture the audio
25
+ const destination = ctx.createMediaStreamDestination();
26
+ source.connect(destination);
27
+ // Create a MediaRecorder with the requested format
28
+ const recorder = new MediaRecorder(destination.stream, {
29
+ mimeType,
30
+ audioBitsPerSecond: bitrate || (actualFormat === 'opus' ? 32000 : 64000),
31
+ });
32
+ const chunks = [];
33
+ recorder.ondataavailable = (e) => {
34
+ if (e.data.size > 0) {
35
+ chunks.push(e.data);
36
+ }
37
+ };
38
+ recorder.onstop = async () => {
39
+ try {
40
+ const blob = new Blob(chunks, { type: mimeType });
41
+ const arrayBuffer = await blob.arrayBuffer();
42
+ // Get the actual bitrate used
43
+ const actualBitrate = Math.round((arrayBuffer.byteLength * 8) / buffer.duration);
44
+ resolve({
45
+ data: arrayBuffer,
46
+ bitrate: actualBitrate / 1000, // Convert to kbps
47
+ });
48
+ // Clean up
49
+ ctx.close();
50
+ }
51
+ catch (error) {
52
+ reject(error);
53
+ }
54
+ };
55
+ // Start recording and playback; stop recorder when playback ends
56
+ recorder.start();
57
+ source.onended = () => recorder.stop();
58
+ source.start(0);
59
+ }
60
+ catch (error) {
61
+ reject(error);
62
+ }
63
+ });
64
+ }
65
+ //# sourceMappingURL=encodeCompressedAudio.web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encodeCompressedAudio.web.js","sourceRoot":"","sources":["../../../src/utils/encodeCompressedAudio.web.ts"],"names":[],"mappings":";;AAKA,sDAwEC;AA7ED;;;;GAIG;AACH,SAAgB,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,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resampleAudioBuffer = resampleAudioBuffer;
4
+ async function resampleAudioBuffer(buffer, targetSampleRate, targetChannels) {
5
+ // If no change needed, return the original buffer
6
+ if (buffer.sampleRate === targetSampleRate &&
7
+ buffer.numberOfChannels === targetChannels) {
8
+ return buffer;
9
+ }
10
+ // Calculate the new length based on the sample rate change
11
+ const newLength = Math.round((buffer.length * targetSampleRate) / buffer.sampleRate);
12
+ // Create an offline context for resampling
13
+ const offlineContext = new OfflineAudioContext(targetChannels, newLength, targetSampleRate);
14
+ // Create a source node
15
+ const source = offlineContext.createBufferSource();
16
+ source.buffer = buffer;
17
+ // The OfflineAudioContext was created with targetChannels; the Web Audio API
18
+ // applies its built-in speaker downmix/upmix rules automatically.
19
+ source.connect(offlineContext.destination);
20
+ // Start rendering
21
+ source.start(0);
22
+ const resampledBuffer = await offlineContext.startRendering();
23
+ return resampledBuffer;
24
+ }
25
+ //# 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,kDAsCC;AAtCM,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"]}