Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 混合两个音频缓冲区,使用web音频Api将一个放在另一个的背景上_Javascript_Html5 Audio_Web Audio Api - Fatal编程技术网

Javascript 混合两个音频缓冲区,使用web音频Api将一个放在另一个的背景上

Javascript 混合两个音频缓冲区,使用web音频Api将一个放在另一个的背景上,javascript,html5-audio,web-audio-api,Javascript,Html5 Audio,Web Audio Api,我想混合两个音频源,把一首歌作为另一首歌的背景放到一个源中 例如,我有以下输入: <input id="files" type="file" name="files[]" multiple onchange="handleFilesSelect(event)"/> 和解码此文件的脚本: window.AudioContext = window.AudioContext || window.webkitAudioContext; var context = new window.

我想混合两个音频源,把一首歌作为另一首歌的背景放到一个源中

例如,我有以下输入:

<input id="files" type="file" name="files[]" multiple onchange="handleFilesSelect(event)"/>

和解码此文件的脚本:

window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new window.AudioContext();
var sources = [];
var files = [];
var mixed = {};

function handleFilesSelect(event){
    if(event.target.files.length <= 1)
          return false;

     files = event.target.files;
     readFiles(mixAudioSources);
}

function readFiles(index, callback){
    var freader = new FileReader();
    var i = index ? index : 0;

    freader.onload = function (e) {     
        context.decodeAudioData(e.target.result, function (buf) {

            sources[i] = context.createBufferSource();
            sources[i].connect(context.destination);
            sources[i].buffer = buf;

            if(files.length > i+1){
                readFiles(i + 1, callback);
            } else {
                if(callback){
                    callback();
                }
            }
        });
    };

    freader.readAsArrayBuffer(files[i]);
}

function mixAudioSources(){
    //So on our scenario we have here two decoded audio sources in "sources" array.
    //How we can mix that "sources" into "mixed" variable by putting "sources[0]" as background of "sources[1]"
}
window.AudioContext=window.AudioContext | | window.webkitadiocontext;
var context=new window.AudioContext();
风险值来源=[];
var文件=[];
var mixed={};
函数句柄文件选择(事件){
if(event.target.files.length i+1){
读取文件(i+1,回调);
}否则{
如果(回调){
回调();
}
}
});
};
readAsArrayBuffer(文件[i]);
}
函数mixAudioSources(){
//在我们的场景中,我们有两个解码的音频源在“源”数组中。
//如何通过将“sources[0]”作为“sources[1]的背景,将“sources”混合到“mixed”变量中
}
那么,我如何将这些源混合到一个源中呢?例如,我有两个文件,如何将一个源作为另一个源的背景,并将此混合放入单个源中

另一个场景:例如,如果我从麦克风读取输入流,并且我想将此输入放在背景歌曲(某种卡拉OK)上,是否可以在支持html5的客户端上执行此工作?性能如何?也许在服务器端混合这些音频源的更好方法

如果可能,那么mixAudioSources功能的可能实现是什么


谢谢。

两种方法最初发布在,调整为在
元素的
更改
事件中处理
文件
对象

第一种方法利用
OfflineAudioContext()
AudioContext.createBufferSource()
AudioContext.createMediaStreamDestination()
Promise
构造函数,
Promise.all()
MediaRecorder()
来混合音频曲目,然后提供混合音频文件供下载

var div=document.querySelector(“div”);
功能手柄文件选择(输入){
div.innerHTML=“正在加载音频曲目..请稍候”;
var files=Array.from(input.files);
风险值持续时间=60000;
var chunks=[];
var audio=新的AudioContext();
var mixedAudio=audio.createMediaStreamDestination();
var player=新音频();
var语境;
无功记录仪;
var description=“”;
player.controls=“controls”;
函数get(文件){
description+=file.name.replace(/\..*\s+/g,“”);
返回新承诺(功能(解决、拒绝){
var reader=新文件读取器;
reader.readAsArrayBuffer(文件);
reader.onload=函数(){
解析(reader.result)
}
})
}
功能停止混合(持续时间,…介质){
设置超时(功能(介质){
media.forEach(函数(节点){
node.stop()
})
},持续时间,媒体)
}
Promise.all(files.map(get)).then(函数(数据){
var len=Math.max.apply(数学,数据,映射(函数,缓冲区){
返回缓冲区
}));
上下文=新的OfflineAudioContext(2,len,44100);
返回Promise.all(data.map)(函数(缓冲区){
返回音频。解码音频数据(缓冲区)
.then(函数(缓冲源){
var source=context.createBufferSource();
source.buffer=缓冲源;
source.connect(context.destination);
返回source.start()
})
}))
.然后(函数(){
返回上下文。startRendering()
})
.then(函数(renderedBuffer){
返回新承诺(函数(解析){
var mix=audio.createBufferSource();
mix.buffer=renderedBuffer;
混合。连接(音频。目的地);
mix.connect(mixedAudio);
记录器=新的媒体记录器(mixedAudio.stream);
记录器。启动(0);
混合启动(0);
div.innerHTML=“播放和录制曲目..”;
//60秒后停止播放和录制
stopMix(持续时间、混合、记录器)
recorder.ondataavailable=功能(事件){
推送(事件数据);
};
recorder.onstop=功能(事件){
var blob=新blob(块{
“类型”:“音频/ogg;编解码器=作品”
});
控制台日志(“记录完成”);
解析(blob)
};
})
})
.then(函数(blob){
控制台日志(blob);
div.innerHTML=“混合音频曲目可供下载..”;
var audioDownload=URL.createObjectURL(blob);
var a=document.createElement(“a”);
a、 下载=description++“+blob.type.replace(/.+\/.+/g)”;
a、 href=音频下载;
a、 innerHTML=a.download;
文件.正文.附件(a);
a、 insertAdjacentHTML(“afterend”,“br>”);
player.src=音频下载;
document.body.appendChild(播放器);
})
})
.catch(函数(e){
控制台日志(e)
});
}

