ios – 混合midi文件,每个文件都有自己的声音字体

我正在寻找一种方法来混合2个或更多的midi文件,每个文件都有自己的声音文件。 我已经find了一个文件的下面的代码,并试图做多个音乐播放器,但我想这不应该是正确的做法。 另外我每秒都会听到一些奇怪的stream行音乐。

那么有没有其他的方法,也许没有音乐播放器和音乐序列的方法,只使用au单位?

这是我在另一个线程中find的代码:

-(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); } 

多MusicPlayer实例听起来有点尴尬(保持同步),我怀疑多个AUGraphs将工作。 我没有自己尝试过。

使用MusicPlayer的唯一实例的一种方法是将来自每个MIDI文件的音轨加载到“主”序列中。 您可以为每个音轨( MusicTrackSetDestNode )分配一个AUSampler节点(带有独特的soundFont),并通过AUMixer连接它们。 您需要pipe理每个MIDI文件的速度(使用MusicTrackNewExtendedTempoEvent )将文件速度分配给相关轨道。 在轨道或混音器级别轻松处理轨道+轨道音量。

我想这很大程度上取决于你正在使用的MIDI文件的性质。 Fwiw – 我在iOS上进行了大量关于MIDI文件播放的研究,没有任何东西与MusicPlayer一样易于使用。 但是,如果MusicPlayer不能为您工作,那么Bass lib可能值得一看。

指定混频器input的数量:

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

我和你有完全相同的问题。 所有曲目都使用第一个声音文字工具播放。 我跟着你的解决scheme,但它不起作用。 最后,我解决了这个问题。 正如你所提到的,调用函数的顺序确实是主调。 是的。 其实序列调用应该是这样的:

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

这在我的项目中工作。

所以我尝试设置每个轨道的节点,但是这并没有改变任何东西。 soundfont只能设置为第一个samplerUnit 。 以下是我如何设置图表:

 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); 

这是苹果开发者页面的示例方法,我修改为将soundfont分配给特定的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; } 

然后,我做了两次,让每个音乐进入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); 

最后:

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

但是这不会将soundfont分配给samplerUnit2

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

分配到samplerUnit工作正常。 任何想法,我在这里失踪?