Reputation: 177
I created some javascript code that generates midi files based on a passed note and octave. For the most part it works rather well. The problem is that the C note (note=0) plays much shorter than any other note (1 (C#) through 11 (B)).
Here is my code:
function play(note, octave, program){
var note = (octave*12 + note).toString(16);
var velocity = 'ff';
var MIDI_DATA =
'MThd%00%00%00%06%00%01%00%01%00%C0' + // midi header
'MTrk%00%00%00%0E' + // track header
'%00%C0%'+program+
'%00%90%'+note+'%'+velocity+
'%70%30%00' +
'%00%FF%2F%00';
MIDI_DATA = btoa(unescape(MIDI_DATA));
var e = document.createElement('embed');
e.src = "data:audio/mid;base64,"+MIDI_DATA;
e.type = "video/quicktime";
document.body.appendChild(e);
return e;
}
Why is a C note - play(0, 4, '18') sound so much shorter than any other - play(1, 4, '18')? The pitch seems to be correct, just the note's play length.
I think it may have something to do with C being of value 0, but I don't know enough about what I'm doing here with midi to spot a problem.
NOTE: This code does not work in IE (any version).
Upvotes: 0
Views: 945
Reputation: 700680
When the note value is less than 16, you will end up with an invalid escape sequence, i.e. %0
instead of %00
. The unescape
function will not turn that into a character, but leave it unchanged. As it is two characters instead of one, it spills over into the velocity byte and the rest of the MIDI code gets out of sync.
You can use code like this to format a number into two hexadecimal digits:
function toHex(n) {
var code = '0' + n.toString(16);
return code.substr(code.length - 2, 2);
}
Use it to make the note value two digits:
var note = toHex(octave*12 + note);
Upvotes: 0
Reputation: 31893
If I remember correctly, MIDI notes are played by giving a pitch and a velocity (i.e., loudness) between 1 and 127, and stopped by giving the same pitch with a velocity of 0.
Upvotes: 1