我只想补充一下的优秀答案,并在这里发布基于第二个场景答案的解决方案(第二个来源是麦克风输入)。实际上是客户卡拉OK。脚本:

window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new window.AudioContext();
var playbackTrack = null;

function handleFileSelect(event){

     var file = event.files[0];
     var freader = new FileReader();

    freader.onload = function (e) {     
        context.decodeAudioData(e.target.result, function (buf) {

            playbackTrack = context.createBufferSource();
            playbackTrack.buffer = buf;

            var karaokeButton = document.getElementById("karaoke_start");
            karaokeButton.style.display = "inline-block";
            karaokeButton.addEventListener("click", function(){
                startKaraoke();
            });
        });
    };

    freader.readAsArrayBuffer(file);
}

function stopMix(duration, mediaRecorder) {
    setTimeout(function(mediaRecorder) {
      mediaRecorder.stop();
      context.close();
    }, duration, mediaRecorder)
 }

function startKaraoke(){

    navigator.mediaDevices.getUserMedia({audio: true,video: false})
        .then(function(stream) {
            var mixedAudio = context.createMediaStreamDestination();
            var merger = context.createChannelMerger(2);
            var splitter = context.createChannelSplitter(2);
            var duration = 5000;

            var chunks = [];
            var channel1 = [0,1];
            var channel2 = [1, 0];

            var gainNode = context.createGain();
            playbackTrack.connect(gainNode);
            gainNode.connect(splitter);
            gainNode.gain.value = 0.5; // From 0 to 1
            splitter.connect(merger, channel1[0], channel1[1]);

            var microphone = context.createMediaStreamSource(stream);
            microphone.connect(splitter);
            splitter.connect(merger, channel2[0], channel2[1]);

            merger.connect(mixedAudio);
            merger.connect(context.destination);

            playbackTrack.start(0);
            var mediaRecorder = new MediaRecorder(mixedAudio.stream);
            mediaRecorder.start(1);

            mediaRecorder.ondataavailable = function (event) {
                chunks.push(event.data);
            }

            mediaRecorder.onstop = function(event) {
              var player = new Audio();
              player.controls = "controls";

              var blob = new Blob(chunks, {
                "type": "audio/mp3"
              });

              audioDownload = URL.createObjectURL(blob);
              var a = document.createElement("a");
              a.download = "karaokefile." + blob.type.replace(/.+\/|;.+/g, "");
              a.href = audioDownload;
              a.innerHTML = a.download;
              player.src = audioDownload;
              document.body.appendChild(a);
              document.body.appendChild(player);
            };

            stopMix(duration, mediaRecorder);
        })
        .catch(function(error) {
          console.log('error: ' + error);
        });

}
和Html:

<input id="file" 
         type="file" 
         name="file" 
         accept="audio/*" 
         onchange="handleFileSelect(this)" />
  <span id="karaoke_start" style="display:none;background-color:yellow;cursor:pointer;">start karaoke</span>

开始卡拉OK

这里是正在工作的plnkr示例:

看看交叉衰落部分Hi。在本文中,与我的问题最接近的示例是同时播放两个源代码。这对我帮助不大,因为我需要上传一个源并保存到服务器上。我明白了,您希望您的用户能够预览他正在做的事情吗?如果是,可能是这样,否则可能在服务器上执行会更好。@OlegYudovich使用GainNode来减少选择为“background”plnkr plnkr.co/edit/5c36gNgO6bvtFGjDoh02?p=previewGreat-answer的音频曲目的音量。谢谢