From 4a035ec5b6fd6fc8c6a5b013e701c5dc3ddd5f89 Mon Sep 17 00:00:00 2001 From: Correl Roush Date: Wed, 2 Sep 2020 09:15:27 -0400 Subject: [PATCH] Add a basic GUI --- poetry.lock | 14 +++++++- pyproject.toml | 4 ++- turntable/application.py | 74 +++++++++++++++++++++++++++++++++++++++ turntable/cli.py | 75 ++-------------------------------------- turntable/gui.py | 52 ++++++++++++++++++++++++++++ turntable/turntable.py | 4 ++- 6 files changed, 147 insertions(+), 76 deletions(-) create mode 100644 turntable/application.py create mode 100644 turntable/gui.py diff --git a/poetry.lock b/poetry.lock index 7e9029d..1928815 100644 --- a/poetry.lock +++ b/poetry.lock @@ -289,6 +289,14 @@ optional = false python-versions = "*" version = "0.23.1" +[[package]] +category = "main" +description = "Cross-platform windowing and multimedia library" +name = "pyglet" +optional = false +python-versions = "*" +version = "1.5.7" + [[package]] category = "main" description = "Python parsing module" @@ -414,7 +422,7 @@ secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0 socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] [metadata] -content-hash = "7145f097b34f0bbe62825427b4ecc8c916fa48c8255a9b5da539edf6b990540f" +content-hash = "3af542607f4ccaa3afe08d275174f664cdacedac31ce8278e059d4aca2b9edeb" lock-version = "1.0" python-versions = "^3.8" @@ -626,6 +634,10 @@ pydub = [ {file = "pydub-0.23.1-py2.py3-none-any.whl", hash = "sha256:d29901a486fb421c5d7b0f3d5d3a60527179204d8ffb20e74e1ae81c17e81b46"}, {file = "pydub-0.23.1.tar.gz", hash = "sha256:c362fa02da1eebd1d08bd47aa9b0102582dff7ca2269dbe9e043d228a0c1ea93"}, ] +pyglet = [ + {file = "pyglet-1.5.7-py3-none-any.whl", hash = "sha256:9832442d59ee06acbeff12e128cf6d5aee271e94c09386040db8f0feae277013"}, + {file = "pyglet-1.5.7.zip", hash = "sha256:3faac2dad34946aecbce79a8658f89155436fe5c07332229160c6eba302ff40d"}, +] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, diff --git a/pyproject.toml b/pyproject.toml index e80b002..e796fc5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,7 @@ python = "^3.8" pyalsaaudio = "^0.9.0" pydejavu = {git = "https://github.com/worldveil/dejavu.git"} requests = "^2.24.0" +pyglet = "^1.5.7" [tool.poetry.dev-dependencies] black = "^20.8b1" @@ -17,7 +18,8 @@ mypy = "^0.782" pytest = "^6.0.1" [tool.poetry.scripts] -turntable = "turntable.cli:main" +turntable = "turntable.gui:main" +turntable-cli = "turntable.cli:main" [build-system] requires = ["poetry>=0.12"] diff --git a/turntable/application.py b/turntable/application.py new file mode 100644 index 0000000..c00aa7f --- /dev/null +++ b/turntable/application.py @@ -0,0 +1,74 @@ +import argparse +from contextlib import contextmanager +import importlib.metadata +import json +import logging +from multiprocessing import Queue +import os +from typing import Any, Dict, Iterator + +from dejavu import Dejavu # type: ignore + +from turntable.audio import Listener +from turntable.icecast import Icecast +from turntable.models import PCM +from turntable.turntable import ( + Event, + NewMetadata, + StartedPlaying, + StoppedPlaying, + Turntable, +) + +VERSION = importlib.metadata.version("turntable") +logger = logging.getLogger(__name__) + +@contextmanager +def run() -> "Iterator[Queue[Event]]": + parser = argparse.ArgumentParser() + parser.add_argument( + "--config", default=os.path.expanduser("~/.config/turntable.json") + ) + args = parser.parse_args() + with open(args.config, "r") as config_file: + config: Dict[str, Any] = json.load(config_file) + + logging.basicConfig(level=logging.DEBUG if config.get("debug") else logging.INFO) + logger.info("Turntable version %s", VERSION) + + + pcm_in: "Queue[PCM]" = Queue() + events: "Queue[Event]" = Queue() + + audio_config = config.get("audio", dict()) + listener = Listener( + pcm_in, + audio_config.get("device", "default"), + framerate=audio_config.get("framerate", 44100), + channels=audio_config.get("channels", 2), + period_size=audio_config.get("period_size", 4096), + ) + + dejavu = Dejavu(config.get("dejavu", dict())) + + player = Turntable(listener.framerate, listener.channels, dejavu, pcm_in, events) + + icecast_config = config.get("icecast", dict()) + icecast = Icecast( + host=icecast_config.get("host", "localhost"), + port=icecast_config.get("port", 8000), + mountpoint=icecast_config.get("mountpoint", "stream.mp3"), + user=icecast_config.get("admin_user", "admin"), + password=icecast_config.get("admin_password", "hackme"), + ) + + processes = [listener, player] + for process in processes: + process.daemon = True + process.start() + try: + yield events + except: + for process in processes: + if process.is_alive(): + process.terminate() diff --git a/turntable/cli.py b/turntable/cli.py index 25bbd98..2efd379 100644 --- a/turntable/cli.py +++ b/turntable/cli.py @@ -1,80 +1,9 @@ -import argparse -import importlib.metadata -import json import logging -from multiprocessing import Queue -import os -from typing import Any, Dict -from dejavu import Dejavu # type: ignore - -from turntable.audio import Listener -from turntable.icecast import Icecast -from turntable.models import PCM -from turntable.turntable import ( - Event, - NewMetadata, - StartedPlaying, - StoppedPlaying, - Turntable, -) - -VERSION = importlib.metadata.version("turntable") +from turntable import application def main() -> None: - print(f"Turntable {VERSION}") - - parser = argparse.ArgumentParser() - parser.add_argument( - "--config", default=os.path.expanduser("~/.config/turntable.json") - ) - args = parser.parse_args() - with open(args.config, "r") as config_file: - config: Dict[str, Any] = json.load(config_file) - - logging.basicConfig(level=logging.DEBUG if config.get("debug") else logging.INFO) - - pcm_in: "Queue[PCM]" = Queue() - events: "Queue[Event]" = Queue() - - audio_config = config.get("audio", dict()) - listener = Listener( - pcm_in, - audio_config.get("device", "default"), - framerate=audio_config.get("framerate", 44100), - channels=audio_config.get("channels", 2), - period_size=audio_config.get("period_size", 4096), - ) - - dejavu = Dejavu(config.get("dejavu", dict())) - - player = Turntable(listener.framerate, listener.channels, dejavu, pcm_in, events) - - icecast_config = config.get("icecast", dict()) - icecast = Icecast( - host=icecast_config.get("host", "localhost"), - port=icecast_config.get("port", 8000), - mountpoint=icecast_config.get("mountpoint", "stream.mp3"), - user=icecast_config.get("admin_user", "admin"), - password=icecast_config.get("admin_password", "hackme"), - ) - - processes = [listener, player] - for process in processes: - process.daemon = True - process.start() - try: - icecast.set_title("") + with application.run() as events: while event := events.get(): logging.info("Event: %s", event) - if isinstance(event, StartedPlaying): - icecast.set_title("") - elif isinstance(event, StoppedPlaying): - icecast.set_title("") - elif isinstance(event, NewMetadata): - icecast.set_title(event.title) - except KeyboardInterrupt: - for process in processes: - if process.is_alive(): - process.terminate() diff --git a/turntable/gui.py b/turntable/gui.py new file mode 100644 index 0000000..e599e38 --- /dev/null +++ b/turntable/gui.py @@ -0,0 +1,52 @@ +import logging +import queue + +import pyglet # type: ignore +import pyglet.clock # type: ignore + +from turntable import application, turntable + +def main(): + window = pyglet.window.Window(fullscreen=True) + with application.run() as events: + label = pyglet.text.Label( + "", + font_name='Noto Sans', + font_size=36, + x = window.width // 2, + y = window.height // 2, + anchor_x = 'center', + anchor_y = 'center') + + @window.event + def on_draw(): + window.clear() + label.draw() + + def check_events(dt): + try: + event = events.get(False) + logging.info("Event: %s", event) + logging.info("Label: %s", label) + if isinstance(event, turntable.StartedPlaying): + label.text = "" + elif isinstance(event, turntable.StoppedPlaying): + label.text = "" + elif isinstance(event, turntable.NewMetadata): + label.text = event.title + except queue.Empty: + ... + except: + logging.exception("Oops") + + pyglet.clock.schedule_interval_soft(check_events, 0.5) + pyglet.app.run() + # icecast.set_title("") + # while event := events.get(): + # logging.info("Event: %s", event) + # if isinstance(event, StartedPlaying): + # icecast.set_title("") + # elif isinstance(event, StoppedPlaying): + # icecast.set_title("") + # elif isinstance(event, NewMetadata): + # icecast.set_title(event.title) diff --git a/turntable/turntable.py b/turntable/turntable.py index 29ff834..a3e872c 100644 --- a/turntable/turntable.py +++ b/turntable/turntable.py @@ -122,7 +122,9 @@ class Turntable(Process): >= FINGERPRINT_DELAY + FINGERPRINT_IDENTIFY_SECONDS and self.identified == False ): - startframe = self.buffer.framerate * FINGERPRINT_DELAY + startframe = self.buffer.framerate * ( + FINGERPRINT_DELAY + FINGERPRINT_IDENTIFY_DELAY + ) endframe = ( startframe + self.buffer.framerate * FINGERPRINT_IDENTIFY_SECONDS )