Как мне аудио кроссфейд с использованием 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"s preloadTrackForPlayback: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 и чередовать, какой из них является делегатом доставки аудио, вы должны быть великолепны.

Другие вопросы по тегам