AudioContext panning audio of playing media

前端 未结 2 666
Happy的楠姐
Happy的楠姐 2020-12-31 20:55

I wonder if is there a way to pan the audio of a video with JavaScript.

The same way you can adjust volume, I need to pan an stereo audio left to right or right to l

相关标签:
2条回答
  • 2020-12-31 21:34

    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. As Mantiur already stated you can use the channelSplitter to get the desired result. 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. Please keep in mind that only chrome and Firefox support the web audio 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. 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:

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

    This might fix the problem in iOS devices, as we should be able to use this there. Despite that MDN is not sure about the compatibility on safari. Sadly there is no workaround to this, due to the behaviour of the web audio 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).

    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)?

    0 讨论(0)
  • 2020-12-31 21:38

    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. 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()

    0 讨论(0)
提交回复
热议问题