2013-04-06 97 views
6

我想在Spotify启用的应用程序中从一条曲目交叉淡入到下一条曲目。这两条曲目都是Spotify曲目,并且由于Spotify一次只能有一个数据流,所以我怀疑我需要在第一首曲目的最后几秒缓冲(我想我可以提前读取1.5倍的播放速度),然后开始播放流对于第二首曲目,使用AudioUnit淡入淡出。如何使用cocoalibspotify音频交叉淡入淡出?

我查看示例应用程序: 万岁 - https://github.com/iKenndac/Viva SimplePlayer与EQ - https://github.com/iKenndac/SimplePlayer-with-EQ并试图让我的脑海里围绕SPCircularBuffer,但我仍然需要帮助。有人能指点我另一个例子吗?或者帮助子弹点轨道交叉淡入淡出游戏计划?

更新:感谢iKenndac,我在那里95%左右。我会后我到目前为止有:

在SPPlaybackManager.m

:initWithPlaybackSession:(SPSession *)aSession {

补充说:

self.audioController2 = [[SPCoreAudioController alloc] init]; 
self.audioController2.delegate = self; 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 

... 


self.audioController.audioOutputEnabled = self.playbackSession.isPlaying; 

// for crossfade, add 

self.audioController2.audioOutputEnabled = self.playbackSession.isPlaying; 

和添加了基于playTrack的新方法

-(void)crossfadeTrack:(SPTrack *)aTrack callback:(SPErrorableOperationCallback)block { 
// switch audiocontroller from current to other 
if (self.playbackSession.audioDeliveryDelegate == self.audioController) 
{ 
    self.playbackSession.audioDeliveryDelegate = self.audioController2; 
    self.audioController2.delegate = self; 
    self.audioController.delegate = nil; 
} 
else 
{ 

    self.playbackSession.audioDeliveryDelegate = self.audioController; 
    self.audioController.delegate = self; 
    self.audioController2.delegate = nil; 
} 

if (aTrack.availability != SP_TRACK_AVAILABILITY_AVAILABLE) { 
    if (block) block([NSError spotifyErrorWithCode:SP_ERROR_TRACK_NOT_PLAYABLE]); 
    self.currentTrack = nil; 
} 

self.currentTrack = aTrack; 
self.trackPosition = 0.0; 

[self.playbackSession playTrack:self.currentTrack callback:^(NSError *error) { 

    if (!error) 
     self.playbackSession.playing = YES; 
    else 
     self.currentTrack = nil; 

    if (block) { 
     block(error); 
    } 
}]; 
} 

此开始用于淡入淡出

crossfadeTimer = [的NSTimer scheduledTimerWithTimeInterval:0.5 目标:自 选择器:@selector(crossfadeCountdown) USERINFO:无 重复:YES]定时器;

而且为了保持第一播放曲目的数据SPCoreAudioController.m加载之后我改变了目标缓冲区长度:

static NSTimeInterval const kTargetBufferLength = 20; 

和SPSession.m:音轨结尾(sp_session *会话){

我除去

// sess.playing = NO; 

我请preloadTrackForPlayback:轨道的端部约15秒之前,然后crossfadeTrack:在之前10秒。

然后设置crossfadeCountdownTime = [您想要交叉淡入淡出多少秒] * 2;

我褪色与成交量较crosssfade:

- (void) crossfadeCountdown 
    { 

     [UIAppDelegate.playbackSPManager setVolume:(1- (((float)crossfadeCountdownTime/  (thisCrossfadeSeconds*2.0)) *0.2))]; 
    crossfadeCountdownTime -= 0.5; 


    if (crossfadeCountdownTime == 1.0) 
    { 
    NSLog(@"Crossfade countdown done"); 
    crossfadeCountdownTime = 0; 
    [crossfadeTimer invalidate]; 
    crossfadeTimer = nil; 
    [UIAppDelegate.playbackSPManager setVolume:1.0]; 

    } 
} 

我会继续做这个工作,和更新,如果我可以做的更好。再次感谢iKenndac提供的帮助!

+0

我试图在CocoaLibSpotify中实现交叉淡入淡出功能,目前我坚持最后一步,淡入淡出音频控制器的音量。你能否详细说明你是如何做到的? – 2015-01-01 17:09:44

回答

4

没有预先编写的交叉淡化示例,我知道它使用CocoaLibSpotify。然而,一个(也许不是理想的)游戏计划是:

  • 制作两个独立的音频队列。 SPCoreAudioController是一个音频队列的封装,所以你应该能够实例化它们中的两个。

  • 正常播放音乐到一个队列。当您接近曲目末尾时,请拨打SPSessionpreloadTrackForPlayback:callback:方法,并准备下一首曲目。

  • 当播放曲目的所有音频数据已发送时,SPSession将发出音频委托方法sessionDidEndPlayback:。这意味着所有音频数据都已传送。但是,由于CocoaLibSpotify缓冲了来自libspotify的音频,音频停止前还有一段时间。

  • 此时,开始播放新曲目但将音频数据转移到第二个音频队列。开始减少第一个队列的音量,同时增加下一个音量。这应该让人满意的交叉淡入淡出。

几个要点:

  • SPCoreAudioController.m,你会发现下面的线,它定义了多少音频CocoaLibSpotify缓冲区,以秒计。如果你想要一个更大的交叉淡入淡出,你需要增加它。

    static NSTimeInterval const kTargetBufferLength = 0.5; 
    
  • 既然你以最大1.5倍的实际播放速度的获得音频数据,注意不要做,例如,当用户刚跳过靠近轨道的末端5秒交叉淡入淡出。您可能没有足够的音频数据可用于将其关闭。

  • 看看SPPlaybackManager.m。这个类是CocoaLibSpotify和Core Audio之间的接口。这不是太复杂,理解它会让你走很长的路。 SPCoreAudioControllerSPCircularBuffer几乎是将音频转换为Core Audio的实现细节,您不需要了解它们的实现以实现您想要的效果。

  • 此外,请确保您了解各种代表SPSession有。音频传送代表只有一项工作 - 接收音频数据。回放委托可以获得所有其他回放事件 - 音频完成传递到音频传递代理时等。没有任何事物可以阻止一个类同时存在,但在当前实现中,SPPlaybackManager是回放委托,它创建了一个SPCoreAudioController的实例成为音频传送代表。如果您修改SPPlaybackManager以拥有两个核心音频控制器并替换哪一个是音频传送代表,则应该是黄金版。

+0

谢谢,iKenndac。我在原帖中发布了你帮助我的工作。在交叉淡入淡出之后暂停音频的一个小问题。有任何想法吗? – 2013-04-08 01:29:52

+0

在'SPPlaybackManager'中,KVO观察者中有一行会在播放暂停时停止核心音频控制器的音频输出,否则将继续耗尽其缓冲区。确保您将该呼叫重定向到您的第二个核心音频控制器。寻找'self.audioController.audioOutputEnabled = self.playbackSession.isPlaying;' – iKenndac 2013-04-08 07:59:19

+0

你对我太好了!就是这样。太感谢了。我将尽快更新原始文章中的代码,以指示您的手工。 – 2013-04-08 10:30:54