41651

Convert AudioBuffer to ArrayBuffer / Blob for WAV Download

<h3>Question</h3>

I'd like to convert an AudioBuffer to a Blob so that I can create an ObjectURL from it and then download the audio file.

let rec = new Recorder(async(chunks) => { var blob = new Blob(chunks, { type: 'audio/mp3' }); var arrayBuffer = await blob.arrayBuffer(); const audioContext = new AudioContext() await audioContext.decodeAudioData(arrayBuffer, (audioBuffer) => { // How to I now convert the AudioBuffer into an ArrayBuffer => Blob ? }
<h3>Answer1:</h3>

An AudioBuffer contains non-interleaved Float32Array PCM samples for each decoded audio channel. For a stereo AudioBuffer, it will contain 2 channels. Those channels need to be interleaved first, and then the interleaved PCM must have a WAV header appended to it so you can download and play as a WAV.

// Float32Array samples const [left, right] = [audioBuffer.getChannelData(0), audioBuffer.getChannelData(1)] // interleaved const interleaved = new Float32Array(left.length + right.length) for (let src=0, dst=0; src < left.length; src++, dst+=2) { interleaved[dst] = left[src] interleaved[dst+1] = right[src] } // get WAV file bytes and audio params of your audio source const wavBytes = getWavBytes(interleaved.buffer, { isFloat: true, // floating point or 16-bit integer numChannels: 2, sampleRate: 48000, }) const wav = new Blob([wavBytes], { type: 'audio/wav' }) // create download link and append to Dom const downloadLink = document.createElement('a') downloadLink.href = URL.createObjectURL(wav) downloadLink.setAttribute('download', 'my-audio.wav') // name file

supporting functions below:

// Returns Uint8Array of WAV bytes function getWavBytes(buffer, options) { const type = options.isFloat ? Float32Array : Uint16Array const numFrames = buffer.byteLength / type.BYTES_PER_ELEMENT const headerBytes = getWavHeader(Object.assign({}, options, { numFrames })) const wavBytes = new Uint8Array(headerBytes.length + buffer.byteLength); // prepend header, then add pcmBytes wavBytes.set(headerBytes, 0) wavBytes.set(new Uint8Array(buffer), headerBytes.length) return wavBytes } // adapted from https://gist.github.com/also/900023 // returns Uint8Array of WAV header bytes function getWavHeader(options) { const numFrames = options.numFrames const numChannels = options.numChannels || 2 const sampleRate = options.sampleRate || 44100 const bytesPerSample = options.isFloat? 4 : 2 const format = options.isFloat? 3 : 1 const blockAlign = numChannels * bytesPerSample const byteRate = sampleRate * blockAlign const dataSize = numFrames * blockAlign const buffer = new ArrayBuffer(44) const dv = new DataView(buffer) let p = 0 function writeString(s) { for (let i = 0; i < s.length; i++) { dv.setUint8(p + i, s.charCodeAt(i)) } p += s.length } function writeUint32(d) { dv.setUint32(p, d, true) p += 4 } function writeUint16(d) { dv.setUint16(p, d, true) p += 2 } writeString('RIFF') // ChunkID writeUint32(dataSize + 36) // ChunkSize writeString('WAVE') // Format writeString('fmt ') // Subchunk1ID writeUint32(16) // Subchunk1Size writeUint16(format) // AudioFormat writeUint16(numChannels) // NumChannels writeUint32(sampleRate) // SampleRate writeUint32(byteRate) // ByteRate writeUint16(blockAlign) // BlockAlign writeUint16(bytesPerSample * 8) // BitsPerSample writeString('data') // Subchunk2ID writeUint32(dataSize) // Subchunk2Size return new Uint8Array(buffer) }

来源:https://stackoverflow.com/questions/62172398/convert-audiobuffer-to-arraybuffer-blob-for-wav-download

Recommend

  • How to deal with localization? Is there a standard I should follow?
  • Triggering parameterized build using jenkinsapi in python
  • How to make a UNION with Doctrine?
  • confused about the need for $scope.$apply
  • Angular 2 - Inject a dependency into a decorator factory
  • Where can I find android-v7 support library jar
  • Swift: How to get string values of days, months and year from a date picker?
  • Tracing root cause for R segfault
  • Constructor in an abstract class [duplicate]
  • Using 2 nested Class to get notification from new SMS :D
  • Multiple Inheritance (maybe Abstract class?) C# Entity Framework
  • How I can have previewing permanently when capture video for android?
  • How to restrict user to be logged only one time per session?
  • pip installation of gmpy2
  • XIRR Calc in SQL
  • Full Height Image
  • PHPMailer do not work properly sometimes on gmail port 465 or 587 on localhost
  • SPOJ: GENERAL (Time limit exceeded)
  • Problem with output_buffering and php.ini
  • Can upload photo when using the Google Photos API
  • Xamarin.Forms: How To Populate A Pie Chart From Web API Data?
  • Joining across databases with dbplyr
  • Can someone explain how Yii minimizing assets is supposed to work on Heroku?
  • IE doesn't display png images
  • Git for windows has stopped working
  • Using Java runtime to add registry key, cause process reg.exe to run forever
  • Was there ever a proposal to include the URL fragment into the HTTP request?
  • cSPADE data mining in R using arulesSequences - Error while converting to “transactions” format
  • 'Edit' function for forum posts and such
  • Swift: UIView.animate works unexpectedly
  • Problems to understand DXGI DirectX 11 Desktop Duplication to get a Buffer or Array
  • Google App Engine Datastore: Dealing with eventual consistency
  • Debug `Unexpected end of JSON input Error` on content script
  • Bitrate JWplayer
  • Grails - How to implement a foreign key relationship not using an id column?
  • XEP-0166: Jingle protocol implementation for voice/video chat in iOS
  • How to use FirstOrDefault inside Include
  • PHP Permalinks.. how to change?
  • Running R's aov() mixed effects model from Python using rpy2
  • ReferenceError: TextEncoder is not defined