you can customize your playback settings now. also removed uneeded samples from the repo
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
Reference in New Issue
Block a user