简体   繁体   English

AudioContext平移播放媒体的音频

[英]AudioContext panning audio of playing media

I wonder if is there a way to pan the audio of a video with JavaScript. 我想知道是否有办法用JavaScript平移视频的音频。

The same way you can adjust volume, I need to pan an stereo audio left to right or right to left. 与调整音量的方式相同,我需要从左到右或从右到左平移立体声音频。

This feature would be useful for multilingual events where you can produce a video in two languages using stereo, for instance, pan english audio to left and german translation to right. 此功能对于多语言事件非常有用,您可以使用立体声生成两种语言的视频,例如,将英语音频转换为左侧,将德语转换为右侧。 Then the player could transform the stereo track into mono muting one of the languages depending on user election. 然后,播放器可以根据用户选择将立体声音轨转换为单声道静音中的一种语言。

I already implemented this feature in flash using SoundTransform class http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/SoundTransform.html#pan . 我已经使用SoundTransform类http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/SoundTransform.html#pan在flash中实现了此功能。

I guess SoundTransform html-equivalent is AudioContext http://www.w3.org/TR/webaudio/#AudioContext-section . 我猜SoundTransform与html相当的是AudioContext http://www.w3.org/TR/webaudio/#AudioContext-section

May I access the audio context of a playing video? 我可以访问播放视频的音频上下文吗?

UPDATE : After some intensive research I found out the solution. 更新 :经过深入研究后,我找到了解决方案。 Here is some javascript code I used to develop the videojs plugin videjs-stereopanner: 这是我用来开发videojs插件的一些javascript代码videjs-stereopanner:

//Init AudioContext
var context = new AudioContext();
var gainL = context.createGainNode();
var gainR = context.createGainNode();
gainL.gain.value = 1;
gainR.gain.value = 1;
var merger = this.context.createChannelMerger(2);
var splitter = this.context.createChannelSplitter(2);

//Connect to source
var source = context.createMediaElementSource(node);
//Connect the source to the splitter
source.connect(splitter, 0, 0);
//Connect splitter' outputs to each Gain Nodes
splitter.connect(gainL, 0);
splitter.connect(gainR, 1);

//Connect Left and Right Nodes to the Merger Node inputs
//Assuming stereo as initial status
gainL.connect(merger, 0, 0);
gainR.connect(merger, 0, 1);

//Connect Merger output to context destination
merger.connect(context.destination, 0, 0);

//Disconnect left channel and connect right to both stereo outputs
var function = panToRight(){
    gainL.disconnect();
    gainR.connect(merger, 0, 1);
};

//Disconnect right channel and connect left to both stereo outputs
var function = panToLeft(){
    gainR.disconnect();
    gainL.connect(merger,0,0);
}

//Restore stereo
var function = panToStereo(){
    gainL.connect(merger, 0, 0);
    gainR.connect(merger, 0, 1);
}

That works for me only in Chrome. 这仅适用于Chrome。 If I try to execute this script on iPad/Safari i get an annoying sound which almost deafened me. 如果我尝试在iPad / Safari上执行此脚本,我会听到令人讨厌的声音,这几乎让我感到沮丧。 I'm waiting till Safari implements whole Audio API. 我等待Safari实现整个Audio API。

As there is not yet an accepted answer to this I would like to still help you out. 由于还没有接受这个答案,我还是想帮助你。 At first the planner node from the answer above is not pretty use able, as that calculates the volume and panning depending on a 3 dimensional position, direction and speed in (another) direction. 首先,来自上面答案的计划者节点不能很好地使用,因为它根据(另一)方向上的3维位置,方向和速度计算音量和平移。 As Mantiur already stated you can use the channelSplitter to get the desired result. 正如Mantiur已经声明的那样,您可以使用channelSplitter来获得所需的结果。 You could set it up like so: 您可以这样设置:

var element = document.getElementById('player');
Var source = context.createMediaElementSource(element);
var splitter = context.createSplitter(2);
source.connect(splitter);
var left = context.createGain();
var right = context.createGain();
splitter.connect(left);
splitter.connect(right);

You will now be able to connect the left or right node to the context.destination , depending on which of the two the user needs. 您现在可以将左或右节点连接到context.destination ,具体取决于用户需要的两个节点。 Please keep in mind that only chrome and Firefox support the web audio api. 请记住,只有chrome和Firefox支持网络音频API。

Updated answer: (to the updated question) 更新的答案:(更新的问题)

