Ios - mixing midi files, each with its own sound font

I am looking for a way to mix 2 or more midi files, each with its own font sound files. I found the following code for a single file and tried to make several music players, but I think this should not be the right approach. I also get some weird pop sound every second.

So, is there another way, maybe without the musicplayer and musicsequence methods, using only au units?

Here is the code I found in another thread:

-(void) playMusic:(NSString*) name { NSString *presetURLPath = [[NSBundle mainBundle] pathForResource:@"GortsMiniPianoJ1" ofType:@"SF2"]; NSURL * presetURL = [NSURL fileURLWithPath:presetURLPath]; [self loadFromDLSOrSoundFont: (NSURL *)presetURL withPatch: (int)3]; NSString *midiFilePath = [[NSBundle mainBundle] pathForResource:name ofType:@"mid"]; NSURL * midiFileURL = [NSURL fileURLWithPath:midiFilePath]; NewMusicPlayer(&musicPlayer); if (NewMusicSequence(&musicSequence) != noErr) { [NSException raise:@"play" format:@"Can't create MusicSequence"]; } if(MusicSequenceFileLoad(musicSequence, (CFURLRef)midiFileURL, 0, 0 != noErr)) { [NSException raise:@"play" format:@"Can't load MusicSequence"]; } MusicPlayerSetSequence(musicPlayer, musicSequence); MusicSequenceSetAUGraph(musicSequence, _processingGraph); MusicPlayerPreroll(musicPlayer); MusicPlayerStart(musicPlayer); } 
+4
source share
3 answers

Multiple instances of MusicPlayer sound a bit uncomfortable (to sync), and I doubt that multiple AUGraphs will work. I have not tried it myself.

One approach that uses a single instance of MusicPlayer is to load tracks from each MIDI file into the "master" sequence. You can assign an AUSampler node (with a unique soundFont) to each track ( MusicTrackSetDestNode ) and connect them via AUMixer . You will need to control the tempo from each midi file (using MusicTrackNewExtendedTempoEvent ) to assign the tempo of the files to the corresponding tracks. Muting tracks + track volume is easily handled at the track or mixer level.

I think a lot depends on the nature of the midi files you work with. Fwiw - I researched a lot about playing MIDI files on iOS, and there is nothing that could be easily used as MusicPlayer. However, Bass lib might be worth a look if MusicPlayer doesn't work for you.

Indication of 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;} 
+3
source

I had the same problem as you. All tracks are played using the first audio font tool. I followed your decision, but at first it didn't work. Finally, I solve the problem. As you mentioned, the sequence of calling functions is really paired. Yes. Actually the sequence call should be like this:

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

This works in my project.

+1
source

So, I tried to configure nodes for each track, but that didn’t change anything. Soundfont is installed only for the first samplerUnit . This is how I set the chart:

 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 an example of the method on Apple Developer pages that I changed to assign 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 in 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 will not be assigned to the samplerUnit2 sound screen:

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

Appointment samplerUnit works fine. Any ideas what I'm missing here?

0
source

All Articles