我正在尝试从4-mic阵列ReSpeaker中分离我收到的Buffer中的4个通道。我正在使用nodejs,目前我使用的是spawn命令:
spawn('arecord -r16000 -fS16_LE -traw -c4 -Dac108')
然后在变换器中输出输出,我在4个通道中拆分缓冲区并将它们保存到单独的文件中以检查结果
const stream = require("stream");
const fs = require('fs');
class ChannelTransformer extends stream.Transform {
constructor(options) {
var write_1 = fs.createWriteStream('ch1', {encoding: 'binary'});
var write_2 = fs.createWriteStream('ch2', {encoding: 'binary'});
var write_3 = fs.createWriteStream('ch3', {encoding: 'binary'});
var write_4 = fs.createWriteStream('ch4', {encoding: 'binary'});
options.readableObjectMode = true;
options.writableObjectMode = true;
options.highWaterMark = 20000;
options.transform = (chunk, encoding, callback) => {
let channels = [[],[],[],[]];
for(let i=0; i<source.length;i++ ){
channels[i%4].push(chunk[i])
}
write_1.write(new Uint8Array(channels[0]));
write_2.write(new Uint8Array(channels[1]));
write_3.write(new Uint8Array(channels[2]));
write_4.write(new Uint8Array(channels[3]));
callback();
};
super(options);
}
}
根据这段代码的结果,我得到4个文件,如果我用Audacity导入它,我发现ch2和ch4文件已被正确分开,而ch1和ch3被破坏并导致白噪声文件。 我错过了分离的东西吗?我认为音频存储在模式中:
[[ch1_0],[ch2_0],[ch3_0],[ch4_0],[ch1_1],[ch2_1],...]
此外,我不明白为什么,如果我遵循的模式不正确,2个通道成功分开。 我还尝试将这些块转换成其他类似的东西:
let source = new Int8Array(chunk);
然后在for
cicle:
channels[i%4].push(source[i])
使用不同的类型,例如Float32Array
,Uint8Array
,Uint16Array
,Int16Array
但结果是一样的。
我已经使用命令测试了4mic是否正常工作:
arecord -r16000 -fS16_LE -traw -c4 -Dac108 -I ch1 ch2 ch3 ch4
生成包含每个频道的预期4个文件。
对于每次测试,我会在说话时每隔几秒用mi手指在麦克风上阻挡,这样我就能分辨出每个通道之间的区别。
任何人都可以帮助我吗?或者有一些提示? 谢谢!
答案 0 :(得分:0)
好的,我想出了问题所在。
基本上我用bitWidth = 16
进行录制,而Node中的Buffer
对象是Uint8Array
的一个实例,所以我跟随的模式确实是正确的,但由于8bitArray我必须分配2每个频道的元素。导致8位阵列的格式为:
[[ch1],[ch1],[ch2],[ch2],[ch3],[ch3],[ch4],[ch4],...]
同样强制转换数组也没用,因为生成的16bitArray
没有合并2 8bit
元素来创建16bit
元素,而是每个8bit
元素创建最后一个8bit
元素{1}} 16bit
元素的{1}},其中前8位为0
,如下所示:
8bitArray=[[11111111],[11111111],[2222222],[22222222],...]
16bitArray Casted= [[0000000011111111],[0000000011111111],[0000000022222222],...]
所以我创建了一个方法,将8bitArray
合并到正确的数组中,以便根据您正在录制的bitWidth
正确处理:
var bitMultipler = bitWidth/8; //so i can handle any bitWidth with the same code
let channelsMap = new Map<number, Array<any>>();
for (let channel: number = 0; channel < totalChannels; channel++) {
channelsMap.set(channel, new Array())
}
/**
For each channel i push as many element as needed based on the bitMultipler
*/
let i = 0
while (i < chunk.length) {
for (let channel = 0; channel < totalChannels; channel++) {
for (let indexMultipler = 0; indexMultipler < bitMultipler; indexMultipler++) {
channelsMap.get(channel).push(chunk[i]);
i++;
}
}
}