shuffle gapless playback
This commit is contained in:
parent
c1e023276d
commit
216be6798e
4 changed files with 37 additions and 13 deletions
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue