最新消息:20210917 已从crifan.com换到crifan.org

【暂未解决】去优化Recorderjs降低生成的wav文件大小

JS crifan 2703浏览 0评论

折腾:

【已解决】用Recorderjs实现js录音保存为wav格式

后,虽然可以正常录音和下载wav,但是wav文件太大:

3秒就要600多KB,所以去优化看看:

(估计默认是44100)-〉降低sample rate看看

对于要设置sample rate为多少,参考:

【已解决】web端html+js中如何调用麦克风获取用户语音输入说话

中的:

https://docs.microsoft.com/zh-cn/azure/cognitive-services/Speech/getstarted/getstartedrest?tabs=Powershell

“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 &lt; 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 &gt; 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 &lt; result.length) {
                    var nextOffsetBuffer = Math.round((offsetResult + 1) * sampleRateRatio);
                    var accum = 0, count = 0;
                    for (var i = offsetBuffer; i &lt; nextOffsetBuffer &amp;&amp; i &lt; 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文件大小

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
96 queries in 0.214 seconds, using 20.10MB memory