【问题标题】:How to change from one musicSequence to another without time delay如何在没有时间延迟的情况下从一种音乐序列更改为另一种音乐序列
【发布时间】:2012-08-10 00:39:55
【问题描述】:

我正在通过MusicPlayer 播放一个 MIDI 序列,我从一个 MIDI 文件加载它,我想在播放时将序列更改为另一个序列。 当我尝试这个时:

 MusicPlayerSetSequence(_player, sequence);
 MusicSequenceSetAUGraph(sequence, _processingGraph);

它会停止播放。所以我重新开始并设置时间

MusicPlayerSetTime(_player, currentTime);

所以它会在前一个序列停止的地方再次播放,但会有一点延迟。 我尝试将时间间隔添加到currentTime,这是通过获取停止前和重新开始后的时间得到的。但仍有延迟。

我想知道是否有替代停止 -> 更改顺序 -> 重新开始。

【问题讨论】:

  • 嘿——你放弃了合并音轨的方法吗?我终于找到了一些时间让它工作。你的文件有点躲闪——不知道为什么。这是一个示例,其中一个 midi 文件/sf2 + 我周围的一个随机 midi/sf2 (dl.dropbox.com/u/34715839/MusicPlayerTracksFromFiles.zip) - 干杯
  • 哦 - 在设置轨道循环时,该文件中有一个错误:使用的 trackLen 值来自 sourceTrack。在设置循环长度之前,应从目标轨道重新计算此值。此外,发现 simpletest.mid 文件的奇怪之处在于它有 2 个轨道 - 第一个是空的 - 所以复制该轨道 == 静音。
  • 不,我没有,我已经为自己找到了解决方案,并在那里做出了另一个答案 (stackoverflow.com/questions/11706042)。但无论如何,谢谢,我相信你的代码会帮助我优化我的。我仍在试图弄清楚你是如何循环序列的,因为它没有在正确的时间循环。我愿意 - if (time >=trackLen) MusicPlayerSetTime(_player, 0);
  • 没关系,我明白了:你设置了属性kSequenceTrackProperty_LoopInfo。但这对我不起作用,因为 midi 长度总是像 3.89 或 5.92,所以我实际上是 if (time >=ceil(trackLen))
  • 所以设置轨道节点只有在为序列设置 AUGraph 之后才有效 - 有意义。 @looping - 你可能发现了这一点,但每个轨道都是独立循环的。如果所有曲目的长度相同,这不是问题,但如果不是,事情可能会不同步。在最长的轨道上使用 NSTimer 是可行的——听起来你正在这样做。 - 干杯。

标签: objective-c ios xcode core-audio coremidi


【解决方案1】:

如果您要添加和删除曲目或切换序列,您肯定需要管理 AUSampler。处理 AUSampler 并为每个新轨道创建一个新的可能更清洁,但也可以“回收”AUSampler,但这意味着您需要跟踪它们。

管理 AUSamplers 意味着当您不再使用其中之一的实例时(例如,如果您删除或替换了 MusicTrack),您需要将其与 AUMixer 实例断开连接,将其从 AUGraph 实例中移除,然后更新AUGraph。

有很多方法可以处理这一切。为了方便跟踪 AUSampler 实例的总线号、加载的声音字体和其他一些内容,我使用了一个名为 SamplerAudioUnit 的 NSObject 子类来包含所有需要的属性和方法。 MusicTracks 也是如此 - 我有一个 Track 课程 - 但您的项目中可能不需要它。

不过,要点是需要管理 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;
}

【讨论】:

  • 断开、删除和创建一个新节点解决了这个问题。非常感谢。
【解决方案2】:

因为

MusicPlayerSetSequence(_player, sequence);
MusicSequenceSetAUGraph(sequence, _processingGraph);

仍然会导致玩家停下来,仍然可以听到一点中断。 因此,我没有更新musicSequence,而是继续更改曲目的内容,这不会导致任何中断:

MusicTrack currentTrack;
MusicTrack currentTrack2;
MusicSequenceGetIndTrack(musicSequence, 0, &currentTrack);
MusicSequenceGetIndTrack(musicSequence, 1, &currentTrack2);
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);

不断开节点,不更新图表,不停止播放器。

【讨论】:

    猜你喜欢
    • 2021-10-19
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 2018-09-15
    相关资源
    最近更新 更多