mattdiamond / Recorderjs

A plugin for recording/exporting the output of Web Audio API nodes
4.16k stars 1.46k forks source link

how can i change the sampleRate? #186

Closed cmdedj closed 4 years ago

cmdedj commented 6 years ago

such as i want to change the sampleRate from 44100 to 16000

octavn commented 6 years ago

The sample rate is dictated by your browser/OS/microphone.

Recorder.js will record at whatever sample rate is supported by your browser/OS/mic. You’ll most commonly see 44.1 kHz and 48kHz audio recordings but I've seen 16kHz as well.

This Recorder.js demo shows the sample rate in real time.

cmdedj commented 6 years ago

@octavn i know your mean, but i want to change the code to change the sample. i had try it, but i false.now i want to change the default sample.

YoungSx commented 6 years ago

@cmdedj 我感觉可以参考一下这篇文章,魔改了一下Recorder.js http://www.cnblogs.com/blqw/p/3782420.html 或许用 OfflineAudioContext 可以尝试一下?

octavn commented 6 years ago

After more digging I've found the default sample rate is the one set in your OS for your playback device (as per the spec and this comment from a Chrome developer)

cmdedj commented 6 years ago

@octavn i know the default sample rate is by device, now can i by change the js code to change the default sample rate? now i transfer the wav file to backend and change the sample rate by sox.http://sox.sourceforge.net/. but i don't want to handle the sample rate on backend, i want to change it on web frontend.

ilikerei commented 6 years ago

Before calling encodeWav(), resample the buffer to change sample rate:

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);
                     // Use average value of skipped samples
                    var accum = 0, count = 0;
                    for (var i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i++) {
                        accum += buffer[i];
                        count++;
                    }
                    result[offsetResult] = accum / count;
                    // Or you can simply get rid of the skipped samples:
                    // result[offsetResult] = buffer[nextOffsetBuffer];
                    offsetResult++;
                    offsetBuffer = nextOffsetBuffer;
                }
                return result;
            }

Then call encodeWav with the new sample buffer:

var downsampledBuffer = downsampleBuffer(interleaved, targetRate);
var dataview = encodeWAV(downsampledBuffer);

Also, use new sample rate when encoding:

/* sample rate */
view.setUint32(24, newRate, true);
/* byte rate (sample rate * block align) */
view.setUint32(28, newRate * 4, true);
losymear commented 5 years ago

@ilikerei Thanks, your code works well! But how can I change sampleRate to 8000? Because my browser sample rate varies, sometimes it is 44100 and sometimes it can be 8000, so I have to change the sampleRate to 8000 uniformly. I don't know how your code works, can you explain it clearly or show some docs for this?

ilikerei commented 5 years ago

@losymear Just change targetRate to 8000 when you call downsampleBuffer(interleaved, 8000) Also: /* sample rate */ view.setUint32(24, 8000, true); /* byte rate (sample rate * block align) */ view.setUint32(28, 8000 * 4, true);

The code reduces samples based on rate ratio. For example, 16000->8000, the code generate a new sample buffer by using average value of every 2 samples (Or you can simple get rid of 1 of every 2 samples). So the buffer size is 8000/16000 = 1/2

AniketBhadane commented 4 years ago

@losymear Just change targetRate to 8000 when you call downsampleBuffer(interleaved, 8000) Also: /* sample rate */ view.setUint32(24, 8000, true); /* byte rate (sample rate * block align) */ view.setUint32(28, 8000 * 4, true);

The code reduces samples based on rate ratio. For example, 16000->8000, the code generate a new sample buffer by using average value of every 2 samples (Or you can simple get rid of 1 of every 2 samples). So the buffer size is 8000/16000 = 1/2

Please can you tell where to include this code? Seems like encodeWAV is an internal method of the library. The readme just mentions rec.exportWAV([callback][, type]). I'm using npm to add the library to my project. So does your solution mean modifying the library's code instead of taking it from npm?

ArunMeghanathan97 commented 3 years ago

@ilikerei Thank you, your code works well. ):

sophister commented 3 months ago

Before calling encodeWav(), resample the buffer to change sample rate:

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);
                     // Use average value of skipped samples
                    var accum = 0, count = 0;
                    for (var i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i++) {
                        accum += buffer[i];
                        count++;
                    }
                    result[offsetResult] = accum / count;
                    // Or you can simply get rid of the skipped samples:
                    // result[offsetResult] = buffer[nextOffsetBuffer];
                    offsetResult++;
                    offsetBuffer = nextOffsetBuffer;
                }
                return result;
            }

Then call encodeWav with the new sample buffer:

var downsampledBuffer = downsampleBuffer(interleaved, targetRate);
var dataview = encodeWAV(downsampledBuffer);

Also, use new sample rate when encoding:

/* sample rate */
view.setUint32(24, newRate, true);
/* byte rate (sample rate * block align) */
view.setUint32(28, newRate * 4, true);

@ilikerei good job, it works well.

And for anyone comes in to this issue, I've forked this repo and add the sample changing behavior using the above code. Also add a TypeScript definition file for it.

https://github.com/sophister/recorderjs-ex