From 8afd1a62404c7d859da9a2f3d572f12007d3749d Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Sun, 28 May 2023 16:51:30 -0400 Subject: [PATCH] audio: Replace the playbin audio-filter with the new filter And wire up the bg-enabled and bg-volume properties from the header to the playbin properties with the same name. Implements: #50 ("Background Music Mode") Signed-off-by: Anna Schumaker --- emmental/__init__.py | 3 ++- emmental/audio/__init__.py | 14 +++++++++----- tests/audio/test_audio.py | 32 ++++++++++++++++++++++++-------- tests/test_emmental.py | 15 +++++++++++++++ 4 files changed, 50 insertions(+), 14 deletions(-) diff --git a/emmental/__init__.py b/emmental/__init__.py index 8039a1c..bd62781 100644 --- a/emmental/__init__.py +++ b/emmental/__init__.py @@ -127,7 +127,8 @@ class Application(Adw.Application): def build_header(self) -> header.Header: """Build a new header instance.""" hdr = header.Header(sql=self.db, title=VERSION_STRING) - hdr.bind_property("volume", self.player, "volume") + for prop in ["bg-enabled", "bg-volume", "volume"]: + hdr.bind_property(prop, self.player, prop) for (setting, property) in [("audio.volume", "volume"), ("audio.background.enabled", "bg-enabled"), ("audio.background.volume", "bg-volume"), diff --git a/emmental/audio/__init__.py b/emmental/audio/__init__.py index 4659140..2107d1b 100644 --- a/emmental/audio/__init__.py +++ b/emmental/audio/__init__.py @@ -4,7 +4,7 @@ import pathlib from gi.repository import GObject from gi.repository import GLib from gi.repository import Gst -from . import replaygain +from . import filter from .. import path from .. import tmpdir @@ -35,16 +35,18 @@ class Player(GObject.GObject): playtime = GObject.Property(type=float) savedtime = GObject.Property(type=float) + bg_enabled = GObject.Property(type=bool, default=False) + bg_volume = GObject.Property(type=float, default=0.5) pause_on_load = GObject.Property(type=bool, default=False) def __init__(self): """Initialize the audio Player.""" super().__init__() - self._replaygain = replaygain.Filter() + self._filter = filter.Filter() self._timeout = None self._playbin = Gst.ElementFactory.make("playbin") - self._playbin.set_property("audio-filter", self._replaygain) + self._playbin.set_property("audio-filter", self._filter) self._playbin.set_property("video-sink", Gst.ElementFactory.make("fakesink")) self._playbin.set_state(Gst.State.READY) @@ -58,6 +60,8 @@ class Player(GObject.GObject): bus.connect("message::tag", self.__msg_tags) self.bind_property("volume", self._playbin, "volume") + self.bind_property("bg-enabled", self._filter, "bg-enabled") + self.bind_property("bg-volume", self._filter, "bg-volume") self.connect("notify::file", self.__notify_file) @@ -163,7 +167,7 @@ class Player(GObject.GObject): def get_replaygain(self) -> tuple[bool, str | None]: """Get the current ReplayGain mode.""" - mode = self._replaygain.mode + mode = self._filter.rg_mode return (False, None) if mode == "disabled" else (True, mode) def get_state(self) -> Gst.State: @@ -191,7 +195,7 @@ class Player(GObject.GObject): def set_replaygain(self, enabled: bool, mode: str) -> None: """Set the ReplayGain mode.""" - self._replaygain.mode = mode if enabled else "disabled" + self._filter.rg_mode = mode if enabled else "disabled" def set_state_sync(self, state: Gst.State) -> None: """Set the state of the playbin, and wait for it to change.""" diff --git a/tests/audio/test_audio.py b/tests/audio/test_audio.py index 9ded546..30e154c 100644 --- a/tests/audio/test_audio.py +++ b/tests/audio/test_audio.py @@ -53,6 +53,27 @@ class TestAudio(unittest.TestCase): self.assertRegex(self.player._playbin.get_property("video-sink").name, r"fakesink\d+") + @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) + def test_filter(self, mock_stdout: io.StringIO): + """Test the filter element added to the playbin.""" + self.assertIsInstance(self.player._filter, + emmental.audio.filter.Filter) + self.assertEqual(self.player._playbin.get_property("audio-filter"), + self.player._filter) + + self.assertFalse(self.player.bg_enabled) + self.assertEqual(self.player.bg_volume, 0.5) + + self.player.bg_enabled = True + self.player.bg_volume = 0.75 + self.assertTrue(self.player._filter.bg_enabled) + self.assertEqual(self.player._filter.bg_volume, 0.75) + + self.player.bg_enabled = False + self.player.bg_volume = 0.5 + self.assertFalse(self.player._filter.bg_enabled) + self.assertEqual(self.player.bg_volume, 0.5) + @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) def test_eos(self, mock_stdout: io.StringIO): """Test handling an EOS message.""" @@ -297,22 +318,17 @@ class TestAudio(unittest.TestCase): @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) def test_replaygain(self, mock_stdout: io.StringIO): """Test that ReplayGain functions work as expected.""" - self.assertIsInstance(self.player._replaygain, - emmental.audio.replaygain.Filter) - self.assertEqual(self.player._playbin.get_property("audio-filter"), - self.player._replaygain) - - self.assertEqual(self.player._replaygain.mode, "disabled") + self.assertEqual(self.player._filter.rg_mode, "disabled") self.assertEqual(self.player.get_replaygain(), (False, None)) self.player.set_replaygain(True, "album") - self.assertEqual(self.player._replaygain.mode, "album") + self.assertEqual(self.player._filter.rg_mode, "album") self.assertEqual(self.player.get_replaygain(), (True, "album")) self.assertRegex(mock_stdout.getvalue(), r"audio: setting ReplayGain mode to 'album'") self.player.set_replaygain(False, "track") - self.assertEqual(self.player._replaygain.mode, "disabled") + self.assertEqual(self.player._filter.rg_mode, "disabled") self.assertEqual(self.player.get_replaygain(), (False, None)) self.assertRegex(mock_stdout.getvalue(), r"audio: setting ReplayGain mode to 'disabled'") diff --git a/tests/test_emmental.py b/tests/test_emmental.py index 70ecc64..bbe7cf4 100644 --- a/tests/test_emmental.py +++ b/tests/test_emmental.py @@ -220,3 +220,18 @@ class TestEmmental(unittest.TestCase): self.assertEqual(player.get_replaygain(), (True, "track")) win.header.rg_mode = "album" self.assertEqual(player.get_replaygain(), (True, "album")) + + @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) + def test_background_mode(self, mock_stdout: io.StringIO): + """Test setting background mode.""" + self.application.db = emmental.db.Connection() + self.application.factory = emmental.playlist.Factory( + self.application.db) + self.application.player = emmental.audio.Player() + win = self.application.build_window() + player = self.application.player + + win.header.bg_enabled = True + win.header.bg_volume = 0.5 + self.assertTrue(player.bg_enabled) + self.assertEqual(player.bg_volume, 0.5)