Skip to content

Commit

Permalink
增加FrequencyHistogramView频率直方图显示扩展
Browse files Browse the repository at this point in the history
  • Loading branch information
xiangyuecn committed Jan 13, 2020
1 parent 9a4dcc3 commit e5b1447
Show file tree
Hide file tree
Showing 11 changed files with 713 additions and 28 deletions.
56 changes: 54 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ Recorder({type:"aac"})
`src/extensions`目录内为扩展支持库,这些扩展库默认都没有合并到生成代码中,需单独引用(`dist``src`中的)才能使用。

## `WaveView`扩展
`waveview.js`,4kb大小源码,录音时动态显示波形,具体样子参考演示地址页面。此扩展参考[MCVoiceWave](https://github.com/HaloMartin/MCVoiceWave)库编写的,具体代码在`https://github.com/HaloMartin/MCVoiceWave/blob/f6dc28975fbe0f7fc6cc4dbc2e61b0aa5574e9bc/MCVoiceWave/MCVoiceWaveView.m`中。
(waveview.js](https://github.com/xiangyuecn/Recorder/blob/master/src/extensions/waveview.js),4kb大小源码,录音时动态显示波形,具体样子参考演示地址页面。此扩展参考[MCVoiceWave](https://github.com/HaloMartin/MCVoiceWave)库编写的,具体代码在`https://github.com/HaloMartin/MCVoiceWave/blob/f6dc28975fbe0f7fc6cc4dbc2e61b0aa5574e9bc/MCVoiceWave/MCVoiceWaveView.m`中。

此扩展是在录音时`onProcess`回调中使用;`Recorder.BufferSize`会影响绘制帧率,越小越流畅(但越消耗cpu),默认配置的大概12帧/s。基础使用方法:[](?Ref=WaveView.Codes&Start)
``` javascript
Expand Down Expand Up @@ -611,9 +611,61 @@ set={
输入音频数据,更新波形显示,这个方法调用的越快,波形越流畅。pcmData `[Int16,...]` 一维数组,为当前的录音数据片段,其他参数和`onProcess`回调相同。


## `FrequencyHistogramView`扩展
[frequency.histogram.view.js](https://github.com/xiangyuecn/Recorder/blob/master/src/extensions/frequency.histogram.view.js) + [lib.fft.js](https://github.com/xiangyuecn/Recorder/blob/master/src/extensions/lib.fft.js),12kb大小源码,音频可视化频率直方图显示,具体样子参考演示地址页面。此扩展核心算法参考Java开源库[jmp123 ](https://sourceforge.net/projects/jmp123/files/)的代码编写的,jmp123版本0.3。

此扩展的使用方式和`WaveView`扩展完全相同,请参考上面的`WaveView`来使用,请注意:必须同时引入`lib.fft.js`才能正常工作。

![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_histogram.png)

### 【构造】histogram=Recorder.FrequencyHistogramView(set)
构造函数,`set`参数为配置对象,默认配置值如下:
``` javascript
set={
elem:"css selector" //自动显示到dom,并以此dom大小为显示大小
//或者配置显示大小,手动把frequencyObj.elem显示到别的地方
,width:0 //显示宽度
,height:0 //显示高度

//以上配置二选一

scale:2 //缩放系数,应为正整数,使用2(3? no!)倍宽高进行绘制,避免移动端绘制模糊

,fps:20 //绘制帧率,不可过高

,lineCount:15 //直方图柱子数量
,lineWidth:10 //柱子线条基础粗细
,minHeight:0 //柱子保留基础高度,position不为±1时应该保留点高度
,position:-1 //绘制位置,取值-1到1,-1为最底下,0为中间,1为最顶上,小数为百分比

,stripeEnable:true //是否启用柱子顶上的峰值小横条,position不是-1时应当关闭,否则会很丑
,stripeHeight:5 //峰值小横条基础高度
,stripeMargin:8 //峰值小横条和柱子保持的基础距离

,fallDuration:600 //柱子从最顶上下降到最底部最长时间ms
,stripeFallDuration:1200 //峰值小横条从最顶上下降到底部最长时间ms

//柱子颜色配置:[位置,css颜色,...] 位置: 取值0.0-1.0之间
,linear:[0,"rgba(0,187,17,1)",0.5,"rgba(255,215,0,1)",1,"rgba(255,102,0,1)"]
//峰值小横条css颜色 #abc,留空为柱子的渐变颜色
,stripeColor:""

,shadowBlur:0 //柱子阴影基础大小,设为0不显示阴影
,shadowColor:"#bbb" //柱子阴影颜色
,stripeShadowBlur:-1 //峰值小横条阴影基础大小,设为0不显示阴影,-1为柱子的大小
,stripeShadowColor:"" //峰值小横条阴影颜色,留空为柱子的阴影颜色

//当发生绘制时会回调此方法,参数为当前绘制的频率数据和采样率,可实现多个直方图同时绘制,只消耗一个input输入和计算时间
,onDraw:function(frequencyData,sampleRate){}
}
```

### 【方法】histogram.input(pcmData,powerLevel,sampleRate)
输入音频数据,更新直方图显示。pcmData `[Int16,...]` 一维数组,为当前的录音数据片段,其他参数和`onProcess`回调相同。


## `Sonic`扩展
`sonic.js`,37kb大小源码(压缩版gzip后4.5kb),音频变速变调转换,[参考此demo片段在线测试使用](https://xiangyuecn.github.io/Recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.sonic.transform)。此扩展从[Sonic.java](https://github.com/waywardgeek/sonic/blob/71c51195de71627d7443d05378c680ba756545e8/Sonic.java)移植,并做了适当精简。
[sonic.js](https://github.com/xiangyuecn/Recorder/blob/master/src/extensions/sonic.js),37kb大小源码(压缩版gzip后4.5kb),音频变速变调转换,[参考此demo片段在线测试使用](https://xiangyuecn.github.io/Recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.sonic.transform)。此扩展从[Sonic.java](https://github.com/waywardgeek/sonic/blob/71c51195de71627d7443d05378c680ba756545e8/Sonic.java)移植,并做了适当精简。

可到[assets/sonic-java](https://github.com/xiangyuecn/Recorder/tree/master/assets/sonic-java)目录运行java代码测试原版效果。

Expand Down
88 changes: 80 additions & 8 deletions app-support-sample/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,19 @@
<script>
(function(){
//注册可选扩展库
RecordApp.Platforms.Default.Config.paths.push({
var paths=RecordApp.Platforms.Default.Config.paths;
paths.push({
url:PageSet_RecordAppBaseFolder+"extensions/waveview.js"
,check:function(){return !Recorder.WaveView}
});
paths.push({
url:PageSet_RecordAppBaseFolder+"extensions/lib.fft.js"
,check:function(){return !Recorder.LibFFT}
});
paths.push({
url:PageSet_RecordAppBaseFolder+"extensions/frequency.histogram.view.js"
,check:function(){return !Recorder.FrequencyHistogramView}
});

//立即加载环境,自动把Recorder加载进来
RecordApp.Install(function(){
Expand Down Expand Up @@ -122,6 +131,29 @@
background: #f00;
}

.recwaveChoice{
cursor: pointer;
display:inline-block;
vertical-align: bottom;
border-right:1px solid #ccc;
background:#ddd;
line-height:28px;
font-size:13px;
color:#666;
padding:0 5px;
}
.recwaveChoice:first-child{
border-radius: 99px 0 0 99px;
}
.recwaveChoice:last-child{
border-radius: 0 99px 99px 0;
border-right:none;
}
.recwaveChoice.slc,.recwaveChoice:hover{
background:#f60;
color:#fff;
}

.lb{
display:inline-block;
vertical-align: middle;
Expand Down Expand Up @@ -252,6 +284,12 @@
</div>
<div class="pd">
<div style="height:100px;width:300px;border:1px solid #ccc;box-sizing: border-box;display:inline-block" class="recwave"></div>

<span style="font-size:0">
<span class="recwaveChoice" key="WaveView">WaveView</span>
<span class="recwaveChoice" key="Histogram1">Histogram1</span>
<span class="recwaveChoice" key="Histogram2">Histogram2</span>
</span>
</div>
<div class="webrtcBox">
<label><input type="checkbox" class="realTimeSendSet">模拟准实时编码传输(H5版语音通话聊天)</label>
Expand Down Expand Up @@ -406,7 +444,7 @@
var type=$("[name=type]:checked").val();
var bit=+$(".bit").val();
var sample=+$(".sample").val();
var wave;
var waveStore={};

var realTimeSendSet=$(".realTimeSendSet")[0].checked;
var realTimeSendTime=+$(".realTimeSend").val();
Expand All @@ -420,12 +458,20 @@
type:type
,bitRate:bit
,sampleRate:sample
,onProcess:function(buffers,level,time,sampleRate){
$(".recpowerx").css("width",level+"%");
$(".recpowert").text(formatMs(time,1)+" / "+level);
,onProcess:function(buffers,powerLevel,duration,sampleRate){
$(".recpowerx").css("width",powerLevel+"%");
$(".recpowert").text(formatMs(duration,1)+" / "+powerLevel);

wave && wave.input(buffers[buffers.length-1],level,sampleRate);
//可视化图形绘制
if(waveStore[recwaveChoiceKey]){
if(waveStore.choice!=recwaveChoiceKey){
waveStore.choice=recwaveChoiceKey;
$(".recwave").html("").append(waveStore[recwaveChoiceKey].elem);
};
waveStore[recwaveChoiceKey].input(buffers[buffers.length-1],powerLevel,sampleRate);
};

//实时传输
if(realTimeSendSet&&window.realTimeSendTry){
realTimeSendTry(set,realTimeSendTime,buffers,sampleRate);
};
Expand All @@ -436,7 +482,17 @@
curSet=set;
reclog(RecordApp.Current.Key+"已打开:"+type+" "+bit+"kbps");

wave=Recorder.WaveView({elem:".recwave"});
//此处创建这些音频可视化图形绘制浏览器支持妥妥的
waveStore.WaveView=Recorder.WaveView({elem:".recwave"});
waveStore.Histogram1=Recorder.FrequencyHistogramView({elem:".recwave"});
waveStore.Histogram2=Recorder.FrequencyHistogramView({
elem:".recwave"
,position:0
,minHeight:1
,shadowBlur:6
,stripeEnable:false
});

call();
},function(err){
call(RecordApp.Current.Key+"打开失败:"+err);
Expand Down Expand Up @@ -603,8 +659,24 @@
};
reader.readAsDataURL(o.blob);
};


var recwaveChoiceKey=localStorage["RecWaveChoiceKey"]||"WaveView";
$(".recwaveChoice").bind("click",function(e){
var elem=$(e.target);
$(".recwaveChoice").removeClass("slc");
recwaveChoiceKey=elem.addClass("slc").attr("key");
localStorage["RecWaveChoiceKey"]=recwaveChoiceKey;
});
$(".recwaveChoice[key="+recwaveChoiceKey+"]").click();


reclog("点击录制开始哦");
reclog("WaveView Extensions已启用");
var s="https://github.com/xiangyuecn/Recorder/blob/master/src/extensions/";
reclog('已启用Extensions:\
<b>WaveView</b> (<a href="'+s+'waveview.js">waveview.js</a> 音频可视化波形)\
、<b>FrequencyHistogramView</b> (<a href="'+s+'frequency.histogram.view.js">frequency.histogram.view.js</a> + <a href="'+s+'lib.fft.js">lib.fft.js</a> 音频可视化频率直方图)\
');


if(window.top!=window){
Expand Down
8 changes: 4 additions & 4 deletions assets/npm-home/hash-history.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
[
{
"sha1": "c4a7d796fe658b33a012e69650d5663f1b6c7471",
"time": "2020-1-14 03:03:00"
},
{
"sha1": "49a3e316c57542696a81f0d413ffe9c9ea08053a",
"time": "2020-1-10 17:05:41"
Expand All @@ -14,9 +18,5 @@
{
"sha1": "9500379da03792a852263e36703e618e2bb9fd8c",
"time": "2020-1-2 22:15:42"
},
{
"sha1": "c119b8c5637aea481784280c3ef7e91b50e03b4d",
"time": "2020-1-2 22:11:33"
}
]
Binary file added assets/use_histogram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 71 additions & 7 deletions assets/工具-代码运行和静态分发Runtime.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
<title>Recorder代码运行和静态分发工具</title>

<script src="../src/recorder-core.js"></script>
<script src="../src/extensions/lib.fft.js"></script>
<script src="../src/extensions/frequency.histogram.view.js"></script>
<script src="../src/extensions/waveview.js"></script>

<script src="ztest-jquery.min-1.9.1.js"></script>
Expand Down Expand Up @@ -72,6 +74,29 @@
.mainBtn:active{
background: #f00;
}

.recwaveChoice{
cursor: pointer;
display:inline-block;
vertical-align: bottom;
border-right:1px solid #ccc;
background:#ddd;
line-height:28px;
font-size:13px;
color:#666;
padding:0 5px;
}
.recwaveChoice:first-child{
border-radius: 99px 0 0 99px;
}
.recwaveChoice:last-child{
border-radius: 0 99px 99px 0;
border-right:none;
}
.recwaveChoice.slc,.recwaveChoice:hover{
background:#f60;
color:#fff;
}
</style>
</head>

Expand All @@ -97,9 +122,17 @@
<div class="mainBox mainCtrl" style="display:none">
<div style="padding-bottom:12px">
<div style="height:100px;width:300px;border:1px solid #ccc;box-sizing: border-box;display:inline-block;vertical-align:bottom" class="ctrlProcessWave"></div>
<div style="height:40px;width:300px;display:inline-block;background:#999;position:relative;vertical-align:bottom">
<div class="ctrlProcessX" style="height:40px;background:#0B1;position:absolute;"></div>
<div class="ctrlProcessT" style="padding-left:50px; line-height:40px; position: relative;"></div>
<div style="width:300px;display:inline-block;vertical-align:bottom">
<div style="height:40px;width:300px;display:inline-block;background:#999;position:relative;margin-bottom:12px">
<div class="ctrlProcessX" style="height:40px;background:#0B1;position:absolute;"></div>
<div class="ctrlProcessT" style="padding-left:50px; line-height:40px; position: relative;"></div>
</div>

<span style="font-size:0">
<span class="recwaveChoice" key="WaveView">WaveView</span>
<span class="recwaveChoice" key="Histogram1">Histogram1</span>
<span class="recwaveChoice" key="Histogram2">Histogram2</span>
</span>
</div>
</div>

Expand Down Expand Up @@ -144,7 +177,9 @@
<script>
(function(){
var WaveViewBak=Recorder.WaveView;
var ProcessWaveView;
var LibFFTBak=Recorder.LibFFT;
var FrequencyHistogramViewBak=Recorder.FrequencyHistogramView;
var WaveStore;
var LogAudios=[0];

window.NOOP=function(){};
Expand Down Expand Up @@ -206,14 +241,31 @@

,Process:function(buffers,powerLevel,bufferDuration,bufferSampleRate){
Recorder.WaveView=WaveViewBak;
if(!ProcessWaveView){
ProcessWaveView=Recorder.WaveView({elem:".ctrlProcessWave"});
Recorder.LibFFT=LibFFTBak;
Recorder.FrequencyHistogramView=FrequencyHistogramViewBak;
var waveStore=WaveStore;
if(!waveStore){
waveStore=WaveStore={};
waveStore.WaveView=Recorder.WaveView({elem:".ctrlProcessWave"});
waveStore.Histogram1=Recorder.FrequencyHistogramView({elem:".ctrlProcessWave"});
waveStore.Histogram2=Recorder.FrequencyHistogramView({
elem:".ctrlProcessWave"
,position:0
,minHeight:1
,shadowBlur:6
,stripeEnable:false
});
};

$(".ctrlProcessX").css("width",powerLevel+"%");
$(".ctrlProcessT").text(formatMs(bufferDuration,1)+" / "+powerLevel);

ProcessWaveView.input(buffers[buffers.length-1],powerLevel,bufferSampleRate);
//可视化图形绘制
if(waveStore.choice!=recwaveChoiceKey){
waveStore.choice=recwaveChoiceKey;
$(".ctrlProcessWave").html("").append(waveStore[recwaveChoiceKey].elem);
};
waveStore[recwaveChoiceKey].input(buffers[buffers.length-1],powerLevel,bufferSampleRate);
}

,DecodeAudio:function(fileName,arrayBuffer,True,False){
Expand Down Expand Up @@ -279,6 +331,18 @@
+("00"+ms%1000).substr(-3);
return s;
};


var recwaveChoiceKey=localStorage["RecWaveChoiceKey"]||"WaveView";
$(".recwaveChoice").bind("click",function(e){
var elem=$(e.target);
$(".recwaveChoice").removeClass("slc");
recwaveChoiceKey=elem.addClass("slc").attr("key");
localStorage["RecWaveChoiceKey"]=recwaveChoiceKey;
});
$(".recwaveChoice[key="+recwaveChoiceKey+"]").click();


$(window).bind("error",function(e){
Runtime.Log('【Error】:<pre>'+(e.error?e.error.stack:event.message)+'</pre>',1);
});
Expand Down
6 changes: 6 additions & 0 deletions dist/extensions/frequency.histogram.view.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions dist/extensions/lib.fft.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e5b1447

Please sign in to comment.