I need a bit of help understanding some simple C bitshifting in the Apple/iOS LoadPresetDemo source code. It is dead simple but will take a bunch of space to provide context, so thanks for bearing with me.
I am trying to understand why the programmer is using this line:
UInt32 noteCommand = kMIDIMessage_NoteOn << 4 | 0;
The programmer has defined the constants elsewhere in the code (below). When I pull out my calculator and enter 0x9 and shift it left 4 places, I get 0x90. I’ve plugged that number into the code in place of the line above the code runs fine, so I am confused. My two questions:
-
Why didn’t the programmer just define the constant as 0x90?
-
What is the purpose of the OR operator in the code above?
I know this is a small, silly detail but I’d like to know if there is a good reason behind this and understand bitshifting a bit better (no pun intended…). The full method and details are below. – Thanks!
// some MIDI constants:
enum {
kMIDIMessage_NoteOn = 0x9,
kMIDIMessage_NoteOff = 0x8,
};
// Play the mid note
- (IBAction) startPlayMidNote:(id)sender {
UInt32 noteNum = kMidNote;
UInt32 onVelocity = 127;
UInt32 noteCommand = kMIDIMessage_NoteOn << 4 | 0;
OSStatus result = noErr;
require_noerr (result = MusicDeviceMIDIEvent(self.samplerUnit, noteCommand, noteNum, onVelocity, 0), logTheError);
logTheError:
if (result != noErr) NSLog (@"Unable to start playing the mid note. Error code: %d '%.4s'\n", (int) result, (const char *)&result);
}
// Stop the mid note
- (IBAction) stopPlayMidNote:(id)sender {
UInt32 noteNum = kMidNote;
UInt32 noteCommand = kMIDIMessage_NoteOff << 4 | 0;
OSStatus result = noErr;
require_noerr (result = MusicDeviceMIDIEvent(self.samplerUnit, noteCommand, noteNum, 0, 0), logTheError);
logTheError:
if (result != noErr) NSLog (@"Unable to stop playing the mid note. Error code: %d '%.4s'\n", (int) result, (const char *)&result);
}
/*!
@function MusicDeviceMIDIEvent
@abstract Used to sent MIDI channel messages to an audio unit
@discussion This is the API used to send MIDI channel messages to an audio unit. The status and data parameters
are used exactly as described by the MIDI specification, including the combination of channel and
command in the status byte.
@param inUnit
The audio unit
@param inStatus
The MIDI status byte
@param inData1
The first MIDI data byte (value is in the range 0 < 128)
@param inData2
The second MIDI data byte (value is in the range 0 < 128). If the MIDI status byte only has one
data byte, this should be set to zero.
@param inOffsetSampleFrame
If you are scheduling the MIDI Event from the audio unit's render thread, then you can supply a
sample offset that the audio unit may apply when applying that event in its next audio unit render.
This allows you to schedule to the sample, the time when a MIDI command is applied and is particularly
important when starting new notes. If you are not scheduling in the audio unit's render thread,
then you should set this value to 0
@result noErr, or an audio unit error code
*/
extern OSStatus
MusicDeviceMIDIEvent( MusicDeviceComponent inUnit,
UInt32 inStatus,
UInt32 inData1,
UInt32 inData2,
UInt32 inOffsetSampleFrame) __OSX_AVAILABLE_STARTING(__MAC_10_0,__IPHONE_5_0);
The reason the author wrote the code this way is most likely to make it easier to understand. MIDI event codes are divided into 2 parts where the upper 4 bits are the event and the lower 4 bits are the channel number. By showing you a constant shifted left 4 bits and OR’d with 0 he was indicating that the MIDI event was using that constant as the event code on channel 0.