Midi File Length (Part 2)

I am having the same problem as described in this post : https://forum.juce.com/t/midi-file-length/8164

However, the post is old and contains no real solution. So I’ve decided to post a second version.

I go into a DAW like Reaper and create a midi clip containing several notes where the last note is not flush to the end of the clip. When I try to import the file with tracktion, the clip is truncated to the end of the last note. In other words, the silent part at the end is not included. The file is a .mid.

I can’t seem to find a way to create a midi clip in tracktion that will include the silent part at the end. There has to be a simple way because dropping the file into Waveform includes the silent part.

Here is the code i’m using:

// Path to a .mid file
FileInputStream stream(path);
MidiFile midiFile{};
if (midiFile.readFrom(stream))
{
    midiFile.convertTimestampTicksToSeconds();

    juce::MidiMessageSequence sequence;
    for (auto i = 0; i < midiFile.getNumTracks(); i++)
        sequence.addSequence(*midiFile.getTrack(i), 0.0, 0.0, 1.0e6);
    sequence.updateMatchedPairs();

    // The track that will contain the midi clip.
    te::AudioTrack* audioTrack = getTrack();
    if (nullptr != audioTrack)
    {
        const double start = 0.0;
        if (auto midiClip = audioTrack->insertMIDIClip(
            {
                tracktion::TimePosition::fromSeconds(0.0),
                tracktion::TimePosition::fromSeconds(1.0)
            },
            nullptr))
        {
            // Add midi notes
            midiClip->mergeInMidiSequence(sequence, te::MidiList::NoteAutomationType::none);

            auto length = sequence.getEndTime(); // Problem here! Needs to be the length of the clip.

            tracktion::ClipPosition position = { { tracktion::TimePosition::fromSeconds(start), tracktion::TimePosition::fromSeconds(start + length) }, {} };
            midiClip->setPosition(position);
        }
    }
}

I don’t think the length is encoded in the MIDI file anywhere is it?

I think in Waveform we just make the clip the end of the bar.

I don’t think the length is encoded in the MIDI file anywhere is it?

There’s an “end of track” meta event (source)

FF 2F 00 End of Track
This event is not optional. It is included so that an exact ending point may be specified for the track, so that an exact length is defined, which is necessary for tracks which are looped or concatenated.

In the old post, I think the guy seems to say that you can have a track (MidiMessageSequence) for the end of the clip so you can use MidiMessage::isEndOfTrackMetaEvent() and get the time stamp for the end. Anyway, I’ve traced a bunch of stuff and there seems to be one for the beginning but not the end. Also, the header of the file does not contain any information on the length of the clip.

Tried that. The timestamp for the “end of track” for the last track in the clip is the end time of the last note. Not the end of the clip itself.

It sounds like that’s a bug then, there should be a non-zero delta time before the meta event in the file.

So you’re saying that there should be a track representing for the end of the clip? With a meta event containing a timestamp for the end of the clip itself?

In a midi file, a “track” is roughly the same thing as a “clip.” It can contain multiple tracks. Every track needs to have a start and end meta event at the beginning/end.

If the midi track that you write has an "end’ event that is after the previous event it needs to be prefixed with a non-zero delta time.

I’m not writing anything, I’m loading a .mid file that was created in a DAW (in this case Reaper). If I load the file in tracktion and dump the content, I get this for a midi clip with one note:

Begin of track 0
Meta event, Time Stamp - 0
Meta event, Time Stamp - 0
Meta event, Time Stamp - 0
Meta event, Time Stamp - 0
End of track 0

Begin of track 1
Meta event, Time Stamp - 0
Meta event, Time Stamp - 0
Note on D#3 Velocity 96 Channel 1, Time Stamp - 0.0625
Note off D#3 Velocity 0 Channel 1, Time Stamp - 0.75
Meta event, Time Stamp - 0.75
End of track 1

Note the 0.75 is not the end of the clip. It is the end of the track containing the note. There is nothing else after that. So maybe MidiFile::readFrom has a bug. I don’t know. Haven’t looked at it.
Or, the note timestamp are normalized over the clip. In which case the missing lenght at the would be 0.25.

You’ll have to look at the actual MIDI file data to verify if its the decoder or the file. From what it sounds like it’s whatever is writing the file, Reaper in this case.

Quick way to confirm is to drop a breakpoint here and see what the interval that gets read is when the meta-event is ff 2f 00. If it’s zero then it sounds like the issue is in Reaper. Like the other thread said, if the deltatime is zero, then the end of the track is equal to the last event (meaning there’s no way to get this information back).