Col*_*ent 3 javascript audio html5-audio raw-data web-audio-api
我目前正在开展一个项目,该项目由一个图表组成,该图表显示由另一台设备拾取的音频电平。图表是通过浮点 API 制作的,我具有缩放和选择功能,以便在图表上选择一个时间范围并放大到该选定区域。我的下一步是允许用户收听与图表该区域对应的音频。我将音频文件存储在共享服务器上,所有文件都是单独的,一分钟一分钟,RAW 数据文件。我没有在网页中使用音频的经验,目前正在努力研究如何完成这项任务。据我所知,<audio>HTML 标签无法处理用于播放的 RAW 数据文件。我一直在研究 Web Audio API,但对它的工作原理和实现方式感到困惑。
我的第一个问题是如何从服务器解码 RAW 音频文件并将它们显示在 HTML 页面上以供客户端收听?
我的第二个任务是抓取与所选范围相对应的所有音频文件,并将它们组合成一个音频输出。例如,如果客户选择了 1:00pm - 1:50pm 的时间范围,我需要每分钟访问 50 个 RAW 数据音频文件。然后我想将它们组合在一起以产生一个单一的播放声音。因此,我的第二个问题是是否有人知道如何顺利完成此操作。
感谢您提供任何帮助!
RAW 文件已经解码 PCM 音频,但Audio元素不能直接播放 PCM。您需要首先将 RIFF/WAV 标头附加到 PCM 字节。可以组合多个 RAW 文件,在标题中设置总样本/帧长度。50 分钟的解码音频将占用浏览器中的大量内存,因此请密切注意并相应地进行测量/优化。
initAudio()
async function initAudio() {
// specify your file and its audio properties
const url = 'https://dev.anthum.com/audio-worklet/audio/decoded-left.raw'
const sampleRate = 48000
const numChannels = 1 // mono or stereo
const isFloat = true // integer or floating point
const buffer = await (await fetch(url)).arrayBuffer()
// create WAV header
const [type, format] = isFloat ? [Float32Array, 3] : [Uint8Array, 1]
const wavHeader = new Uint8Array(buildWaveHeader({
numFrames: buffer.byteLength / type.BYTES_PER_ELEMENT,
bytesPerSample: type.BYTES_PER_ELEMENT,
sampleRate,
numChannels,
format
}))
// create WAV file with header and downloaded PCM audio
const wavBytes = new Uint8Array(wavHeader.length + buffer.byteLength)
wavBytes.set(wavHeader, 0)
wavBytes.set(new Uint8Array(buffer), wavHeader.length)
// show audio player
const audio = document.querySelector('audio')
const blob = new Blob([wavBytes], { type: 'audio/wav' })
audio.src = URL.createObjectURL(blob)
document.querySelector('#loading').hidden = true
audio.hidden = false
}
// adapted from https://gist.github.com/also/900023
function buildWaveHeader(opts) {
const numFrames = opts.numFrames;
const numChannels = opts.numChannels || 2;
const sampleRate = opts.sampleRate || 44100;
const bytesPerSample = opts.bytesPerSample || 2;
const format = opts.format
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 buffer;
}Run Code Online (Sandbox Code Playgroud)
body {
text-align: center;
padding-top: 1rem;
}
[hidden] {
display: none;
}
audio {
display: inline-block;
}Run Code Online (Sandbox Code Playgroud)
<div id="loading">Loading...</div>
<audio hidden controls></audio>Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4721 次 |
| 最近记录: |