MidiBuffer losing time stamp

While debugging an issue with some of my code, I came across some odd behavior with MidiBuffer.

This test:

TEST(JuceMidiBuffer, TimeStamp) {
  double t{123.4};
  juce::MidiBuffer midiBuffer;
  juce::MidiMessage msg = juce::MidiMessage::noteOn(1, 2, 0.5f);
  msg.setTimeStamp(t);
  ASSERT_FLOAT_EQ(msg.getTimeStamp(), t);
  midiBuffer.addEvent(msg, 0);
  ASSERT_FLOAT_EQ(msg.getTimeStamp(), t);
  ASSERT_EQ(midiBuffer.getNumEvents(), 1);
  for (const auto metadata : midiBuffer) {
    auto m = metadata.getMessage();
    ASSERT_FLOAT_EQ(m.getTimeStamp(), t); // failing on this line
  }
}

fails with:

Expected equality of these values:
  m.getTimeStamp()
    Which is: 0
  t
    Which is: 123.4

This seems like a bug. But is there something else I should be doing to keep the timestamp when I pull the MidiMessage out of the MidiBuffer?

The docs for MidiBuffer::addEvent say:

    /** Adds an event to the buffer.

        The sample number will be used to determine the position of the event in
        the buffer, which is always kept sorted. The MidiMessage's timestamp is
        ignored.

If you need to keep some timing information alongside the midi message, you should use the sampleNumber argument to MidiBuffer::addEvent.

Ah, ok. My read of that told me the ordering of the events in the buffer would ignore the timestamp, not that you would lose some data from the MidiMessage if you add it to a MidiBuffer. So I guess if the value for the timestamp is too big for int, which is the type of the sampleNumber parameter for MidiBuffer::addEvent, you need to use another structure instead of MidiBuffer. Is that right?

Edit: same applies if the value of the timestamp needs to be floating point, as in my use case.

The sample number is relative to the buffer, so it starts on each MidiBuffer at 0 (see @reuk’s quote).
And a buffersize of 2,147,483,647 is rather unlikely :wink:

From the docs for MidiMessage::getTimeStamp():

The exact meaning of this time and its units will vary, as messages are used in a variety of different contexts.

What the time stamp in a MidiMessage actually is is arbitrary, and it’s of type double. So it’s really just an inconsistency in the library. Or, more likely, MidiBuffer was never intended to retain the user-supplied time stamp.

Either way, no big deal. It’s easy enough to roll your own queue/buffer of MIDI events. Just wanted to call out that unexpected behavior. Thanks folks!

Ah I see, I missed that point. Thanks for explaining.
I really thought MidiBuffer was really intended for the processBlock only, in which case the int makes sense.
I can see how storing an intrusive timestamp in MidiMessage can be useful, but it leads to the problems you pointed out.

1 Like