519 lines
16 KiB
JavaScript
519 lines
16 KiB
JavaScript
function IMRecorder() {
|
|
var me = this;
|
|
var recorded = false;
|
|
|
|
//------------------------------------------------------------
|
|
// Destroy all
|
|
//------------------------------------------------------------
|
|
terminate = function () {
|
|
reset(); // Chronometer
|
|
me.recorder && me.recorder.stop();
|
|
me.recorder && me.recorder.clear() && delete me.recorder;
|
|
if(me.wavesurfer.isPlaying()) {
|
|
me.wavesurfer.pause();
|
|
};
|
|
me.wavesurfer.empty();
|
|
me.microphone.stop();
|
|
delete me.microphone;
|
|
delete me.wavesurfer;
|
|
//document.body.innerHTML = ''; | Elimina el html del grabador.
|
|
//window.location.replace('about:blank'); | Carga una pantalla en blanco.
|
|
};
|
|
|
|
this.terminate = function() {
|
|
terminate();
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
// Open wav from server arrayBuffer
|
|
//------------------------------------------------------------
|
|
this.openFromArrayBuffer = function(arrayBuffer) {
|
|
Ciseaux.from(arrayBuffer).then(function(tape) {
|
|
tape.render().then(function(audiobuffer) {
|
|
me.wavesurfer.loadDecodedBuffer(audiobuffer);
|
|
me.oldtape = tape;
|
|
set(tottime()); // Chronometer
|
|
});
|
|
}, function(error) {
|
|
console.log('El archivo solicitado no existe o está corrupto.');
|
|
//terminate();
|
|
if(afterLoad !== null) afterLoad();
|
|
});
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
// Load wav from server
|
|
//------------------------------------------------------------
|
|
this.load = function (url, afterLoad) {
|
|
Ciseaux.from(url).then(function(tape) {
|
|
if(afterLoad !== null) afterLoad();
|
|
tape.render().then(function(audiobuffer) {
|
|
me.wavesurfer.loadDecodedBuffer(audiobuffer);
|
|
me.oldtape = tape;
|
|
set(tottime()); // Chronometer
|
|
});
|
|
}, function(error) {
|
|
console.log('El archivo solicitado no existe o está corrupto.');
|
|
//terminate();
|
|
if(afterLoad !== null) afterLoad();
|
|
});
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
// Quit recording.
|
|
//------------------------------------------------------------
|
|
var out = function () {
|
|
var q = confirm("Si desea salir sin grabar, pulse Ok.\nEn caso contrario, pulse Cancel.");
|
|
if (q == true) {
|
|
terminate();
|
|
}
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
// Save wav to server
|
|
//------------------------------------------------------------
|
|
this.save = function (url, aOnProgress, aOnDone) {
|
|
if(recorded === false) {
|
|
|
|
// Saliendo sin guardar audio.
|
|
aOnDone();
|
|
return;
|
|
};
|
|
// Guardando audio.
|
|
//
|
|
// primero obtenemos "oldtape" como audiobuffer
|
|
var progr = aOnProgress;
|
|
var ondone = aOnDone;
|
|
me.oldtape.render().then(function(audiobuffer) {
|
|
// una vez obtenido el buffer generamos el wav
|
|
|
|
// código obtenido desde: http://stackoverflow.com/questions/22560413/html5-web-audio-convert-audio-buffer-into-wav-file
|
|
// start a new worker
|
|
// we can't use Recorder directly, since it doesn't support what we're trying to do
|
|
|
|
|
|
var worker = new Worker('js/recorderWorker.js');
|
|
|
|
// initialize the new worker
|
|
worker.postMessage({
|
|
command: 'init',
|
|
config: {
|
|
numChannels: me.recorder.config.numChannels,
|
|
sampleRate: me.recorder.context.sampleRate
|
|
}
|
|
});
|
|
|
|
// callback for "exportWAV"
|
|
worker.onmessage = function( e ) {
|
|
var blob = e.data;
|
|
// this is would be your WAV blob
|
|
// por último enviamos el wav a destino
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open('POST', url, true);
|
|
xhr.upload.onprogress = progr;
|
|
xhr.onload = function () {
|
|
if (xhr.status === 200) {
|
|
aOnDone();
|
|
} else {
|
|
alert('An error occurred while uploading recording!');
|
|
}
|
|
};
|
|
xhr.send(blob);
|
|
};
|
|
|
|
// send the channel data from our buffer to the worker
|
|
worker.postMessage({
|
|
command: 'record',
|
|
buffer: [
|
|
audiobuffer.getChannelData(0)
|
|
//audiobuffer.getChannelData(1)
|
|
]
|
|
});
|
|
|
|
// ask the worker for a WAV
|
|
worker.postMessage({
|
|
command: 'exportWAV',
|
|
type: 'audio/wav'
|
|
});
|
|
|
|
});
|
|
//terminate();
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
// Save wav to websocket
|
|
//------------------------------------------------------------
|
|
// La función está asignada a la propiedad onmessage del WebSocket,
|
|
//lo que significa que se ejecutará cada vez que el WebSocket reciba un mensaje.
|
|
// El mensaje recibido es un objeto Blob de audio, que se procesa con la función exportWAV del objeto recorder.
|
|
// Esta función devuelve un objeto Blob con el audio codificado en formato WAV.
|
|
// El objeto Blob se convierte a una matriz de bytes (ArrayBuffer) con la ayuda del objeto FileReader.
|
|
// Finalmente, se envía la matriz de bytes a través del WebSocket con el método send.
|
|
this.save1 = function () {
|
|
|
|
// me.ws.onmessage = function() {
|
|
|
|
// // Aquí puedes procesar el mensaje recibido y hacer algo con él
|
|
// const audioBlob = me.recorder.exportWAV(
|
|
// function(blob) {
|
|
// me.url = URL.createObjectURL(blob);
|
|
// me.myblob = blob;
|
|
// Ciseaux.from(me.url).then(function(tape) {
|
|
// var lPos = me.seekpos;
|
|
// var lDur = tape.tracks[0].duration;
|
|
// me.oldtape = me.oldtape.replace(lPos, lDur, tape);
|
|
// me.oldtape.render().then(function(audiobuffer){
|
|
// me.ws.binaryType = "blob";
|
|
// me.recorder.clear();
|
|
// me.wavesurfer.empty();
|
|
// me.wavesurfer.loadDecodedBuffer(audiobuffer);
|
|
// me.wavesurfer.skip(lPos + lDur);
|
|
// });
|
|
// });
|
|
// }
|
|
// );
|
|
// const reader = new FileReader();
|
|
// reader.onload = function() {
|
|
// me.ws = new WebSocket("ws://localhost:8000");
|
|
|
|
// me.ws.send(reader.result);
|
|
// };
|
|
|
|
|
|
// };
|
|
me.ws.onmessage = function(event) {
|
|
console.log(event.data)
|
|
var audioData = me.wavesurfer.microphone.getAudioData();
|
|
var binaryAudioData = new Float32Array(audioData);
|
|
var buffer = new ArrayBuffer(binaryAudioData.length * 4);
|
|
var view = new Float32Array(buffer);
|
|
for (var i = 0; i < binaryAudioData.length; i++) {
|
|
view[i] = binaryAudioData[i];
|
|
}
|
|
|
|
var ws = new WebSocket('ws://localhost:8000');
|
|
ws.binaryType = 'arraybuffer';
|
|
ws.onopen = function() {
|
|
ws.send(buffer);
|
|
};
|
|
|
|
};
|
|
|
|
terminate();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
// Calculate total blob duration on wavesurfer canvas
|
|
//------------------------------------------------------------
|
|
totlen = function () {
|
|
var ini = new Date().getTime();
|
|
var num = Math.ceil(me.wavesurfer.getDuration() * 1000);
|
|
var fin = ini + num;
|
|
var lap = fin - ini;
|
|
totpos = lap / 1000;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
// Calculate partial blob duration on wavesurfer canvas
|
|
//------------------------------------------------------------
|
|
parlen = function () {
|
|
var ini = new Date().getTime();
|
|
var num = Math.ceil(me.wavesurfer.getCurrentTime() * 1000);
|
|
var fin = ini + num;
|
|
var lap = fin - ini;
|
|
me.seekpos = lap / 1000;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
// Calculate total blob duration on stopwatch display
|
|
//------------------------------------------------------------
|
|
tottime = function () {
|
|
var ini = new Date().getTime();
|
|
var num = Math.ceil(me.wavesurfer.getDuration() * 1000);
|
|
var fin = ini + num;
|
|
var lap = fin - ini;
|
|
return lap;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
// Calculate partial blob duration on stopwatch display
|
|
//------------------------------------------------------------
|
|
partime = function () {
|
|
var ini = new Date().getTime();
|
|
var num = Math.ceil(me.wavesurfer.getCurrentTime() * 1000);
|
|
var fin = ini + num;
|
|
var lap = fin - ini;
|
|
return lap;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
// Create empty blob
|
|
//------------------------------------------------------------
|
|
emptyBlob = function () {
|
|
me.oldtape = new Ciseaux.Tape();
|
|
me.recorder && me.recorder.clear();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------
|
|
// Generate blob
|
|
//------------------------------------------------------------
|
|
createBlob = function () {
|
|
me.recorder.exportWAV(function(blob) {
|
|
me.url = URL.createObjectURL(blob);
|
|
me.myblob = blob;
|
|
Ciseaux.from(me.url).then(function(tape) {
|
|
var lPos = me.seekpos;
|
|
var lDur = tape.tracks[0].duration;
|
|
me.oldtape = me.oldtape.replace(lPos, lDur, tape);
|
|
me.oldtape.render().then(function(audiobuffer){
|
|
me.recorder.clear();
|
|
me.wavesurfer.empty();
|
|
me.wavesurfer.loadDecodedBuffer(audiobuffer);
|
|
me.wavesurfer.skip(lPos + lDur);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
// PLAY/STOP on button click
|
|
//------------------------------------------------------------
|
|
this.play_stop = function() {
|
|
me.wavesurfer.playPause();
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
// RECORD on button click
|
|
//------------------------------------------------------------
|
|
record = function() {
|
|
start(); // Chronometer
|
|
me.microphone.play();
|
|
me.recorder.record(function() {
|
|
console.log("here");
|
|
});
|
|
recorded = true;
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
// PAUSE on button click
|
|
//------------------------------------------------------------
|
|
this.pause = function(){
|
|
stop(); // Chronometer
|
|
me.microphone.pause();
|
|
me.recorder.stop();
|
|
createBlob();
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
// REVIEW on button click
|
|
//------------------------------------------------------------
|
|
this.review = function() {
|
|
me.wavesurfer.skipBackward(me.wavesurfer.getDuration() / 5);
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
// CUE on button click
|
|
//------------------------------------------------------------
|
|
this.cue = function() {
|
|
me.wavesurfer.skipForward(me.wavesurfer.getDuration() / 5);
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
// Get voiceRecognitionBuffer
|
|
//------------------------------------------------------------
|
|
this.processVoiceRecognition = function(voiceRecognitionAudioBlob) {
|
|
if(!me.recorder) return;
|
|
|
|
|
|
// Web Socket is connected, send data using send()
|
|
var d = { "config": { "sample_rate": 44100 } };
|
|
me.ws.send(JSON.stringify(d));
|
|
me.ws.binaryType = "blob";
|
|
me.ws.send(voiceRecognitionAudioBlob);
|
|
};
|
|
|
|
|
|
|
|
//------------------------------------------------------------
|
|
// CLEAR on button click
|
|
//------------------------------------------------------------
|
|
this.clear_rec = function() {
|
|
var r = confirm("Para borrar la grabación y crear una nueva, pulse Ok.\nPara continuar, pulse Cancel.");
|
|
if (r == true) {
|
|
reset(); // Chronometer
|
|
me.recorder && me.recorder.clear();
|
|
me.wavesurfer.empty();
|
|
emptyBlob();
|
|
}
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
// QUIT on button click
|
|
//------------------------------------------------------------
|
|
quit_click = function() {
|
|
out();
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
// START/STOP mic on button click or start recording
|
|
//------------------------------------------------------------
|
|
this.rec_pause_toggle = function() {
|
|
if( me.recstate === undefined ) {
|
|
// esto abre la ventana de solicitud de habilitación del micrófono
|
|
me.microphone.start();
|
|
}
|
|
else if( me.recstate === "REC" ) {
|
|
me.recstate = "PAUSED";
|
|
this.pause();
|
|
} else {
|
|
me.recstate = "REC";
|
|
record();
|
|
}
|
|
};
|
|
//------------------------------------------------------------
|
|
// STOP mic on button click
|
|
//------------------------------------------------------------
|
|
this.rec_pause = function() {
|
|
if( me.recstate === "REC" ) {
|
|
me.recstate = "PAUSED";
|
|
this.pause();
|
|
}
|
|
};
|
|
//------------------------------------------------------------
|
|
// STOP play on button click
|
|
//------------------------------------------------------------
|
|
this.play_pause = function() {
|
|
if(me.wavesurfer.isPlaying()) {
|
|
me.wavesurfer.pause();
|
|
};
|
|
};
|
|
|
|
|
|
//------------------------------------------------------------
|
|
// voiceRecognitionAudioBlobCallback
|
|
//------------------------------------------------------------
|
|
this.voiceRecognitionAudioBlobCallback = function(blob) {
|
|
var audioBlob = new Blob([blob], { type: 'audio/wav' });
|
|
me.processVoiceRecognition(audioBlob);
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
// Initialize object
|
|
//------------------------------------------------------------
|
|
init = function () {
|
|
|
|
//------------------------------------------------------------
|
|
// General global variables
|
|
//------------------------------------------------------------
|
|
me.recorder;
|
|
me.recstate = undefined; // Primera pasada (sólo para incializar el micrófono
|
|
me.newtape;
|
|
me.oldtape;
|
|
me.totpos = 0;
|
|
me.seekpos = 0;
|
|
me.url = null;
|
|
me.recContext;
|
|
recContext = new AudioContext;
|
|
|
|
//------------------------------------------------------------
|
|
// Options for playing canvas
|
|
//------------------------------------------------------------
|
|
me.optplay = {
|
|
container : '#waveform',
|
|
waveColor : 'darkorange',
|
|
progressColor : 'purple',
|
|
height : 40,
|
|
interact : true,
|
|
hideScrollbar : true,
|
|
cursorColor : 'darkgray',
|
|
cursorWidth : 1,
|
|
normalize : true,
|
|
audioRate : 1
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
// Create a wavesurfer instance
|
|
//------------------------------------------------------------
|
|
me.wavesurfer = Object.create(WaveSurfer);
|
|
me.wavesurfer.init(me.optplay); // Init wavesurfer for recording
|
|
|
|
//------------------------------------------------------------
|
|
// Wavesurfer events
|
|
//------------------------------------------------------------
|
|
me.wavesurfer.on('seek', function () {
|
|
set(partime()); // Chronometer
|
|
totlen();
|
|
parlen();
|
|
});
|
|
|
|
me.wavesurfer.on('play', function () {
|
|
set(partime()); // Chronometer
|
|
start(); // Chronometer
|
|
});
|
|
|
|
me.wavesurfer.on('pause', function () {
|
|
stop(); // Chronometer
|
|
});
|
|
|
|
me.wavesurfer.on('ready', function () {
|
|
//
|
|
});
|
|
|
|
//------------------------------------------------------------
|
|
// Create new audio context and blank tape
|
|
//------------------------------------------------------------
|
|
|
|
var cisContext = new AudioContext();
|
|
Ciseaux.context = cisContext;
|
|
emptyBlob();
|
|
show(); // muestra el timer
|
|
|
|
//------------------------------------------------------------
|
|
// Init Microphone plugin
|
|
//------------------------------------------------------------
|
|
me.microphone = Object.create(WaveSurfer.Microphone);
|
|
me.microphone.init({wavesurfer: me.wavesurfer});
|
|
|
|
me.microphone.on('deviceReady', function(stream) {
|
|
var mic_input = recContext.createMediaStreamSource(stream);
|
|
me.recorder = new Recorder(mic_input, {numChannels: 1}, me.voiceRecognitionAudioBlobCallback);
|
|
me.recstate = "REC";
|
|
record();
|
|
});
|
|
|
|
me.microphone.on('deviceError', function(code) {
|
|
console.warn('Device error: ' + code);
|
|
});
|
|
|
|
me.ws = new WebSocket("ws://localhost:8000");
|
|
|
|
me.ws.onopen = function() {
|
|
console.log("conectado");
|
|
me.wsoen = true;
|
|
};
|
|
|
|
me.ws.onclose = function() {
|
|
|
|
// websocket is closed.
|
|
console.log("desconectado");
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
// init method is called fron within object
|
|
// no need to be called from the outside
|
|
init();
|
|
};
|