From 85e5c33aecdc82286e320f0a404b973b45975d9d Mon Sep 17 00:00:00 2001 From: me Date: Sat, 12 Oct 2024 12:57:37 +0000 Subject: [PATCH] shuffle gapless playback --- src/play_queue.blp | 2 ++ src/play_queue.vala | 28 +++++++++++++++++++++------- src/playbin.vala | 16 +++++++++++----- src/window.vala | 4 +++- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/play_queue.blp b/src/play_queue.blp index 5663e5a..e36abfc 100644 --- a/src/play_queue.blp +++ b/src/play_queue.blp @@ -11,12 +11,14 @@ template $WaveletPlayQueue: Adw.NavigationPage { ScrolledWindow { ListView list_view { single-click-activate: true; + show-separators: true; activate => $on_song_activate (); factory: BuilderListItemFactory { template ListItem { child: Label { + styles [ "bold" ] halign: start; label: bind template.item as <$WaveletSong>.title; }; diff --git a/src/play_queue.vala b/src/play_queue.vala index 0e9109e..b3c7fb7 100644 --- a/src/play_queue.vala +++ b/src/play_queue.vala @@ -23,7 +23,9 @@ public class Wavelet.PlayQueue : Adw.NavigationPage { [GtkChild] private unowned Gtk.ListView list_view; private ListStore songs; - private uint next_song; + + // this is the index of the song that will play on next on_stream_start + private uint next_stream_index; public signal void play_now (Song song); public signal void now_playing (Song song); @@ -31,7 +33,7 @@ public class Wavelet.PlayQueue : Adw.NavigationPage { construct { this.songs = new ListStore (typeof (Song)); - this.next_song = 0; + this.next_stream_index = 0; this.list_view.model = new Gtk.NoSelection (this.songs); } @@ -41,22 +43,34 @@ public class Wavelet.PlayQueue : Adw.NavigationPage { } public void queue (Song song) { + uint new_index = this.songs.get_n_items (); this.songs.append (song); + if (new_index == next_stream_index) { + this.play_next (song); + } } [GtkCallback] private void on_song_activate (uint position) { - this.next_song = position; + this.next_stream_index = position; Song song = (Song) this.songs.get_item (position); + this.play_next (song); this.play_now (song); } internal void on_stream_start (Playbin playbin) { - Song song = (Song) this.songs.get_item (this.next_song); + Song song = (Song) this.songs.get_item (this.next_stream_index); this.now_playing (song); - // prepare for next song gapless - this.next_song += 1; - Song? next_song = (Song?) this.songs.get_item (this.next_song); + // prepare for next song ahead of time (gapless) + this.next_stream_index += 1; + Song? next_song = (Song?) this.songs.get_item (this.next_stream_index); this.play_next (next_song); } + + internal void restart () { + this.next_stream_index = 0; + Song song = (Song) this.songs.get_item (0); + this.play_next (song); + this.play_now (song); + } } diff --git a/src/playbin.vala b/src/playbin.vala index ff572c9..2d4ac46 100644 --- a/src/playbin.vala +++ b/src/playbin.vala @@ -44,6 +44,7 @@ class Playbin : Object { public int64 duration { get; private set; } public signal void stream_started (); + public signal void stream_over (); construct { this.playbin = Gst.ElementFactory.make ("playbin3", null); @@ -81,8 +82,6 @@ class Playbin : Object { } if (Gst.MessageType.STREAM_START in message.type) { - print ("stream start\n"); - int64 new_duration; assert (this.playbin.query_duration (Gst.Format.TIME, out new_duration)); this.duration = new_duration; @@ -95,7 +94,16 @@ class Playbin : Object { } if (Gst.MessageType.EOS in message.type) { - print ("eos\n"); + string next_uri; + + this.next_uri_lock.lock (); + next_uri = this.next_uri; + this.next_uri_lock.unlock (); + + if (next_uri == null) { + // no next track was arranged, we're done + this.stream_over (); + } } return true; @@ -181,8 +189,6 @@ class Playbin : Object { // called when uri can be switched for gapless playback // need async queue because this might be called from a gstreamer thread private void on_about_to_finish (dynamic Gst.Element playbin) { - print("about to finish\n"); - this.next_uri_lock.lock (); string? next_uri = this.next_uri; this.next_uri_lock.unlock (); diff --git a/src/window.vala b/src/window.vala index 845f469..6057cd2 100644 --- a/src/window.vala +++ b/src/window.vala @@ -41,6 +41,7 @@ public class Wavelet.Window : Adw.ApplicationWindow { private Cancellable cancel_loading_art; public bool cover_art_loading { get; set; default = false; } public Gdk.Paintable playing_cover_art { get; set; } + private Gdk.Paintable next_cover_art; internal Playbin playbin { get; default = new Playbin (); } @@ -65,13 +66,14 @@ public class Wavelet.Window : Adw.ApplicationWindow { error ("could not get random songs: %s", e.message); } this.shuffle_all_tracks.sensitive = true; + + this.play_queue.restart (); }); }); playbin.stream_started.connect (this.play_queue.on_stream_start); this.play_queue.now_playing.connect ((song) => { - print ("now playing %s\n", song.title); this.song = song; });