Skip to content

Commit

Permalink
Encode after record
Browse files Browse the repository at this point in the history
Added new config param: encodeAfterRecord (closeio#13)
Updated sample to show this feature too
  • Loading branch information
Maciej Kubiak committed Aug 9, 2020
1 parent 5cd2ad7 commit dc7aa88
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 16 deletions.
37 changes: 31 additions & 6 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15816,20 +15816,25 @@ var MicRecorder = function () {
// 128 or 160 kbit/s – mid-range bitrate quality
bitRate: 128,

deviceId: null,
// Encode to mp3 after finish recording
// Encoding during recording may result in distorted audio
// This could be crucial on mobile devices
encodeAfterRecord: true,
// There is a known issue with some macOS machines, where the recording
// will sometimes have a loud 'pop' or 'pop-click' sound. This flag
// prevents getting audio from the microphone a few milliseconds after
// the begining of the recording. It also helps to remove the mouse
// the beginning of the recording. It also helps to remove the mouse
// "click" sound from the output mp3 file.
startRecordingAt: 300,
deviceId: null
startRecordingAt: 300
};

this.activeStream = null;
this.context = null;
this.microphone = null;
this.processor = null;
this.startTime = 0;
this.rawChunksBuffer = null;

Object.assign(this.config, config);
}
Expand Down Expand Up @@ -15864,8 +15869,15 @@ var MicRecorder = function () {
return;
}

// Send microphone data to LAME for MP3 encoding while recording.
_this.lameEncoder.encode(event.inputBuffer.getChannelData(0));
var rawChunk = event.inputBuffer.getChannelData(0);

if (_this.config.encodeAfterRecord) {
// Save copy of raw chunk for future encoding
_this.rawChunksBuffer.push(Object.assign([], rawChunk));
} else {
// Send microphone data to LAME for MP3 encoding while recording.
_this.lameEncoder.encode(rawChunk);
}
};

this.connectMicrophone();
Expand All @@ -15881,12 +15893,18 @@ var MicRecorder = function () {
value: function initialize() {
var _this2 = this;

var _config = this.config,
deviceId = _config.deviceId,
encodeAfterRecord = _config.encodeAfterRecord;

var AudioContext = window.AudioContext || window.webkitAudioContext;
this.context = new AudioContext();
this.config.sampleRate = this.context.sampleRate;
this.rawChunksBuffer = encodeAfterRecord ? [] : null;
this.lameEncoder = new Encoder(this.config);
this.i = 0;

var audio = this.config.deviceId ? { deviceId: { exact: this.config.deviceId } } : true;
var audio = deviceId ? { deviceId: { exact: deviceId } } : true;

return new Promise(function (resolve, reject) {
navigator.mediaDevices.getUserMedia({ audio: audio }).then(function (stream) {
Expand Down Expand Up @@ -15993,6 +16011,13 @@ var MicRecorder = function () {
value: function getMp3() {
var _this3 = this;

if (this.config.encodeAfterRecord) {
this.rawChunksBuffer.forEach(function (rawChunk) {
_this3.lameEncoder.encode(rawChunk);
});
this.rawChunksBuffer = null;
}

var finalBuffer = this.lameEncoder.finish();

return new Promise(function (resolve, reject) {
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

24 changes: 21 additions & 3 deletions samples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ <h1>Mic Recorder to Mp3 Example</h1>

<hr />

<div title="Warning: Disable this option can cause audio distortion">
<input id="encode-after-record" type="checkbox" checked>
Encode after record
</div>

<br />
<br />

<button id="start-pause" class="btn btn-primary"></button>
<button id="stop" class="btn btn-danger" disabled></button>

Expand All @@ -33,20 +41,29 @@ <h1>Mic Recorder to Mp3 Example</h1>
STOP: 'Stop recording'
};

const encodeAfterRecordCheck = document.getElementById('encode-after-record');
const startPauseButton = document.getElementById('start-pause');
const stopButton = document.getElementById('stop');
const recorder = new MicRecorder({
bitRate: 128
});
let recorder
initRecorder()

startPauseButton.textContent = LABELS.START;
stopButton.textContent = LABELS.STOP;

encodeAfterRecordCheck.addEventListener('change', initRecorder)
startPauseButton.addEventListener('click', startRecording);
stopButton.addEventListener('click', stopRecording);

function initRecorder() {
recorder = new MicRecorder({
bitRate: 128,
encodeAfterRecordCheck: encodeAfterRecordCheck.checked
});
}

function startRecording() {
recorder.start().then(() => {
encodeAfterRecordCheck.disabled = true;
startPauseButton.textContent = LABELS.PAUSE;
startPauseButton.classList.add('btn-info');
stopButton.disabled = false;
Expand All @@ -71,6 +88,7 @@ <h1>Mic Recorder to Mp3 Example</h1>
function stopRecording() {
recorder.stop().getMp3().then(([buffer, blob]) => {
console.log(buffer, blob);
encodeAfterRecordCheck.disabled = false;
stopButton.disabled = true;
const file = new File(buffer, 'music.mp3', {
type: blob.type,
Expand Down
2 changes: 1 addition & 1 deletion src/encoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,6 @@ class Encoder {

return this.dataBuffer;
}
};
}

export default Encoder;
32 changes: 27 additions & 5 deletions src/mic-recorder.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,25 @@ class MicRecorder {
// 128 or 160 kbit/s – mid-range bitrate quality
bitRate: 128,

deviceId: null,
// Encode to mp3 after finish recording
// Encoding during recording may result in distorted audio
// This could be crucial on mobile devices
encodeAfterRecord: true,
// There is a known issue with some macOS machines, where the recording
// will sometimes have a loud 'pop' or 'pop-click' sound. This flag
// prevents getting audio from the microphone a few milliseconds after
// the begining of the recording. It also helps to remove the mouse
// the beginning of the recording. It also helps to remove the mouse
// "click" sound from the output mp3 file.
startRecordingAt: 300,
deviceId: null,
};

this.activeStream = null;
this.context = null;
this.microphone = null;
this.processor = null;
this.startTime = 0;
this.rawChunksBuffer = null;

Object.assign(this.config, config);
}
Expand Down Expand Up @@ -48,8 +53,15 @@ class MicRecorder {
return;
}

// Send microphone data to LAME for MP3 encoding while recording.
this.lameEncoder.encode(event.inputBuffer.getChannelData(0));
const rawChunk = event.inputBuffer.getChannelData(0);

if (this.config.encodeAfterRecord) {
// Save copy of raw chunk for future encoding
this.rawChunksBuffer.push( Object.assign([], rawChunk));
} else {
// Send microphone data to LAME for MP3 encoding while recording.
this.lameEncoder.encode(rawChunk);
}
};

this.connectMicrophone();
Expand All @@ -60,12 +72,15 @@ class MicRecorder {
* @return Promise
*/
initialize() {
const { deviceId, encodeAfterRecord } = this.config;
const AudioContext = window.AudioContext || window.webkitAudioContext;
this.context = new AudioContext();
this.config.sampleRate = this.context.sampleRate;
this.rawChunksBuffer = encodeAfterRecord ? [] : null;
this.lameEncoder = new Encoder(this.config);
this.i = 0;

const audio = this.config.deviceId ? { deviceId: { exact: this.config.deviceId } } : true;
const audio = deviceId ? { deviceId: { exact: deviceId } } : true;

return new Promise((resolve, reject) => {
navigator.mediaDevices.getUserMedia({ audio })
Expand Down Expand Up @@ -151,6 +166,13 @@ class MicRecorder {
* @return Promise
*/
getMp3() {
if (this.config.encodeAfterRecord) {
this.rawChunksBuffer.forEach((rawChunk) => {
this.lameEncoder.encode(rawChunk);
})
this.rawChunksBuffer = null;
}

const finalBuffer = this.lameEncoder.finish();

return new Promise((resolve, reject) => {
Expand Down

0 comments on commit dc7aa88

Please sign in to comment.