//============================================================================
// sound.js
//============================================================================
//============================================================================
// sound$initilize
//============================================================================
function sound$initilize(div, clips)
{
if (! navigator.mediaDevices)
{
alert('Sound Recording not supported on your browser!');
return;
}
window.sound = {};
sound.name = 'sample';
sound.div = div;
sound.canvas = document.createElement('Canvas');
sound.canvas.style.height = '60px';
sound.div.appendChild(sound.canvas);
sound.canvasContext = sound.canvas.getContext("2d");
sound.recordButton = sdocument.createElement('button');
sound.recordButton.id ='recordButton';
sound.recordButton.innerText = 'Record';
sound.div.appendChild(sound.recordButton);
sound.stopButton = sdocument.createElement('button');
sound.stopButton.id = 'stopButton';
sound.stopButton.innerText = 'Stop';
sound.div.appendChild(sound.stopButton);
sound.link = document.createElement('a');
sound.table = document.createElement('table');
sound.addClip = sound$addClip;
clips.appendChild(sound.table);
sound.stopButton.disabled = true;
sound.audioContext = null;
sound.constraints = { audio: true };
sound.chunks = [];
navigator.mediaDevices.getUserMedia(sound.constraints).then(sound$onSuccess, sound$onError);
window.onresize = sound$resize;
window.onresize();
//=======================================================================
// sound$addClip
//=======================================================================
function sound$addClip(name,clip, blob)
{
var cell,row, deleteButton, saveButton, downloadOggButton, downloadWavButton;
row = sound.table.insertRow(-1);
row.clip = clip;
row.blob = blob;
deleteButton = document.createElement('button');
deleteButton.onclick = sound$removeClip;
deleteButton.textContent = 'Delete';
deleteButton.row = row;
saveButton = document.createElement('button');
saveButton.onclick = sound$saveClip;
saveButton.textContent = 'Save';
saveButton.row = row;
downloadOggButton = document.createElement('button');
downloadOggButton.onclick = sound$downloadOgg;
downloadOggButton.textContent = 'Download .ogg';
downloadOggButton.row = row;
downloadWavButton = document.createElement('button');
downloadWavButton.onclick = sound$downloadWav;
downloadWavButton.textContent = 'Download .wav';
downloadWavButton.row = row;
cell = row.insertCell();
cell.appendChild(clip);
cell = row.insertCell();
cell.appendChild(downloadWavButton);
cell = row.insertCell();
cell.appendChild(downloadOggButton);
cell = row.insertCell();
cell.appendChild(saveButton);
cell = row.insertCell();
cell.appendChild(deleteButton);
}
//=======================================================================
// sound$saveClip
//=======================================================================
function sound$saveClip(e)
{
var row,clip,reader;
row = e.target.row;
clip = row.clip;
sound$uploadFile(sound.name,row.blob);
}
//=======================================================================
// sound$downloadWav
//=======================================================================
function sound$downloadWav(e)
{
sound$saveAs_wav(e.target.row);
}
//=======================================================================
// sound$downloadOgg
//=======================================================================
function sound$downloadOgg(e)
{
var row,clip,reader;
row = e.target.row;
sound.link.download = sound.name + '.ogg';
sound.link.href = window.URL.createObjectURL(row.blob);
sound.link.click();
}
//=======================================================================
// sound$clear
//=======================================================================
function sound$clear()
{
sound.table.rows.length = 0;
}
//=======================================================================
// sound$removeClip
//=======================================================================
function sound$removeClip(e)
{
sound.table.deleteRow(e.target.row);
}
//=======================================================================
// sound$resize
//=======================================================================
function sound$resize()
{
sound.canvas.width = sound.mainSection.offsetWidth;
}
//======================================================================
// sound$onSuccess
//======================================================================
function sound$onSuccess(stream)
{
const recordedChunks = [];
sound.mediaRecorder = new MediaRecorder(stream, {mimeType: 'audio/webm'});
sound$visualize(stream);
sound.recordButton.onclick = sound$record_onClick;
sound.stopButton.onclick = sound$stop_onClick;
sound.mediaRecorder.onstop = sound$mediaRecorder_onstop;
sound.mediaRecorder.ondataavailable = sound$mediaRecorder_onDataAvailable;
}
//======================================================================
// sound$record_onClick;
//======================================================================
function sound$record_onClick(stream)
{
sound.chunks = [];
sound.recordButton.style.background = "red";
sound.stopButton.disabled = false;
sound.recordButton.disabled = true;
sound.recording = true;
sound.myBuffers = [];
sound.mediaRecorder.start();
}
//======================================================================
// sound$stop_onClick;
//======================================================================
function sound$stop_onClick(stream)
{
sound.mediaRecorder.stop();
sound.recordButton.style.background = "";
sound.recordButton.style.color = "";
sound.stopButton.disabled = true;
sound.recordButton.disabled = false;
sound.recording = false;
}
//======================================================================
// sound$mediaRecorder_onstop
//======================================================================
function sound$mediaRecorder_onstop(e)
{
var clipName, audio,blob;
sound.recording = false;
audio = document.createElement('audio');
audio.setAttribute('controls', '');
audio.controls = true;
blob = new Blob(sound.chunks, { 'type' : 'audio/ogg; codecs=opus' });
audio.src = window.URL.createObjectURL(blob);
sound.chunks = [];
sound$addClip(clipName,audio,blob)
}
//=========================================================================
// sound$uploadFile
//=========================================================================
function sound$uploadFile(name,blob)
{
var reader;
if (! sound.form) makeForm();
sound.filename = name;
var reader = new FileReader();
reader.onload = onLoad;
reader.readAsDataURL(blob);
//------------------- onLoad ---------------------
function onLoad(event)
{
var i,data;
i = event.target.result.indexOf(',');
data = event.target.result.substr(i+1);
sound.form.filename.value = sound.filename;
sound.form.data.value = data;
sound.form.f.submit();
alert('Recording Saved');
}
//------------------- makeForm ---------------------
function makeForm()
{
sound.form = {};
sound.form.iframe = document.createElement('iframe');
sound.form.iframe.name = 'sound_iframe';
sound.form.iframe.style.width = '100%';
sound.form.iframe.style.height = '400px';
sound.form.iframe.style.display = 'none';
document.body.appendChild(sound.form.iframe);
sound.form.f = document.createElement('form');
sound.form.f.method = 'post';
sound.form.f.action = 'writeSound.aspx';
sound.form.f.target = 'sound_iframe';
sound.form.f.style.display = 'none';
document.body.appendChild(sound.form.f);
sound.form.filename = document.createElement('input');
sound.form.filename.type = 'text';
sound.form.filename.name = 'name';
sound.form.f.appendChild(sound.form.filename);
sound.form.data = document.createElement('input');
sound.form.data.type = 'text';
sound.form.data.name = 'data';
sound.form.f.appendChild(sound.form.data);
}
}
//=========================================================================
// sound$deleteButton_onClick
//=========================================================================
function sound$deleteButton_onClick(e)
{
e.target.parentNode.parentNode.removeChild(e.target.parentNode);
}
//=========================================================================
// sound$mediaRecorder.ondataavailable
//=========================================================================
function sound$mediaRecorder_onDataAvailable(e)
{
if (e.data.size == 0) return;
sound.chunks.push(e.data);
}
//======================================================================
// sound$onError
//======================================================================
function sound$onError (error)
{
console.log('The following error occured: ' + error);
}
//=======================================================================
// sound$visualize
//=======================================================================
function sound$visualize(stream)
{
if(! sound.audioContext) sound.audioContext = new AudioContext();
sound.source = sound.audioContext.createMediaStreamSource(stream);
sound.analyser = sound.audioContext.createAnalyser();
sound.analyser.fftSize = 2048;
sound.bufferLength = sound.analyser.frequencyBinCount;
sound.dataArray = new Uint8Array(sound.bufferLength);
sound.channelCount = sound.source.channelCount;
sound.sampleRate = sound.source.sampleRate;
sound.source.connect(sound.analyser);
sound$draw()
}
//=======================================================================
// sound$draw
//=======================================================================
function sound$draw()
{
var x,y,v,i,sliceWidth;
requestAnimationFrame(sound$draw);
sound.analyser.getByteTimeDomainData(sound.dataArray);
sound.canvasContext.fillStyle = 'rgb(230, 230, 230)';
sound.canvasContext.fillRect(0, 0, sound.canvas.width, sound.canvas.height);
sound.canvasContext.lineWidth = 2;
sound.canvasContext.strokeStyle = 'rgb(0, 0, 0)';
sound.canvasContext.beginPath();
sliceWidth = sound.canvas.width * 1.0 / sound.bufferLength;
x = 0;
for(i = 0; i < sound.bufferLength; i++)
{
v = sound.dataArray[i] / 128.0;
y = v * sound.canvas.height/2;
if (i == 0) sound.canvasContext.moveTo(x, y); else sound.canvasContext.lineTo(x, y);
x += sliceWidth;
}
sound.canvasContext.lineTo(sound.canvas.width, sound.canvas.height/2);
sound.canvasContext.stroke();
}
//==============================================================================
// sound$saveAs_wav
//==============================================================================
function sound$saveAs_wav(row)
{
var http,i,nam,filename, wavName, url;
if (typeof(window.audioContext) != 'object') window.audioContext = new (window.AudioContext || window.webkitAudioContext)();
url = window.URL.createObjectURL(row.blob);
http = new XMLHttpRequest();
http.open('GET', url, true);
http.responseType = 'arraybuffer';
http.onload = onLoad.bind(null,http);
http.send();
//------------------------- onLoad --------------------------
function onLoad(http)
{
var audioData = http.response;
audioContext.decodeAudioData(audioData, onSuccess);
}
function onSuccess(buffer)
{
var output, data, s, i, j, link, result, blob;
data = buffer.getChannelData(0);
output = new Uint8Array(44 + (data.length * 2));
makeWAV(buffer,output);
j = 44;
for (i = 0; i < data.length; i++)
{
s = Math.max(-1, Math.min(1, data[i]));
if (s < 0) s *= 0x8000; else s *= 0x7FFF;
output[j++] = (s & 0xFF);
output[j++] = (s >>> 8);
}
result = toBase64(output);
sound.link.download = sound.name + '.wav';
sound.link.href = 'data:audio/wav;base64,' + result;
sound.link.click();
}
function toBase64(data)
{
var i = 0, text = '', c1, c2, c3, e1, e2, e3, e4, key;
key = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz0123456789+/=";
while (i < data.length)
{
c1 = data[i++];
c2 = data[i++];
c3 = data[i++];
e1 = c1 >> 2;
e2 = ((c1 & 3) << 4) | (c2 >> 4);
e3 = ((c2 & 15) << 2) | (c3 >> 6);
e4 = c3 & 63;
if (isNaN(c2)) { e3 = 64; e4 = 64; }
if (isNaN(c3)) { e4 = 64; }
text += key.charAt(e1) + key.charAt(e2) + key.charAt(e3) + key.charAt(e4);
}
return text;
}
function makeWAV(buffer, output)
{
var bitsPerSample, audio, pos = 0, position;
position = 0;
bitsPerSample = 16;
add_Text('RIFF');
add_I4(36 + (buffer.length * 2));
add_Text('WAVE');
add_Text('fmt ');
add_I4(16); // chunk length
add_I2(1); // format (raw)
add_I2(buffer.numberOfChannels );
add_I4(buffer.sampleRate);
add_I4((buffer.sampleRate * bitsPerSample * buffer.numberOfChannels) / 8);
add_I2(buffer.numberOfChannels * 2);
add_I2(bitsPerSample);
add_Text('data');
add_I4(buffer.length * 2);
function add_Text(value)
{
var i;
for (i=0; i < value.length; ++i)
{
output[position++] = value.charCodeAt(i);
}
}
function add_I4(value)
{
var i, a,b,c,d;
a = (value >>> 24) & 0xFF;
b = (value >>> 16) & 0xFF;
c = (value >>> 8) & 0xFF;
d = value & 0xFF;
output[position++] = d;
output[position++] = c;
output[position++] = b;
output[position++] = a;
}
function add_I2(value)
{
var i, a,b;
a = (value >>> 8) & 0xFF;
b = value & 0xFF;
output[position++] = b;
output[position++] = a;
}
}
}
}