如何使用javascript直接从网页录制

如何使用javascript直接从网页录制,javascript,web-audio-api,mediarecorder,recording,Javascript,Web Audio Api,Mediarecorder,Recording,我正在制作一个小音乐应用程序。 我希望能够录制在浏览器中发出的声音,而不依赖于麦克风。 到目前为止,我所看到的关于api的一切都表明它依赖于麦克风。 理想情况下,我希望在不使用外部库的情况下实现这一目标 作为参考,这里是我如何制作一个非常简单的声音 var congo = new Audio('http://www.denhaku.com/r_box/sr16/sr16perc/hi conga.wav'); var drumpad = document.getElementById('dru

我正在制作一个小音乐应用程序。 我希望能够录制在浏览器中发出的声音,而不依赖于麦克风。 到目前为止,我所看到的关于api的一切都表明它依赖于麦克风。 理想情况下,我希望在不使用外部库的情况下实现这一目标

作为参考,这里是我如何制作一个非常简单的声音

var congo = new Audio('http://www.denhaku.com/r_box/sr16/sr16perc/hi conga.wav');

var drumpad = document.getElementById('drumpad');

drumpad.addEventListener('click', function(){
    congo.play();
});
多谢各位

编辑:更清楚地说,我如何记录我所包含的代码片段发出的声音,而不依赖计算机内置麦克风。例如,假设一个用户正在用鼓发声,而他们戴着耳机,那么麦克风就没用了。即使他们不戴耳机,也会听到很多背景噪音。我想隔离正在录制的声音,仅隔离在用户打开此应用程序的特定浏览器选项卡中制作的音乐

到目前为止,我所看到的关于MediaRecorder api的一切都表明它依赖于麦克风

不,API确实依赖于,但这些媒体流不必是LocalMediaStreams(即来自):

如果加载的媒体符合同源策略,则可以从(
方法)获取媒体流

但这将为每个MediaElement返回一个MediaStream,在您的情况下,这可能不是最好的解决方案

取而代之的是,跳转到更适合鼓垫这样的应用场合。 Web Audio API确实有一个返回的方法,该方法将在其
.stream
属性中包含一个MediaStream。您将连接到此MediaStreamAudioDestinationNode的每个其他节点都将在MediaStream中播放,并且您将能够从MediaRecorder中录制它

让我们循环使用它以包括一个记录器:

(函数myFirstDrumKit(){
常数db_url=https://dl.dropboxusercontent.com/s/“;//我们所有的媒体都存储在dropbox上
//我们需要先加载所有的音频
函数initAudios(){
const promises=drum.parts.map(part=>{
return fetch(db\u url+part.audio\u src)//获取文件
.then(resp=>resp.arrayBuffer())//作为arrayBuffer
.then(buf=>drum.a_ctx.decodeAudioData(buf))//然后解码其音频数据
。然后(AudioBuf=>{
part.buf=AudioBuf;//存储音频缓冲区(不会更改)
返回承诺。解决(部分);//完成
});
});
返回承诺。全部(承诺);//全部加载时
}
函数initImages(){
//在这个版本中,我们只有一个静态图像,
//但我们可以有多个部件,逻辑与音频相同
var img=新图像();
img.src=db_url+drum.bg_src;
鼓。bg=img;
返回新承诺((res,rej)=>{
img.onload=res;
img.onerror=rej;
});
}
让general_solo=false;
让part_solo=false;
常数鼓={
a_ctx:new AudioContext(),
产生声音:(部分)=>{
//每次需要播放源代码时都会打电话
const source=drum.a_ctx.createBufferSource();
source.buffer=part.buf;
源连接(鼓增益);
//一次只让一个人玩
//只需存储此sourceNode,并停止上一个
国际单项体育联合会(一般独奏){
//停止所有播放源
鼓.parts.forEach(p=>(p.source和p.source.stop(0));
}
else if(part_solo和part.source){
//只停止这一部分
部分源停止(0);
}
//存储源代码
part.source=来源;
source.start(0);
},
部分:[{
姓名:'你好',
x:90,
y:116,
w:160,
h:70,
audio_src:'kbgd2jm7ezk3u3x/hihat.mp3'
},
{
名称:“陷阱”,
x:79,
y:192,
w:113,
h:58,
audio_src:'h2j6vm17r07jf03/snare.mp3'
},
{
名字:'踢',
x:80,
y:250,
w:200,
h:230,
音频提示:“1cdwpm3gca9mlo0/kick.mp3”
},
{
名字:“汤姆”,
x:290,
y:210,
w:110,
h:80,
音频:h8pvqoqol3ovyle8/tom.mp3
}
],
bg_src:'0jkaeoxls18n3y5/_drumkit.jpg?dl=0',
//////////////////////
///录音部分
//////////////////////    
记录:功能记录(e){
const btn=document.getElementById('record');
常量块=[];
//使用StreamNode的流初始化一个新的MediaRecorder
const recorder=新的媒体记录器(drum.streamNode.stream);
//保存每一块
recorder.ondataavailable=e=>chunks.push(e.data);
//一旦我们完成录音
recorder.onstop=e=>{
//导出我们的录音
const blob=新blob(块);
const url=url.createObjectURL(blob);
//这里是一个元素
常量a=新音频(url);
a、 控制=真;
document.getElementById(“记录”).appendChild(a);
//重置默认单击处理程序
btn.onclick=drum.record;
btn.textContent='记录';
}
btn.onclick=函数(){
录音机。停止();
};
//开始录音
recorder.start();
btn.textContent='停止录制';
}
};
drum.gain=drum.a_ctx.createGain();
鼓增益增益值=.5;
磁鼓增益连接(磁鼓a\u ctx目的地);
//记录
drum.streamNode=drum.a_ctx.createMediaStreamDestination();
鼓.增益.连接(鼓.流节点);
document.getElementById('record').onclick=drum.record;
/////////////
//与当前问题无关
////////////
函数initCanvas(){
const c=drum.canvas=document.createElement('canvas');
const ctx=drum.ctx=c.getContext('2d');
c、 宽度=滚筒宽度;
c、 高度=滚筒高度;
ctx.drawImage(drum.bg,0,0);
文件.正文.附件(c);
增编(c);
}
常数isHover=(x,y)=>
(滚筒、零件、过滤器(p=>(p.xx&&p.y