From 2cc564092739f97935e364b6d939a9d85d3b0680 Mon Sep 17 00:00:00 2001 From: me Date: Fri, 11 Oct 2024 06:57:01 +0000 Subject: [PATCH] buncha changes --- src/application.vala | 57 +++++++++++++++++++++++++++++++++++++++++--- src/meson.build | 1 + src/play_queue.vala | 15 ++++++++++-- src/window.blp | 34 ++++++++++++++------------ src/window.vala | 27 +++++++++++++++++++++ 5 files changed, 114 insertions(+), 20 deletions(-) diff --git a/src/application.vala b/src/application.vala index 5f84900..84e6340 100644 --- a/src/application.vala +++ b/src/application.vala @@ -28,9 +28,6 @@ public class Wavelet.Application : Adw.Application { flags: ApplicationFlags.DEFAULT_FLAGS ); - playbin = Gst.ElementFactory.make ("playbin3", null); - assert (playbin != null); - var app_config_dir = Path.build_filename (Environment.get_user_config_dir (), "wavelet"); try { File.new_build_filename (app_config_dir).make_directory_with_parents (); @@ -89,12 +86,66 @@ public class Wavelet.Application : Adw.Application { }); win.play_queue.play_now.connect ((song) => { + win.play_position.sensitive = false; + playbin.set_state (Gst.State.READY); playbin.set ("uri", api.stream_uri (song.id)); playbin.set_state (Gst.State.PLAYING); }); }); win.setup.load (config_db); + + playbin = Gst.ElementFactory.make ("playbin3", null); + assert (playbin != null); + + win.notify["volume"].connect ((s, p) => { + // gst docs: Volume sliders should usually use a cubic volume. + ((Gst.Audio.StreamVolume) playbin).set_volume (Gst.Audio.StreamVolumeFormat.CUBIC, win.volume); + }); + + win.mute.clicked.connect (() => { + var vol = (Gst.Audio.StreamVolume) playbin; + if (vol.get_mute ()) { + win.show_unmute (); + vol.set_mute (false); + } else { + win.show_mute (); + vol.set_mute (true); + } + }); + + Timeout.add (100, () => { + int64 position_ns; + if (playbin.query_position (Gst.Format.TIME, out position_ns)) { + win.play_position_ms = position_ns / 1000000; + } + return Source.CONTINUE; + }); + + playbin.get_bus ().add_watch (Priority.DEFAULT, (bus, message) => { + switch (message.type) { + case Gst.MessageType.ASYNC_DONE: + win.play_position.sensitive = true; + + int64 duration_ns; + assert(playbin.query_duration (Gst.Format.TIME, out duration_ns)); + print("%lld\n", duration_ns); + + win.play_position_ms = 0; + win.play_duration_ms = duration_ns / 1000000; + + break; + + default: + print ("%s\n", message.type.to_string ()); + break; + } + return true; + }); + + Signal.connect (playbin, "about-to-finish", () => { + print("about to finish\n"); + }, null); } private void on_about_action () { diff --git a/src/meson.build b/src/meson.build index 5a4ad47..78d63d5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,6 +12,7 @@ wavelet_sources = [ wavelet_deps = [ config_dep, dependency('gstreamer-1.0'), + dependency('gstreamer-audio-1.0'), dependency('gtk4'), dependency('json-glib-1.0'), dependency('libadwaita-1', version: '>= 1.4'), diff --git a/src/play_queue.vala b/src/play_queue.vala index 9c7d2ec..b15b0be 100644 --- a/src/play_queue.vala +++ b/src/play_queue.vala @@ -29,10 +29,12 @@ public class Wavelet.PlayQueue : Adw.NavigationPage { construct { this.songs = new ListStore (typeof (Song)); - this.list_view.model = new Gtk.NoSelection (this.songs); + this.current = 0; + this.list_view.model = new Gtk.NoSelection (this.songs); this.list_view.activate.connect ((position) => { - Song song = (Song) this.songs.get_item(position); + this.current = position; + Song song = (Song) this.songs.get_item (position); this.play_now (song); }); } @@ -45,4 +47,13 @@ public class Wavelet.PlayQueue : Adw.NavigationPage { public void queue (Song song) { this.songs.append (song); } + + public Song? next () { + if (this.current >= this.songs.get_n_items ()) { + return null; + } else { + this.current += 1; + return (Song) this.songs.get_item (this.current); + } + } } diff --git a/src/window.blp b/src/window.blp index fcdd797..c6d2e25 100644 --- a/src/window.blp +++ b/src/window.blp @@ -126,23 +126,32 @@ template $WaveletWindow: Adw.ApplicationWindow { halign: start; orientation: horizontal; - Label { + Label play_position_label { + styles [ + "numeric", + ] + label: "00:00"; } - Scale { + Scale play_position { orientation: horizontal; width-request: 200; + sensitive: false; adjustment: Adjustment { lower: 0; - upper: 100; - value: 0; + value: bind template.play_position_ms bidirectional; + upper: bind template.play_duration_ms; }; } - Label { - label: "99:99"; + Label play_duration { + styles [ + "numeric", + ] + + label: "00:00"; } } } @@ -175,7 +184,7 @@ template $WaveletWindow: Adw.ApplicationWindow { valign: center; } - Button { + Button mute { icon-name: "audio-volume-high"; valign: center; } @@ -185,16 +194,11 @@ template $WaveletWindow: Adw.ApplicationWindow { width-request: 130; adjustment: Adjustment { - lower: 0; - upper: 100; - value: 100; + lower: 0.0; + value: bind template.volume bidirectional; + upper: 1.0; }; } - - Button { - icon-name: "media-playlist-consecutive"; - valign: center; - } } }; } diff --git a/src/window.vala b/src/window.vala index ca3873f..ed79e1a 100644 --- a/src/window.vala +++ b/src/window.vala @@ -31,11 +31,30 @@ public class Wavelet.Window : Adw.ApplicationWindow { [GtkChild] public unowned Wavelet.PlayQueue play_queue; [GtkChild] public unowned Adw.ButtonRow shuffle_all_tracks; + [GtkChild] public unowned Gtk.Button mute; + [GtkChild] private unowned Gtk.Label play_position_label; + [GtkChild] public unowned Gtk.Scale play_position; + [GtkChild] private unowned Gtk.Label play_duration; + + public int64 play_position_ms { get; set; default = 0; } + public int64 play_duration_ms { get; set; default = 1; } + + public double volume { get; set; default = 1.0; } + public Window (Gtk.Application app) { Object (application: app); } construct { + this.notify["play-position-ms"].connect ((s, p) => { + int seconds = (int)(this.play_position_ms/1000); + this.play_position_label.label = "%02d:%02d".printf(seconds/60, seconds%60); + }); + this.notify["play-duration-ms"].connect ((s, p) => { + int seconds = (int)(this.play_duration_ms/1000); + this.play_duration.label = "%02d:%02d".printf(seconds/60, seconds%60); + }); + this.sidebar.row_activated.connect ((row) => { if (row == this.sidebar_setup) { this.stack.set_visible_child_name("setup"); @@ -46,4 +65,12 @@ public class Wavelet.Window : Adw.ApplicationWindow { this.sidebar.select_row (this.sidebar.get_row_at_index (0)); } + + public void show_mute () { + this.mute.icon_name = "audio-volume-muted"; + } + + public void show_unmute () { + this.mute.icon_name = "audio-volume-high"; + } }