在 Web Audio API 中使用 ChannelSplitter 和 MergeSplitter 节点
Posted
技术标签:
【中文标题】在 Web Audio API 中使用 ChannelSplitter 和 MergeSplitter 节点【英文标题】:Using ChannelSplitter and MergeSplitter nodes in Web Audio API 【发布时间】:2013-12-17 20:46:55 【问题描述】:我正在尝试使用 ChannelSplitter 节点将音频信号发送到 ChannelMerger 节点和目的地,然后尝试使用 ChannelMerger 节点合并两个不同的音频信号(一个来自拆分源,一个来自使用 getUserMedia 的麦克风)到使用 Recorder.js 的录音机中。
我不断收到以下错误:“未捕获的语法错误:指定了无效或非法的字符串。”
错误在以下代码行:
audiosource.splitter.connect(merger);
其中audioSource是ThreeAudio.js库中的ThreeAudio.Source的一个实例,splitter是我通过修改原型自己实例化的通道分流器,merge是我的合并节点。前面的代码是:
merger = context.createChannelMerger(2);
userInput.connect(merger);
其中 userInput 是来自用户麦克风的流。那一个连接而不会引发错误。声音从 audioSource 传到目的地(我能听到),所以分离器似乎不一定是错误的 - 我似乎无法连接它。
有人有什么见解吗?
【问题讨论】:
如果你有完整的代码示例会容易很多。我怀疑还有什么问题。 不幸的是,我认为在一个问题上发布的代码太多了!我也有这种感觉,我现在正在编写一个不使用 ThreeAudio 库的版本,所以我可以确定我正在以正确的方式连接所有内容。如果您看到了一个使用拆分器和合并器的正确示例的链接,那也会很有帮助。 【参考方案1】:我很难理解ChannelSplitterNode
和ChannelMergerNode
API。最后我找到了缺失的部分,connect()
方法的第二个和第三个可选参数——输入和输出通道。
connect(destinationNode: AudioNode, output?: number, input?: number): AudioNode;
当使用带有 Splitter 或 Merger 节点的 connect()
方法时,请分隔输入/输出通道。这就是您拆分和合并到音频数据的方式。
您可以在此示例中看到我如何加载音频数据、将其拆分为 2 个通道以及控制左/右输出。注意connect()
方法的第二个和第三个参数:
const audioUrl = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/858/outfoxing.mp3";
const audioElement = new Audio(audioUrl);
audioElement.crossOrigin = "anonymous"; // cross-origin - if file is stored on remote server
const audioContext = new AudioContext();
const audioSource = audioContext.createMediaElementSource(audioElement);
const volumeNodeL = new GainNode(audioContext);
const volumeNodeR = new GainNode(audioContext);
volumeNodeL.gain.value = 2;
volumeNodeR.gain.value = 2;
const channelsCount = 2; // or read from: 'audioSource.channelCount'
const splitterNode = new ChannelSplitterNode(audioContext, numberOfOutputs: channelsCount );
const mergerNode = new ChannelMergerNode(audioContext, numberOfInputs: channelsCount );
audioSource.connect(splitterNode);
splitterNode.connect(volumeNodeL, 0); // connect OUTPUT channel 0
splitterNode.connect(volumeNodeR, 1); // connect OUTPUT channel 1
volumeNodeL.connect(mergerNode, 0, 0); // connect INPUT channel 0
volumeNodeR.connect(mergerNode, 0, 1); // connect INPUT channel 1
mergerNode.connect(audioContext.destination);
let isPlaying;
function playPause()
// check if context is in suspended state (autoplay policy)
if (audioContext.state === 'suspended')
audioContext.resume();
isPlaying = !isPlaying;
if (isPlaying)
audioElement.play();
else
audioElement.pause();
function setBalance(val)
volumeNodeL.gain.value = 1 - val;
volumeNodeR.gain.value = 1 + val;
<h3>Try using headphones</h3>
<button onclick="playPause()">play/pause</button>
<br><br>
<button onclick="setBalance(-1)">Left</button>
<button onclick="setBalance(0)">Center</button>
<button onclick="setBalance(+1)">Right</button>
P.S:音轨不是真正的立体声轨道,而是同一单声道播放的左右副本。你可以试试这个例子,用真正的立体声播放来获得真正的平衡效果。
【讨论】:
如果你有一个单声道你把它改成 splitterNode.connect(volumeNodeR, 0);? @Curtis,对于单声道,audioSource.channelCount
的值将是 1。但是为什么要控制单声道的平衡呢?如果你想改变左右扬声器输出可以使用StereoPannerNode
,看这个例子:codepen.io/Rumyra/pen/qyMzqN
感谢您的提示。我不能使用 StereoPannerNode,因为 Safari 不支持它。不过很酷的例子。【参考方案2】:
这里有一些有效的分离器/合并器代码会产生乒乓延迟 - 也就是说,它会在立体声信号的 L 和 R 通道上设置单独的延迟,并跨越反馈。这是来自我在 webaudiodemos.appspot.com 上的输入效果演示(github 上的代码)。
var merger = context.createChannelMerger(2);
var leftDelay = context.createDelayNode();
var rightDelay = context.createDelayNode();
var leftFeedback = audioContext.createGainNode();
var rightFeedback = audioContext.createGainNode();
var splitter = context.createChannelSplitter(2);
// Split the stereo signal.
splitter.connect( leftDelay, 0 );
// If the signal is dual copies of a mono signal, we don't want the right channel -
// it will just sound like a mono delay. If it was a real stereo signal, we do want
// it to just mirror the channels.
if (isTrueStereo)
splitter.connect( rightDelay, 1 );
leftDelay.delayTime.value = delayTime;
rightDelay.delayTime.value = delayTime;
leftFeedback.gain.value = feedback;
rightFeedback.gain.value = feedback;
// Connect the routing - left bounces to right, right bounces to left.
leftDelay.connect(leftFeedback);
leftFeedback.connect(rightDelay);
rightDelay.connect(rightFeedback);
rightFeedback.connect(leftDelay);
// Re-merge the two delay channels into stereo L/R
leftFeedback.connect(merger, 0, 0);
rightFeedback.connect(merger, 0, 1);
// Now connect your input to "splitter", and connect "merger" to your output destination.
【讨论】:
非常感谢!这真的很有帮助。以上是关于在 Web Audio API 中使用 ChannelSplitter 和 MergeSplitter 节点的主要内容,如果未能解决你的问题,请参考以下文章
可以使用Web Audio API和createMediaElementSource分析来自Icecast的流式音频吗?
如何在 Web Audio API 中更改音频缓冲源的时间?
使用 Web Audio API 或其他任何东西在前端修剪静音