MidiMessageSequence and updateMatchedPairs


#1

Hi Everyone,

I’m writing a piano roll. The piano roll basically manipulates a MidiMessageSequence (I think that this is a common approach with Juce). I’m now at the stage where I’m inserting new midi notes, and it’s working apart from a one situation. Here’s what I’m doing at the moment:

        // create new midi note and add it to the sequence
        juce::MidiMessage noteOn(juce::MidiMessage::noteOn(kMidiChannel, noteNum, kVelocity));
        midiSequence.addEvent(noteOn, ticks);
        juce::MidiMessage noteOff(juce::MidiMessage::noteOff(kMidiChannel, noteNum));
        midiSequence.addEvent(noteOff, ticks+noteLength);
        midiSequence.updateMatchedPairs(); // tell the midi message sequence to connect the note-on and note-off messages 

This works fine, unless we have the following situation (the timestamp values are just for illustration):
[list]
[] My sequence has an existing note that plays from timestamp 100 to timestamp 200[/]
[] I then add a new note (on the same channel, at the same pitch) that plays from timestamp 110 to timestamp 120[/]
[/list]

The problem is that when I call MidiMessageSequence::updateMatchedPairs after adding the second note, it truncates the first note, so the first note is from timestamp 100 to timestamp 110, and the second note is from timestamps 110 to timestamp 120. (What I want is for the first note to be unaffected by adding the second note).

Reading the source for MidiMessageSequence::updateMatchedPairs it appears that the current behaviour is by design, which makes me wonder if I’m going about things the wrong way.

A simple solution would be to change MidiMessageSequence::addEvent() so it returns the index (or the pointer) of the MidiEventHolder object that it has just inserted into the sequence. This would mean that I could manually set up the MidiEventHolder::noteOffObject member of my new note-on event. This also has the benefit of preserving the current behaviour of MidiMessageSequence::updateMatchedPairs, which lots of people’s existing code will no doubt rely on! :slight_smile:

Jules, do you think my suggested change a reasonable request?

Thanks


#2

Yes, the existing behaviour is deliberately done like that, because that’s how midi sequences work: a note-on following another similar note-on is never ignored.

But yes, your suggestion about returning the new object is totally reasonable, I’ll add that for you!


MidiMessageSequence copy constructor has incorrect hidden side-effect
#3

Ah, that makes sense.

Excellent! Thanks very much :slight_smile:


#4

Hi there, I am trying to write midi files using the note on feature in the exact way you have done in your code example but this bit of code claims call to noteOn is ambiguous?

Have I done something stupid?


#5

Yes of course I did, there are two noteOn functions one takes velocity as a uint8 the other as a float. I hadn’t specified which I was using. Sorry for the Necro!


#6

Can someone please clarify, in which case updateMatchedPairs() should be call?

I'm mostly interested in this 2 scenarios:

  1. When an event removed from a MidiMessageSequence, do I need to call it?
  2. When event's time updated through addTimeToMessages(), do I need to call it?

Thanks!


#7

If you add, remove or re-order note on/off events, then you'd need to call it.


#8

I suppose that addTimeToMessages() adds the same offset amount to all events of a midi sequence, so it's stay consistent. 

But do I still need to call updateMatchedPairs() after it?


#9

If nothing has happened that would re-order any notes, then no, you wouldn't need to call it.