mixedinkey-opensource / MIKMIDI

MIDI Library for Swift and Objective-C Mac and iOS apps.
Other
492 stars 95 forks source link

how to use customed sf2 to play midi file? #328

Open catiga opened 2 years ago

catiga commented 2 years ago

test code is below:

MIKMIDISynthesizer synthesizer = [[MIKMIDISynthesizer alloc] init]; NSURL soundfont = [[NSBundle mainBundle] URLForResource:@"FancyNode" withExtension:@"sf2"]; NSError *error = nil; if (![synthesizer loadSoundfontFromFileAtURL:soundfont error:&error]) { NSLog(@"Error loading soundfont for synthesizer. Sound will be degraded. %@", error); }

NSURL *midifile = [[NSBundle mainBundle] URLForResource:@"loop" withExtension:@"mid"];
MIKMIDISequence *seq = [[MIKMIDISequence alloc] initWithFileAtURL:midifile error:nil];
NSArray* alltracks = [seq tracks];

MIKMIDISequencer *seqr = [[MIKMIDISequencer alloc] initWithSequence:seq];
if(!seqr.isPlaying) {
    NSLog(@"prepare to start play");
}
for(int i=0; i<alltracks.count; i++) {
    MIKMIDITrack* track = alltracks[i];
    MIKMIDISynthesizer *synth = [seqr builtinSynthesizerForTrack:track];

    //[synth scheduleMIDICommands:<#(nonnull NSArray<MIKMIDICommand *> *)#>]

    NSLog(@"track done");
}
[synthesizer ]
[seqr setCreateSynthsIfNeeded:TRUE];
[seqr shouldCreateSynthsIfNeeded]
[seqr startPlayback];

midi could play but not to use aimed target sf2, anyone know how to handle it?

timothystulman commented 2 years ago

This is probably a no-brainer, but left me scratching my head for a minute...

builtinSynthesizer will return nil if the given track is being sent to a command scheduler.

`

let midiFileURL = Bundle.main.url(forResource: self.fileName, withExtension: "mid")! sequence = try! MIKMIDISequence(fileAt: midiFileURL)

    let globalTrack = sequence.tracks[0]
    let userTrack = sequence.tracks[1]
    let keysTrack = sequence.tracks[2]
    let accompanimentTrack = sequence.tracks[3]
    let clickTrack = sequence.tracks[4]

    globalTrack.isMuted = true
    clickTrack.isMuted = !midiManager.metroEnabled

    sequencer.sequence = sequence
    sequencer.setCommandScheduler(self, for: keysTrack)

    var i = 0
    for track in sequencer.sequence.tracks {

        do{
            let url = SynthManager.soundFontURL

            //will return nil on keysTrack
            let seq = sequencer.builtinSynthesizer(for: track)!
            try seq.loadSoundfontFromFile(at: url!)
        }catch{
            print("error on track \(i)")
        }
    }

` This works, though...

`let midiFileURL = Bundle.main.url(forResource: self.fileName, withExtension: "mid")! sequence = try! MIKMIDISequence(fileAt: midiFileURL)

    let globalTrack = sequence.tracks[0]
    let userTrack = sequence.tracks[1]
    let keysTrack = sequence.tracks[2]
    let accompanimentTrack = sequence.tracks[3]
    let clickTrack = sequence.tracks[4]

    globalTrack.isMuted = true
    clickTrack.isMuted = !midiManager.metroEnabled

    sequencer.sequence = sequence
    sequencer.setCommandScheduler(self, for: keysTrack)

    let url = SynthManager.soundFontURL!

    let seq1 = sequencer.builtinSynthesizer(for: userTrack)!
    try! seq1.loadSoundfontFromFile(at: url)

    let seq2 = sequencer.builtinSynthesizer(for: userTrack)!
    try! seq2.loadSoundfontFromFile(at: url)

`