MIDI event handler
parent
e15a168152
commit
e09dd47f4d
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
Copyright 2014 matrix.org
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
String.prototype.endsWith = function(suffix) {
|
||||
return this.indexOf(suffix, this.length - suffix.length) !== -1;
|
||||
};
|
||||
|
||||
var MidiEventHandler = {
|
||||
midiQueue: [],
|
||||
|
||||
startTime: 0,
|
||||
|
||||
vexTabString: "",
|
||||
|
||||
currentMeasureTime: 0,
|
||||
perLine: -1,
|
||||
|
||||
init: function () {
|
||||
MIDI.loadPlugin({
|
||||
soundfontUrl: "./soundfont/",
|
||||
instrument: "acoustic_grand_piano",
|
||||
callback: function () {
|
||||
/*
|
||||
var delay = 0; // play one note every quarter second
|
||||
var note = 50; // the MIDI note
|
||||
var velocity = 127; // how hard the note hits
|
||||
// play the note
|
||||
MIDI.setVolume(0, 127);
|
||||
MIDI.noteOn(0, note, velocity, delay);
|
||||
MIDI.noteOff(0, note, delay + 0.75);
|
||||
*/
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
|
||||
this.vexTabString = "";
|
||||
this.currentMeasureTime = 0;
|
||||
this.perLine = -1;
|
||||
this.ready = false;
|
||||
|
||||
this.beat = 0;
|
||||
this.intial4Timings = [];
|
||||
|
||||
this.renderer = new Vex.Flow.Renderer($('#boo')[0],
|
||||
Vex.Flow.Renderer.Backends.CANVAS);
|
||||
|
||||
this.artist = new Vex.Flow.Artist(10, 10, 750, {scale: 0.8});
|
||||
this.vextab = new Vex.Flow.VexTab(this.artist);
|
||||
|
||||
// key is the note string, value its midi_ts value when it went to ON
|
||||
this.notesON = {};
|
||||
},
|
||||
|
||||
/*
|
||||
vextab.parse("tabstave notation=true tablature=false \n\
|
||||
notes 4-5-6/3 ## =|: 5-4-2/3 2/2 =:|\n\
|
||||
\n\
|
||||
tabstave notation=true tablature=false\n\
|
||||
notes C-D-E/4 #0# =:: C-D-E-F/4 =|=");
|
||||
artist.render(renderer);
|
||||
*/
|
||||
|
||||
|
||||
setReady: function() {
|
||||
this.ready = true;
|
||||
this.render();
|
||||
},
|
||||
|
||||
handleEvent: function(event) {
|
||||
|
||||
if (0 === this.beat)
|
||||
{
|
||||
// We do not know the beat yeat
|
||||
// Wait for 4 notes to compute the tempo
|
||||
if ("on" === event.content.state) {
|
||||
|
||||
this.intial4Timings.push(parseInt(event.content.midi_ts));
|
||||
|
||||
if (4 === this.intial4Timings.length) {
|
||||
// un beat: duree d'un temps
|
||||
this.beat = (this.intial4Timings[3] - this.intial4Timings[0]) / 3;
|
||||
|
||||
console.log("## beat: " + this.beat);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var vexNote = this.getVexNote( this.getMidiNote(event.content.note) );
|
||||
|
||||
if ("on" === event.content.state) {
|
||||
this.notesON[vexNote] = parseInt(event.content.midi_ts);
|
||||
}
|
||||
else if (this.notesON[vexNote])
|
||||
{
|
||||
// How long the note last
|
||||
var duration = parseInt(event.content.midi_ts) - this.notesON[vexNote];
|
||||
delete this.notesON[vexNote];
|
||||
|
||||
var fraction = duration / this.beat;
|
||||
|
||||
console.log(fraction);
|
||||
|
||||
var musicFraction;
|
||||
|
||||
|
||||
var duration = Math.floor(Math.log2(1 / fraction)) - 1;
|
||||
switch (duration) {
|
||||
case 4:
|
||||
musicFraction = "w";
|
||||
break;
|
||||
case 2:
|
||||
musicFraction = "h";
|
||||
break;
|
||||
case 1:
|
||||
musicFraction = "q";
|
||||
break;
|
||||
case 0:
|
||||
musicFraction = "8";
|
||||
break;
|
||||
case -1:
|
||||
musicFraction = "16";
|
||||
break;
|
||||
case -2:
|
||||
musicFraction = "32";
|
||||
break;
|
||||
|
||||
}
|
||||
this.currentMeasureTime += duration;
|
||||
|
||||
|
||||
vexNote = ":" + musicFraction + " " + vexNote;
|
||||
|
||||
this.addNote(vexNote);
|
||||
}
|
||||
},
|
||||
|
||||
c: function(fraction) {
|
||||
return Math.floor(Math.log2(1 / fraction)) - 1;
|
||||
|
||||
},
|
||||
|
||||
addNote: function (vexNote) {
|
||||
|
||||
if (-1 === this.perLine)
|
||||
{
|
||||
// Create a new line
|
||||
if ("" !== this.vexTabString) {
|
||||
// Add a line break with the previous line
|
||||
this.vexTabString += "\n";
|
||||
}
|
||||
this.vexTabString += "tabstave notation=true tablature=false clef=treble time=C\nnotes ";
|
||||
this.perLine = 0;
|
||||
}
|
||||
|
||||
this.vexTabString += vexNote;
|
||||
|
||||
console.log(this.currentMeasureTime);
|
||||
if (this.currentMeasureTime >= 4) {
|
||||
|
||||
this.perLine = this.perLine + 1;
|
||||
|
||||
if (this.perLine <= 3) {
|
||||
this.vexTabString += " | ";
|
||||
}
|
||||
else {
|
||||
// Break the line
|
||||
this.vexTabString += "\n";
|
||||
this.perLine = -1;
|
||||
}
|
||||
|
||||
this.currentMeasureTime = 0;
|
||||
|
||||
}
|
||||
else {
|
||||
this.vexTabString += " ";
|
||||
}
|
||||
|
||||
if (this.ready) {
|
||||
this.render();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getVexNote: function(midiNote) {
|
||||
|
||||
return midiNote;
|
||||
|
||||
// TODO: manage this
|
||||
var vexNote;
|
||||
if (2 === midiNote.length) {
|
||||
|
||||
if (this.vexTabString.endsWith('#')) {
|
||||
vexNote = midiNote[0] + 'n/' + midiNote[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
vexNote = midiNote[0] + '/' + midiNote[1];
|
||||
}
|
||||
}
|
||||
|
||||
return vexNote;
|
||||
},
|
||||
|
||||
getMidiNote: function(midiNoteNumber) {
|
||||
var noteString = [ "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" ];
|
||||
var octave = Math.floor(midiNoteNumber / 12) - 1;
|
||||
var noteIndex = (midiNoteNumber % 12);
|
||||
return noteString[noteIndex] + "/" + octave;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
console.log("####\n" + this.vexTabString);
|
||||
|
||||
this.vextab.reset();
|
||||
this.artist.reset();
|
||||
|
||||
this.vextab.parse(this.vexTabString);
|
||||
this.artist.render(this.renderer);
|
||||
}
|
||||
|
||||
};
|
Loading…
Reference in New Issue