/** @constructor */
MusicXMLAnalyzer.ResultController = function(){
var that = {},
model = null,
view = null,
once = true,
once2 = true,
stop = false,
tooLong = false,
tonika = { 'C':0, 'D':2, 'E':4, 'F':5, 'G':7, 'A':9, 'B':11 },
/**
* Init method of ResultController
* @function
* @public
*/
init = function(){
model = MusicXMLAnalyzer.ResultModel();
$(model).on('resultExtractReceived', onResultExtractReceived);
model.init();
view = MusicXMLAnalyzer.ResultView();
$(view).on('addResultItem', onAddResultItem);
view.init();
//init MIDI
MIDI.loadPlugin({
soundfontUrl: "../../../libs/midijs/soundfont/",
instrument: "acoustic_grand_piano",
callback: function() {
}
});
$playResult = $('.playResult');
$stopResult = $('.stopResult');
$stopResult.prop('disabled', true);
$playResult.click(function(){
stop = false;
once2 = true;
once = true;
playResult();
$playResult.prop('disabled', true);
$stopResult.prop('disabled', false);
});
$stopResult.click(function(){
stop = true;
$playResult.prop('disabled', false);
$stopResult.prop('disabled', true);
});
$(document).ajaxStop(onModelReady);
},
/**
* Method to add results to model
* @function
* @public
*
* @param {event} event the triggered event
* @param {int} numItems number of items
* @param {object} result contains results
*/
onAddResultItem = function(event, numItems, result) {
model.setNumItems(numItems);
model.addResultItem(result);
},
/**
* Method to pass result to view
* @function
* @public
*
* @param {event} event the triggered event
* @param {int} index the result index
* @param {object} data the result data
*/
onResultExtractReceived = function(event, index, data) {
view.renderResultExtract(index, data);
},
/**
* Callback when model has loaded results
* @function
* @public
*
* @param {Event} event The triggered event
*/
onModelReady = function(event) {
view.setModelReady();
},
/**
* Function to get note durations
* @function
* @public
*
* @param {string} type The note type
*/
getDuration = function(type){
var duration;
if (type == "whole"){
duration = 1;
} else if (type == "half") {
duration = 0.5;
} else if (type == "quarter") {
duration = 0.25;
} else if (type == "eighth") {
duration = 0.125;
} else if (type == "16th") {
duration = 0.0625;
} else if (type == "32nd") {
duration = 0.03125;
} else if (type == "64th") {
duration = 0.015625;
}
return duration;
},
/**
* Function to get MIDI values
* @function
* @public
*
* @param {int} step the notes step
* @param {int} octave the notes octave
* @param {int} alter the notes accidential (as alter)
*
* @return {int} the MIDI value
*/
getMidiValue = function(step, octave, alter) {
return (parseInt(octave) * 12) + (tonika[step] + parseInt(alter));
},
/**
* Function to play the found Pattern
* @function
* @public
*/
playResult = function(){
var notesToBePlayed = [];
//get notes of current extract:
var currentResultNotes = JSON.parse($('#extract-carousel').find('div.carousel-inner').find('div.item.active').find('.resultExtract').val());
MIDI.setVolume(0, 127);
//determine MIDI values for currentResultNotes
for(var i = 0; i < currentResultNotes.measures.length; i++){
if (currentResultNotes.measures[i].notes) {
for(var j = 0; j < currentResultNotes.measures[i].notes.length; j++){
// check if rest
if(currentResultNotes.measures[i].notes[j].type == 'rest'){
var rest = currentResultNotes.measures[i].notes[j];
var restDuration = getDuration(currentResultNotes.measures[i].notes[j].duration);
notesToBePlayed.push({'note': 0, 'noteDuration': restDuration});
}else if(currentResultNotes.measures[i].notes[j].type == 'note'){
var note = currentResultNotes.measures[i].notes[j];
var noteStep = note.pitch.step;
var noteOctave = note.pitch.octave;
var noteAlter = note.pitch.alter;
var noteDuration = getDuration(note.pitch.type);
var noteTuplet = note.pitch.tuplet;
if(typeof noteDuration === 'undefined'){
noteDuration = 0.25;
}
if(note.pitch.dot){
noteDuration += 0.5*noteDuration;
}
if(typeof noteTuplet === 'undefined'){
console.log("beam is undefined");
noteTuplet = false;
}
var chord = note.pitch.chord;
var midiNote = getMidiValue(noteStep, noteOctave, noteAlter);
notesToBePlayed.push({'note': midiNote, 'noteDuration': noteDuration, 'chord': chord, 'noteTuplet' : noteTuplet});
}
}
}
}
var i = 0;
playTune = function(){
var chordsToBePlayed = [];
if(i < notesToBePlayed.length) {
var note = notesToBePlayed[i].note;
var noteDuration = notesToBePlayed[i].noteDuration;
var velocity = 127; // how hard the note hits
var delay = 0;
var timeout = 0;
if(!once){
timeout = notesToBePlayed[i-1].noteDuration*2000;
if(notesToBePlayed[i-1].noteTuplet == 3) {
timeout = (timeout * 2) / 3;
}
}
once = false;
setTimeout(function() {
if(stop){
i = notesToBePlayed.length;
}else{
if(i + 1 < notesToBePlayed.length) {
tooLong = false;
}else{
tooLong = true;
}
if(!tooLong && notesToBePlayed[i].chord == false && notesToBePlayed[i + 1].chord == true) {
do{
chordsToBePlayed.push(notesToBePlayed[i].note);
i++;
}while(notesToBePlayed[i] && notesToBePlayed[i].chord == true && i < notesToBePlayed.length)
MIDI.chordOn(0, chordsToBePlayed, velocity, delay);
MIDI.chordOff(0, chordsToBePlayed, delay + 0.75);
}
else{
MIDI.noteOn(0, note, velocity, delay);
MIDI.noteOff(0, note, delay + 0.75);
i++;
}
MIDI.Player.stop();
}
// recursively call playTune()
playTune();
}, timeout);
}
// else when finished - reset play&stop buttons after 1.5 sec
else{
setTimeout(function(){
$playResult.prop('disabled', false);
$stopResult.prop('disabled', true);
}, 1500);
}
}
if(once2){
once2 = false;
playTune();
}
};
that.init = init;
return that;
}