如何将一个或两个乐器连接到 Web Audio API 并拆分立体声信号?

Posted

技术标签:

【中文标题】如何将一个或两个乐器连接到 Web Audio API 并拆分立体声信号?【英文标题】:How to connect one or two musical instruments to the Web Audio API and split the stereo signal? 【发布时间】:2015-09-13 14:59:04 【问题描述】:

编辑 3:

这只是 Firefox 的问题,在 Chrome 中有效,所以问题解决了,请参阅下面的答案。感谢克里斯的帮助!

编辑 2:

按照 Chris 的建议,我在 getUserMedia 调用上更改了一行,但它现在不起作用,也许我使用了错误的语法,但此功能未记录:

if(navigator.getUserMedia)
  navigator.getUserMedia(
     audio:  optional: [ echoCancellation: false ]  
    ,function(stream) init_stream(stream); 
    ,function(err) console.log('The following gUM error occured: ' + err); 
  );

此外,您现在可以在此处关注进度:

http://jsfiddle.net/stratboy/aapafrbu/1/

编辑 1:

我目前正在弹奏键盘 > 混音器 > behringer UCA222 > mac (usb)。我当前查看一些数据的代码如下。我看到左声道的数据发生变化,但右声道没有变化,尽管我在混音器上做了什么。可能是什么原因?

window.AudioContext = window.AudioContext || window.webkitAudioContext;

navigator.getUserMedia = (navigator.getUserMedia ||
                          navigator.webkitGetUserMedia ||
                          navigator.mozGetUserMedia ||
                          navigator.msGetUserMedia);


var audiocontext = new (window.AudioContext || window.webkitAudioContext)();
var analyser_left = audiocontext.createAnalyser();
var analyser_right = audiocontext.createAnalyser();
var splitter = audiocontext.createChannelSplitter(2);
var index = 0;

function init_stream(stream)
  window.audiosource = audiocontext.createMediaStreamSource(stream);

  audiosource.connect(splitter);
  splitter.connect(analyser_left,0);
  splitter.connect(analyser_right,1);

  listen();


function listen()
  requestAnimationFrame(listen);

  analyser_left.fftSize = 256;
  var leftBufferLength = analyser_left.frequencyBinCount;
  var leftDataArray = new Uint8Array(leftBufferLength);

  analyser_left.getByteTimeDomainData(leftDataArray);
  $('.monitor_left').html(JSON.stringify(leftDataArray));


  analyser_right.fftSize = 256;
  var rightBufferLength = analyser_right.frequencyBinCount;
  var rightDataArray = new Uint8Array(rightBufferLength);

  analyser_right.getByteTimeDomainData(rightDataArray);
  $('.monitor_right').html(JSON.stringify(rightDataArray));



if(navigator.getUserMedia)
  navigator.getUserMedia(
     audio: true 
    ,function(stream) init_stream(stream); 
    ,function(err) console.log('The following gUM error occured: ' + err); 
  );

我想将我的吉他弹入计算机并通过网络音频 API 分析声音。我知道可以使用麦克风,但插入真正的乐器呢?

【问题讨论】:

你必须得到一个前置放大器,将你的吉他插入前置放大器,然后从前置放大器获取输出并将其插入你的麦克风输入。 【参考方案1】:

是的。我一直这样做(使用非麦克风源)。只需获得支持吉他/乐器输入的 USB 音频接口即可。

【讨论】:

哇!我几乎可以肯定我不能......还有两个问题:你用什么 js 类/接口来从 USB 获取声音?从 MDN 我了解了如何获取麦克风,但我还不清楚获取 USB 源的正确代码是什么。和 q#2:是否可以分别分析 2 个同时源(例如 usb + mic)?我想为 [keyboards: source 1] 和其他乐器 [guitar+bass+sax: source 2] 进行不同视觉效果的现场表演。 您可以通过getMediaDevices选择输入设备-我在输入效果演示中使用它(webaudiodemos.appspot.com/input/index.html)-相关代码从github.com/cwilso/Audio-Input-Effects/blob/master/js/…开始。 (搜索 gotSources 看看它的作用。) 关于分析单独的音源——Chrome 至少目前只支持单声道和立体声源;当然,您可以通过立体声输入的单独通道为您的键盘和其他乐器提供信号,并这样做。 (您需要使用 ChannelSplitterNode 拆分成两个输出并通过单独的 AnalyserNode 运行每个输出。)多通道(不仅仅是立体声)输入是我们正在处理的一个错误。另一方面,多设备——同时使用你的耳机麦克风和USB音频输入设备——要复杂得多,我不希望在不久的将来工作。 非常感谢,我会选择立体声方式。你的演示非常令人印象深刻! :) cwilso:请注意,如果您可以/想要/有时间/等.. ;) ***.com/questions/32915635/…【参考方案2】:

