Yeah, remote devices doing synchronization use MIDI clock messages — an errant one would screw them up.
I think the empty Sysex message is the best.
Having said that, I’m still not quite sure what would be so wrong with an “empty” midi message. Apart from the fact that it could just be ignored when sending out data, it’s very rare that it would actually get sent out anyway as the goal is to always fill the message with something else anyway.
If there was such a thing as an invalid message, it puts a responsibility on code that uses MidiMessages to check them before using them, which could be a significant overhead in some circumstances.
I haven’t looked at the code for how MIDI messages are actually sent out but I assume that at some point there has to be a count of bytes to be sent. So an ‘invalid’ message could simply be a MidiMessage with zero bytes in it. Since you have to test that count anyway, a value of 0 would just mean there’s nothing there to be sent out so one just skips it.
However, taking Voltaire’s position that perfect is the enemy of good enough, I’ll take anything that works (grin) …
just found a nice thing for midi messages and midi in general, i wish they finish it some day with all the vendor id’s and stuff (btw it would be a nice addition to add the getDeviceName() based on the device id byte in the sysex message, it’s just a static array of manufacturer names)
On the subject of MidiBuffer and its Iterator, isnt it high time that
the MidiBuffer just had a build in Iterator or cursor system ?.
I suppose one can grow ones own. There are lots of places where these iterators get created and destroyed inside methods - in the plugin audio stream itself.
Wouldnt it make things more efficient - both in our apps AND int he JUCE framework if the creation of these temporary iterators gets cut to a bare minmum ?
If I remember correctly, the class for creating an iterator does live inside the midibuffer class. It would be convenient if you could ask a midibuffer to create a new iterator instance on the fly and return it. But that style doesn’t seem to be the normal C++ idiom, unfortunately.
the definition and code live inside the buffer class, but you still have to instantiate it manually.
ive nothing against iterators, but for certain situations - particularly when needing to take care over re-entancy and issues concerning code being executed inside a callback from an external process ( eg CoreAudio callbacks etc ) i’d prefer to keep object instantiation ( or mallocs for that matter ) to a minimum.
If you think that, then you clearly don’t understand how c++ object instantiation works! Creating a midibuffer::iterator (or pretty much any kind of iterator) requires no more work than pushing a couple of primitive values on the stack, it certainly doesn’t require a malloc (!)
[quote=“jules”]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…)[/quote]
One thing about midi clock pulses: if you have a host which is syncing based on the first clock pulse, a clock message apropos of nothing else may cause sync issues.
I’m not an expert on MIDI, but from what I can tell, a message of all 00 bytes should be interpreted as a data byte with no leading message (or a quiet signal, if I were to fictitiously extrapolate back to the 5-pin DIN hardware standard, excluding start and stop bits). Since there are no no-ops, which means it’s impossible to make a valid MIDI message that does nothing, I think this is the safest and most consistent thing you can do.
The other philosophy is that it’s a fool’s errand to try to take care of initialization when you don’t know what something will be used for, or if an error status isn’t passed back through it. Leave it up to the programmer to use it right, as they do with most other copy-by-value types in C++.
Edit: I just realized this thread had many more replies to it (which covered most of my points) beyond the first page, which I was responding to. Big doh.
Suppose you send out a Control Change message (3 bytes) and then send out bytes afterwards whose high-order bit is not 1. Those bytes will be considered to be new values for the CC that was previously sent out, which is probably not what you want.
[quote=“dhjdhj”]Unfortunately that won’t work.
Suppose you send out a Control Change message (3 bytes) and then send out bytes afterwards whose high-order bit is not 1. Those bytes will be considered to be new values for the CC that was previously sent out, which is probably not what you want.
[/quote]
Yes, I completely forgot that MIDI could do that. Your F0 F7 solutions seems like a good compromise, except that because system exclusive messages are not considered real-time messages, F0 F7 can interrupt a running status as well. Although, it wouldn’t break state as badly as just sending 00. It would effectively silence any data after it until the next status, which is not so bad.
I don’t see how that’s an issue in practice because if you have code that is sending out messages, you would have to be aware of what you were sending out anyway, particularly if you were trying to do the non-status two byte optimization trick.
I still suspect that a zero byte ‘message’ should work as somewhere lower down, there has to be a mechanism that counts how many bytes to send out anyway and so a zero byte message would just be skipped.
the problem with f0 f7 is that some devices will do “clicks” like the Matrix 6R, you can edit some parameters without “clicking” but some sysex messages will cause the device to break it’s processing for a short time and then resume causing a click.
this might happen with f0 f7 since it’s a valid sysex message some devices might reset their buffers and “click”
There are actually two completely different answers to this issue.
Answer 1 is “what should the default constructed MIDIMessage be?” Answer: it should be a 0-byte MIDI message that emits nothing when sent to the queue. (The tweak to MIDIMessage and its buddies to do this is quite small).
This makes complete sense. If you create an empty MIDIMessage and send it somewhere, then nothing at all should happen…
But the more important question is a metaquestion - could this tweak possibly change the behaviour of real-world software in an observable fashion?
First and foremost, consider the two rules of optimization: rule 1 is DON’T and rule 2 (for experts only) is DON’T (yet).
Second, consider that attempting to optimize software without benchmarks is building on sand.
But finally - consider that you’re talking about MIDI messages here! MIDI is 30k baud, or 3K bytes per second. So there is a minimum gap of 300µs between MIDI events - and more likely 1ms as most MIDI events end up being 3 bytes. Your modern microprocessor’s clock is running 2 gig or so these days, which means about a million cycles between MIDI events - and that’s for a completely jammed-full MIDI stream, which never happens.
It’s likely the default MIDI event loads in two simple instructions, which is far less than 20 cycles… so if you filled one extra MIDI event for each MIDI event that entered the system, then you’d have one part in 50,000 overhead - or a dozen or so nanoseconds of CPU.
Modern computers are so much faster than MIDI! Now, it’s never a good idea to waste clock cycles, but rather than spend time dealing with minutia that will never occupy 0.1% of your CPU, it’s better to be looking for better algorithms on a higher level, where you can sometimes realize order of magnitude gains.
While I happen to agree that answer 1 is the correct approach for both estetic and correctness reasons, I have a more pragmatic issue driving me.
The real problem is that you can’t declare an array of objects if there is no default constructor … at least if you can, then it has happened in a more recent version of C++ than with which I’m familiar.
I ended up subclassing MidiMessage to make a new class with a default constructor so that I could have an array of them.
I agree with you totally in principle. In practice however, such an event should never get sent out anyway, as there’s a presumption that a legit value is going to be assigned to it in the future. (Remember the problem is the inability to declare temporary MidiMessage variable without actually assigning SOMETHING to them)
[quote=“TomSwirly”]It’s likely the default MIDI event loads in two simple instructions, which is far less than 20 cycles… so if you filled one extra MIDI event for each MIDI event that entered the system, then you’d have one part in 50,000 overhead - or a dozen or so nanoseconds of CPU.
Modern computers are so much faster than MIDI! Now, it’s never a good idea to waste clock cycles, but rather than spend time dealing with minutia that will never occupy 0.1% of your CPU, it’s better to be looking for better algorithms on a higher level, where you can sometimes realize order of magnitude gains.[/quote]
I agree completely. But it’s those damn gradient fills that are killing me!