Save the above link as *.mid or *.kar file and open it in MIDI/karaoke player.
If an approppriate plugin/extension (like this) is enabled in your browser, you will also see an embedded object next to the link.
The code below creates MIDI file from scratch and writes it into HTML document.
<!DOCTYPE html> <html> <head> <title>Write MIDI File</title> <script src="JZZ.js"></script> <script src="JZZ.midi.SMF.js"></script> </head> <body> <h1>Write MIDI File</h1> <div id=out></div> <script><!-- // Create a MIDI file. Type 1; 100 clocks per quarter note. // Normally, it would rather be 96, but 100 makes it easier to count. var smf = new JZZ.MIDI.SMF(1, 100); // Add MIDI file tracks: var trk0 = new JZZ.MIDI.SMF.MTrk(); smf.push(trk0); // First track in Type 1 MIDI file is normally used for tempo changes var trk1 = new JZZ.MIDI.SMF.MTrk(); smf.push(trk1); // This one will be for the karaoke lyrics var trk2 = new JZZ.MIDI.SMF.MTrk(); smf.push(trk2); // This one will be for the music trk0.smfSeqName('Little Lame') // The name of the first track serves as the file title .smfBPM(90); // Tempo. Normally set at clock 0, but can be also changed later trk1.smfSeqName('Lyrics') // The names of other tracks don't have any particular meaning .smfText('@TMary Was A Little Lame') // Karaoke player will recognize this track by the "@T" tag .tick(100).smfText('\\Ma') // New verse starts with a backslash "\" .tick(75).smfText('ry ') .tick(25).smfText('was ') .tick(50).smfText('a ') .tick(50).smfText('lit') .tick(50).smfText('tle ') .tick(50).smfText('lame,') .tick(100).smfText('/Lit') // New line starts with a slash "/" .tick(50).smfText('tle ') .tick(50).smfText('lame,') .tick(100).smfText('/Lit') .tick(50).smfText('tle ') .tick(50).smfText('lame,') .tick(100).smfText('/Ma') .tick(75).smfText('ry ') .tick(25).smfText('was ') .tick(50).smfText('a ') .tick(50).smfText('lit') .tick(50).smfText('tle ') .tick(50).smfText('lame,') .tick(50).smfText('/A ') .tick(50).smfText('lit') .tick(50).smfText('tle ') .tick(50).smfText('lame ') .tick(50).smfText('was ') .tick(50).smfText('she!'); trk2.smfSeqName('Music') .ch(0) // all subsequent messahes will go to channel 0 .program(0x0b) // set channel 0 program to vibraphone .tick(100).note('E5', 127, 75) // clock: 100, MIDI channel: 0, note: E5, velocity: 127, duration: 50 clocks .tick(75).note('D5', 127, 25) // etc... .tick(25).note('C5', 127, 50) .tick(50).note('D5', 127, 50) .tick(50).note('E5',127, 50) .tick(50).note(64, 127, 50) // can also use numerical values for the notes .tick(50).note(0x40, 127, 90) .tick(100).note('D5', 127, 50) .tick(50).note('D5', 127, 50) .tick(50).note('D5', 127, 90) .tick(100).note('E5', 127, 50) .tick(50).note('G5', 127, 50) .tick(50).note('G5', 127, 90) .tick(100).note('E5', 127, 75) .tick(75).note('D5', 127, 25) .tick(25).note('C5', 127, 50) .tick(50).note('D5', 127, 50) .tick(50).note('E5', 127, 50) .tick(50).note('E5', 127, 50) .tick(50).note('E5', 127, 50) .tick(75).note('E5', 127, 25) .tick(25).note('D5', 127, 50) .tick(50).note('D5', 127, 50) .tick(50).note('E5', 127, 50) .tick(50).note('D5', 127, 50) .tick(50).note('C5', 127, 190) .tick(100).note('E5', 100, 90).note('G5', 100, 90).note('C6', 127, 90) .tick(100).smfEndOfTrack(); // otherwise it will end on clock 1690 var str = smf.dump(); // MIDI file dumped as a string var b64 = JZZ.lib.toBase64(str); // convert to base-64 string var uri = 'data:audio/midi;base64,' + b64; // data URI // Finally, write it to the document as a link and as an embedded object: document.getElementById('out').innerHTML = 'New file: <a download=lame.mid href=' + uri + '>DOWNLOAD</a> <embed src=' + uri + ' autostart=false>'; --></script> </body> </html>