Note that there are some explanatory texts on larger screens.

plurals
  1. POHow do I audio crossfade using cocoalibspotify?
    primarykey
    data
    text
    <p>I'd like to crossfade from one track to the next in a Spotify enabled app. Both tracks are Spotify tracks, and since only one data stream at a time can come from Spotify, I suspect I need to buffer (I think I can read ahead 1.5 x playback speed) the last few seconds of the first track, start the stream for track two, fade out one and fade in two using an AudioUnit.</p> <p>I've reviewed sample apps: Viva - <a href="https://github.com/iKenndac/Viva" rel="nofollow noreferrer">https://github.com/iKenndac/Viva</a> SimplePlayer with EQ - <a href="https://github.com/iKenndac/SimplePlayer-with-EQ" rel="nofollow noreferrer">https://github.com/iKenndac/SimplePlayer-with-EQ</a> and tried to get my mind around the SPCircularBuffer, but I still need help. Could someone point me to another example or help bullet-point a track crossfade game plan? </p> <p>Update: Thanks to iKenndac, I'm about 95% there. I'll post what I have so far:</p> <p>in SPPlaybackManager.m: initWithPlaybackSession:(SPSession *)aSession {</p> <p>added:</p> <pre><code>self.audioController2 = [[SPCoreAudioController alloc] init]; self.audioController2.delegate = self; </code></pre> <p>and in</p> <pre><code>- (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; </code></pre> <p>and added a new method based on playTrack</p> <pre><code>-(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); } }]; } </code></pre> <p>this starts a timer for crossfade</p> <p>crossfadeTimer = [NSTimer scheduledTimerWithTimeInterval: 0.5 target: self selector: @selector ( crossfadeCountdown) userInfo: nil repeats: YES];</p> <p>And in order to keep the first track playing after its data has loaded in SPCoreAudioController.m I changed target buffer length:</p> <pre><code>static NSTimeInterval const kTargetBufferLength = 20; </code></pre> <p>and in SPSession.m : end_of_track(sp_session *session) {</p> <p>I removed</p> <pre><code>// sess.playing = NO; </code></pre> <p>I call preloadTrackForPlayback: about 15 seconds before end of track, then crossfadeTrack: at 10 seconds before. </p> <p>Then set crossfadeCountdownTime = [how many seconds you want the crossfade]*2;</p> <p>I fade volume over the crosssfade with:</p> <pre><code> - (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]; } } </code></pre> <p>I'll keep working on it, and update if I can make it better. Thanks again to iKenndac for his always spot-on help! </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload