简体   繁体   中英

Downloading audio from web that has been modified with wavesurfer.js

I have created a multitrack web player using wavesurfer.js which can adjust the levels and panning of the different tracks.

What I want to do is export the mixed tracks with new levels and panning as a single.wav file.

I've done a bit of research into this and alot of people are pointing to https://github.com/mattdiamond/Recorderjs but development stopped on this over 4 years ago and from what I've found it seems to have a load of issues.

Just initializing it like so var rec = new Recorder(spectrum); I get an error saying Cannot read property 'createScriptProcessor' of undefined at new Recorder And a quick search shows that is deprecated, see https://developer.mozilla.org/en-US/docs/Web/API/BaseAudioContext/createScriptProcessor .

Although I have a multitrack player if I can figure out how to export a single track with the levels and panning I could go from there. Is there any other way of exporting web audio with just the web audio API or can anybody point me to any other js libraries like this that might work?

Assuming you have PCM audio, you can add a RIFF/WAV header to it, create a Blob from that, and then set blob as an Object URL on the a.href attribute. StackOverflow blocks the download here, but you run it locally to test. Hope this helps!

 // fetch stereo PCM Float 32 little-endian file const url = 'https://batman.dev/static/61881209/triangle-stereo-float.pcm' const ctx = new AudioContext() const elStatus = document.querySelector('#status') const elButton = document.querySelector('#download') init().catch(showError) async function init() { // get raw/PCM buffer (you will presumably already have your own) const buffer = await (await fetch(url)).arrayBuffer() // get WAV file bytes and audio params of your audio source const wavBytes = getWavBytes(buffer, { isFloat: true, // floating point or 16-bit integer (WebAudio API decodes to Float32Array) numChannels: 2, sampleRate: 44100, }) // add the button elButton.href = URL.createObjectURL( new Blob([wavBytes], { type: 'audio/wav' }) ) elButton.setAttribute('download', 'my-audio.wav') // name file status('') elButton.hidden = false } function status(msg) { elStatus.innerText = msg } function showError(e) { console.error(e) status(`ERROR: ${e}`) } // 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) }
 body { padding: 2rem; font-family: sans-serif; text-align: center; } #download { padding: 1em 2em; color: #fff; background: #4c8bf5; text-decoration: none; }
 <div id="status">Loading...</div> <a hidden id="download">⬇ Download</a>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM