webdaw-modules
Version:
a set of modules for building a web-based DAW
220 lines (177 loc) • 7.06 kB
JavaScript
function audioEncoder() {
'use strict';
var
self,
importScripts,
Lame,
// import
encode64, // defined in util.js
base64EncArr, // defined in util.js
context, // defined in open_module.js
oggEncoder,
mp3Encoder;
function encodeAudio(audioBuffer, type, bitrate, callback) {
if (type === 'mp3') {
var interleavedSamples = getInterleavedSamples(audioBuffer);
bitrate = bitrate || sequencer.bitrate_mp3_encoding; //kbps
if (mp3Encoder === undefined) {
mp3Encoder = createWorker();
mp3Encoder.onmessage = function (e) {
if (e.data.cmd === 'data') {
//console.log(e);
callback({
blob: new Blob([new Uint8Array(e.data.buf)], { type: 'audio/mp3' }),
base64: base64EncArr(e.data.buf),
dataUrl: 'data:audio/mp3;base64,' + encode64(e.data.buf)
});
}
};
}
mp3Encoder.postMessage({
cmd: 'init',
config: {
mode: 3,
channels: 1,
samplerate: context.sampleRate,
bitrate: bitrate
}
});
mp3Encoder.postMessage({
cmd: 'encode',
buf: interleavedSamples
});
mp3Encoder.postMessage({
cmd: 'finish'
});
} else if (type === 'ogg') {
if (sequencer.debug >= sequencer.WARN) {
console.warn('support for ogg is not yet implemented');
}
callback(false);
} else {
if (sequencer.debug >= sequencer.WARN) {
console.warn('unsupported type', type);
}
callback(false);
}
}
function getInterleavedSamples(audioBuffer) {
if (audioBuffer.numberOfChannels === 1) {
return audioBuffer.getChannelData(0);
}
if (audioBuffer.numberOfChannels === 2) {
var left = audioBuffer.getChannelData(0),
right = audioBuffer.getChannelData(1),
numFrames = left.length,
interleaved = new Float32Array(numFrames),
i, index = 0;
for (i = 0; i < numFrames; i++) {
interleaved[index++] = left[i];
interleaved[index++] = right[i];
}
return interleaved;
}
}
function cleanUp() {
if (mp3Encoder !== undefined) {
mp3Encoder.terminate();
}
if (oggEncoder !== undefined) {
oggEncoder.terminate();
}
}
// credits: https://nusofthq.com/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/
function encoder() {
/*
credits:
https://github.com/akrennmair/libmp3lame-js/
https://github.com/kobigurk/libmp3lame-js
*/
importScripts('https://raw.githubusercontent.com/kobigurk/libmp3lame-js/master/dist/libmp3lame.min.js');
//importScripts('/heartbeat/src/kobigurk/libmp3lame.min.js');
var mp3codec,
mp3data;
self.onmessage = function (e) {
switch (e.data.cmd) {
case 'init':
if (!e.data.config) {
e.data.config = {};
}
mp3codec = Lame.init();
Lame.set_mode(mp3codec, e.data.config.mode || Lame.JOINT_STEREO);
Lame.set_num_channels(mp3codec, e.data.config.channels || 2);
Lame.set_num_samples(mp3codec, e.data.config.samples || -1);
Lame.set_in_samplerate(mp3codec, e.data.config.samplerate || 44100);
Lame.set_out_samplerate(mp3codec, e.data.config.samplerate || 44100);
Lame.set_bitrate(mp3codec, e.data.config.bitrate || 128);
Lame.init_params(mp3codec);
/*
console.log('Version :'+ Lame.get_version() + ' / ' +
'Mode: ' + Lame.get_mode(mp3codec) + ' / ' +
'Samples: ' + Lame.get_num_samples(mp3codec) + ' / ' +
'Channels: ' + Lame.get_num_channels(mp3codec) + ' / ' +
'Input Samplate: ' + Lame.get_in_samplerate(mp3codec) + ' / ' +
'Output Samplate: ' + Lame.get_in_samplerate(mp3codec) + ' / ' +
'Bitlate :' + Lame.get_bitrate(mp3codec) + ' / ' +
'VBR :' + Lame.get_VBR(mp3codec));
*/
break;
case 'encode':
//console.log('encode');
mp3data = Lame.encode_buffer_ieee_float(mp3codec, e.data.buf, e.data.buf);
self.postMessage({ cmd: 'data', buf: mp3data.data });
break;
case 'finish':
//console.log('finish');
mp3data = Lame.encode_flush(mp3codec);
self.postMessage({ cmd: 'end', buf: mp3data.data });
Lame.close(mp3codec);
mp3codec = null;
break;
}
};
}
function createWorker() {
var blob = new Blob(['(', encoder.toString(), ')()'], { type: 'application/javascript' });
return new Worker(URL.createObjectURL(blob));
}
sequencer.encodeAudio = encodeAudio;
sequencer.protectedScope.cleanupAudioEncoder = cleanUp;
sequencer.protectedScope.addInitMethod(function () {
encode64 = sequencer.util.encode64;
base64EncArr = sequencer.util.base64EncArr;
context = sequencer.protectedScope.context;
});
}
/*
//not needed anymore because we use AudioBuffer for input
function parseWav(wav) {
function readInt(i, bytes) {
var ret = 0,
shft = 0;
while (bytes) {
ret += wav[i] << shft;
shft += 8;
i++;
bytes--;
}
return ret;
}
if (readInt(20, 2) != 1) throw 'Invalid compression code, not PCM';
if (readInt(22, 2) != 1) throw 'Invalid number of channels, not 1';
return {
sampleRate: readInt(24, 4),
bitsPerSample: readInt(34, 2),
samples: wav.subarray(44)
};
}
function convertUint8ArrayToFloat32Array(u8a){
var f32Buffer = new Float32Array(u8a.length);
for (var i = 0; i < u8a.length; i++) {
var value = u8a[i<<1] + (u8a[(i<<1)+1]<<8);
if (value >= 0x8000) value |= ~0x7FFF;
f32Buffer[i] = value / 0x8000;
}
return f32Buffer;
}
*/