Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

<script src="js/audiodisplay.js"></script>
<script src="js/recorderjs/recorder.js"></script>
<script src="js/recorderjs/recorderWorker.js"></script>
<script src="js/main.js"></script>
<style>
html { overflow: hidden; }
Expand Down Expand Up @@ -69,4 +70,4 @@
<a id="save" href="#"><img src="img/save.svg"></a>
</div>
</body>
</html>
</html>
18 changes: 11 additions & 7 deletions js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

window.AudioContext = window.AudioContext || window.webkitAudioContext;

var audioContext = new AudioContext();
var audioContext = null;
var audioInput = null,
realAudioInput = null,
inputPoint = null,
Expand Down Expand Up @@ -62,6 +62,7 @@ function toggleRecording( e ) {
// start recording
if (!audioRecorder)
return;
// $(window).ready(initAudio);
e.classList.add("recording");
audioRecorder.clear();
audioRecorder.record();
Expand Down Expand Up @@ -136,6 +137,9 @@ function toggleMono() {
}

function gotStream(stream) {

audioContext = new AudioContext();

inputPoint = audioContext.createGain();

// Create an AudioNode from the stream.
Expand All @@ -159,12 +163,12 @@ function gotStream(stream) {
}

function initAudio() {
if (!navigator.getUserMedia)
navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (!navigator.cancelAnimationFrame)
navigator.cancelAnimationFrame = navigator.webkitCancelAnimationFrame || navigator.mozCancelAnimationFrame;
if (!navigator.requestAnimationFrame)
navigator.requestAnimationFrame = navigator.webkitRequestAnimationFrame || navigator.mozRequestAnimationFrame;
if (!navigator.getUserMedia)
navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (!navigator.cancelAnimationFrame)
navigator.cancelAnimationFrame = navigator.webkitCancelAnimationFrame || navigator.mozCancelAnimationFrame;
if (!navigator.requestAnimationFrame)
navigator.requestAnimationFrame = navigator.webkitRequestAnimationFrame || navigator.mozRequestAnimationFrame;

navigator.getUserMedia(
{
Expand Down
7 changes: 4 additions & 3 deletions js/recorderjs/recorder.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ DEALINGS IN THE SOFTWARE.

(function(window){

var WORKER_PATH = 'js/recorderjs/recorderWorker.js';
//var WORKER_PATH = 'js/recorderjs/recorderWorker.js';

var Recorder = function(source, cfg){
var config = cfg || {};
Expand All @@ -30,8 +30,9 @@ DEALINGS IN THE SOFTWARE.
} else {
this.node = this.context.createScriptProcessor(bufferLen, 2, 2);
}

var worker = new Worker(config.workerPath || WORKER_PATH);


var worker = new Worker(URL.createObjectURL(new Blob(["("+worker_function.toString()+")()"], {type: 'text/javascript'})));
worker.postMessage({
command: 'init',
config: {
Expand Down
285 changes: 143 additions & 142 deletions js/recorderjs/recorderWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,146 +16,147 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

var recLength = 0,
recBuffersL = [],
recBuffersR = [],
sampleRate;

this.onmessage = function(e){
switch(e.data.command){
case 'init':
init(e.data.config);
break;
case 'record':
record(e.data.buffer);
break;
case 'exportWAV':
exportWAV(e.data.type);
break;
case 'exportMonoWAV':
exportMonoWAV(e.data.type);
break;
case 'getBuffers':
getBuffers();
break;
case 'clear':
clear();
break;
}
};

function init(config){
sampleRate = config.sampleRate;
}

function record(inputBuffer){
recBuffersL.push(inputBuffer[0]);
recBuffersR.push(inputBuffer[1]);
recLength += inputBuffer[0].length;
}

function exportWAV(type){
var bufferL = mergeBuffers(recBuffersL, recLength);
var bufferR = mergeBuffers(recBuffersR, recLength);
var interleaved = interleave(bufferL, bufferR);
var dataview = encodeWAV(interleaved);
var audioBlob = new Blob([dataview], { type: type });

this.postMessage(audioBlob);
}

function exportMonoWAV(type){
var bufferL = mergeBuffers(recBuffersL, recLength);
var dataview = encodeWAV(bufferL, true);
var audioBlob = new Blob([dataview], { type: type });

this.postMessage(audioBlob);
}

function getBuffers() {
var buffers = [];
buffers.push( mergeBuffers(recBuffersL, recLength) );
buffers.push( mergeBuffers(recBuffersR, recLength) );
this.postMessage(buffers);
}

function clear(){
recLength = 0;
recBuffersL = [];
recBuffersR = [];
}

function mergeBuffers(recBuffers, recLength){
var result = new Float32Array(recLength);
var offset = 0;
for (var i = 0; i < recBuffers.length; i++){
result.set(recBuffers[i], offset);
offset += recBuffers[i].length;
}
return result;
}

function interleave(inputL, inputR){
var length = inputL.length + inputR.length;
var result = new Float32Array(length);

var index = 0,
inputIndex = 0;

while (index < length){
result[index++] = inputL[inputIndex];
result[index++] = inputR[inputIndex];
inputIndex++;
}
return result;
}

function floatTo16BitPCM(output, offset, input){
for (var i = 0; i < input.length; i++, offset+=2){
var s = Math.max(-1, Math.min(1, input[i]));
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
}

function writeString(view, offset, string){
for (var i = 0; i < string.length; i++){
view.setUint8(offset + i, string.charCodeAt(i));
}
}

function encodeWAV(samples, mono){
var buffer = new ArrayBuffer(44 + samples.length * 2);
var view = new DataView(buffer);

/* RIFF identifier */
writeString(view, 0, 'RIFF');
/* file length */
view.setUint32(4, 32 + samples.length * 2, true);
/* RIFF type */
writeString(view, 8, 'WAVE');
/* format chunk identifier */
writeString(view, 12, 'fmt ');
/* format chunk length */
view.setUint32(16, 16, true);
/* sample format (raw) */
view.setUint16(20, 1, true);
/* channel count */
view.setUint16(22, mono ? 1 : 2, true);
/* sample rate */
view.setUint32(24, sampleRate, true);
/* byte rate (sample rate * channels * bytes per sample) */
view.setUint32(28, sampleRate * (mono ? 1 : 2) * 2, true);
/* block align (channel count * bytes per sample) */
view.setUint16(32, (mono ? 1 : 2) * 2, true);
/* bits per sample */
view.setUint16(34, 16, true);
/* data chunk identifier */
writeString(view, 36, 'data');
/* data chunk length */
view.setUint32(40, samples.length * 2, true);

floatTo16BitPCM(view, 44, samples);

return view;
function worker_function() {
var recLength = 0,
recBuffersL = [],
recBuffersR = [],
sampleRate;

this.onmessage = function(e){
switch(e.data.command){
case 'init':
init(e.data.config);
break;
case 'record':
record(e.data.buffer);
break;
case 'exportWAV':
exportWAV(e.data.type);
break;
case 'exportMonoWAV':
exportMonoWAV(e.data.type);
break;
case 'getBuffers':
getBuffers();
break;
case 'clear':
clear();
break;
}
};

function init(config){
sampleRate = config.sampleRate;
}

function record(inputBuffer){
recBuffersL.push(inputBuffer[0]);
recBuffersR.push(inputBuffer[1]);
recLength += inputBuffer[0].length;
}

function exportWAV(type){
var bufferL = mergeBuffers(recBuffersL, recLength);
var bufferR = mergeBuffers(recBuffersR, recLength);
var interleaved = interleave(bufferL, bufferR);
var dataview = encodeWAV(interleaved);
var audioBlob = new Blob([dataview], { type: type });

this.postMessage(audioBlob);
}

function exportMonoWAV(type){
var bufferL = mergeBuffers(recBuffersL, recLength);
var dataview = encodeWAV(bufferL, true);
var audioBlob = new Blob([dataview], { type: type });

this.postMessage(audioBlob);
}

function getBuffers() {
var buffers = [];
buffers.push( mergeBuffers(recBuffersL, recLength) );
buffers.push( mergeBuffers(recBuffersR, recLength) );
this.postMessage(buffers);
}

function clear(){
recLength = 0;
recBuffersL = [];
recBuffersR = [];
}

function mergeBuffers(recBuffers, recLength){
var result = new Float32Array(recLength);
var offset = 0;
for (var i = 0; i < recBuffers.length; i++){
result.set(recBuffers[i], offset);
offset += recBuffers[i].length;
}
return result;
}

function interleave(inputL, inputR){
var length = inputL.length + inputR.length;
var result = new Float32Array(length);

var index = 0,
inputIndex = 0;

while (index < length){
result[index++] = inputL[inputIndex];
result[index++] = inputR[inputIndex];
inputIndex++;
}
return result;
}

function floatTo16BitPCM(output, offset, input){
for (var i = 0; i < input.length; i++, offset+=2){
var s = Math.max(-1, Math.min(1, input[i]));
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
}

function writeString(view, offset, string){
for (var i = 0; i < string.length; i++){
view.setUint8(offset + i, string.charCodeAt(i));
}
}

function encodeWAV(samples, mono){
var buffer = new ArrayBuffer(44 + samples.length * 2);
var view = new DataView(buffer);

/* RIFF identifier */
writeString(view, 0, 'RIFF');
/* file length */
view.setUint32(4, 32 + samples.length * 2, true);
/* RIFF type */
writeString(view, 8, 'WAVE');
/* format chunk identifier */
writeString(view, 12, 'fmt ');
/* format chunk length */
view.setUint32(16, 16, true);
/* sample format (raw) */
view.setUint16(20, 1, true);
/* channel count */
view.setUint16(22, mono ? 1 : 2, true);
/* sample rate */
view.setUint32(24, sampleRate, true);
/* byte rate (sample rate * channels * bytes per sample) */
view.setUint32(28, sampleRate * (mono ? 1 : 2) * 2, true);
/* block align (channel count * bytes per sample) */
view.setUint16(32, (mono ? 1 : 2) * 2, true);
/* bits per sample */
view.setUint16(34, 16, true);
/* data chunk identifier */
writeString(view, 36, 'data');
/* data chunk length */
view.setUint32(40, samples.length * 2, true);

floatTo16BitPCM(view, 44, samples);

return view;
}
}