ios - mixing midi files, each with own sound font

后端 未结 3 1334
半阙折子戏
半阙折子戏 2021-01-01 05:12

I\'m looking for a way to mix 2 or more midi files, each with their own sound font files. I\'ve found the following code for one file and tried to do multiple music players

相关标签:
3条回答
  • 2021-01-01 05:39

    I had exactly same issue as you. All tracks play with the first sound font instrument. I followed your solution but it not work at first. Finally, I resolve the problem. As your mentioned, the sequence of calling functions really maters. Yes, it is. Actually, the sequence calling should be like this:

    .....
    MusicSequenceSetAUGraph(s, _processingGraph);
    .......
    MusicTrackSetDestNode(track[i], samplerNodes[i]);
    ......
    [self loadFromDLSOrSoundFont];
    ......
    MusicPlayerStart(p);
    

    This works in my project.

    0 讨论(0)
  • 2021-01-01 05:40

    Multiple MusicPlayer instances sounds a bit awkward (to keep in sync) and I have doubts that multiple AUGraphs would work. I haven't tried it myself.

    One approach using a sole instance of MusicPlayer would be to load the tracks from each midi file into a 'master' sequence. You can assign an AUSampler node (with unique soundFont) to each track (MusicTrackSetDestNode) and connect them all through an AUMixer. You would need to manage the tempos from each midi file (using MusicTrackNewExtendedTempoEvent) to assign file tempos to the relevant tracks. Muting tracks + track volume is easily handled at the track or mixer level.

    I guess much depends on the nature of the midi files you are working with. Fwiw - I did lots of research on midi file playback on iOS and there is nothing out there that is as easy to use as MusicPlayer. However, the Bass lib might be worth looking at if MusicPlayer turns out not to work for you.

    Specifying the number of mixer inputs:

    // set the bus count
    UInt32 numBuses = BUS_COUNT; // a constant defined elsewhere
    result = AudioUnitSetProperty(mixerUnit, 
                                  kAudioUnitProperty_ElementCount, 
                                  kAudioUnitScope_Input, 
                                  0, 
                                  &numBuses, 
                                  sizeof(numBuses));
    
    if (noErr != result) {[self printErrorMessage: @"Error setting Bus Count" withStatus: result]; return;}
    
    0 讨论(0)
  • 2021-01-01 05:41

    So i tried setting the nodes for each track, but that didn't change anything. The soundfont gets only set for the first samplerUnit. Here's how i set up the graph:

    AudioComponentDescription MixerUnitDescription;
    MixerUnitDescription.componentType          = kAudioUnitType_Mixer;
    MixerUnitDescription.componentSubType       = kAudioUnitSubType_MultiChannelMixer;
    MixerUnitDescription.componentManufacturer  = kAudioUnitManufacturer_Apple;
    MixerUnitDescription.componentFlags         = 0;
    MixerUnitDescription.componentFlagsMask     = 0;
    
    AudioComponentDescription cd = {};
    cd.componentManufacturer     = kAudioUnitManufacturer_Apple;
    cd.componentType = kAudioUnitType_MusicDevice; // type - music device
    cd.componentSubType = kAudioUnitSubType_Sampler; // sub type - sampler to convert our MIDI
    
    result = NewAUGraph (&_processingGraph);
    result = AUGraphAddNode(self.processingGraph, &MixerUnitDescription, &mixerNode);
    
    result = AUGraphAddNode (self.processingGraph, &cd, &samplerNode);
    
    result = AUGraphAddNode (self.processingGraph, &cd, &samplerNode2);
    
    cd.componentType = kAudioUnitType_Output;  // Output
    cd.componentSubType = kAudioUnitSubType_RemoteIO;  // Output to speakers
    
    result = AUGraphAddNode (self.processingGraph, &cd, &ioNode);
    result = AUGraphOpen (self.processingGraph);
    
    result = AUGraphConnectNodeInput (self.processingGraph, samplerNode, 0, mixerNode, 0);
    result = AUGraphConnectNodeInput (self.processingGraph, samplerNode2, 0, mixerNode, 1);
    
    result = AUGraphConnectNodeInput (self.processingGraph, mixerNode, 0, ioNode, 0);
    result = AUGraphNodeInfo (self.processingGraph, samplerNode, 0, &_samplerUnit);
    result = AUGraphNodeInfo (self.processingGraph, samplerNode2, 0, &_samplerUnit2);
    result = AUGraphNodeInfo (self.processingGraph, ioNode, 0, &_ioUnit);
    

    This is the example method from Apple Developer pages which i modified to assign a soundfont to a specific samplerUnit:

    -(OSStatus) loadFromDLSOrSoundFont: (NSURL *)bankURL withPatch: (int)presetNumber withAudioUnit:(AudioUnit)auUnit{
    
    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(auUnit,
                              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;
    }
    

    Then i did this twice to get each track into musicSequence:

    if(MusicSequenceFileLoad(tmpSequence, (__bridge CFURLRef)midiFileURL, 0, 0 != noErr)) 
    {
        [NSException raise:@"play" format:@"Can't load MusicSequence"];
    }
    
    
    MusicSequenceGetIndTrack(tmpSequence, 0, &tmpTrack);
    MusicSequenceNewTrack(musicSequence, &track);
    MusicTimeStamp trackLen = 0;
    UInt32 trackLenLen = sizeof(trackLen);
    MusicTrackGetProperty(tmpTrack, kSequenceTrackProperty_TrackLength, &trackLen, &trackLenLen);
    MusicTrackCopyInsert(tmpTrack, 0, trackLenLen, track, 0);
    

    And finally:

    MusicTrackSetDestNode(track, samplerNode);
    MusicTrackSetDestNode(track2, samplerNode2);
    

    But this won't assign the the soundfont to the samplerUnit2:

    [self loadFromDLSOrSoundFont: (NSURL *)presetURL2 withPatch: (int)0 withAudioUnit:self.samplerUnit2];
    

    Assigning to samplerUnit works fine. Any ideas what i'm missing here?

    0 讨论(0)
提交回复
热议问题