所以,最初的问题是关于将更多乐器/实时源(例如乐器和麦克风)连接到网络音频 api 并分析流。

答案几乎是肯定的 :P 正如 Chris 所写,目前无法获得多个乐器,但可以拆分立体声信号!所以我所做的是通过一个带有 2 个源(例如,一个键盘和一个麦克风)的混音器,将一个放在左声道,一个放在右声道。然后连接到某种 USB 声卡(我目前使用的是便宜的 behringer UCA222)。

原来Firefox似乎仍然无法拆分信号,但Chrome可以做到,对我来说已经足够了。一些工作代码是这样的,它是不言自明的:

window.AudioContext = window.AudioContext || window.webkitAudioContext;

navigator.getUserMedia = (navigator.getUserMedia ||
                          navigator.webkitGetUserMedia ||
                          navigator.mozGetUserMedia ||
                          navigator.msGetUserMedia);


var audiocontext = new (window.AudioContext || window.webkitAudioContext)();
var analyser_left = audiocontext.createAnalyser();
var analyser_right = audiocontext.createAnalyser();
var splitter = audiocontext.createChannelSplitter(2);
var index = 0;

function init_stream(stream)
  window.audiosource = audiocontext.createMediaStreamSource(stream);

  audiosource.connect(splitter);
  splitter.connect(analyser_left,0);
  splitter.connect(analyser_right,1);

  listen();


function listen()
  requestAnimationFrame(listen);

  analyser_left.fftSize = 256;
  var leftBufferLength = analyser_left.frequencyBinCount;
  var leftDataArray = new Uint8Array(leftBufferLength);

  analyser_left.getByteTimeDomainData(leftDataArray);
  $('.monitor_left').html(JSON.stringify(leftDataArray));


  analyser_right.fftSize = 256;
  var rightBufferLength = analyser_right.frequencyBinCount;
  var rightDataArray = new Uint8Array(rightBufferLength);

  analyser_right.getByteTimeDomainData(rightDataArray);
  $('.monitor_right').html(JSON.stringify(rightDataArray));




if(navigator.getUserMedia)
  navigator.getUserMedia(
     audio: true 
    ,function(stream) init_stream(stream); 
    ,function(err) console.log('The following gUM error occured: ' + err); 
  );

最后要测试的小提琴在这里:jsfiddle.net/stratboy/aapafrbu

您可以在播放时看到位的变化。

作为一名网络程序员,我不明白的一件事是,当在键盘上播放单个音符时,没有可以捕捉到的“onAudioSomething”事件。但也许这很合乎逻辑,因为我猜这样的事件通常对一首音乐毫无用处,因为音频增益通常没有“零点”。所以分析来源的方法是通过 requestAnimationFrame() 进行轮询。

希望它可以帮助其他一些探索者:)

【讨论】:

它仍然使用麦克风,所以没有区别。

以上是关于如何将一个或两个乐器连接到 Web Audio API 并拆分立体声信号?的主要内容,如果未能解决你的问题,请参考以下文章

如何将带有前缀列的表连接到 PHP MySQL 或 Laravel 中的另外两个表

IOS上的 Audio Memos SE 如何分享和传输录音到电脑?

Inter App Audio 技术:使效果节点和乐器节点独立

如何使用 Web3.js 将 Metamask 连接到 Angular App?

是否可以将JS WebSocket连接到Python服务器?

数据仓库如何将具有外键的事实表连接到主键包含两个属性的维度表