Objective c 如何在没有时间延迟的情况下从一个音乐序列切换到另一个音乐序列
我正在通过从MIDI文件加载的Objective c 如何在没有时间延迟的情况下从一个音乐序列切换到另一个音乐序列,objective-c,ios,xcode,core-audio,coremidi,Objective C,Ios,Xcode,Core Audio,Coremidi,我正在通过从MIDI文件加载的MusicPlayer播放MIDI序列,我想在播放时将序列更改为另一个序列。 当我尝试这个: MusicPlayerSetSequence(_player, sequence); MusicSequenceSetAUGraph(sequence, _processingGraph); 它停止播放。所以我重新开始,用 MusicPlayerSetTime(_player, currentTime); 所以它在前一个序列停止的地方再次播放,但是有一点延迟。 我试
MusicPlayer
播放MIDI序列,我想在播放时将序列更改为另一个序列。
当我尝试这个:
MusicPlayerSetSequence(_player, sequence);
MusicSequenceSetAUGraph(sequence, _processingGraph);
它停止播放。所以我重新开始,用
MusicPlayerSetTime(_player, currentTime);
所以它在前一个序列停止的地方再次播放,但是有一点延迟。
我试图将时间间隔添加到currentTime
,这是通过获取停止前和再次启动后的时间得到的。但仍有延迟
我想知道除了停止->更改序列->重新开始之外,是否还有其他选择。如果要添加和删除曲目或切换序列,您肯定需要管理音频采集器。丢弃AUSampler并为每个新曲目创建一个新的AUSampler可能更干净,但也可以“回收”AUSampler,但这意味着您需要跟踪它们 管理AuSampler意味着当您不再使用一个实例的实例时(例如,如果您删除或替换MusicTrack),您需要断开它与AUMixer实例的连接,将其从AUGraph实例中删除,然后更新AUGraph 有很多方法可以处理这一切。为了方便跟踪AUSampler实例的总线号、加载的声音字体和其他内容,我使用名为
sampleaudiounit
的NSObject子类来包含所有需要的属性和方法。MusicTracks也一样-我有一个曲目
课程-但这在你的项目中可能不需要
不过,要点是需要对Ausampler进行性能和内存管理。如果一个实例不再被使用,它应该被删除,并且AUMixer总线输入被释放
顺便说一句-我检查了文件,显然没有对混音器总线数量的技术限制-但是需要指定数量
// this is not cut and paste code - just an example of managing the AUSampler instance
- (OSStatus)deleteTrack:(Track*) trackObj
{
OSStatus result = noErr;
// turn off MP if playing
BOOL MPstate = [self isPlaying];
if (MPstate){
MusicPlayerStop(player);
}
//-disconnect node from mixer + update list of mixer buses
SamplerAudioUnit * samplerObj = trackObj.sampler;
UInt32 busNumber = samplerObj.busNumber;
result = AUGraphDisconnectNodeInput(graph, mixerNode, busNumber);
if (result) {[self printErrorMessage: @"AUGraphDisconnectNodeInput" withStatus: result];}
[self clearMixerBusState: busNumber]; // routine that keeps track of available busses
result = MusicSequenceDisposeTrack(sequence, trackObj.track);
if (result) {[self printErrorMessage: @"MusicSequenceDisposeTrack" withStatus: result];}
// remove AUSampler node
result = AUGraphRemoveNode(graph, samplerObj.samplerNode);
if (result) {[self printErrorMessage: @"AUGraphRemoveNode" withStatus: result];}
result = AUGraphUpdate(graph, NULL);
if (result) {[self printErrorMessage: @"AUGraphUpdate" withStatus: result];}
samplerObj = nil;
trackObj = nil;
if (MPstate){
MusicPlayerStart(player);
}
// CAShow(graph);
// CAShow(sequence);
return result;
}
因为
MusicPlayerSetSequence(_player, sequence);
MusicSequenceSetAUGraph(sequence, _processingGraph);
仍将导致玩家停止,仍有可能听到一点中断。
因此,我没有更新音乐序列
,而是改变了曲目的内容,这不会造成任何中断:
MusicTrack currentTrack;
MusicTrack currentTrack2;
MusicSequenceGetIndTrack(musicSequence, 0, ¤tTrack);
MusicSequenceGetIndTrack(musicSequence, 1, ¤tTrack2);
MusicTrackClear(currentTrack, 0, _trackLen);
MusicTrackClear(currentTrack2, 0, _trackLen);
MusicSequence tmpSequence;
switch (number) {
case 0:
tmpSequence = musicSequence1;
break;
case 1:
tmpSequence = musicSequence2;
break;
case 2:
tmpSequence = musicSequence3;
break;
case 3:
tmpSequence = musicSequence4;
break;
default:
tmpSequence = musicSequence1;
break;
}
MusicTrack tmpTrack;
MusicTrack tmpTrack2;
MusicSequenceGetIndTrack(tmpSequence, 0, &tmpTrack);
MusicSequenceGetIndTrack(tmpSequence, 1, &tmpTrack2);
MusicTimeStamp trackLen = 0;
UInt32 trackLenLenLen = sizeof(trackLen);
MusicTrackGetProperty(tmpTrack, kSequenceTrackProperty_TrackLength, &trackLen, &trackLenLenLen);
_trackLen = trackLen;
MusicTrackCopyInsert(tmpTrack, 0, _trackLen, currentTrack, 0);
MusicTrackCopyInsert(tmpTrack2, 0, _trackLen, currentTrack2, 0);
没有断开节点连接,没有更新图表,没有停止播放器。Hey-你放弃了合并轨迹的方法吗?我终于找到时间让它工作了。你的文件有点狡猾——不知道为什么。下面是一个例子,其中一个midi文件/sf2+我周围有一个随机的midi/sf2()-cheesoh-设置曲目循环时,该文件中有一个错误:使用的
trackLen
值来自sourceTrack。在设置环路长度之前,应从目标轨迹重新计算该值。此外,我还发现simpletest.mid文件的奇怪之处在于它有两个磁道——第一个磁道是空的——因此复制该磁道==静默。不,我没有,我为自己找到了解决方案,并在那里给出了另一个答案()。但无论如何,谢谢你,我相信你的代码会帮助我优化我的。我仍在试图弄清楚你是如何循环序列的,因为它没有在正确的时间循环。我做-如果(时间>=trackLen)MusicLayerSetTime(_player,0)代码>没关系,我已经弄明白了:您设置了属性kSequenceTrackProperty\u LoopInfo
。但这对我不起作用,因为midi的长度总是像3.89或5.92,所以我实际上是这样做的if(time>=ceil(trackLen))
所以设置轨迹节点只有在设置序列的曲线图之后才起作用-这是有意义的@循环-您可能发现了这一点,但每条轨迹都是独立循环的。如果所有曲目的长度都相同,这不是问题,但如果它们不同步,则可能会发生不同步。在最长的赛道上使用NSTimer是有效的-听起来你正在这么做。-干杯。断开、删除和创建新节点解决了问题。非常感谢你。