How to Record From A Microphone


<script type="text/javascript">
//Make multi browser compatible
navigator.getUserMedia=(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
window.AudioContext=(window.webkitAudioContext || window.AudioContext || window.mozAudioContext);
// Global Variables for Audio
var gRecording=false,gSourceNode,gAudioContext,gJavascriptNode,gAudioStream,gSampleSize=4096; // number of samples to collect before analyzing
var BufferL,BufferR,gSampleRate;
function InitMic() {
    gAudioContext = new AudioContext();
    navigator.getUserMedia({video:false,audio:true},SetupAudioNodes,function(e) {alert("Sorry, a problem has occurred trying to connect to your microphone:\n\n(Error: "+e+")");});
}
function Start() {//Finish setting up the audio nodes, and start processing audio streaming in from the input device
    BufferL=new Float32Array(0); BufferR=new Float32Array(0); gRecording=true;
}
function SetupAudioNodes(Stream) {
    gSourceNode=gAudioContext.createMediaStreamSource(Stream); //create the media stream from the audio input source (microphone)
    gAudioStream=Stream; //Set global in order to stop later
    gSampleRate=gAudioContext.sampleRate;
    if (gAudioContext.createScriptProcessor) {
        gJavascriptNode=gAudioContext.createScriptProcessor(gSampleSize,2,2);
    } else {
        gJavascriptNode=gAudioContext.createJavaScriptNode(gSampleSize,2,2);
    }
    gJavascriptNode.onaudioprocess=function(e){
        if (gRecording) {
            BufferL=ConcatFloat32Arrays(BufferL,e.inputBuffer.getChannelData(0));
            BufferR=ConcatFloat32Arrays(BufferR,e.inputBuffer.getChannelData(1));
        }
    }
    gSourceNode.connect(gJavascriptNode); gJavascriptNode.connect(gAudioContext.destination);
}
function Stop(f) {// Stop the audio processing, note time is BufferL.length/gSampleRate
    var m,c,l,i,j,b,u,flag,start,stop,combined;
    gRecording=false;
    //Note: dB=20*log10(factor) and factor=10^(dB/20)
    m=0; //max value
    for (i=0;i<BufferL.length;i++) {if (BufferL[i]>m) {m=BufferL[i];}}
    for (i=0;i<BufferR.length;i++) {if (BufferR[i]>m) {m=BufferR[i];}}
    m=1/m; //Factor to multiply by so that max is 1
    for (i=0;i<BufferL.length;i++) {BufferL[i]*=m;}
    for (i=0;i<BufferR.length;i++) {BufferR[i]*=m;}
    l=BufferL.length;
    //Find start time, i.e. look for first non-silence then see whether 0.2 seconds ahead has 0.5 seconds of silence and jump to it if so
    start=0; flag=true;
    while (flag) {
        if (start<l) {
            if (IsWAVZero(BufferL[start]) && IsWAVZero(BufferR[start])) {
                start++;
            } else {
                j=start+Math.round(0.2*gSampleRate);
                c=0;
                for (j=start+Math.round(0.2*gSampleRate);j<Math.min(l,start+Math.round(0.7*gSampleRate));j++) {
                    if (!(IsWAVZero(BufferL[j]) && IsWAVZero(BufferR[j]))) {c++;}
                }
                if (c==0) {
                    start=Math.min(l,start+Math.round(0.7*gSampleRate));
                } else {
                    flag=false;
                }
            }
        } else {
            flag=false; //i.e. stop
        }
    }
    start-=0.1*gSampleRate; if (start<0) {start=0;}
    //Find stop time, i.e. look from end for first non-silence then see whether 0.2 seconds before has 0.5 seconds of silence before and jump back if so
    stop=l; flag=true;
    while (flag) {
        if (stop>=0) {
            if (IsWAVZero(BufferL[stop]) && IsWAVZero(BufferR[stop])) {
                stop--;
            } else {
                j=stop-Math.round(0.2*gSampleRate);
                c=0;
                for (j=stop-Math.round(0.2*gSampleRate);j>Math.max(0,stop-Math.round(0.7*gSampleRate));j--) {
                    if (!(IsWAVZero(BufferL[j]) && IsWAVZero(BufferR[j]))) {c++;}
                }
                if (c==0) {
                    stop=Math.max(0,stop-Math.round(0.7*gSampleRate));
                } else {
                    flag=false;
                }
            }
        } else {
            flag=false; //i.e. stop
        }
    }
    stop+=0.1*gSampleRate; if (stop>l) {stop=l;}
    //Fill buffer
    if (stop<start) {stop=start;}
    l=2*(stop-start);
    combined=new Float32Array(l);
    i=0; j=0; while (i<l){combined[i++]=BufferL[start+j]; combined[i++]=BufferR[start+j]; j++;}
    b=new Blob([EncodeWAV(combined)], {type:'audio/wav'});
    UploadAudio(b,f);
    u=(window.URL || window.webkitURL).createObjectURL(b);
    l=document.getElementById("Save");
    l.href=u;
    l.download="New.wav";//Works in Chrome, in others default name is used
}
function IsWAVZero(i) {return (Math.abs(i)<0.05);} //About -26 dB
function ConcatFloat32Arrays(a1,a2) {var ans=new Float32Array(a1.length+a2.length); ans.set(a1,0); ans.set(a2,a1.length); return ans;}
function FloatTo16BitPCM(output, offset, input){
    var i,s;
    for (i=0;i<input.length;i++,offset+=2){
        s=Math.max(-1,Math.min(1, input[i]));
        output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
    }
}
function EncodeWAV(samples){
    var buffer = new ArrayBuffer(44+samples.length*2);
    var view = new DataView(buffer);
    WriteString(view, 0, 'RIFF'); // RIFF identifier zz
    view.setUint32(4, 32 + samples.length * 2, true); // file length
    WriteString(view, 8, 'WAVE'); // RIFF type
    WriteString(view, 12, 'fmt '); // format chunk identifier
    view.setUint32(16, 16, true); // format chunk length
    view.setUint16(20, 1, true); // sample format (raw)
    view.setUint16(22, 2, true); // channel count
    view.setUint32(24, gSampleRate, true); // sample rate
    view.setUint32(28, gSampleRate * 4, true); // byte rate (sample rate * block align)
    view.setUint16(32, 4, true); // block align (channel count * bytes per sample)
    view.setUint16(34, 16, true); // bits per sample
    WriteString(view, 36, 'data'); // data chunk identifier
    view.setUint32(40, samples.length * 2, true); // data chunk length
    FloatTo16BitPCM(view, 44, samples);
    return view;
}
function WriteString(view, offset, string){var i; for (i=0;i<string.length;i++){view.setUint8(offset+i,string.charCodeAt(i));}}
function GetXMLHttpRequest() {try {return new XMLHttpRequest();} catch(e) {return new ActiveXObject("Microsoft.XMLHTTP");}}
function GetNewFormData() {if(typeof FormData == "undefined"){return [];} return new FormData();} //Needed for IE9
function AppendToFormData(fd, s, t) {if(typeof FormData=="undefined") {fd.push(s,t);} else {fd.append(s,t);} return fd;}
function UploadAudio(blob,f) {
    var s,req=GetXMLHttpRequest();
    //var Page,TargetLang,Voice;
    //TargetLang=GetVars()["TargetLang"];
    //Page=GetVars()["Page"];
    //Voice="Default";
    req.onload=function(e) {}; // readyState=4 means done
    var fd=GetNewFormData();
    fd=AppendToFormData(fd,"action","upload");
    fd=AppendToFormData(fd,"filetype","audio");
    //if (Page=="TestRecording") {s="Data/TestRecording.mp3";} else {s="Data/"+TargetLang+"/"+Voice+"/"+GetFileName()+".mp3";}
    s="TestRecording.mp3";
    fd=AppendToFormData(fd,"filename",s);
    fd=AppendToFormData(fd,"tempfile",blob);
    req.onreadystatechange = function() {
        if (req.readyState == 4) {
            s=req.responseText;
            if (document.getElementById("FBAudioMessage")) {
                if (IsEmpty(s)) {
                    ShowRecordPage();
                } else {
                    document.getElementById("FBAudioMessage").innerHTML="Error uploading audio: "+s+"<br /><br />";
                }
            } else {
                if (s!="") {alert(s);}
            }
        }
    }
    req.open("POST","Fraze.php",true); //Note: POST has no restriction on length
    req.send(fd);
    if (document.getElementById("FBAudioMessage")) {
        document.getElementById("FBAudioMessage").innerHTML="[Uploading audio...]<br /><br />";
        document.getElementById("FBPlay").className="off";
        document.getElementById("FBRecord").className="off";
        document.getElementById("FBStop").className="off";
    }
}    
//Play file
function Play(s) {var au=new Audio(s+".mp3?n="+Math.random()); au.play();} //Adding .random refreshes file, i.e. doesn't use cache

</script>
</head>
<body onload='InitMic();'>
<input type="button" id="start_button" value="Start" onclick="Start();">
<input type="button" id="stop_button" value="Stop" onclick="Stop('TestRecording');">
<input type="button" id="play_button" value="Play" onclick="Play('TestRecording');">
<a id="Save" href="#">Click</a>
<br />