mirror of
https://github.com/storytold/soundcraft.git
synced 2026-10-14 14:26:46 -04:00
Audio device: keep the new choice only once the devices reopen with it
ui.audio_device and Playback Engine › Apply wrote ui.audio before apply_audio_config could refuse (while recording), so the saved choice no longer matched the open device. apply_audio_config now takes the new configuration and stores it only after the refusal check. Adds a test for ui.audio_device: no-op query, a bad rate, refusal while recording, and an applied change. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
9e84e0e351
commit
3d1a30b61d
3 files changed
+36
-11
No files matched your search
@@ -558,13 +558,15 @@ impl SoundApp {
|
||||
|| (self.recorder.is_some() && self.engine.session().tracks.iter().any(|t| t.mixer.input_monitor || t.mixer.record_arm))
|
||||
}
|
||||
|
||||
/// Reopens the audio devices with `ui.audio` (Setup › Playback Engine › Apply), keeping the
|
||||
/// transport position. Plugin instances and their editors are recreated with the new player.
|
||||
/// Refused while recording, which would lose the take.
|
||||
pub fn apply_audio_config(&mut self) -> Result<(), String> {
|
||||
/// Reopens the audio devices with `cfg` (Setup › Playback Engine › Apply), keeping the
|
||||
/// transport position, and keeps it as `ui.audio`. Plugin instances and their editors are
|
||||
/// recreated with the new player. Refused while recording, which would lose the take; `ui.audio`
|
||||
/// then stays the configuration of the open device.
|
||||
pub fn apply_audio_config(&mut self, cfg: soundcraft_playback::AudioConfig) -> Result<(), String> {
|
||||
if self.engine.transport.recording {
|
||||
return Err("stop recording before changing the audio device".into());
|
||||
}
|
||||
self.ui.audio = cfg;
|
||||
let at = self.position();
|
||||
if let Some(p) = &self.player {
|
||||
p.stop();
|
||||
|
||||
@@ -547,11 +547,8 @@ pub fn playback_engine(app: &mut SoundApp, ctx: &egui::Context) {
|
||||
if refresh {
|
||||
audio_systems(ctx, true);
|
||||
}
|
||||
if apply {
|
||||
app.ui.audio = draft.clone();
|
||||
if let Err(e) = app.apply_audio_config() {
|
||||
app.ui.status = e;
|
||||
}
|
||||
if apply && let Err(e) = app.apply_audio_config(draft.clone()) {
|
||||
app.ui.status = e;
|
||||
}
|
||||
if open {
|
||||
ctx.data_mut(|d| d.insert_temp(draft_id, draft));
|
||||
@@ -588,8 +585,7 @@ pub fn audio_device_command(app: &mut SoundApp, p: &serde_json::Value) -> Result
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
app.ui.audio = cfg;
|
||||
app.apply_audio_config()?;
|
||||
app.apply_audio_config(cfg)?;
|
||||
}
|
||||
let device = app.player.as_ref().map(|pl| {
|
||||
json!({"name": pl.device_name, "sample_rate": pl.device_rate, "channels": pl.device_channels, "buffer_size": pl.device_buffer, "silent": pl.silent})
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
//! `ui.audio_device`: the audio device choice is kept only once the devices reopen with it.
|
||||
use serde_json::json;
|
||||
use soundcraft_ui_egui::{Services, SoundApp};
|
||||
|
||||
#[test]
|
||||
fn the_audio_device_choice_is_kept_only_when_it_is_applied() {
|
||||
let mut app = SoundApp::new(soundcraft_engine::Engine::default(), None, Services::default());
|
||||
let before = app.ui.audio.clone();
|
||||
|
||||
let r = app.run("ui.audio_device", json!({})).unwrap();
|
||||
assert_eq!(r["config"], json!(before), "no change: just the choice and the device");
|
||||
|
||||
assert!(app.run("ui.audio_device", json!({"sample_rate": 12})).is_err());
|
||||
assert_eq!(app.ui.audio, before, "an out-of-range rate changes nothing");
|
||||
|
||||
app.engine.transport.recording = true;
|
||||
let err = app.run("ui.audio_device", json!({"buffer_size": 256, "output": "Elsewhere"})).unwrap_err();
|
||||
assert!(err.contains("stop recording"), "{err}");
|
||||
assert_eq!(app.ui.audio, before, "refused while recording: the saved choice stays the open device's");
|
||||
app.engine.transport.recording = false;
|
||||
|
||||
// Opens the chosen device, or the default, or a silent clock without one.
|
||||
let r = app.run("ui.audio_device", json!({"buffer_size": 256})).unwrap();
|
||||
assert_eq!(app.ui.audio.buffer_size, Some(256));
|
||||
assert_eq!(r["config"]["buffer_size"], 256);
|
||||
assert!(r["device"].is_object(), "{r}");
|
||||
}
|
||||
Reference in new issue
Block a user