Cloning audio source without having to download it again

前端 未结 3 372
野趣味
野趣味 2020-12-06 19:02

I\'m creating a piano in the browser using javascript. In order for me to play the same key multiple times simultaneously, instead of just playing the Audio object, I clone

相关标签:
3条回答
  • 2020-12-06 19:21

    Load it manually and assign a Blob URL of the binary data to src:

    <audio id="audioEl" data-src="audio.mp3"></audio>
    
    var xhr = new XMLHttpRequest();
    xhr.open('GET', audioEl.dataset.src);
    xhr.responseType = 'blob';
    xhr.onload = () => {
        audioEl.src = URL.createObjectURL(xhr.response);
    };
    xhr.send();
    

    This way when you clone it, only the reference to the in-memory binary data is cloned.

    0 讨论(0)
  • 2020-12-06 19:36

    cloneNode have one boolean argument:

    var dupNode = node.cloneNode(deep);
    /*
      node
        The node to be cloned.
      dupNode
        The new node that will be a clone of node
      deep(Optional)
         true if the children of the node should also be cloned, or false to clone only the specified node.
    */
    

    Also note from MDN:

    Deep is an optional argument. If omitted, the method acts as if the value of deep was true, defaulting to using deep cloning as the default behavior. To create a shallow clone, deep must be set to false.

    This behavior has been changed in the latest spec, and if omitted, the method will act as if the value of deep was false. Though It's still optional, you should always provide the deep argument both for backward and forward compatibility

    So, try to use deep = false to prevent download resource:

    var audioSrc = new Audio('path/');
    window.onkeypress = function(event) {
        var currentAudioSrc = audioSrc.cloneNode(false);
        currentAudioSrc.play();
    }
    
    0 讨论(0)
  • 2020-12-06 19:40

    With the webAudioAPI you could do something like that :

    • Download once the file via XMLHttpRequest.
    • Append the response to a buffer
    • Create a new bufferSource and play it on each call
    • Fallback to your first implementation if webAudioAPI is not supported (IE)

    window.AudioContext = window.AudioContext||window.webkitAudioContext;
    if(!window.AudioContext)
      yourFirstImplementation();
    else{
    var buffer,
    ctx = new AudioContext(),
    gainNode = ctx.createGain();
    gainNode.connect(ctx.destination);
    var vol = document.querySelector('input');
    vol.value = gainNode.gain.value;
    vol.addEventListener('change', function(){
        gainNode.gain.value = this.value;
      }, false);
    
    function createBuffer(){
      ctx.decodeAudioData(this.response, function(b) {
        buffer = b;
        }, function(e){console.warn(e)});
      var button = document.querySelector('button');
      button.addEventListener('click', function(){playSound(buffer)});
      button.className = 'ready';
      }
    
    var file = 'https://dl.dropboxusercontent.com/s/agepbh2agnduknz/camera.mp3',
    xhr = new XMLHttpRequest();
    xhr.onload = createBuffer;
    xhr.open('GET', file, true);
    xhr.responseType = 'arraybuffer';
    xhr.send();
    
    function playSound(buf){
      var source = ctx.createBufferSource();
      source.buffer = buf;
      source.connect(gainNode);
      source.onended = function(){if(this.stop)this.stop(); if(this.disconnect)this.disconnect();}
      source.start(0);
      }
    }
    
    function yourFirstImplementation(){
      alert('webAudioAPI is not supported by your browser');
      }
    button{opacity: .2;}
    button.ready{opacity: 1};
    <button>play</button>
    <input type="range" max="5" step=".01" title="volume"/>

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