kovaxis / midly

A feature-complete MIDI parser and writer focused on speed.
The Unlicense
138 stars 26 forks source link

Difficulty with timing #13

Closed Ploppz closed 3 years ago

Ploppz commented 4 years ago

Maybe not an issue with this library, but I cannot seem to get timing right.

const TICKS_PER_FRAME: u8 = 80;
const TICKS_PER_SECOND: u64 = 24 * (TICKS_PER_FRAME as u64);

fn midi_header() -> Header {
    Header::new(
        Format::SingleTrack,
        Timing::Timecode(Fps::Fps24, TICKS_PER_FRAME),
    )
}

Then when I receive a midi event, I calculate the tick based on the microseconds (us):

let tick = (us * TICKS_PER_SECOND) / 1_000_000;

In a small test run that lasted less than 10 seconds, I log:

Nov 07 09:35:21.921 DEBG MIDI event, us: 3398330, tick: 6524, event: Midi { channel: u4(0), message: NoteOn { key: u7(60), vel: u7(1) } }
Nov 07 09:35:22.078 DEBG MIDI event, us: 3555581, tick: 6826, event: Midi { channel: u4(0), message: NoteOff { key: u7(60), vel: u7(120) } }
Nov 07 09:35:22.209 DEBG MIDI event, us: 3686743, tick: 7078, event: Midi { channel: u4(0), message: NoteOn { key: u7(60), vel: u7(34) } }
Nov 07 09:35:22.390 DEBG MIDI event, us: 3867814, tick: 7426, event: Midi { channel: u4(0), message: NoteOff { key: u7(60), vel: u7(104) } }
Nov 07 09:35:22.856 DEBG MIDI event, us: 4334220, tick: 8321, event: Midi { channel: u4(0), message: NoteOn { key: u7(60), vel: u7(25) } }
Nov 07 09:35:23.097 DEBG MIDI event, us: 4575175, tick: 8784, event: Midi { channel: u4(0), message: NoteOff { key: u7(60), vel: u7(101) } }
Nov 07 09:35:23.112 DEBG MIDI event, us: 4590073, tick: 8812, event: Midi { channel: u4(0), message: NoteOn { key: u7(64), vel: u7(36) } }
Nov 07 09:35:24.298 DEBG MIDI event, us: 5775449, tick: 11088, event: Midi { channel: u4(0), message: NoteOff { key: u7(64), vel: u7(56) } }
Nov 07 09:35:24.302 DEBG MIDI event, us: 5780360, tick: 11098, event: Midi { channel: u4(0), message: NoteOn { key: u7(60), vel: u7(16) } }
Nov 07 09:35:27.139 DEBG MIDI event, us: 8617264, tick: 16545, event: Midi { channel: u4(0), message: NoteOff { key: u7(60), vel: u7(110) } }

But when I import the resulting MIDI file into Bitwig, it lasts for 35 seconds... Attaching zip file with midi file inside. out.mid.zip

Boscop commented 4 years ago

Some DAWs have poor midi support, such as Ableton. Bitwig was modeled after Ableton. Maybe try with timing in terms of ticks per quarter note, that works everywhere.

Ploppz commented 4 years ago

Thanks for the reply. I tried to give timing in relation to BPM:

const TICKS_PER_BEAT: u16 = 4_000;
const US_PER_BEAT: u32 = 1_000_000 / 2; // half a second per beat = 120 bpm
fn us_to_tick2(us: u64) -> u32 {
    (TICKS_PER_BEAT as u64 * us / US_PER_BEAT as u64) as u32
}
fn midi_header2() -> Header {
    Header::new(
        Format::SingleTrack,
        Timing::Metrical(TICKS_PER_BEAT.into()),
    )
}
fn initial_message<'a>() -> MetaMessage<'a> {
    MetaMessage::Tempo(US_PER_BEAT.into())
}

But again it's too long when I load it into Bitwig. Same with Ardour. Moreover, if I change US_PER_BEAT, the length of the MIDI clip stretches proportionally in Bitwig (probably in Ardour too, didn't test yet), which hints that Bitwig does not pay attention to the timing info in my midi file, because changing US_PER_BEAT should not change the actual timing in the MIDI file because I use it both in the initial Tempo message and in calculation of tick from microseconds. If my math is right that is. out.mid.zip

Boscop commented 4 years ago

Yeah, that's because bitwig uses the project's bpm, but when you import the Midi file, at least it will be on the grid. And if you set the project bpm to the midi file's bpm, it should have the intended length.

kovaxis commented 4 years ago

Doesn't look like a midly issue. Create two midi files from the same notes at the same timestamps, but with different US_PER_BEAT and/or TICKS_PER_BEAT. Then load them up in a MIDI player, or upload them here. If they play back the same in a MIDI player, it's a bitwig issue.

kovaxis commented 3 years ago

Okay, closing.