grimmdude / MidiPlayerJS

♬ MIDI parser & player engine for browser or Node. As a parser converts MIDI events into JSON. Works well with single or multitrack MIDI files.
https://grimmdude.com/MidiPlayerJS/
MIT License
357 stars 52 forks source link

Unable to achieve accurate playback timing #83

Open alexshenker opened 2 years ago

alexshenker commented 2 years ago

Hi there!

I attempted to implement your demo in React. I noticed that in your live demo, the midi I use plays back quite accurately. However, in my local implementation, it is a bit funky, with in-exact rhythms and overlapping / late notes. Wondering if you have a suggestion as to what might cause that / how to improve on it.

const init = () => {
    var audioCtx = new window.AudioContext()
    Soundfont.instrument(audioCtx, 'https://raw.githubusercontent.com/gleitz/midi-js-soundfonts/gh-pages/MusyngKite/acoustic_guitar_nylon-mp3.js' as any).then((instrument: SoundfontPlayerType) => {
      const __player = new MidiPlayer.Player((e: MidiEvent) => {
        if (e.noteName && e.name == 'Note on') {
          instrument.play(e.noteName, audioCtx.currentTime, { gain: e.velocity ? e.velocity / 100 : 0 })
        }
      })
      const midi: any = Midi.fromUrl('beethoven.mid')
      const arrayBuffer = midi.toArray()
      __player.loadArrayBuffer(arrayBuffer)
      __player.play()
    })
  }

Thank you beethoven.zip !

bethanrv commented 6 months ago

Hey Alex!

I've open a similar issue. I noticed that midi events that should fire only a single note consistently trigger about 45ms before they should, while events that should send multiple notes fire about 10ms late. The simplest way I've found around this is to just send all single notes on a delay of 55ms, and play multiple notes as soon as they come in. Definitely note ideal, but seems to work consistently across browsers.