ios — смешивание MIDI-файлов, каждый со своим звуковым шрифтом
-
13-12-2019 - |
Вопрос
Я ищу способ объединить 2 или более миди-файла, каждый со своими собственными файлами звуковых шрифтов.Я нашел следующий код для одного файла и попытался создать несколько музыкальных проигрывателей, но думаю, это неправильный подход.Кроме того, каждую секунду я слышу какой-то странный поп-звук.
Так есть ли другой способ, может быть, без методов музыкального проигрывателя и музыкальной последовательности, используя только единицы измерения?
Вот код, который я нашел в другой теме:
-(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 звучит немного неловко (чтобы сохранить синхронизацию), и у меня есть сомнения, что множественные айграфи будут работать. Я не пробовал сам.
Один подход, использующий единственный экземпляр MusicPlayer
, будет загружать дорожки из каждого файла MIDI в последовательность «главной». Вы можете назначить узел AUSAMPLER (с уникальным SoundFont) на каждый трек (MusicTrackSetDestNode
) и подключить их все через AUMixer
. Вам нужно будет управлять Tempos из каждого файла MIDI (используя MusicTrackNewExtendedTempoEvent
), чтобы назначить файл Tempos на соответствующие дорожки. Объем отслеживания + громкость трека легко обрабатывается на уровне дорожки или смесителя.
Я думаю, многое зависит от характера файлов MIDI, с которыми вы работаете. FWIW - я сделал много исследований воспроизведения MIDI-файла на iOS, и там ничего нет, что так просто в использовании в качестве MusicPlayer. Тем не менее, Bass lib может стоить посмотреть, если MusicPlayer получается не работать для вас.
// 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;}
. Другие советы
У меня был точно такой же проблема, как вы.Все треки играют с первым звуковым шрифтом.Я следовал вашему решению, но он не работает сначала.Наконец, я решаю проблему.Как вы упоминались, последовательность вызовов функций действительно туров.Да, это.На самом деле, последовательность вызывания должна быть такой:
.....
MusicSequenceSetAUGraph(s, _processingGraph);
.......
MusicTrackSetDestNode(track[i], samplerNodes[i]);
......
[self loadFromDLSOrSoundFont];
......
MusicPlayerStart(p);
.
Это работает в моем проекте.
Итак, я попробовал установить узлы для каждой дорожки, но это ничего не изменило.Звуковой шрифт устанавливается только для первого 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);
Это пример метода со страниц Apple Developer, который я изменил, чтобы назначить звуковой шрифт определенному 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);
Но это не присвоит звуковой шрифт samplerUnit2
:
[self loadFromDLSOrSoundFont: (NSURL *)presetURL2 withPatch: (int)0 withAudioUnit:self.samplerUnit2];
Назначение samplerUnit
работает отлично.Есть идеи, чего мне здесь не хватает?