your code looks nice, but it is a lot better to just set the gains for left and right to 0 or 1 rather than disconnect and connect them. 你的代码看起来不错,但是将左边和右边的增益设置为0或1而不是断开并连接它们要好得多。 With the current issue you will get the one ear problem, but then you'd better not use a merger but just push the audio directly to the destination (or through an extra gain node for setting the final volume. Also notice that your code might work on chrome, but on the version I use this doesn't work, as there a naming issue in context.createGain() and context.createGainNode() . The official document uses .createGain , so we'd better stick to that and create a fallback: 对于当前的问题,您将遇到单耳问题,但是您最好不要使用合并,而只是将音频直接推送到目的地(或通过额外的增益节点来设置最终音量。还要注意您的代码可能在chrome上工作,但在我使用的版本上这不起作用,因为context.createGain()context.createGainNode()有一个命名问题。 官方文档使用.createGain ,所以我们最好坚持这一点,创建一个后备:

context.createGain = context.createGain||context.createGainNode;

This might fix the problem in iOS devices, as we should be able to use this there. 可能会解决iOS设备中的问题,因为我们应该可以在那里使用它。 Despite that MDN is not sure about the compatibility on safari. 尽管MDN 不确定 Safari的兼容性。 Sadly there is no workaround to this, due to the behaviour of the web audio API. 遗憾的是,由于Web音频API的行为,没有解决方法。 Lets say the source, which has only one output, but contains two channels inside. 让我们说源,它只有一个输出,但内部包含两个通道。 There is no other way to split those channels (as at first I was thinking like source.connect(gainL, 0, 0); and source.connect(gainR, 1, 0); but that didn't work due to the numbers being related to the number of in/outputs, not to the channels inside those lines). 没有其他方法可以拆分这些通道(起初我的想法就像source.connect(gainL, 0, 0);source.connect(gainR, 1, 0);但由于数字不起作用与输入/输出的数量有关,而不是与这些线内的通道有关)。

So I recommend change the code to something like this: 所以我建议将代码更改为:

//Init AudioContext
window.audioContext = window.audioContext||window.webkitAudioContext; //fallback for older chrome browsers
var context = new AudioContext();
context.createGain = context.createGain||context.createGainNode; //fallback for gain naming
var gainL = context.createGain();
var gainR = context.createGain();

var splitter = this.context.createChannelSplitter(2);

//Connect to source
var source = context.createMediaElementSource(audioElement);
//Connect the source to the splitter
source.connect(splitter, 0, 0);
//Connect splitter' outputs to each Gain Nodes
splitter.connect(gainL, 0);
splitter.connect(gainR, 1);

//Connect Left and Right Nodes to the output
//Assuming stereo as initial status
gainL.connect(context.destination, 0);
gainR.connect(context.destination, 0);


//Mute left channel and set the right gain to normal
function panToRight(){
    gainL.gain.value = 0;
    gainR.gain.value = 1;
}

//Mute right channel and set the left gain to normal
function panToLeft(){
    gainL.gain.value = 1;
    gainR.gain.value = 0;
}

//Restore stereo
function panToStereo(){
    gainL.gain.value = 1;
    gainR.gain.value = 1;
}

Oh and btw var function = funcName(){} is not valid javascript (ar are you using some API that changes this behavior)? 哦,顺便说一下var function = funcName(){}是无效的javascript(你使用的是一些改变这种行为的API)吗?

I added ambient audio on one of my pages that I'm trying to build for a game. 我在我试图为游戏构建的一个页面上添加了环境音频。 Here's my experimentation with panning that I'll be using later on certain sound effects throughout the game. 这是我对平移的实验,我稍后会在整个游戏中使用某些声音效果。 Took forever to realize there was this nice createStereoPanner thing, which simplified the whole process significantly . 永远意识到有一个很好的createStereoPanner东西,它显着简化了整个过程。 I tested it with a video and it worked just as well. 我用视频对它进行了测试,效果也一样。

 var ambientAudio = new Audio('./ambientVideo.mp4'); document.addEventListener('keydown', ambientAudioControl) function ambientAudioControl(e) { if (e.keyCode === 37) panToLeft() if (e.keyCode === 39) panToRight() if (e.keyCode === 40) panToStereo() } const ambientContext = new AudioContext(); const source = ambientContext.createMediaElementSource(ambientAudio); const ambientPan = ambientContext.createStereoPanner() function panToLeft(){ ambientPan.pan.value = -1 } function panToRight(){ ambientPan.pan.value = 1 } function panToStereo(){ ambientPan.pan.value = 0 } source.connect(ambientPan) ambientPan.connect(ambientContext.destination) ambientAudio.play() 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM