Search code examples
iosobjective-ccoremidimusicsequence

Adding a Sound Font to a MusicTrack with MIDINotes? CoreMIDI iOS


I'm successfully loading a Sound Font (.sf2) to a MusicSequence when the MusicSequence it's loaded by file (.mid) like the following:

        //the interesting code ...

        NSString *midiFilePath = [[NSBundle mainBundle]
                                   pathForResource:@"song"
                                   ofType:@"mid"];

        // Create a new URL which points to the MIDI file
        NSURL * midiFileURL = [NSURL fileURLWithPath:filePath];


        MusicSequenceFileLoad(s, (__bridge CFURLRef) midiFileURL, 0, 0);

        // Create a new music player
        MusicPlayer  p;
        // Initialise the music player
        NewMusicPlayer(&p);

        // ************* Set the endpoint of the sequence to be our virtual endpoint
        MusicSequenceSetMIDIEndpoint(s, virtualEndpoint);

        // Load the sound font from file
        NSURL *presetURL = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Full Grand Piano" ofType:@"sf2"]];

        // Initialise the sound font
        [self loadFromDLSOrSoundFont: (NSURL *)presetURL withPatch: (int)10];

        // Load the sequence into the music player
        MusicPlayerSetSequence(p, s);
        // Called to do some MusicPlayer setup. This just
        // reduces latency when MusicPlayerStart is called
        MusicPlayerPreroll(p);
        // Starts the music playing
        MusicPlayerStart(p);

        //code continues here ...


-(OSStatus) loadFromDLSOrSoundFont: (NSURL *)bankURL withPatch: (int)presetNumber {

    OSStatus result = noErr;

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

    // 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;
    }

But If I want to apply the same to a MusicSequence with a MusicTrack build with MIDINoteMessages:

//the interesting code here

MusicSequenceNewTrack(musicSequence, &musicTrack);

MusicSequenceGetIndTrack(musicSequence, 0, &(musicTrack));

MIDINoteMessage aMessage;
aMessage.channel = 1;

aMessage.duration = 0.3f;
aMessage.velocity = 200;

for(int i=0; i<numerator; ++i)
{
    if (i==0) {
        aMessage.note = 80;
    }else {
        aMessage.note = 60;
    }

    MusicTrackNewMIDINoteEvent(musicTrack, i, &aMessage);
}

MusicSequenceSetMIDIEndpoint(musicSequence, virtualEndpoint);

// Load the sound font from file
NSURL *presetURL = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Full Grand Piano" ofType:@"sf2"]];

// Initialise the sound font
[self loadFromDLSOrSoundFont: (NSURL *)presetURL withPatch: (int)10];

//code continues here

I'm getting a (lldb) error. Any idea how to solve this?


Solution

  • This is the sound font relevant code from my github project. This loads the sound font into your sampler unit. If you need more on setting up the augraph see the project or read this post.

    func loadSF2Preset(preset:UInt8)  {
    
        // This is the MuseCore soundfont. Change it to the one you have.
        if let bankURL = NSBundle.mainBundle().URLForResource("GeneralUser GS MuseScore v1.442", withExtension: "sf2") {
            var instdata = AUSamplerInstrumentData(fileURL: Unmanaged.passUnretained(bankURL),
                instrumentType: UInt8(kInstrumentType_DLSPreset),
                bankMSB: UInt8(kAUSampler_DefaultMelodicBankMSB),
                bankLSB: UInt8(kAUSampler_DefaultBankLSB),
                presetID: preset)
    
    
            var status = AudioUnitSetProperty(
                self.samplerUnit,
                AudioUnitPropertyID(kAUSamplerProperty_LoadInstrument),
                AudioUnitScope(kAudioUnitScope_Global),
                0,
                &instdata,
                UInt32(sizeof(AUSamplerInstrumentData)))
            CheckError(status)
        }
    }
    

    You associate the augraph with the MusicSequence like this

        MusicSequenceSetAUGraph(musicSequence, self.processingGraph)