iOS - MIDIファイルを混在させる、それぞれのサウンドフォント
-
13-12-2019 - |
質問
それぞれ独自のサウンドフォントファイルを持つ2つ以上のMIDIファイルを混在させる方法を探しています。私は1つのファイルに対して次のコードを見つけて、複数の音楽プレーヤーをやろうとしましたが、私はそれが正しいアプローチではないと思います。また、私は毎秒奇妙なポップサウンドを手に入れます。
それでも、AU単位のみを使用して、MusicPlayerとMusicSequenceメソッドを使用せずに、他の方法はありますか?
他のスレッドで見つけたコードは次のとおりです。
-(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インスタンスは(同期に保つために)少し厄介に聞こえます(同期に保つため)、私は複数のAUGRAPHがうまくいくと疑問があります。私はそれを試していません。
MusicPlayer
のソールインスタンスを使用した1つのアプローチは、各MIDIファイルからのトラックを 'Master'シーケンスにロードすることです。各トラック(MusicTrackSetDestNode
)にAusamplerノードを割り当て、それらをAUMixer
を通して接続します。関連トラックにファイルテンポを割り当てるには、各MIDIファイルからテンポを管理する必要があります。 Tracks +トラックボリュームは、トラックまたはミキサーレベルで簡単に処理できます。
私はあなたが働いているMIDIファイルの性質に大きく依存しています。 FWIW - 私はiOSでMIDIファイルの再生に関する研究がたくさんあり、そこにはそこには何もありません。ただし、 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);
.
私のプロジェクトでは機能します。
だから私は各トラックのノードを設定しようとしましたが、それは何も変わりませんでした。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
に割り当てるように変更したApple Developerページの例です。
-(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
に入れるために2回行った:
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
への割り当てはうまく機能します。私がここにありませんか?