Слияние кода завершено, страница обновится автоматически
/*
录音 Recorder扩展,DTMF(电话拨号按键信号)编码生成器,生成按键对应的音频PCM信号
本扩展分两个功能:
DTMF_Encode
DTMF_EncodeMix
本扩展生成信号代码、原理简单粗暴,纯js实现易于移植,0依赖
使用场景:DTMF按键信号生成,软电话实时发送DTMF按键信号等
https://github.com/xiangyuecn/Recorder
*/
(function(factory){
var browser=typeof window=="object" && !!window.document;
var win=browser?window:Object; //非浏览器环境,Recorder挂载在Object下面
var rec=win.Recorder,ni=rec.i18n;
factory(rec,ni,ni.$T,browser);
}(function(Recorder,i18n,$T,isBrowser){
"use strict";
/**
本方法用来生成单个按键信号pcm数据,属于底层方法,要混合多个按键信号到别的pcm中请用封装好的DTMF_EncodeMix方法
参数:
key: 单个按键0-9#*
sampleRate:123 要生成的pcm采样率
duration:100 按键音持续时间
mute:50 按键音前后静音时长
返回:
pcm:[Int16,...],生成单个按键信号
**/
Recorder.DTMF_Encode=function(key,sampleRate,duration,mute){
var durSize=Math.floor(sampleRate*(duration||100)/1000);
var muteSize=Math.floor(sampleRate*(mute==null?50:mute)/1000);
var pcm0=new Int16Array(durSize+muteSize*2);
var pcm1=new Int16Array(durSize+muteSize*2);
// https://github.com/watilde/node-dtfm/blob/master/encode.js
var f0=DTMF_Freqs[key][0];
var f1=DTMF_Freqs[key][1];
var vol=0.3;
for(var i=0;i<durSize;i++){
var v0=vol*Math.sin((2 * Math.PI) * f0 * (i / sampleRate));
var v1=vol*Math.sin((2 * Math.PI) * f1 * (i / sampleRate));
pcm0[i+muteSize]=Math.max(-1,Math.min(1,v0))*0x7FFF;
pcm1[i+muteSize]=Math.max(-1,Math.min(1,v1))*0x7FFF;
};
//简单叠加 低群 和 高群 信号
Mix(pcm0,0,pcm1,0);
return pcm0;
};
/**返回EncodeMix对象,将输入的按键信号混合到持续输入的pcm流中,当.mix(inputPcms)提供的太短的pcm会无法完整放下一个完整的按键信号,所以需要不停调用.mix(inputPcms)进行混合**/
Recorder.DTMF_EncodeMix=function(set){
return new EncodeMix(set);
};
var EncodeMix=function(set){
var This=this;
This.set={
duration:100 //按键信号持续时间 ms,最小值为30ms
,mute:25 //按键音前后静音时长 ms,取值为0也是可以的
,interval:200 //两次按键信号间隔时长 ms,间隔内包含了duration+mute*2,最小值为120ms
};
for(var k in set){
This.set[k]=set[k];
};
This.keys="";
This.idx=0;
This.state={keyIdx:-1,skip:0};
};
EncodeMix.prototype={
/** 添加一个按键或多个按键 "0" "123#*",后面慢慢通过mix方法混合到pcm中,无返回值 **/
add:function(keys){
this.keys+=keys;
}
/** 将已添加的按键信号混合到pcm中,pcms:[[Int16,...],...]二维数组,sampleRate:pcm的采样率,index:pcms第一维开始索引,将从这个pcm开始混合。
返回混合状态对象。
注意:调用本方法会修改pcms中的内容,因此混合结果就在pcms内。 **/
,mix:function(pcms,sampleRate,index){
index||(index=0);
var This=this,set=This.set;
var newEncodes=[];
var state=This.state;
var pcmPos=0;
loop:
for(var i0=index;i0<pcms.length;i0++){
var pcm=pcms[i0];
var key=This.keys.charAt(This.idx);
if(!key){//没有需要处理的按键,把间隔消耗掉
state.skip=Math.max(0, state.skip-pcm.length);
} else while(key){
//按键间隔处理
if(state.skip){
var op=pcm.length-pcmPos;
if(op<=state.skip){
state.skip-=op;
pcmPos=0;
continue loop;
};
pcmPos+=state.skip;
state.skip=0;
};
var keyPcm=state.keyPcm;
//这个key已经混合过,看看有没有剩余的信号
if(state.keyIdx==This.idx){
if(state.cur>=keyPcm.length){
state.keyIdx=-1;
};
};
//新的key,生成信号
if(state.keyIdx!=This.idx){
keyPcm=Recorder.DTMF_Encode(key,sampleRate,set.duration,set.mute);
state.keyIdx=This.idx;
state.cur=0;
state.keyPcm=keyPcm;
newEncodes.push({
key:key
,data:keyPcm
});
};
//将keyPcm混合到当前pcm中,实际是替换逻辑
var res=Mix(pcm,pcmPos,keyPcm,state.cur,true);
state.cur=res.cur;
pcmPos=res.last;
//下一个按键
if(res.cur>=keyPcm.length){
This.idx++;
key=This.keys.charAt(This.idx);
state.skip=Math.floor(sampleRate*(set.interval-set.duration-set.mute*2)/1000);
};
//当前pcm的位置已消耗完
if(res.last>=pcm.length){
pcmPos=0;
continue loop;//下一个pcm
};
};
};
return {
newEncodes:newEncodes //本次混合新生成的按键信号列表 [{key:"*",data:[Int16,...]},...],如果没有产生新信号将为空数组
,hasNext:This.idx<This.keys.length //是否还有未混合完的信号
};
}
};
//teach.realtime.mix_multiple 抄过来的简单混合算法
var Mix=function(buffer,pos1,add,pos2,mute){
for(var j=pos1,cur=pos2;;j++,cur++){
if(j>=buffer.length || cur>=add.length){
return {
last:j
,cur:cur
};
};
if(mute){
buffer[j]=0;//置为0即为静音
};
var data_mix,data1=buffer[j],data2=add[cur];
//简单混音算法 https://blog.csdn.net/dancing_night/article/details/53080819
if(data1<0 && data2<0){
data_mix = data1+data2 - (data1 * data2 / -0x7FFF);
}else{
data_mix = data1+data2 - (data1 * data2 / 0x7FFF);
};
buffer[j]=data_mix;
};
};
var DTMF_Freqs={
'1': [697, 1209] ,'2': [697, 1336] ,'3': [697, 1477] ,'A': [697, 1633]
,'4': [770, 1209] ,'5': [770, 1336] ,'6': [770, 1477] ,'B': [770, 1633]
,'7': [852, 1209] ,'8': [852, 1336] ,'9': [852, 1477] ,'C': [852, 1633]
,'*': [941, 1209] ,'0': [941, 1336] ,'#': [941, 1477] ,'D': [941, 1633]
};
}));
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )