折腾:
【已解决】用Recorderjs实现js录音保存为wav格式
后,虽然可以正常录音和下载wav,但是wav文件太大:
3秒就要600多KB,所以去优化看看:
(估计默认是44100)-〉降低sample rate看看
对于要设置sample rate为多少,参考:
【已解决】web端html+js中如何调用麦克风获取用户语音输入说话
中的:
“Content-type: The Content-type field describes the format and codec of the audio stream. Currently, only WAV file and PCM Mono 16000 encoding is supported. The Content-type value for this format is audio/wav; codec=audio/pcm; samplerate=16000”
应该是设置为:
采样率:16000=16k
声道数量:1 -》 单声道=mono
去找找如何配置sample rate:
https://github.com/mattdiamond/Recorderjs
和:
搜索源码:sampleRate

但是看到:

好像不支持sampleRate的配置?
去试试代码
<code> recorderConfig = {
sampleRate: 16000
}
gRecorder = new Recorder(input, recorderConfig)
</code>结果:
好像是没用的:
3秒左右还是要600多KB

而百度的:
http://ai.baidu.com/docs#/ASR-API/top
-》
16000=16K采样率的wav,4秒,(估计是mono 单声道)才130KB:

-》微软的wav也是:单声道,16000采样率
此处,感觉是:
441000的采样率,然后还是双声道,3秒要600多KB
此处看看,能否修改源码,实现直接设置
16000
单声道
貌似js库中,可以直接去修改

config的numChannels,从2改为1:
<code>var Recorder = exports.Recorder = (function () {
...
this.config = {
bufferLen: 4096,
numChannels: 1,
mimeType: 'audio/wav'
};
</code>
看看效果
同时,注意到:
此处的
.sampleRate
好像是:
worker中的.sampleRate:

是调用了:
config中的.sampleRate

所以后续还可以继续去试试:
给config中添加sampleRate,设置为16000,再看看效果
先去看看
numChannels从2变1
效果如何:
但是为何初始化后,还是2啊:

<code>audioContext= AudioContext {baseLatency: 0.005804988662131519, destination: AudioDestinationNode, currentTime: 0, sampleRate: 44100, listener: AudioListener, …}audioWorklet: AudioWorklet {}baseLatency: 0.005804988662131519currentTime: 31.759092970521543destination: AudioDestinationNode {maxChannelCount: 2, context: AudioContext, numberOfInputs: 1, numberOfOutputs: 0, channelCount: 2, …}listener: AudioListener {positionX: AudioParam, positionY: AudioParam, positionZ: AudioParam, forwardX: AudioParam, forwardY: AudioParam, …}onstatechange: nullsampleRate: 44100state: "running"__proto__: AudioContext
main.js:412 input= MediaStreamAudioSourceNode {mediaStream: MediaStream, context: AudioContext, numberOfInputs: 0, numberOfOutputs: 1, channelCount: 2, …}channelCount: 2channelCountMode: "max"channelInterpretation: "speakers"context: AudioContextaudioWorklet: AudioWorklet {}baseLatency: 0.005804988662131519currentTime: 47.74022675736961destination: AudioDestinationNode {maxChannelCount: 2, context: AudioContext, numberOfInputs: 1, numberOfOutputs: 0, channelCount: 2, …}listener: AudioListener {positionX: AudioParam, positionY: AudioParam, positionZ: AudioParam, forwardX: AudioParam, forwardY: AudioParam, …}onstatechange: nullsampleRate: 44100state: "running"__proto__: AudioContextmediaStream: MediaStream {id: "IC5UKcx2fJRq5xk0sk5iYnaq1gByya9aQcYl", active: true, onaddtrack: null, onremovetrack: null, onactive: null, …}numberOfInputs: 0numberOfOutputs: 1__proto__: MediaStreamAudioSourceNode
main.js:417 gRecorder= Recorder {config: {…}, recording: false, callbacks: {…}, context: AudioContext, node: ScriptProcessorNode, …}
</code>

先试试结果:
好像真的是降低一半大小了,3秒左右,300多KB了:

而再去看代码:

好像这处:
<code>var Recorder = exports.Recorder = (function () {
function Recorder(source, cfg) {
...
this.config = {
bufferLen: 4096,
//numChannels: 2,
numChannels: 1,
mimeType: 'audio/wav'
};
...
Object.assign(this.config, cfg);
</code>是可以支持传入的参数中包含我们希望的:
numChannels
sampleRate
-》所以去把直接修改库
Recorderjs/recorder.js
中的config的numChannels的做法,还原:

放到调用代码中:
<code> var recorderConfig = {
sampleRate: 16000,
numChannels: 1
}
gRecorder = new Recorder(input, recorderConfig)
</code>-》同时发现,之前代码是:
recorderConfig = {
好像缺少了个var
此处加上了
-〉那干脆单独试试之前的:
<code>recorderConfig = {
sampleRate: 16000
}
console.log("recorderConfig=", recorderConfig)
gRecorder = new Recorder(input, recorderConfig)
</code>看看log是啥,是否是正常的js的变量

-》说明之前没有加var也是对的。
那么现在就可以去:
先单独试试numChannels
<code> var recorderConfig = {
// sampleRate: 16000,
numChannels: 1
}
</code>结果:

去录音看看:

是对的:3秒只有300多KB了
-》numChannels是可以通过调用参数config去传递进去的
同理,再去加上sampleRate:
<code> var recorderConfig = {
sampleRate: 16000,
numChannels: 1
}
console.log("recorderConfig=", recorderConfig)
gRecorder = new Recorder(input, recorderConfig)
</code>结果:
5秒,只有500多KB

以及:
4秒-》400多KB

-〉感觉只有单声道使得wav大小降低了
-》而sampleRate从44100变成16000,好像没啥变化啊
-〉还是sampleRate根本就没生效?
-》
同样的:
单声道
采样率 16000
-〉
百度的wav示例:4秒-〉130KB

而我们的:4秒-〉400KB
相差3倍左右
-》好像就是 44100 和16000的3倍关系
-〉很像是sampleRate设置16000作为config,传递进去,没有起效果。
试试,手动去:
Recorderjs/recorder.js
改为16k:
<code>var Recorder = exports.Recorder = (function () {
function Recorder(source, cfg) {
...
this.config = {
bufferLen: 4096,
sampleRate: 16000,
numChannels: 2,
mimeType: 'audio/wav'
};
</code>
结果:
log中看到:

<code>1. AudioContext
1. audioWorklet:AudioWorklet {}
2. baseLatency:0.005804988662131519
3. currentTime:6.3854875283446715
4. destination:AudioDestinationNode {maxChannelCount: 2, context: AudioContext, numberOfInputs: 1, numberOfOutputs: 0, channelCount: 2, …}
5. listener:AudioListener {positionX: AudioParam, positionY: AudioParam, positionZ: AudioParam, forwardX: AudioParam, forwardY: AudioParam, …}
6. onstatechange:null
7. sampleRate:44100
8. state:"running"
1. config:
1. bufferLen:4096
2. mimeType:"audio/wav"
3. numChannels:1
4. sampleRate:16000
</code>即:
config的sampleRate是16000
AudioContext的sampleRate是44100
-》先去运行看看效果
4秒-〉近400KB

好像也不对
不行的话:
直接给worker设置sampleRate为16000,看看效果如何
再去找找,如何改变AudioContext的(初始化时的)sampleRate
或者说是sampleRate生效了,但是Recorderjs内部的算法有问题?
recorder js sample rate not work
How to Reduce wav File-size created by Recorder.js · Issue #53 · mattdiamond/Recorderjs
改为:
<code> function encodeWAV(samples) {
...
/* byte rate (sample rate * block align) */
//view.setUint32(28, sampleRate * 4, true);
// fixbug from https://github.com/mattdiamond/Recorderjs/issues/53
view.setUint32(28, sampleRate * numChannels * 2, true);
</code>效果是:
3秒-》300多KB

没啥区别。
html5 – Decrease bitrate on WAV file created with recorderjs – Stack Overflow
试试:
<code> // function exportWAV(type) {
// var buffers = [];
// for (var channel = 0; channel < numChannels; channel++) {
// buffers.push(mergeBuffers(recBuffers[channel], recLength));
// }
// var interleaved = undefined;
// if (numChannels === 2) {
// interleaved = interleave(buffers[0], buffers[1]);
// } else {
// interleaved = buffers[0];
// }
// var dataview = encodeWAV(interleaved);
// var audioBlob = new Blob([dataview], { type: type });
// self.postMessage({ command: 'exportWAV', data: audioBlob });
// }
function downsampleBuffer(buffer, rate) {
if (rate == sampleRate) {
return buffer;
}
if (rate > sampleRate) {
throw "downsampling rate show be smaller than original sample rate";
}
var sampleRateRatio = sampleRate / rate;
var newLength = Math.round(buffer.length / sampleRateRatio);
var result = new Float32Array(newLength);
var offsetResult = 0;
var offsetBuffer = 0;
while (offsetResult < result.length) {
var nextOffsetBuffer = Math.round((offsetResult + 1) * sampleRateRatio);
var accum = 0, count = 0;
for (var i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i++) {
accum += buffer[i];
count++;
}
result[offsetResult] = accum / count;
offsetResult++;
offsetBuffer = nextOffsetBuffer;
}
return result;
}
function exportWAV(rate, type) {
var bufferL = mergeBuffers(recBuffersL, recLength);
var bufferR = mergeBuffers(recBuffersR, recLength);
var interleaved = interleave(bufferL, bufferR);
var downsampledBuffer = downsampleBuffer(interleaved, rate);
var dataview = encodeWAV(rate, downsampledBuffer, false);
var audioBlob = new Blob([ dataview ], {
type : type
});
// this.postMessage(audioBlob);
self.postMessage({ command: 'exportWAV', data: audioBlob });
}
</code>结果:
出错:
<code>Uncaught ReferenceError: recBuffersL is not defined at exportWAV (blob:null/46831f77-b9a5-4626-a42b-646c1000843a:86) at self.onmessage (blob:null/46831f77-b9a5-4626-a42b-646c1000843a:16) exportWAV @ blob:null/46831f77-b9a5-4626-a42b-646c1000843a:86 self.onmessage @ blob:null/46831f77-b9a5-4626-a42b-646c1000843a:16 </code>
Changing the bitrate and recording the mono wav files · Issue #40 · mattdiamond/Recorderjs
recorder-worker.js in pubnub-api | source code search engine
javascript – Change sample rate of AudioContext (getUserMedia) – Stack Overflow
去试试
<code> var input = audioContext.createMediaStreamSource(mediaStream)
console.log("input=", input)
var resampler = new Resampler(44100, 16000)
input.connect(resampler)
var recorderConfig = {
sampleRate: 16000,
numChannels: 1
}
console.log("recorderConfig=", recorderConfig)
gRecorder = new Recorder(input, recorderConfig)
</code>结果:
和我猜的一样,找不到Resampler:
<code>Try getUserMedia error: ReferenceError: Resampler is not defined at testRecorderjs (main.js:414) at onSuccessGetUserMedia (main.js:468) </code>
然后对于上面的:recBuffersL
突然有点看懂了:
好像就是自己去加上:
recBuffersL
和:
recBuffersR
<code> this.worker = new _inlineWorker2.default(function () {
var recLength = 0,
recBuffers = [],
recBuffersL = [],
recBuffersR = [],
sampleRate = undefined,
numChannels = undefined;
</code>
估计就可以了:
但是发现:
估计也不对:
因为代码里还有其他地方调用了之前的:recBuffers呢。
先去试试看看
果然不对:

需要改很多代码:
保存时,要传递参数才行?
Highest Voted ‘recorder.js’ Questions – Stack Overflow
-》
https://stackoverflow.com/questions/16296645/decrease-bitrate-on-wav-file-created-with-recorderjs
然后注意到了:
有人去问:
“How to have recBuffersL and recBuffersR in your function? – Minh-Hung Nguyen Jul 27 ’15 at 0:09”
那人回复:
“They are attributes in recorderWorker.js. Be careful, there’s a new version of Recorder.js and now the number of channels is configurable recBuffers = [], you will have to adapt my solution if you use this version of the library. ”
但是不知道如何修改啊
javascript – record audio from user and save to server – Stack Overflow
通过调试发现:
<code> function encodeWAV(samples) {
console.log("encodeWAV: numChannels=", numChannels, ", sampleRate=", sampleRate)
</code>输出:

然后就好办了,去搞清楚,sampleRate为何不是此处设置的16000
AudioContext config sampleRate
AudioContext config sample Rate
先去试试前面的:
https://github.com/taisel/XAudioJS/blob/master/resampler.js
加进来试试
结果报错:
<code>main.js:483 Try getUserMedia error: Error: inputBuffer is not an object. at new Resampler (resampler.js:14) at testRecorderjs (main.js:413) at onSuccessGetUserMedia (main.js:467) </code>
好像是少了?
resampler.connect(audioContext.destination)
加上:
<code> var audioContext = new AudioContext()
console.log("audioContext=", audioContext)
var input = audioContext.createMediaStreamSource(mediaStream)
console.log("input=", input)
var resampler = new Resampler(44100, 16000)
console.log("resampler=", resampler)
input.connect(resampler)
resampler.connect(audioContext.destination)
var recorderConfig = {
sampleRate: 16000,
numChannels: 1
}
console.log("recorderConfig=", recorderConfig)
gRecorder = new Recorder(input, recorderConfig)
console.log("gRecorder=", gRecorder)
</code>结果:
错误依旧。
直接设置:
<code>var audioContext = new AudioContext()
console.log("audioContext=", audioContext)
audioContext.sampleRate = 16000
</code>结果:
没用。还是44100。
Uncaught ReferenceError: recBuffersL is not defined
recBuffersL is not defined
暂时先不继续优化了:
等后期:
语音识别接口无法识别此处wav
觉得wav的确太大了,的确需要优化时
再去优化
转载请注明:在路上 » 【暂未解决】去优化Recorderjs降低生成的wav文件大小