6

I'm using this MIDI.js library: https://github.com/mudcube/MIDI.js

To load the plugin and play the midi file, I'm doing this:

window.onload = function () {
    MIDI.loadPlugin({
        soundfontUrl: "./soundfont/",
        instruments: [ "acoustic_grand_piano" ],
        callback: function() {
            MIDI.programChange(0, 0);   
                    _player = MIDI.Player;

        }
    });

};

function playSong(){            
        _player.timeWarp = 1; // speed the song is played back
        _player.loadFile(song[songid], _player.start);

        _player.addListener(function(data) {
            var now = data.now; // where we are now
            var end = data.end; // time when song ends
            var channel = data.channel; // channel note is playing on
            var message = data.message; // 128 is noteOff, 144 is noteOn
            var note = data.note; // the note
            var velocity = data.velocity; // the velocity of the note


        });
}

var songid = 0;
var song = ['data:audio/mid;base64,TVRoZAAAAA...

My question is, is there anyway to transpose this midi file before playing? Basically I want to parse a midi file (either a .mid file, or the base64 format), change all the notes by +1 and then send it to the player. Any way to do this in javascript?

Prabhu
  • 12,995
  • 33
  • 127
  • 210

2 Answers2

0

This is not a complete answer but it may point you in the right direction if you're still stuck. It's based on spending a few minutes looking at the source for MIDI.js and a couple of the packages it's built on. I'm assuming you want to apply the transposition when the file is read in and are not particularly interested in saving a transposed file.

  1. The addListener method is unlikely to be useful. It looks like a callback that happens immediately after the note is sent to the synth, i.e too late to change the pitch.
  2. You'll want to find the function that's converting the incoming file characters into javascript array elements. That's probably in the jasmid library.
  3. If you're really lucky the developer will have provided a hook you can use to set a callback to alter event properties before the function writes them to an array. Otherwise, you'll need to modify the function accordingly. If you can get it working well, try to convince the developer to patch it into the source -- otherwise you're stuck maintaining your own branch of the library.

Hope this helps.

EDIT: I think the file you want is https://github.com/gasman/jasmid/blob/master/midifile.js . You could apply the transposition in the case that handles note-on events starting at line 155

case 0x09:
    event.noteNumber = param1;
    event.velocity = stream.readInt8();
    if (event.velocity == 0) {
        event.subtype = 'noteOff';
    } else {
        event.subtype = 'noteOn';
    }
    return event;

or, alternatively, when just before the returned event is pushed onto the track array starting at line 227

while (!trackStream.eof()) {
    var event = readEvent(trackStream);
    tracks[i].push(event);
Mike Ellis
  • 1,120
  • 1
  • 12
  • 27
0

You can add a listener to Player with

addListener(
  data => {
     data.note += 1;
  }
);

I believe that it is called before the note itself.

If you use my ES6 fork of mudcube's MIDI.js called midicube [https://github.com/mscuthbert/midicube] it's all in ES6 modules so you can more easily subclass Player and manipulate the data before playing.