mirror of
https://github.com/correl/turntable.git
synced 2024-11-23 19:19:55 +00:00
Add a basic GUI
This commit is contained in:
parent
d8a175c358
commit
4a035ec5b6
6 changed files with 147 additions and 76 deletions
14
poetry.lock
generated
14
poetry.lock
generated
|
@ -289,6 +289,14 @@ optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
version = "0.23.1"
|
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]]
|
[[package]]
|
||||||
category = "main"
|
category = "main"
|
||||||
description = "Python parsing module"
|
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)"]
|
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
content-hash = "7145f097b34f0bbe62825427b4ecc8c916fa48c8255a9b5da539edf6b990540f"
|
content-hash = "3af542607f4ccaa3afe08d275174f664cdacedac31ce8278e059d4aca2b9edeb"
|
||||||
lock-version = "1.0"
|
lock-version = "1.0"
|
||||||
python-versions = "^3.8"
|
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-py2.py3-none-any.whl", hash = "sha256:d29901a486fb421c5d7b0f3d5d3a60527179204d8ffb20e74e1ae81c17e81b46"},
|
||||||
{file = "pydub-0.23.1.tar.gz", hash = "sha256:c362fa02da1eebd1d08bd47aa9b0102582dff7ca2269dbe9e043d228a0c1ea93"},
|
{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 = [
|
pyparsing = [
|
||||||
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
|
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
|
||||||
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
||||||
|
|
|
@ -10,6 +10,7 @@ python = "^3.8"
|
||||||
pyalsaaudio = "^0.9.0"
|
pyalsaaudio = "^0.9.0"
|
||||||
pydejavu = {git = "https://github.com/worldveil/dejavu.git"}
|
pydejavu = {git = "https://github.com/worldveil/dejavu.git"}
|
||||||
requests = "^2.24.0"
|
requests = "^2.24.0"
|
||||||
|
pyglet = "^1.5.7"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
black = "^20.8b1"
|
black = "^20.8b1"
|
||||||
|
@ -17,7 +18,8 @@ mypy = "^0.782"
|
||||||
pytest = "^6.0.1"
|
pytest = "^6.0.1"
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poetry.scripts]
|
||||||
turntable = "turntable.cli:main"
|
turntable = "turntable.gui:main"
|
||||||
|
turntable-cli = "turntable.cli:main"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry>=0.12"]
|
requires = ["poetry>=0.12"]
|
||||||
|
|
74
turntable/application.py
Normal file
74
turntable/application.py
Normal file
|
@ -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()
|
|
@ -1,80 +1,9 @@
|
||||||
import argparse
|
|
||||||
import importlib.metadata
|
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
from multiprocessing import Queue
|
|
||||||
import os
|
|
||||||
from typing import Any, Dict
|
|
||||||
|
|
||||||
from dejavu import Dejavu # type: ignore
|
from turntable import application
|
||||||
|
|
||||||
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")
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
print(f"Turntable {VERSION}")
|
with application.run() as events:
|
||||||
|
|
||||||
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("<Idle>")
|
|
||||||
while event := events.get():
|
while event := events.get():
|
||||||
logging.info("Event: %s", event)
|
logging.info("Event: %s", event)
|
||||||
if isinstance(event, StartedPlaying):
|
|
||||||
icecast.set_title("<Record starting...>")
|
|
||||||
elif isinstance(event, StoppedPlaying):
|
|
||||||
icecast.set_title("<Idle>")
|
|
||||||
elif isinstance(event, NewMetadata):
|
|
||||||
icecast.set_title(event.title)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
for process in processes:
|
|
||||||
if process.is_alive():
|
|
||||||
process.terminate()
|
|
||||||
|
|
52
turntable/gui.py
Normal file
52
turntable/gui.py
Normal file
|
@ -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(
|
||||||
|
"<Idle>",
|
||||||
|
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 = "<Record starting...>"
|
||||||
|
elif isinstance(event, turntable.StoppedPlaying):
|
||||||
|
label.text = "<Idle>"
|
||||||
|
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("<Idle>")
|
||||||
|
# while event := events.get():
|
||||||
|
# logging.info("Event: %s", event)
|
||||||
|
# if isinstance(event, StartedPlaying):
|
||||||
|
# icecast.set_title("<Record starting...>")
|
||||||
|
# elif isinstance(event, StoppedPlaying):
|
||||||
|
# icecast.set_title("<Idle>")
|
||||||
|
# elif isinstance(event, NewMetadata):
|
||||||
|
# icecast.set_title(event.title)
|
|
@ -122,7 +122,9 @@ class Turntable(Process):
|
||||||
>= FINGERPRINT_DELAY + FINGERPRINT_IDENTIFY_SECONDS
|
>= FINGERPRINT_DELAY + FINGERPRINT_IDENTIFY_SECONDS
|
||||||
and self.identified == False
|
and self.identified == False
|
||||||
):
|
):
|
||||||
startframe = self.buffer.framerate * FINGERPRINT_DELAY
|
startframe = self.buffer.framerate * (
|
||||||
|
FINGERPRINT_DELAY + FINGERPRINT_IDENTIFY_DELAY
|
||||||
|
)
|
||||||
endframe = (
|
endframe = (
|
||||||
startframe + self.buffer.framerate * FINGERPRINT_IDENTIFY_SECONDS
|
startframe + self.buffer.framerate * FINGERPRINT_IDENTIFY_SECONDS
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue