1
votes

I have an app that handles playing multiple midi instruments. Everything works great except for playing percussion instruments. I understand that in order to play percussion in General MIDI you must send the events to channel 10. I've tried a bunch of different things, and I can't figure out how to get it to work, here's an example of how I'm doing it for melodic instruments vs percussion.

    // Melodic instrument
    MusicDeviceMIDIEvent(self.samplerUnit, 0x90, (UInt8)pitch, 127, 0);

    // Percussion Instruments
    MusicDeviceMIDIEvent(self.samplerUnit, 0x99, (UInt8)pitch, 127, 0);

The sampler Unit is an AudioUnit and the pitch is given as an int through my UI.

Thanks in advance!

2
Those two lines of code look fine. Are you using AUSampler or AUMIDISynth? Is the problem that the percussion sounds are silent, or do you see an error message somewhere? - Andrew Madsen
@AndrewMadsen Using AUSampler, and the output when I set the channel to 10 is just the same as channel 1 - CodyMace
Have you loaded a soundfont? As far as I know, AUSampler just uses sine wave tones on iOS unless you load a soundfont yourself. - Andrew Madsen
Oh, yeah. I'm using a soundfont, Fluid. The instruments all sound great, it just doesn't seem like the reserved channel 10 is doing what it should. - CodyMace
Are you sending any program change or bank select messages? - CL.

2 Answers

1
votes

Assuming you have some sort of a General MIDI sound font or similar loaded, you need to set the correct status byte before sending pitch/velocity information. So in case of a Standard MIDI Drum Kit (channel 9), you'd do something like this in Swift:

var status  = OSStatus(noErr)
let drumCommand = UInt32( 0xC9 | 0 )
let noteOnCommand = UInt32(0x90 | channel)
status = MusicDeviceMIDIEvent(self._samplerUnit, drumCommand, 0, 0, 0) // set device
status = MusicDeviceMIDIEvent(self._samplerUnit, noteOnCommand, noteNum, velocity, 0)  // sends note ON message

No need to undertake anything special for MIDI note off messages.

0
votes

Ok, so I got it working. I guess the way I load the sound font makes it so the channel stuff doesn't do anything. Instead I had to set the bankMSB property on AUSamplerBankPresetData to kAUSampler_DefaultPercussionBankMSB instead of kAUSampler_DefaultMelodicBankMSB

I added a different font loading method specifically for percussion:

- (OSStatus) loadPercussionWithSoundFont: (NSURL *)bankURL {
    OSStatus result = noErr;

    // fill out a bank preset data structure
    AUSamplerBankPresetData bpdata;
    bpdata.bankURL  = (__bridge CFURLRef) bankURL;
    bpdata.bankMSB  = kAUSampler_DefaultPercussionBankMSB;
    bpdata.bankLSB  = kAUSampler_DefaultBankLSB;
    bpdata.presetID = (UInt8) 32;

    // set the kAUSamplerProperty_LoadPresetFromBank property
    result = AudioUnitSetProperty(self.samplerUnit,
                                  kAUSamplerProperty_LoadPresetFromBank,
                                  kAudioUnitScope_Global,
                                  0,
                                  &bpdata,
                                  sizeof(bpdata));

    // check for errors
    NSCAssert (result == noErr,
               @"Unable to set the preset property on the Sampler. Error code:%d '%.4s'",
               (int) result,
               (const char *)&result);

    return result;
}