Как сделать аудио crossfade с помощью cocoalibspotify?
Я хотел бы перейти с одного трека на другой в приложении с поддержкой Spotify. Оба трека являются треками Spotify, и поскольку только один поток данных за раз может исходить от Spotify, я подозреваю, что мне нужно буферизировать (я думаю, что могу читать вперед 1.5 x скорость воспроизведения) последние несколько секунд первого трека, запустить поток для второго трека, выцветать один и исчезать в два с помощью AudioUnit.
Я рассмотрел примеры приложений: Вива - https://github.com/iKenndac/Viva SimplePlayer с EQ -https://github.com/iKenndac/SimplePlayer-with-EQ и попытался сосредоточиться на SPCircularBuffer, но мне все еще нужна помощь. Может ли кто-нибудь указать мне на другой пример или помочь bullet-point план игры track crossfade?
обновление: благодаря 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: nil повторяет: Да];
и для того, чтобы первый трек играл после того, как его данные загружены в SPCoreAudioController.m я изменил длину целевого буфера:
static NSTimeInterval const kTargetBufferLength = 20;
и в SPSession.m: end_of_track (sp_session *session) {
Я убрал
// sess.playing = NO;
Я вызываю preloadTrackForPlayback: около 15 секунд до конца трека, затем crossfadeTrack: за 10 секунд до этого.
затем установите crossfadeCountdownTime = [сколько секунд вы хотите crossfade]*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 за его всегда точечную помощь!
1 ответов
нет предварительно написанного примера crossfade, который я знаю, что использует CocoaLibSpotify. Однако (возможно, не идеальный) план игры такой:
сделайте две отдельные очереди аудио.
SPCoreAudioController
является инкапсуляцией аудио очереди, поэтому вы должны просто иметь возможность создавать экземпляры двух из них.воспроизведение музыки в обычном режиме в одну очередь. Когда вы приближаетесь к концу пути, называют
SPSession
' spreloadTrackForPlayback:callback:
метод со следующей дорожкой к приготовься.когда все аудио данные для воспроизведения трека были доставлены,
SPSession
запустит метод делегата аудиоsessionDidEndPlayback:
. Это означает, что все аудиоданные были доставлены. Однако, поскольку CocoaLibSpotify буферизует аудио из libspotify, есть еще некоторое время до остановки звука.на этом этапе начните воспроизведение нового трека, но перенаправьте аудиоданные во вторую очередь аудио. Начать сворачивать объем первая очередь при увеличении громкости следующей. Это должно дать приятный crossfade.
несколько советов:
-
на
SPCoreAudioController.m
, вы найдете следующую строку, которая определяет, сколько аудио cocoalibspotify буферов, в секундах. Если вы хотите больше crossfade, вам нужно увеличить его.static NSTimeInterval const kTargetBufferLength = 0.5;
поскольку вы получаете звуковые данные с максимальной скоростью воспроизведения 1.5 x, будьте осторожны, чтобы не делать, например, 5-секундный кроссфейд, когда пользователь только что пропустил около конца дорожки. Возможно, у вас недостаточно аудиоданных, чтобы снять его.
посмотрите на
SPPlaybackManager.m
. Этот класс является интерфейсом между CocoaLibSpotify и Core Audio. Это не слишком сложно, и понимание этого поможет вам пройти долгий путь.SPCoreAudioController
иSPCircularBuffer
в значительной степени детали реализации получения звука в Core Audio, и вам не нужно понять их реализации, чтобы достичь того, чего вы хотите.кроме того, убедитесь, что вы понимаете различные делегатов
SPSession
есть. Делегат доставки аудио имеет только одно задание-получение аудиоданных. Делегат воспроизведения получает все другие события воспроизведения - когда аудио закончено доставляться делегату доставки звука и т. д. Ничто не мешает одному классу, но в текущей реализацииSPPlaybackManager
является делегатом воспроизведения, который создает примерSPCoreAudioController
быть делегатом доставки аудио. Если вы изменитеSPPlaybackManager
чтобы иметь два основных аудиоконтроллера и чередовать, какой из них является делегатом доставки звука, вы должны быть золотыми.