从 wavesurfer.js 修改过的网络下载音频
Downloading audio from web that has been modified with wavesurfer.js
我使用 wavesurfer.js 创建了一个多轨网络播放器,它可以调整不同轨道的电平和平移。
我想要做的是导出具有新级别的混合曲目并将声像作为单个 .wav 文件。
我对此做了一些研究,很多人都指向 https://github.com/mattdiamond/Recorderjs 但开发在 4 年前就停止了,从我发现的情况来看,它似乎有很多问题。
像这样初始化它 var rec = new Recorder(spectrum);
我收到一条错误消息 Cannot read property 'createScriptProcessor' of undefined at new Recorder
快速搜索显示它已被弃用,请参阅 https://developer.mozilla.org/en-US/docs/Web/API/BaseAudioContext/createScriptProcessor。
虽然我有一个多轨播放器,但如果我能弄清楚如何导出具有电平和平移的单个轨道,我可以从那里开始。是否有任何其他方法可以仅使用网络音频 API 导出网络音频,或者任何人都可以向我指出任何其他可能有效的 js 库吗?
假设您有 PCM 音频,您可以向其添加 RIFF/WAV header,从中创建一个 Blob,然后将 blob 设置为 Object URL在 a.href
属性上。 Whosebug 在此处阻止下载,但您 运行 在本地进行测试。希望这可以帮助!
// 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>
我使用 wavesurfer.js 创建了一个多轨网络播放器,它可以调整不同轨道的电平和平移。
我想要做的是导出具有新级别的混合曲目并将声像作为单个 .wav 文件。
我对此做了一些研究,很多人都指向 https://github.com/mattdiamond/Recorderjs 但开发在 4 年前就停止了,从我发现的情况来看,它似乎有很多问题。
像这样初始化它 var rec = new Recorder(spectrum);
我收到一条错误消息 Cannot read property 'createScriptProcessor' of undefined at new Recorder
快速搜索显示它已被弃用,请参阅 https://developer.mozilla.org/en-US/docs/Web/API/BaseAudioContext/createScriptProcessor。
虽然我有一个多轨播放器,但如果我能弄清楚如何导出具有电平和平移的单个轨道,我可以从那里开始。是否有任何其他方法可以仅使用网络音频 API 导出网络音频,或者任何人都可以向我指出任何其他可能有效的 js 库吗?
假设您有 PCM 音频,您可以向其添加 RIFF/WAV header,从中创建一个 Blob,然后将 blob 设置为 Object URL在 a.href
属性上。 Whosebug 在此处阻止下载,但您 运行 在本地进行测试。希望这可以帮助!
// 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>