audio: Create a new audio filter for ReplayGain and Background Mode
This links together our ReplayGain filter with a volume element that is set to the user configured background volume when background listening mode is enabled, and 100% when background listening mode is disabled. Implements: #50 ("Background Music Mode") Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
7155fa9db5
commit
84fbd94aa1
|
@ -0,0 +1,45 @@
|
|||
# Copyright 2023 (c) Anna Schumaker.
|
||||
"""A custom Gst.Bin with our audio filter effects."""
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gst
|
||||
from . import replaygain
|
||||
|
||||
|
||||
class Filter(Gst.Bin):
|
||||
"""The audio filter element."""
|
||||
|
||||
bg_enabled = GObject.Property(type=bool, default=False)
|
||||
bg_volume = GObject.Property(type=float, default=0.5)
|
||||
rg_mode = GObject.Property(type=str, default="disabled")
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the audio filter."""
|
||||
super().__init__()
|
||||
self._replaygain = replaygain.Filter()
|
||||
self._volume = Gst.ElementFactory.make("volume")
|
||||
|
||||
self.add(self._replaygain)
|
||||
self.add(self._volume)
|
||||
|
||||
rg_pad = self._replaygain.get_static_pad("src")
|
||||
rg_pad.link(self._volume.get_static_pad("sink"))
|
||||
|
||||
self.__add_ghost_pad("sink", self._replaygain)
|
||||
self.__add_ghost_pad("src", self._volume)
|
||||
|
||||
self.connect("notify", self.__notify)
|
||||
|
||||
def __add_ghost_pad(self, pad: str, elm: Gst.Element) -> None:
|
||||
self.add_pad(Gst.GhostPad.new(pad, elm.get_static_pad(pad)))
|
||||
|
||||
def __notify(self, filter: Gst.Bin, param: GObject.ParamSpec) -> None:
|
||||
match param.name:
|
||||
case "bg-enabled" | "bg-volume":
|
||||
vol = self.bg_volume if self.bg_enabled else 1.0
|
||||
if vol != self._volume.get_property("volume"):
|
||||
vs = f"{round(vol * 100)}%" if self.bg_enabled else "off"
|
||||
print(f"audio: setting background listening to {vs}")
|
||||
self._volume.set_property("volume", vol)
|
||||
case "rg-mode":
|
||||
if self.rg_mode != self._replaygain.mode:
|
||||
self._replaygain.mode = self.rg_mode
|
|
@ -0,0 +1,72 @@
|
|||
# Copyright 2023 (c) Anna Schumaker.
|
||||
"""Tests our combined Filter element."""
|
||||
import io
|
||||
import unittest
|
||||
import emmental.audio.filter
|
||||
from gi.repository import Gst
|
||||
|
||||
|
||||
class TestFilter(unittest.TestCase):
|
||||
"""Tests our custom Filter element."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up common variables."""
|
||||
self.filter = emmental.audio.filter.Filter()
|
||||
|
||||
def test_init(self):
|
||||
"""Test that the filter is set up correctly."""
|
||||
self.assertIsInstance(self.filter, Gst.Bin)
|
||||
self.assertIsInstance(self.filter.get_static_pad("src"), Gst.GhostPad)
|
||||
self.assertIsInstance(self.filter.get_static_pad("sink"), Gst.GhostPad)
|
||||
|
||||
@unittest.mock.patch("sys.stdout", new_callable=io.StringIO)
|
||||
def test_replaygain(self, mock_stdout: io.StringIO):
|
||||
"""Test the ReplayGain element in the filter."""
|
||||
self.assertIsInstance(self.filter._replaygain,
|
||||
emmental.audio.replaygain.Filter)
|
||||
|
||||
self.assertEqual(self.filter.rg_mode, "disabled")
|
||||
self.filter.rg_mode = "track"
|
||||
self.assertEqual(self.filter._replaygain.mode, "track")
|
||||
self.filter.rg_mode = "track"
|
||||
self.assertEqual(mock_stdout.getvalue(),
|
||||
"audio: setting ReplayGain mode to 'track'\n")
|
||||
|
||||
@unittest.mock.patch("sys.stdout", new_callable=io.StringIO)
|
||||
def test_volume(self, mock_stdout: io.StringIO):
|
||||
"""Test the Volume element in the filter."""
|
||||
self.assertIsInstance(self.filter._volume, Gst.Element)
|
||||
self.assertRegex(self.filter._volume.name, r"volume\d+")
|
||||
self.assertEqual(self.filter._volume.get_property("volume"), 1.0)
|
||||
|
||||
self.assertFalse(self.filter.bg_enabled)
|
||||
self.assertEqual(self.filter.bg_volume, 0.5)
|
||||
|
||||
self.filter.bg_enabled = True
|
||||
self.assertEqual(self.filter._volume.get_property("volume"), 0.5)
|
||||
self.assertEqual(mock_stdout.getvalue(),
|
||||
"audio: setting background listening to 50%\n")
|
||||
|
||||
self.filter.bg_volume = 0.50
|
||||
self.assertEqual(mock_stdout.getvalue(),
|
||||
"audio: setting background listening to 50%\n")
|
||||
|
||||
self.filter.bg_volume = 0.75
|
||||
self.assertEqual(self.filter._volume.get_property("volume"), 0.75)
|
||||
self.assertEqual(mock_stdout.getvalue(),
|
||||
"audio: setting background listening to 50%\n"
|
||||
"audio: setting background listening to 75%\n")
|
||||
|
||||
self.filter.bg_enabled = False
|
||||
self.assertEqual(self.filter._volume.get_property("volume"), 1.0)
|
||||
self.assertEqual(mock_stdout.getvalue(),
|
||||
"audio: setting background listening to 50%\n"
|
||||
"audio: setting background listening to 75%\n"
|
||||
"audio: setting background listening to off\n")
|
||||
|
||||
self.filter.bg_volume = 0.5
|
||||
self.assertEqual(self.filter._volume.get_property("volume"), 1.0)
|
||||
self.assertEqual(mock_stdout.getvalue(),
|
||||
"audio: setting background listening to 50%\n"
|
||||
"audio: setting background listening to 75%\n"
|
||||
"audio: setting background listening to off\n")
|
Loading…
Reference in New Issue