【发布时间】:2020-08-29 19:36:56
【问题描述】:
我正在使用 node-microphone(这只是一个用于 arecord 的 javascript 接口)从 nodejs 录制音频,并希望使用 web-audio-api(这是 Web 的 nodejs 实现)将流块存储在 AudioBuffer音频 API)。
我的音频源有两个通道,而我的 AudioBuffer 只有一个(故意)。
这是我通过 USB 声卡使用 arecord 录制音频的工作配置(我使用的是在 Raspbian buster 上运行的 Raspberry pi 3):
arecord -D hw:1,0 -c 2 -f S16_LE -r 44100
使用输出路径运行此命令并使用 aplay 播放生成的 wav 文件就可以了。所以 node-microphone 能够使用这些参数录制音频,最后我得到一个 nodejs 可读的流数据流。
但是
我正在努力做从流块(Buffer 实例)到AudioBuffer 的桥接。更确切地说;我不确定传入数据的格式,不确定目标格式,也不确定如何进行转换:
流块是Buffers,所以它们也是Uint8Arrays。关于我的配置,我猜它们是 16 位有符号整数的二进制表示(小端,我不知道是什么意思)。
AudioBuffer 拥有多个缓冲区(每个通道一个,因此在我的情况下只有一个),我可以通过调用 AudioBuffer.prototype.getChannelData() 以 Float32Arrays 的身份访问这些缓冲区。 MDN 还说:
缓冲区包含以下格式的数据:非交错 IEEE754 32 位线性 PCM,标称范围在 -1 和 +1 之间,即 32 位浮点缓冲区,每个样本在 -1.0 和 1.0 之间。
关键是要找到我必须从传入的Buffers 中提取的内容以及我应该如何转换它以使其适合Float32Array 目标(并且仍然是有效的波形数据),知道音频源是立体声而AudioBuffer 不是。
到目前为止,我最好的竞争者是 Buffer.prototype.readFloatLE() 方法,它的名字看起来可以解决我的问题,但这并不成功(只是噪音)。
我的第一次尝试(在进行研究之前)只是天真地将缓冲区数据复制到 Float32Array 并交错索引以处理立体声/单声道转换。显然它主要产生噪音,但我可以听到我录制的一些声音(难以置信的失真但肯定存在)所以我想我应该提一下。
这是我天真的尝试的简化版本(我知道这并不意味着效果很好,我只是将它作为讨论的基础包含在我的问题中):
import { AudioBuffer } from 'web-audio-api'
import Microphone from 'node-microphone'
const rate = 44100
const channels = 2 // Number of source channels
const microphone = new Microphone({ // These parameters result to the arecord command above
channels,
rate,
device: 'hw:1,0',
bitwidth: 16,
endian: 'little',
encoding: 'signed-integer'
})
const audioBuffer = new AudioBuffer(
1, // 1 channel
30 * rate, // 30 seconds buffer
rate
})
const chunks = []
const data = audioBuffer.getChannelData(0) // This is the Float32Array
const stream = microphone.startRecording()
setTimeout(() => microphone.stopRecording(), 5000) // Recording for 5 seconds
stream.on('data', chunk => chunks.push(chunk))
stream.on('close', () => {
chunks.reduce((offset, chunk) => {
for (var index = 0; index < chunk.length; index += channels) {
let value = 0
for (var channel = 0; channel < channels; channel++) {
value += chunk[index + channel]
}
data[(offset + index) / channels] = value / channels // Average value from the two channels
}
return offset + chunk.length // Since data comes as chunks, this offsets AudioBuffer's index
}, 0)
})
如果您能提供帮助,我将不胜感激:)
【问题讨论】:
标签: javascript node.js audio web-audio-api alsa