如何循环轨道的一部分?

时间:2013-08-22 06:46:04

标签: ios objective-c audio avaudioplayer

我有一个音乐文件,其中包含一个介绍(0:00-0:10)和一个循环部分(0:10-0:30)。有很多库和简单的解决方案可以从end-gt;开始循环一个音轨,但是我很难找到一种从end->循环开始循环音轨的方法。实现这一目标的最佳方法是什么?

这是我目前使用的代码,基于以下评论。它在循环时仍然会产生一个小的差距:

_player = [AVPlayer playerWithURL:url];
Float64 durationSeconds = CMTimeGetSeconds([asset duration]);
CMTime loopStart = CMTimeMakeWithSeconds(19.2, 1);
CMTime loopEnd = CMTimeMakeWithSeconds(durationSeconds, 1);
NSArray *times = @[[NSValue valueWithCMTime:loopEnd]];

__weak typeof(AVPlayer *)weakPlayer = _player;
self.playerObserver = [_player addBoundaryTimeObserverForTimes:times queue:NULL usingBlock:^{
    [weakPlayer seekToTime:loopStart];
}];

[_player play];

2 个答案:

答案 0 :(得分:1)

如果您可以从AVAudioPlayer切换到AVPlayer,则可以使用addBoundaryObserverForTimes:

来自docs

  

遍历指定时间时请求调用块   在正常播放期间。

“AV基础编程指南”解释了如何使用此方法的代码示例:Tracking Time

答案 1 :(得分:0)

最后,ObjectAL有一个演示项目,它使用两个独立的音频文件进行播放和介绍,然后循环播放一首歌曲的主体而没有间隙播放。我已将其修改为使用单个音频文件:

+(ALBuffer *)bufferFromFile:(NSString *)filePath startTime:(float)startTime endTime:(float)endTime
{
    NSURL *url = [OALTools urlForPath:filePath];
    OALAudioFile *file = [[OALAudioFile alloc] initWithUrl:url reduceToMono:NO];

    // Convert the start and end times into frames
    NSInteger startFrame = startTime*file.streamDescription->mSampleRate;
    NSInteger endFrame = (endTime-startTime)*file.streamDescription->mSampleRate;///file.totalFrames-(endTime*file.streamDescription->mSampleRate);

    ALBuffer* buffer = [file bufferNamed:[url description]
                              startFrame:startFrame
                               numFrames:endFrame];
    //as_release(file); // I've commented this out, but I suspect there may be some kind of leak here. Can anyone comment on how to properly release this memory?
    return buffer;
}

-(void)playBackgroundMusic:(NSString *)file withIntroThatLoopsAt:(CGFloat)seconds
{
    // Uses OpenAL for both the intro and the main loop.
    // Uses a callback to start the main loop playing.
    // Note: This only works on iOS 5+.

    _source = [ALSource source];
    _introBuffer= [JAudioEngine bufferFromFile:file startTime:0 endTime:seconds];
    _mainBuffer = [JAudioEngine bufferFromFile:file startTime:seconds endTime:-1];

    [self stop];

    __block typeof(self) blockSelf = self;
    [_source registerNotification:AL_BUFFERS_PROCESSED
                             callback:^(__unused ALSource *source, __unused ALuint notificationID, __unused ALvoid *userData)
                             {
                                 [blockSelf.source play:blockSelf.mainBuffer loop:YES];
                                 [blockSelf.source unregisterAllNotifications];
                             }
                             userData:nil];

    [_source play:_introBuffer];
}

-(void)stop
{
    [_source unregisterAllNotifications];
    [_source stop];
}