From 24be0597630ba80711f5061345e7807db37c36f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E5=9D=9A=E6=9E=9C?= <753610399@qq.com> Date: Fri, 26 Jun 2020 19:38:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96DTMF=E6=89=A9=E5=B1=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +++++------ assets/npm-home/hash-history.txt | 8 +++---- .../teach.dtmf.decode_and_encode.js | 8 +++---- dist/extensions/dtmf.decode.js | 2 +- dist/extensions/dtmf.encode.js | 2 +- index.html | 6 ++--- src/extensions/dtmf.decode.js | 4 +++- src/extensions/dtmf.encode.js | 24 ++++++++++--------- 8 files changed, 36 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 7c7e4b4..8ce57aa 100644 --- a/README.md +++ b/README.md @@ -785,8 +785,8 @@ sonic.flush(callback) //callback:fn(pcm),和同步方法相同,只是返回 ## `DTMF`扩展 [dtmf.decode.js](https://github.com/xiangyuecn/Recorder/blob/master/src/extensions/dtmf.decode.js) + [lib.fft.js](https://github.com/xiangyuecn/Recorder/blob/master/src/extensions/lib.fft.js)、[dtmf.encode.js](https://github.com/xiangyuecn/Recorder/blob/master/src/extensions/dtmf.encode.js),两个js一个解码、一个编码,体积小均不超过10kb,纯js实现易于移植。[参考此demo片段在线测试使用](https://xiangyuecn.github.io/Recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.dtmf.decode_and_encode)。 -1. DTMF(电话拨号按键信号)解码器,解码得到按键值:可实现实时从音频数据流中解码得到电话拨号按键信息,用于电话录音软解,软电话实时提取DTMF按键信号等;请注意:使用dtmf.decode.js必须同时引入`lib.fft.js`才能正常工作。 -2. DTMF(电话拨号按键信号)编码生成器,生成按键对应的音频PCM信号:可实现生成按键对应的音频PCM信号,用于DTMF按键信号生成,软电话实时发送DTMF按键信号等。 +1. DTMF(电话拨号按键信号)解码器,解码得到按键值:可实现实时从音频数据流中解码得到电话拨号按键信息,用于电话录音软解,软电话实时提取DTMF按键信号等;识别DTMF按键准确度高,误识别率低,支持识别120ms以上按键间隔+30ms以上的按键音,纯js实现易于移植;请注意:使用dtmf.decode.js必须同时引入`lib.fft.js`(由java移植过来的)才能正常工作。 +2. DTMF(电话拨号按键信号)编码生成器,生成按键对应的音频PCM信号:可实现生成按键对应的音频PCM信号,用于DTMF按键信号生成,软电话实时发送DTMF按键信号等;生成信号代码、原理简单粗暴,纯js实现易于移植,0依赖。 ### 【方法】Recorder.DTMF_Decode(pcmData,sampleRate,prevChunk) 解码DTMF只有这个一个函数,此函数支持连续调用,将上次的返回值当做参数即可实现实时音频流数据的连续解码处理。 @@ -827,12 +827,12 @@ sonic.flush(callback) //callback:fn(pcm),和同步方法相同,只是返回 ``` ### 【方法】Recorder.DTMF_EncodeMix(set) -本方法返回EncodeMix对象,将输入的按键信号混合到持续输入的pcm流中,当.mix(inputPcm)提供的太短的pcm会无法完整放下一个完整的按键信号,所以需要不停调用.mix(inputPcm)进行混合。 +本方法返回EncodeMix对象,将输入的按键信号混合到持续输入的pcm流中,当.mix(inputPcms)提供的太短的pcm会无法完整放下一个完整的按键信号,所以需要不停调用.mix(inputPcms)进行混合。 ``` javascript set={ - duration:100 //按键信号持续时间 - ,mute:50 //按键音前后静音时长 - ,interval:250 //两次按键信号间隔时长 + duration:100 //按键信号持续时间 ms,最小值为30ms + ,mute:25 //按键音前后静音时长 ms,取值为0也是可以的 + ,interval:200 //两次按键信号间隔时长 ms,间隔内包含了duration+mute*2,最小值为120ms } EncodeMix对象: @@ -845,7 +845,7 @@ EncodeMix对象: newEncodes:[{key:"*",data:[Int16,...]},...] //本次混合新生成的按键信号列表 ,如果没有产生新信号将为空数组 ,hasNext:false //是否还有未混合完的信号 } - 注意:调用本方法会修改pcms中的内容,因此混合结果就在pcms内。 + 注意:调用本方法会修改pcms中的内容,因此混合结果就在pcms内。 ``` diff --git a/assets/npm-home/hash-history.txt b/assets/npm-home/hash-history.txt index c8f9d03..7544e7f 100644 --- a/assets/npm-home/hash-history.txt +++ b/assets/npm-home/hash-history.txt @@ -1,4 +1,8 @@ [ + { + "sha1": "326682217de610f15e0e456fdfe0725362dc5cd2", + "time": "2020-6-26 19:35:22" + }, { "sha1": "ebbcd0cd7c989445ad1c03a053a75aed4672c10c", "time": "2020-6-25 23:11:10" @@ -14,9 +18,5 @@ { "sha1": "0e8571bd082df5986d815921360eda7f64034ae5", "time": "2020-5-16 23:29:15" - }, - { - "sha1": "7c4f45cbbffd7d739bf8ed1f52d703459575a686", - "time": "2020-5-16 18:43:21" } ] \ No newline at end of file diff --git a/assets/runtime-codes/teach.dtmf.decode_and_encode.js b/assets/runtime-codes/teach.dtmf.decode_and_encode.js index 592030b..c23817f 100644 --- a/assets/runtime-codes/teach.dtmf.decode_and_encode.js +++ b/assets/runtime-codes/teach.dtmf.decode_and_encode.js @@ -69,9 +69,9 @@ var sendKeysClick=function(){ var sendKeys=function(keys){ if(!dtmfMix){ dtmfMix=Recorder.DTMF_EncodeMix({ - duration:100 //按键信号持续时间 - ,mute:50 //按键音前后静音时长 - ,interval:300 //两次按键信号间隔时长 + duration:100 //按键信号持续时间 ms,最小值为30ms + ,mute:25 //按键音前后静音时长 ms,取值为0也是可以的 + ,interval:200 //两次按键信号间隔时长 ms,间隔内包含了duration+mute*2,最小值为120ms }); }; if(!rec){ @@ -80,7 +80,7 @@ var sendKeys=function(keys){ dtmfMix.add(keys); //添加过去就不用管了,实时处理时会调用mix方法混入到pcm中。 }; -var dtmfMix; +var dtmfMix=null; diff --git a/dist/extensions/dtmf.decode.js b/dist/extensions/dtmf.decode.js index f0aaf3c..89e0db7 100644 --- a/dist/extensions/dtmf.decode.js +++ b/dist/extensions/dtmf.decode.js @@ -3,4 +3,4 @@ https://github.com/xiangyuecn/Recorder src: extensions/dtmf.decode.js */ -!function(){"use strict";Recorder.DTMF_Decode=function(t,r,a){a||(a={});var e=a.lastIs||"",o=null==a.lastCheckCount?99:a.lastCheckCount,l=a.totalLen||0,n=a.pcm,h=[];if(!Recorder.LibFFT)throw new Error("需要lib.fft.js支持");var s=256,u=Recorder.LibFFT(s),g=l,c=r/4e3,M=Math.floor(t.length/c);l+=M;var f=0;n&&n.length>s&&(M+=f=256,g-=f);var v=new Int16Array(M);f&&v.set(n.subarray(n.length-f));for(var d=0;dC&&(L=I,w=R):mC&&(m=I,p=R)}var T=_(w,B[0],i),A=_(p,B[1],i),j="";0<=T&&0<=A?(j=E[T][A],e?e.key==j?o++:(j="",o=e.old+o):3<=o?(e={key:j,old:o,start:b,use:0},o=1):(j="",o=0)):e&&(o=e.old+o),j?(3<=o&&!e.use&&(e.use=1,h.push({key:j,time:Math.round((g+e.start)/r*1e3)})),e.use&&(o=e.old=0)):(e="",o++)}return{keys:h,lastIs:e,lastCheckCount:o,totalLen:l,pcm:t}};var B=[[697,770,852,941],[1209,1336,1477,1633]],E=[["1","2","3","A"],["4","5","6","B"],["7","8","9","C"],["*","0","#","D"]],_=function(t,r,a){for(var e=-1,o=1e3,l=0;ls&&(M+=f=256,g-=f);var v=new Int16Array(M);f&&v.set(n.subarray(n.length-f));for(var d=0;dC&&(L=I,w=R):mC&&(m=I,p=R)}var T=_(w,B[0],i),A=_(p,B[1],i),j="";0<=T&&0<=A?(j=E[T][A],e?e.key==j?o++:(j="",o=e.old+o):3<=o?(e={key:j,old:o,start:b,use:0},o=1):(j="",o=0)):e&&(o=e.old+o),j?(3<=o&&!e.use&&(e.use=1,h.push({key:j,time:Math.round((g+e.start)/r*1e3)})),e.use&&(o=e.old=0)):(e="",o++)}return{keys:h,lastIs:e,lastCheckCount:o,totalLen:l,pcm:t}};var B=[[697,770,852,941],[1209,1336,1477,1633]],E=[["1","2","3","A"],["4","5","6","B"],["7","8","9","C"],["*","0","#","D"]],_=function(t,r,a){for(var e=-1,o=1e3,l=0;ln.idx&&u=f.length&&(d.keyIdx=-1),d.keyIdx!=n.idx&&(f=Recorder.DTMF_Encode(h,e,a.duration,a.mute),d.keyIdx=n.idx,d.cur=0,d.keyPcm=f,i.push({key:h,data:f}));var x=l(c,s,f,d.cur,!0);if(d.cur=x.cur,x.cur>=f.length&&(n.idx++,h=n.keys.charAt(n.idx),d.skip=Math.floor(e*(a.interval-a.duration-2*a.mute)/1e3)),x.last>=c.length){s=0;continue t}}o=0}return{newEncodes:i,hasNext:!!o}}};var l=function(t,e,r,n,a){for(var i=e,o=n;;i++,o++){if(i>=t.length||o>=r.length)return{last:i,cur:o};a&&(t[i]=0);var s,u=t[i],c=r[o];s=u<0&&c<0?u+c-u*c/-32767:u+c-u*c/32767,t[i]=s}},f={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]}}(); \ No newline at end of file +!function(){"use strict";Recorder.DTMF_Encode=function(t,e,r,n){for(var a=Math.floor(e*(r||100)/1e3),i=Math.floor(e*(null==n?50:n)/1e3),s=new Int16Array(a+2*i),o=new Int16Array(a+2*i),u=f[t][0],c=f[t][1],h=0;h=k.length&&(s.keyIdx=-1),s.keyIdx!=n.idx&&(k=Recorder.DTMF_Encode(h,e,a.duration,a.mute),s.keyIdx=n.idx,s.cur=0,s.keyPcm=k,i.push({key:h,data:k}));var f=l(c,o,k,s.cur,!0);if(s.cur=f.cur,o=f.last,f.cur>=k.length&&(n.idx++,h=n.keys.charAt(n.idx),s.skip=Math.floor(e*(a.interval-a.duration-2*a.mute)/1e3)),f.last>=c.length){o=0;continue t}}else s.skip=Math.max(0,s.skip-c.length)}return{newEncodes:i,hasNext:n.idx=t.length||s>=r.length)return{last:i,cur:s};a&&(t[i]=0);var o,u=t[i],c=r[s];o=u<0&&c<0?u+c-u*c/-32767:u+c-u*c/32767,t[i]=o}},f={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]}}(); \ No newline at end of file diff --git a/index.html b/index.html index 914d305..34fe2f1 100644 --- a/index.html +++ b/index.html @@ -1081,9 +1081,9 @@ var sendDTMFKeys=function(keys){ if(!dtmfMix){ dtmfMix=Recorder.DTMF_EncodeMix({ - duration:100 //按键信号持续时间 - ,mute:50 //按键音前后静音时长 - ,interval:300 //两次按键信号间隔时长 + duration:100 //按键信号持续时间 ms,最小值为30ms + ,mute:25 //按键音前后静音时长 ms,取值为0也是可以的 + ,interval:200 //两次按键信号间隔时长 ms,间隔内包含了duration+mute*2,最小值为120ms }); }; if(!rec||!rec.buffers){ diff --git a/src/extensions/dtmf.decode.js b/src/extensions/dtmf.decode.js index bd2ce15..516a848 100644 --- a/src/extensions/dtmf.decode.js +++ b/src/extensions/dtmf.decode.js @@ -2,6 +2,8 @@ 录音 Recorder扩展,DTMF(电话拨号按键信号)解码器,解码得到按键值 使用本扩展需要引入lib.fft.js支持 +本扩展识别DTMF按键准确度高,误识别率低,支持识别120ms以上按键间隔+30ms以上的按键音,纯js实现易于移植 + 使用场景:电话录音软解,软电话实时提取DTMF按键信号等 https://github.com/xiangyuecn/Recorder */ @@ -179,7 +181,7 @@ var FindIndex=function(freq, freqs, freqStep){ var xb=Math.abs(freqs[i]-freq); if(idxb>xb){ idxb=xb; - if(xbThis.idx && i0=keyPcm.length){ @@ -137,12 +140,11 @@ EncodeMix.prototype={ continue loop;//下一个pcm }; }; - hasNext=0; }; return { newEncodes:newEncodes //本次混合新生成的按键信号列表 [{key:"*",data:[Int16,...]},...],如果没有产生新信号将为空数组 - ,hasNext:!!hasNext //是否还有未混合完的信号 + ,hasNext:This.idx