关于javascript:在树莓派上使用node.js播放和弦音频

polyphonic audio playback with node.js on raspberry pi

我一直在尝试在运行最新raspbian的raspberry pi 3上使用node.js创建和弦WAV播放:

  • 插入aplay / mpg123 /其他程序-仅允许我一次播放单个声音
  • 我尝试将https://github.com/sebpiq/node-web-audio-api和https://github.com/TooTallNate/node-speaker结合使用(下面的示例代码),但是音频质量很低,很多 失真

我在这里想念什么吗? 我知道我可以轻松地用另一种编程语言来做到这一点(我能够使用SDL和pygame编写C ++代码),但问题是,是否可以使用node.js :)

这是我当前的网络音频API +节点扬声器代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
var AudioContext = require('web-audio-api').AudioContext;
var Speaker      = require('speaker');
var fs           = require('fs');

var track1       = './tracks/1.wav';
var track2       = './tracks/1.wav';

var context      = new AudioContext();

context.outStream = new Speaker({
  channels:   context.format.numberOfChannels,
  bitDepth:   context.format.bitDepth,
  sampleRate: context.format.sampleRate
});

function play(audioBuffer) {
  if (!audioBuffer) { return; }

  var bufferSource = context.createBufferSource();

  bufferSource.connect(context.destination);
  bufferSource.buffer = audioBuffer;
  bufferSource.loop   = false;
  bufferSource.start(0);
}

var audioData1 = fs.readFileSync(track1);
var audioData2 = fs.readFileSync(track2);

var audioBuffer1, audioBuffer2;

context.decodeAudioData(audioData1, function(audioBuffer) {
  audioBuffer1 = audioBuffer;
  if (audioBuffer1 && audioBuffer2) { playBoth(); }
});

context.decodeAudioData(audioData2, function(audioBuffer) {
  audioBuffer2 = audioBuffer;
  if (audioBuffer1 && audioBuffer2) { playBoth(); }
});

function playBoth() {
  console.log('playing...');

  play(audioBuffer1);
  play(audioBuffer2);
}

audio quality is very low, with a lot of distortions

根据WebAudio规范(https://webaudio.github.io/web-audio-api/#SummingJunction):

No clipping is applied at the inputs or outputs of the AudioNode to allow a maximum of dynamic range within the audio graph.

现在,如果您正在播放两个音频流,则将它们相加可能会导致超出可接受范围的值,听起来像是-失真。

尝试通过首先将它们通过GainNode用管道传输来降低每个音频流的音量,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
function play(audioBuffer) {
  if (!audioBuffer) { return; }

  var bufferSource = context.createBufferSource();
  var gainNode = context.createGain();
  gainNode.gain.value = 0.5 // for instance, find a good value

  bufferSource.connect(gainNode);
  gainNode.connect(context.destination);
  bufferSource.buffer = audioBuffer;
  bufferSource.loop   = false;
  bufferSource.start(0);
}

另外,您可以使用DynamicsCompressorNode,但是手动设置增益可以让您更好地控制输出。


这并非完全值得回答,但我目前无法发表评论> <

使用js音频api制作的应用程序也遇到了类似的问题,而且相当容易解决的问题是降低音频质量并更改格式。

在您的情况下,我想到的是将位深度和采样频率设置为尽可能低的值,而不影响听众的体验(例如44.1kHz和16位深度)。

您也可以尝试更改格式,从理论上讲,wav应该可以很好地完成CPU密集型工作,但是,还有其他未压缩的格式(例如.aiff)

您可以尝试使用pi的多个核心:

https://nodejs.org/api/cluster.html

尽管这可能会有些复杂,但是如果与其他不相关的进程并行进行音频流处理,则可以尝试在单独的CPU上移动音频。

您可以尝试的(简单)操作是在具有更多RAM的节点上运行,尽管对于您而言,我怀疑是否可以。

但是,最大的问题可能是代码,可悲的是,我对您所使用的模块没有经验,因此可以就此提供真正的建议(因此,为什么我说这不值得回答:p)


您可以从节点2 aplay生成,每个进程播放一个文件。使用detached: true允许节点继续运行。