Как мне аудио кроссфейд с использованием cocoalibspotify?
Я хотел бы перейти от одного трека к другому в приложении с поддержкой Spotify. Обе дорожки являются дорожками Spotify, и поскольку из Spotify может одновременно поступать только один поток данных, я подозреваю, что мне нужно буферизовать (я думаю, что могу читать вперед 1,5 x скорость воспроизведения) последние несколько секунд первой дорожки, запустить поток для дорожки два: исчезните один и исчезните в два, используя AudioUnit.
Я рассмотрел примеры приложений: Viva - 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 scheduleTimerWithTimeInterval: 0.5 target: self selector: @selector ( crossfadeCountdown) userInfo: nil повторов: ДА];
И чтобы сохранить воспроизведение первого трека после загрузки его данных в 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 за его постоянную помощь!
1 ответ
Я не знаю заранее написанного примера кроссфейдера, который бы использовал CocoaLibSpotify. Тем не менее, (возможно, не идеальный) план игры будет:
Сделайте две отдельные аудио-очереди.
SPCoreAudioController
это инкапсуляция аудио-очереди, так что вы должны просто иметь возможность создать две из них.Слушать музыку как обычно в одну очередь. Когда вы приближаетесь к концу трека, позвоните
SPSession
"spreloadTrackForPlayback:callback:
метод со следующей дорожкой, чтобы подготовить ее.Когда все аудиоданные для воспроизводимой дорожки были доставлены,
SPSession
запустит метод аудио делегатаsessionDidEndPlayback:
, Это означает, что все аудиоданные были доставлены. Тем не менее, поскольку CocoaLibSpotify буферизует звук из libspotify, до остановки звука еще есть время.На этом этапе начните воспроизведение новой дорожки, но перенаправьте аудиоданные во вторую аудио-очередь. Начните увеличивать громкость первой очереди, одновременно увеличивая громкость следующей. Это должно дать приятный переход.
Несколько указателей:
В
SPCoreAudioController.m
Вы найдете следующую строку, которая определяет, сколько аудио CocoaLibSpotify буферизует в секундах. Если вы хотите увеличить кроссфейд, вам нужно его увеличить.static NSTimeInterval const kTargetBufferLength = 0.5;
Поскольку вы получаете аудиоданные с максимальной скоростью воспроизведения в 1,5 раза, будьте осторожны, чтобы не делать, например, 5-секундного перекрестного затухания, когда пользователь только что пропустил ближе к концу дорожки. Возможно, у вас недостаточно аудиоданных, чтобы их снять.
Внимательно посмотрите на
SPPlaybackManager.m
, Этот класс является интерфейсом между CocoaLibSpotify и Core Audio. Это не слишком сложно, и понимание этого поможет вам пройти долгий путь.SPCoreAudioController
а такжеSPCircularBuffer
Это довольно много деталей реализации передачи звука в Core Audio, и вам не нужно разбираться в их реализациях для достижения того, чего вы хотите.Кроме того, убедитесь, что вы понимаете различные делегаты
SPSession
есть. У делегата по доставке аудио есть только одно задание - получать аудиоданные. Делегат воспроизведения получает все остальные события воспроизведения - когда аудиосигнал закончен, доставляется делегату доставки аудио и т. Д. Ничто не мешает одному классу быть обоими, но в текущей реализации,SPPlaybackManager
является делегатом воспроизведения, который создает экземплярSPCoreAudioController
быть делегатом по доставке аудио. Если вы изменитеSPPlaybackManager
чтобы иметь два контроллера Core Audio и чередовать, какой из них является делегатом доставки аудио, вы должны быть великолепны.