mmitch / gbsplay

gameboy sound player

Home Page:https://mmitch.github.io/gbsplay/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MIDI output slowly gets out of sync if written to separate tracks

mmitch opened this issue · comments

Based on the discussion from issue #88 I have done this:

  • write gbsplay files as MIDI as single tracks (muting all other channels)
  • merging the three MIDI files into one project in Rosegarden so they appear as separate tracke
  • playing the three tracks together

At the start all three tracks are perfectly in sync, but after some time they drift apart.
I suspect we have some problems with rounding errors when encoding the gbsplay ticks to a MIDI delta timestamp.
Exporting all channels together hides these rounding errors, but when single channels are exported, they add up (perhaps a busy baseline accumulates more rounding errors than long string notes on another channel).

I use this script for testing:

#!/bin/bash

gbsplay=~/git/gbsplay/gbsplay
plugout=altmidi
timeout=5

die() {
    echo "$@" >&2
    exit 1
}

gbs=$1
track=${2:-1}

[ -z "$gbs" ] && die "need gbs file as first parameter"

"$gbsplay" -o"$plugout" -234 -T $timeout "$gbs" "$track" "$track"
mv "gbsplay-$track.mid" "gbsplay-$track.1.mid"

"$gbsplay" -o"$plugout" -134 -T $timeout "$gbs" "$track" "$track"
mv "gbsplay-$track.mid" "gbsplay-$track.2.mid"

"$gbsplay" -o"$plugout" -124 -T $timeout "$gbs" "$track" "$track"
mv "gbsplay-$track.mid" "gbsplay-$track.3.mid"

Give a GBS file as first parameter. Second parameter is track; it's optional and defaults to track 1.

I think I've found it: In midi_write_event() in midifile.c we throw away the lowest 14 bits of the internal clock cycles to convert to the lower resolution of a MIDI file:

static int midi_write_event(cycles_t cycles, const uint8_t *data, unsigned int length)
{
	unsigned long timestamp_delta = (cycles - cycles_prev) >> 14;

These thrown away bits need to be remembered and added to the cycles the next time midi_write_event() gets called.
A first test sound promising, but my code still needs some cleanup.

Halfway there :)

Ah, reminds me of the phase accumulator thingy I had to do for the VGM output plugin where the resolution is in imaginary 44100Hz audio samples. ^^;

@pclalv please have a look at the midi-in-sync branch
It currently contains only one extra commit d44b24a that should fix the sync issues.
I hope this solves your problems.

my ears tell me that your fix works. well done!

I'll merge it to master then.
Preview: One of the next commits is going to be a fix to the MIDI playback speed, it currently is about 3% too fast.

This has been fixed with commit d44b24a