you can customize your playback settings now. also removed uneeded samples from the repo

This commit is contained in:
2026-01-18 07:52:28 +11:00
parent 23a99fddf5
commit bafbc586e2
6 changed files with 87 additions and 6 deletions

Binary file not shown.

Binary file not shown.

View File

View File

@@ -20,7 +20,7 @@ class ConfigHandler:
return config_dir return config_dir
def get(self, section: str, option: str): def get(self, section: str, option: str) -> str:
if not self.config.has_section(section): if not self.config.has_section(section):
self.config.add_section(section) self.config.add_section(section)
if not self.config.has_option(section, option): if not self.config.has_option(section, option):
@@ -53,6 +53,10 @@ class ConfigHandler:
} }
self.config["appearance"] = { self.config["appearance"] = {
"colour_theme": "textual-dark" "colour_theme": "textual-dark"
},
self.config["audio"] = {
"output_device": "None",
"input_device": "None"
} }
with open(self.config_dir / "config.ini", "w") as configfile: with open(self.config_dir / "config.ini", "w") as configfile:

View File

@@ -88,11 +88,26 @@ class SongPlayer:
if not self.stream.closed: if not self.stream.closed:
self.stream.close() self.stream.close()
# figure out which device we're using
devices = sd.query_devices()
device_index = None
for device in devices:
if device["name"] == self.timeline.app.config_handler.get("audio", "output_device"):
device_index = device["index"]
# something horrible has happened to our user config lmao
# not even the config manager could find a device, idek
# how that would happen.
if not device_index:
self.pause()
self.timeline.app.notify(f"Failed to find the output device you have specified in settings, please check your config.", title="Error while playing song", severity="error")
return False
self.stream = sd.OutputStream( self.stream = sd.OutputStream(
channels=self.audio.shape[1] if self.audio.ndim > 1 else 1, channels=self.audio.shape[1] if self.audio.ndim > 1 else 1,
callback=self.play_callback, callback=self.play_callback,
blocksize=256, blocksize=int(self.timeline.app.config_handler.get("audio", "block_size")),
device=7 device=device_index
) )
self.stream.start() self.stream.start()

View File

@@ -3,6 +3,10 @@ from textual.widgets import Label, Select, TabbedContent, TabPane, Switch, Input
from textual.containers import Vertical, HorizontalGroup, VerticalGroup, VerticalScroll from textual.containers import Vertical, HorizontalGroup, VerticalGroup, VerticalScroll
from textual.binding import Binding from textual.binding import Binding
from textual_slider import Slider
import sounddevice as sd
class SettingsScreen(ModalScreen): class SettingsScreen(ModalScreen):
border_title = "Settings" border_title = "Settings"
@@ -30,6 +34,12 @@ class SettingsScreen(ModalScreen):
margin-top: 2; margin-top: 2;
text-style: bold; text-style: bold;
} }
#block-size-text {
width: 5;
height: 3;
content-align: left middle;
}
.setting { .setting {
padding: 0 2; padding: 0 2;
@@ -52,8 +62,8 @@ class SettingsScreen(ModalScreen):
margin-right: 1; margin-right: 1;
} }
Select, Input { Select, Input, Slider {
max-width: 30; max-width: 35;
} }
} }
} }
@@ -72,7 +82,16 @@ class SettingsScreen(ModalScreen):
def on_select_changed(self, event: Select.Changed): def on_select_changed(self, event: Select.Changed):
if event.select.id == "colour-theme": if event.select.id == "colour-theme":
self.app.theme = event.value self.app.theme = event.value
self.app.config_handler.set("appearance", "colour_theme", str(event.value)) self.app.config_handler.set("appearance", "colour_theme", event.value)
elif event.select.id == "output-device":
self.app.config_handler.set("audio", "output_device", event.value)
elif event.select.id == "input-device":
self.app.config_handler.set("audio", "input_device", event.value)
def on_slider_changed(self, event: Slider.Changed):
if event.slider.id == "block-size":
self.query_one("#block-size-text").update(str(event.value))
self.app.config_handler.set("audio", "block_size", str(event.value))
def compose(self): def compose(self):
with Vertical(id="window") as window: with Vertical(id="window") as window:
@@ -90,4 +109,47 @@ class SettingsScreen(ModalScreen):
allow_blank=False, allow_blank=False,
id="colour-theme", id="colour-theme",
value=self.app.theme value=self.app.theme
)
with TabPane("Audio"):
with VerticalScroll():
with HorizontalGroup(classes="setting"):
with VerticalGroup():
yield Label("Output Device", classes="setting-name")
yield Label("The device that audio will be outputted to. If a device is not shown, then [i]sounddevice[/i] thinks it has 0 output channels.", classes="setting-desc")
devices: list[str] = [device["name"] for device in sd.query_devices() if device["max_output_channels"] > 0]
output_device_name = self.app.config_handler.get("audio", "output_device")
yield Select.from_values(
devices,
allow_blank=False,
id="output-device",
value=output_device_name if output_device_name in devices else devices[0]
)
with HorizontalGroup(classes="setting"):
with VerticalGroup():
yield Label("Input Device", classes="setting-name")
yield Label("The device that will be used for recording audio. If a device is not shown, then [i]sounddevice[/i] thinks it has 0 input channels. (this setting is unused for now)", classes="setting-desc")
devices: list[str] = [device["name"] for device in sd.query_devices() if device["max_input_channels"] > 0]
input_device_name = self.app.config_handler.get("audio", "input_device")
yield Select.from_values(
devices,
allow_blank=False,
id="input-device",
value=input_device_name if input_device_name in devices else devices[0]
)
with HorizontalGroup(classes="setting"):
with VerticalGroup():
yield Label("Block Size", classes="setting-name")
yield Label("Block size of audio playback. Higher block size will reduce stutters or cut outs, but will also lead to higher CPU strain.", classes="setting-desc")
yield Static("N/A", id="block-size-text")
yield Slider(
16,
2048,
step=16,
value=int(self.app.config_handler.get("audio", "block_size")),
id="block-size"
) )