2013-04-06 9 views
6

Chciałbym przechodzić z jednego utworu do następnego w aplikacji obsługującej Spotify. Obie ścieżki są ścieżkami Spotify, a ponieważ tylko jeden strumień danych może pochodzić ze Spotify, podejrzewam, że potrzebuję bufora (myślę, że mogę odczytać prędkość odtwarzania 1,5 x) w ciągu ostatnich kilku sekund pierwszego utworu, rozpocząć strumień na ścieżce drugiej, wycisz jedną i zaniknij na dwie używając AudioUnit.Jak przeskakiwać dźwięk za pomocą cocoalibspotify?

Sprawdziliśmy Przykładowe aplikacje: Viva - https://github.com/iKenndac/Viva SimplePlayer z EQ - https://github.com/iKenndac/SimplePlayer-with-EQ i starał się dostać mój umysł wokół SPCircularBuffer, ale nadal potrzebują pomocy. Czy ktoś może wskazać mi inny przykład lub pomóc punktowi informacyjnemu planu przeniesienia trasy?

Aktualizacja: Dzięki iKenndac, mam około 95%. będę pisać co mam tak daleko:

w SPPlaybackManager.m: initWithPlaybackSession: (SPSession *) aSession {

dodania:

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

oraz w

- (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; 

i dodano nową metodę opartą na 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); 
    } 
}]; 
} 

ten uruchamia czasomierz dla przenikania

crossfadeTimer = [NSTimer scheduledTimerWithTimeInterval 0,5 cel: bez selektora: @selector (crossfadeCountdown) userinfo: zerowe powtórzeń: TAK];

A w celu utrzymania pierwszego odtwarzanie utworu po jego załadowaniu danych w SPCoreAudioController.m Zmieniłem długość docelowy bufor:

static NSTimeInterval const kTargetBufferLength = 20; 

aw SPSession.m: end_of_track (sp_session * session) {

I usunięte

// sess.playing = NO; 

zgłoszę preloadTrackForPlayback: około 15 sekund przed końcem toru, crossfadeTrack: co 10 sekund.

Następnie ustaw crossfadeCountdownTime = [ile sekund chcesz przenikania] * 2;

I znikną głośność nad crosssfade z:

- (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]; 

    } 
} 

będę nad nim i aktualizacji, czy mogę zrobić to lepiej. Jeszcze raz dziękuję iKenndac za jego zawsze pomoc bezpośrednią!

+0

Próbuję zaimplementować funkcję przenikania w CocoaLibSpotify i obecnie utknąłem w ostatnim kroku, zmniejszając głośność obu kontrolerów audio. Czy mógłbyś wyjaśnić, w jaki sposób udało ci się to zrobić? –

Odpowiedz

4

Nie ma wcześniej napisanego przykładu crossfade, o którym wiem, że używa CocoaLibSpotify. Jednak (nienajlepiej) plan gry to:

  • Utwórz dwie osobne kolejki dźwiękowe. SPCoreAudioController to enkapsulacja kolejki audio, więc powinieneś być w stanie utworzyć dwa z nich.

  • Odtwarzanie muzyki jak zwykle w jednej kolejce. Gdy zbliżasz się do końca ścieżki, wywołaj metodę SPSession z następnym utworem, aby przygotować ją.

  • Po dostarczeniu wszystkich danych dźwiękowych do odtwarzanego utworu, SPSession uruchomi metodę delegata audio sessionDidEndPlayback:. Oznacza to, że wszystkie dane audio zostały dostarczone. Jednak ponieważ CocoaLibSpotify buforuje dźwięk z libspotify, jest jeszcze trochę czasu, zanim dźwięk się zatrzyma.

  • W tym momencie rozpocznij odtwarzanie nowej ścieżki, ale przenieś dane audio do drugiej kolejki audio. Zacznij zmniejszać głośność pierwszej kolejki, zwiększając głośność kolejnej. To powinno dać przyjemny efekt.

Kilka wskazówek:

  • W SPCoreAudioController.m znajdziesz następujący wiersz, który określa ile dźwięku buforów CocoaLibSpotify w sekundach. Jeśli chcesz uzyskać większy efekt przejścia, musisz go zwiększyć.

    static NSTimeInterval const kTargetBufferLength = 0.5; 
    
  • Skoro masz dane audio na maksymalnie 1,5x rzeczywistej prędkości odtwarzania, należy uważać, aby nie zrobić, na przykład 5 sekund crossfade gdy użytkownik po prostu pomijane blisko do końca toru. Możesz mieć za mało dostępnych danych dźwiękowych, aby je wyciągnąć.

  • Dobrze przyjrzyj się SPPlaybackManager.m. Ta klasa jest interfejsem między CocoaLibSpotify i Core Audio. Nie jest to zbyt skomplikowane, a zrozumienie tego da ci długą drogę. SPCoreAudioController i SPCircularBuffer to szczegóły implementacji dźwięku w Core Audio i nie musisz rozumieć ich implementacji, aby osiągnąć to, czego chcesz.

  • Upewnij się także, że rozumiesz różne delegacje, które ma SPSession. Delegat dostarczania audio ma tylko jedno zadanie - do odbierania danych dźwiękowych. Delegat odtwarzania otrzymuje wszystkie inne zdarzenia odtwarzania - po zakończeniu przesyłania dźwięku do delegata przekazu audio itp. Nic nie stoi na przeszkodzie, aby jedna klasa była jednocześnie, ale w obecnej implementacji SPPlaybackManager jest delegatem odtwarzania, który tworzy instancję SPCoreAudioController być delegatem dostarczającym audio. Jeśli zmodyfikujesz SPPlaybackManager, aby mieć dwa kontrolery Core Audio i na przemian który z nich jest delegatem dostarczania audio, powinieneś być złoty.

+0

Dzięki, iKenndac. Opublikowalem dzieło, w którym mi pomogłeś w oryginalnym wpisie. Tylko jeden mały problem z zatrzymaniem dźwięku po przejściu. Jakieś pomysły? –

+0

W 'SPPlaybackManager', istnieje linia w obserwatorze KVO, która zatrzymuje wyjście audio głównego kontrolera audio, gdy odtwarzanie jest wstrzymane, w przeciwnym razie będzie nadal zubożał swój bufor. Upewnij się, że przekierowujesz to połączenie do drugiego głównego kontrolera dźwięku. Poszukaj 'self.audioController.audioOutputEnabled = self.playbackSession.isPlaying;' – iKenndac

+0

Jesteś dla mnie taki dobry! To było to. Stukrotne dzięki. Niedługo zaktualizuję kod w oryginalnym wpisie, aby wskazać Twoje dzieło. –

Powiązane problemy