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

走远了吗. 提交于 2020-06-16 03:37:09

问题


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?


回答1:


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>


来源:https://stackoverflow.com/questions/62157122/downloading-audio-from-web-that-has-been-modified-with-wavesurfer-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!