我想在启用Spotify的应用中从一个曲目交叉淡入淡出。这两个曲目都是Spotify曲目,因为一次只有一个数据流可以来自Spotify,我怀疑我需要缓冲(我想我可以提前读取1.5倍的播放速度)第一首曲目的最后几秒,启动流对于音轨2,使用AudioUnit淡出一个并淡入两个。
我查看了示例应用: Viva - https://github.com/iKenndac/Viva带有EQ的SimplePlayer - 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:@selector(crossfadeCountdown) userInfo:无 重复:是];
为了在SPCoreAudioController.m中加载数据后保持第一首曲目播放,我更改了目标缓冲区长度:
static NSTimeInterval const kTargetBufferLength = 20;
并在SPSession.m中:end_of_track(sp_session * session){
我删除了
// sess.playing = NO;
我调用preloadTrackForPlayback:在音轨结束前大约15秒,然后是crossfadeTrack:在10秒之前。
然后设置crossfadeCountdownTime = [你希望交叉渐变的秒数] * 2;
我通过以下方式淡化了交叉渐变的音量:
- (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 :(得分:4)
我不知道使用CocoaLibSpotify的预先编写的crossfade示例。然而,一个(也许不是理想的)游戏计划将是:
制作两个单独的音频队列。 SPCoreAudioController
是音频队列的封装,因此您应该能够实例化其中两个。
将音乐正常播放到一个队列。当您接近音轨的末尾时,请使用下一首音轨调用SPSession
的{{1}}方法以准备好。
当播放曲目的所有音频数据都已发送时,preloadTrackForPlayback:callback:
将触发音频委托方法SPSession
。这意味着已传送所有音频数据。但是,由于CocoaLibSpotify缓冲了来自libspotify的音频,因此在音频停止之前还有一段时间。
此时,开始播放新曲目,但将音频数据转移到第二个音频队列。开始减小第一个队列的音量,同时增加下一个队列的音量。这应该是一个令人愉快的交叉淡入淡出。
一些指示:
在sessionDidEndPlayback:
中,您将找到以下行,它定义了CocoaLibSpotify缓冲的音量,以秒为单位。如果你想要更大的交叉淡入淡出,你需要增加它。
SPCoreAudioController.m
由于您获得的音频数据最大为1.5倍实际播放速度,因此当用户刚刚跳到音轨末端时,请注意不要进行5秒交叉渐变。您可能没有足够的音频数据可以将其关闭。
好好看看static NSTimeInterval const kTargetBufferLength = 0.5;
。此类是CocoaLibSpotify和Core Audio之间的接口。这不是太复杂,理解它会让你走得很远。 SPPlaybackManager.m
和SPCoreAudioController
几乎是将音频导入Core Audio的实现细节,您不需要了解他们的实现来实现您想要的功能。
此外,请确保您了解SPCircularBuffer
的各个代表。音频传送代表只有一个作业 - 接收音频数据。播放代理获取所有其他播放事件 - 当音频已完成传送到音频传送委托等时。没有什么能阻止一个类同时存在,但在当前实现中,SPSession
是播放委托,它创建了一个SPPlaybackManager
的实例作为音频传递代理。如果你修改SPCoreAudioController
以拥有两个核心音频控制器并且替换哪个是音频传输代表,那么你应该是金色的。