MidiMessages and iterator


#1

I apologize in advance if this is a stupid question but it has been at least 10 years since I’ve done any serious C++ programming so I hope I’m just missing something.

I want to use the MidiBuffer iterator and the signature of getNextEvent requires the first parameter to be a MidiMessage.

However, there doesn’t seem to be a way to declare a local MidiMessage variable without actually initializing it to something even though I have no use for any of those initial values.

According to the documentation, all the constructors for MidiMessage require one or more parameters. While I understand it’s just a few bytes and not expensive, it seems odd, particularly when one is in a highspeed callback such as processBlock where every CPU cycle counts and so I’m assuming I’ve forgotten something about local variables are supposed to be declared.

Would appreciate someone reminding me how this is supposed to work.

Thanks,
D


#2

You just initialise the temporary MidiMessage variable to some valid MidiMessage. The code http://www.rawmaterialsoftware.com/viewtopic.php?f=2&t=5565 is what you want.

Jules uses MidiMessage m (0xf4, 0.0); presumably since F4 is a valid but undefined message. See juce_Synthesiser.cpp.


#3

That’s what I did as a temporary workaround (although I just used 0 since I didn’t care what was in it) but given the usage pattern, a decent compiler would be generating a “value not used” warning. A programmer reading this code would be forgiven for wondering about the purpose of such initialization.

Is there a process for modifying the Juce source code and integrating back into the source tree? I would be very tempted to refactor MidiMessage so that it derives from a parent class called something like CustomMidiMessage (where most of the functionality would live, including the iterator but without forced initializers) and then derive MidiMessage adding only those constructors.

That would be a no-op for old code but would allow temporary variables without initialization, and also squeezing a few extra cycles out of the CPU.


#4

Yes, the process is that you can suggest something, and if I think it’s a good idea, I’ll add it. This isn’t a good idea, though: simple copy-by-value types like MidiMessage should never use inheritance unless there’s a very good reason.

I avoided providing a default constructor for a MidiMessage because I wanted to try to ensure that all instances of MidiMessage were actually valid messages. (Of course if you initialise it with 0, then that all goes out the window…) And the overhead of creating a dummy message like Martin suggested is minuscule. If there’s such a thing as a “no-op” midi message, then I guess it wouldn’t be such a bad idea to put in a default constructor that initialises it to that. Anyone know if such a message exists?


#5

Why not use the other MidiBuffer::Iterator::getNextEvent::getNextEvent() version if you’re really worried about speed:

bool getNextEvent (const uint8* &midiData, int& numBytesOfMidiData, int& samplePosition) throw();

It might be useful to have a MidiMessage constructor that doesn’t own the data (like AudioSampleBuffer has) then this raw uint8 midiData could be wrapped in a MidiMessage without memory allocation. But I suspect this may not be worth it as it is with AudioSampleBuffer as it would add complexity to the copying and destructor stuff which is already pretty lean with using the preallocatedData for short messages.


#6

The issue wasn’t so much optimization as it was “understandability”.

To me it seems very odd to have a method whose purpose is to fill in a call-by-ref parameter, (thereby making the previous content completely irrelevant) where variables of that type cannot be declared without prefilling them in with essentially useless data.

Obviously this is not a huge deal but given my very rusty C++ knowledge, I thought it was me doing something wrong although I must admit that I’m glad it wasn’t me (grin).


#7

The only thing I can think of is an empty sysex message if the two byte message F0 F7 is ignored by all devices. (I know the second byte is supposed to be a manufacturer ID but since F7 terminates any sysex message it probably doesn’t matter)

The assert macro is your friend, at least when in debug mode :smiley:


#8

Isn’t there some sort of keep-alive ping that devices send out periodically…? It’s been a while since I’ve done any midi work…


#9

Ha ha ha. While driving to the apple store I suddenly remembered that there is an Active Sense message. I forget thevalue but it’s just one byte. I stopped On the side of the road to write this message and saw your comment


#10

active sense: 0xFE

i think a midi messages should be 0xff and that would mark it as an invalid message and it could be the default parameter to the constructor.


#11

I’d rather it always contained a valid message, just a not-very-useful one. I’ve gone for 0xfe (checked-in already).


#12

First, thanks for making an empty constructor version (grin).

Upon reflection, I am vaguely tempted to argue for the empty sysex message though. It turns out that active sensing isn’t that harmless. Once a device receives its first ActiveSense message, it is supposed to enter a “mode” where it will now check that it continues to receive ActiveSense messages and if it doesn’t, it’s supposed to silence itself on the assumption that the connection broke. So if you ever send one of these default messages out by mistake, you could have continuous grief until you turn your synth off an on again (shades of The IT Crowd)


#13

if you want a message that does not do anything 0xf0 does not do anything it just means a sysex message, but it does not mean there needs to be any data, i use that in my programs it’s harmless to midi devices.

and like it is said above active sense is not harmless, and believe it or not modern devices do use that (my M-Audio ozonic sent out active sense all the time).


#14

You shouldn’'t use f0 by itself — you need to ensure that the next byte “finishes” the sysex message otherwise you run the risk of subsequent shortcut messages (i.e, two byte messages without the status) from being lost due to their being considered part of the sysex message.


#15

Hmm. Interesting. Not sure what to do about it. And 0xff is actually a meta-event, so can’t use that anyway.

Maybe 0xf8, which is just a 1-byte midi clock pulse? Surely everything will just ignore one of those.

(Of course it actually doesn’t really matter too much whether the message is ignored, because this value should never actually reach a real device unless you’ve made a coding error somewhere…)


#16

I think that F0 F7 will be perfectly fine. The first starts a sysex message and the second immediately ends it. No device will respond and they’ll all go back to normale responding right after the F7


#17

jules is right it’s up to the programmer to make sure all sent out messages are valid, that’s why i proposed a non-valid message as a constructor, so that if the programmer makes a mistake and never sets any valid data to the message the driver/os/device will make sure it won’t be sent anywhere and won’t affect anything,

this is a quote from my fav MIDI spec

i guess there is no midi message that can be sent and can also be assumed harmless, that depends on the device state.

here is a link to the sysex specs i quoted http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/midispec/sysex.htm


#18

But that is PRECISELY why the Sysex message F0 F7 would be just fine.


#19

The downside of using active sensing (0xfe) is that if this DOES end up getting sent to a device you should make sure you keep on sending it. Otherwise if the receiving device might reset itself when they don’t keep coming…

Still not sure it matters too much for the reasons already discussed.


#20

And my 0xf8 suggestion? Any objections to a midi clock pulse?