Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web Worker Example for Mono & Stereo #17

Merged
merged 3 commits into from
Nov 9, 2015
Merged

Conversation

logbon72
Copy link
Contributor

  • Fixed examples in README.md
  • Added Web Worker example, which works well with Mono & Stereo input.

- Added Web Worker example, which works well with Mono & Stereo input.
@logbon72 logbon72 mentioned this pull request Oct 26, 2015
@javismiles
Copy link

Thank you dear logbon72, so you already coded it? cant wait to see it, what about making an example that combines my code below to record from microphone using this library with your web worker?

navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia;

allow=0; afl=0;

var contexttemp = new AudioContext();
var conrate=contexttemp.sampleRate;
console.log("mic sample rate:"+conrate);
$("#rate").text("Rate:"+conrate);
liblame = new lamejs(); var mymp3Encoder=new liblame.Mp3Encoder(1,conrate,128);

function upload(blobOrFile) {
var form = new FormData(); form.append("blobbie", blobOrFile);
var xhr = new XMLHttpRequest(); xhr.open('POST', './upload.php', true);xhr.send(form);

var item = document.createElement('li');
var url = URL.createObjectURL(blobOrFile);
valrandom=Math.floor(Math.random() * (10000 - 100) + 100);
item.innerHTML = '' + new Date() + '';
document.getElementById('recresults').appendChild(item);

var au = document.createElement('audio');
au.controls = true;
au.src = url;
document.getElementById('recresults').appendChild(au);

xhr.onreadystatechange = function(e) {
if (xhr.readyState == 4) { if (xhr.status==200) {
cap=xhr.responseText;
}}};
xhr.onload = function(e) {};
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {a = (e.loaded / e.total) * 100;
console.log (e.loaded+"/"+e.total+"/"+a);}};
}

function record() {
thetext=$("#statusbit");
navigator.getUserMedia({audio: true}, function (stream) {
var stopRecording = beginRecording(stream);
var start = +new Date();
thetext.text('Preparing...');
// Run a function every 100 ms to update the UI
var timer = setInterval(function () {
var duration = new Date() - start;
if (duration < 6000) {
if (afl==1){
thetext.text('Recording... ' + ((6000 - duration) / 1000).toFixed(1));}
} else {
var buffers = stopRecording();
clearInterval(timer);
console.log ("Get MP3");
mp3Buffer=mymp3Encoder.flush();
if (mp3Buffer.length>0) buffers.push(mp3Buffer);
var blob=new Blob(buffers, {type: 'audio/mpeg'});
upload(blob);

                }
            }, 100);
        }, function (error) {thetext.text('Error! Try again.');});

}

    function beginRecording(stream) {
        var context = new AudioContext();
        var microphone = context.createMediaStreamSource(stream);
        var processor = context.createScriptProcessor(0, 1, 1);
        // Set up Web Audio API to process data from the media stream (microphone).
        var buffers = [];
        processor.onaudioprocess = function (event) {
            var data = event.inputBuffer.getChannelData(0);
            var lo = data; //the decoded data range: -1 +1
            //console.log(lo);
            var l = new Float32Array(lo.length); 
            for(var i=0;i<lo.length;i++) {l[i] = lo[i]*32767.5;}
            var buffer = mymp3Encoder.encodeBuffer(l);

// console.log(buffer);
buffers.push(buffer)
};
// Begin retrieving microphone data.
microphone.connect(processor);
processor.connect(context.destination);
if (allow==0) {allow=1; afl=1;}
// Return a function which will stop recording and return all MP3 data.
return function stopRecording() {
console.log ("FINISHED RECORDING");
// Clean up the Web Audio API resources.
//if (context.close) context.close();
microphone.disconnect();
processor.disconnect();
processor.onaudioprocess = null;
// Return the buffers array. Note that there may be more buffers pending here.
console.log ("Finished cleaning");
return buffers;
};
}

@sflusov
Copy link

sflusov commented Oct 27, 2015

I'm use next code for convert floatArray to int16Array.

    var floatbuffer = audioProcEvent.inputBuffer.getChannelData(0);
    var int16Buffer = new Int16Array(floatbuffer.length);

    for (var i = 0, len = floatbuffer.length; i < len; i++) {
        if (floatbuffer[i] < 0) {
            int16Buffer[i] = 0x8000 * floatbuffer[i];
        } else {
            int16Buffer[i] = 0x7FFF * floatbuffer[i];
        }
    }

@javismiles
Copy link

dear Joseph, your code for the web worker works great
http://torchprinciple.com/tests/rec6/worker-example/
Now what i would want is to mix that with recording from microphone and in real time, like here:
http://torchprinciple.com/tests/rec1/alexrec.html

a blend of both, that worked in Chrome, Firefox and Edge (because Safari doesnt support apparently GetUserMedia), in both desktop and mobile, would be the Perfect solution

@logbon72
Copy link
Contributor Author

See the latest commit,

  • mic.html for the HTML file,
  • mic.js for the recorder
  • worker-realtime.js for the realtime conversion.

@javismiles
Copy link

Dear Joseph, this is exciting, im testing, it, one first thing, the sound recorded is not matching the speed rate of Mic, are you doing this?
var contexttemp = new AudioContext();
var conrate=contexttemp.sampleRate;

to get the sampleRate of system and convert to mp3 at same rate?
this problem also happened to me in past, if not system may be at 48000 and you may convert at 41000 and then the sound will come out slightly lower in frequency/pitch

thats why we need to detect rate first
var contexttemp = new AudioContext();
var conrate=contexttemp.sampleRate;

and use same rate in the encoder :)

@javismiles
Copy link

here it is, in the worker file
mp3Encoder = new lame.Mp3Encoder(1, config.sampleRate || 44100, config.bitRate || 123);

we need to change that config.sampleRate || 44100
to match instead what we get from

var contexttemp = new AudioContext();
var conrate=contexttemp.sampleRate;

so that there is a match, then sound recorded will sound same frequency/pitch as sound coming from mic :)

this is a fantastic example by the way dear Joseph thank you very much :)

apart from the rate issue, next question will be to test this to see if it works in:

  • chrome, firefox and edge on both desktop and mobile
  • it should not work on safari because safari doesnt support GetUserMedia (unfortunately...)

i will test it in those platforms to see if it works :)

@zhuker
Copy link
Owner

zhuker commented Nov 9, 2015

@javismiles @logbon72 thanks for your input, great work!
merging now, sorry for being so slow

zhuker added a commit that referenced this pull request Nov 9, 2015
Web Worker Example for Mono & Stereo
@zhuker zhuker merged commit a282226 into zhuker:master Nov 9, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants