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

View File

@@ -88,11 +88,26 @@ class SongPlayer:
if not self.stream.closed:
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(
channels=self.audio.shape[1] if self.audio.ndim > 1 else 1,
callback=self.play_callback,
blocksize=256,
device=7
blocksize=int(self.timeline.app.config_handler.get("audio", "block_size")),
device=device_index
)
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.binding import Binding
from textual_slider import Slider
import sounddevice as sd
class SettingsScreen(ModalScreen):
border_title = "Settings"
@@ -31,6 +35,12 @@ class SettingsScreen(ModalScreen):
text-style: bold;
}
#block-size-text {
width: 5;
height: 3;
content-align: left middle;
}
.setting {
padding: 0 2;
content-align: center middle;
@@ -52,8 +62,8 @@ class SettingsScreen(ModalScreen):
margin-right: 1;
}
Select, Input {
max-width: 30;
Select, Input, Slider {
max-width: 35;
}
}
}
@@ -72,7 +82,16 @@ class SettingsScreen(ModalScreen):
def on_select_changed(self, event: Select.Changed):
if event.select.id == "colour-theme":
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):
with Vertical(id="window") as window:
@@ -91,3 +110,46 @@ class SettingsScreen(ModalScreen):
id="colour-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"
)