diff --git a/Aural.xcodeproj/project.xcworkspace/xcuserdata/kven.xcuserdatad/UserInterfaceState.xcuserstate b/Aural.xcodeproj/project.xcworkspace/xcuserdata/kven.xcuserdatad/UserInterfaceState.xcuserstate index 8354ce9c5..185b51d19 100644 Binary files a/Aural.xcodeproj/project.xcworkspace/xcuserdata/kven.xcuserdatad/UserInterfaceState.xcuserstate and b/Aural.xcodeproj/project.xcworkspace/xcuserdata/kven.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Documentation/Release Notes.md b/Documentation/Release Notes.md index c60b4f534..b8471efab 100644 --- a/Documentation/Release Notes.md +++ b/Documentation/Release Notes.md @@ -1,8 +1,6 @@ -# What's New in Version 4.0.0-preview21 +# What's New in Version 4.0.0-preview22 -## #74 - Prevent log file bloating (ffmpeg I/O errors) - -## Fixed window layout bug +## Fixed gapless playback ## Fixed other bugs diff --git a/Source/Core/Playback/Delegates/PlaybackDelegate.swift b/Source/Core/Playback/Delegates/PlaybackDelegate.swift index 3076169d2..b4e4ebffe 100644 --- a/Source/Core/Playback/Delegates/PlaybackDelegate.swift +++ b/Source/Core/Playback/Delegates/PlaybackDelegate.swift @@ -139,40 +139,59 @@ class PlaybackDelegate: PlaybackDelegateProtocol { trackReader.loadArtAsync(for: firstTrack, immediate: true) } - func previousTrack() { + private func changeGaplessTrack(mustStopIfNoTrack: Bool, trackProducer: TrackProducer) { - guard state.isPlayingOrPaused else {return} + let beginTrack = playQueueDelegate.currentTrack + let beginState = player.state - if isInGaplessPlaybackMode { + if let newTrack = trackProducer() { - let beginTrack = playQueueDelegate.currentTrack - let beginState = player.state + do { + try trackReader.prepareForPlayback(track: newTrack) + + } catch { + + Messenger.publish(TrackNotPlayedNotification(oldTrack: beginTrack, errorTrack: newTrack, + error: error as? DisplayableError ?? TrackNotPlayableError(newTrack.file))) + } - let endTrack = playQueueDelegate.previous() player.playGapless(tracks: playQueueDelegate.tracksPendingPlayback) - messenger.publish(TrackTransitionNotification(beginTrack: beginTrack, beginState: beginState, - endTrack: endTrack, endState: player.state)) + } else if mustStopIfNoTrack { + doStop(beginTrack) } else { - doPlay({playQueueDelegate.previous()}) + return } + + messenger.publish(TrackTransitionNotification(beginTrack: beginTrack, beginState: beginState, + endTrack: playQueueDelegate.currentTrack, endState: player.state)) } - func nextTrack() { + func previousTrack() { guard state.isPlayingOrPaused else {return} if isInGaplessPlaybackMode { - let beginTrack = playQueueDelegate.currentTrack - let beginState = player.state + changeGaplessTrack(mustStopIfNoTrack: false) { + playQueueDelegate.previous() + } - let endTrack = playQueueDelegate.next() - player.playGapless(tracks: playQueueDelegate.tracksPendingPlayback) + } else { + doPlay({playQueueDelegate.previous()}) + } + } + + func nextTrack() { + + guard state.isPlayingOrPaused else {return} + + if isInGaplessPlaybackMode { - messenger.publish(TrackTransitionNotification(beginTrack: beginTrack, beginState: beginState, - endTrack: endTrack, endState: player.state)) + changeGaplessTrack(mustStopIfNoTrack: false) { + playQueueDelegate.next() + } } else { doPlay({playQueueDelegate.next()}) @@ -298,26 +317,10 @@ class PlaybackDelegate: PlaybackDelegateProtocol { if isInGaplessPlaybackMode { - let beginTrack = playQueueDelegate.currentTrack - let beginState = player.state - - if let subsequentTrack = playQueueDelegate.subsequent() { - - do { - try trackReader.prepareForPlayback(track: subsequentTrack) - - } catch { - - Messenger.publish(TrackNotPlayedNotification(oldTrack: beginTrack, errorTrack: subsequentTrack, - error: error as? DisplayableError ?? TrackNotPlayableError(subsequentTrack.file))) - } - - player.playGapless(tracks: playQueueDelegate.tracksPendingPlayback) + changeGaplessTrack(mustStopIfNoTrack: true) { + playQueueDelegate.subsequent() } - messenger.publish(TrackTransitionNotification(beginTrack: beginTrack, beginState: beginState, - endTrack: playQueueDelegate.currentTrack, endState: player.state)) - } else { doTrackPlaybackCompleted() } diff --git a/Source/Core/Playback/FFmpegPlaybackContext.swift b/Source/Core/Playback/FFmpegPlaybackContext.swift index dda7b1853..4387d3678 100644 --- a/Source/Core/Playback/FFmpegPlaybackContext.swift +++ b/Source/Core/Playback/FFmpegPlaybackContext.swift @@ -119,6 +119,12 @@ class FFmpegPlaybackContext: PlaybackContextProtocol { } } + func refresh() throws { + + fileContext = try FFmpegFileContext(for: file) + decoder = try FFmpegDecoder(for: fileContext!) + } + func close() { decoder = nil diff --git a/Source/Core/Playback/Scheduling/FFmpeg/FFmpegScheduler+Gapless.swift b/Source/Core/Playback/Scheduling/FFmpeg/FFmpegScheduler+Gapless.swift index 4a7d43ac5..13d991308 100644 --- a/Source/Core/Playback/Scheduling/FFmpeg/FFmpegScheduler+Gapless.swift +++ b/Source/Core/Playback/Scheduling/FFmpeg/FFmpegScheduler+Gapless.swift @@ -14,12 +14,12 @@ extension FFmpegScheduler { func playGapless(tracks: [Track], currentSession: PlaybackSession) { - doPlayGapless(firstTrack: tracks[0], + doPlayGapless(firstTrack: tracks[0], fromTime: 0, otherTracks: tracks.count > 1 ? Array(tracks[1..