diff --git a/ROADMAP.md b/ROADMAP.md index 12377c0..e3b4f84 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -128,6 +128,7 @@ mutated and truncated movies. Field reports from the first public week are track - **2026-10-12:** `soundcraft-cli convert` rejects an unparsable or zero `--rate` and an unknown `--bit-depth` (exit 1, nothing written) instead of converting with a default (#256) - **2026-10-12:** Timecode labels with huge fields no longer overflow: frame counts are computed in 128 bits and clamp, so `setup.current_timecode` and `session.format_time` saturate instead of failing (#248) - **2026-10-12:** `session.format_time` with the smallest bar number no longer fails with an internal error: the bar offset saturates (#249) +- **2026-10-12 (audio device settings):** Setup › Playback Engine chooses the audio system, output and input device, sample rate and buffer size, kept per machine with the preferences; 16/32-bit integer devices are converted; ASIO is available behind the opt-in `asio` build feature (verified with an SSL 2+ at 128 samples). Channel routing, one duplex clock and latency compensation remain (G-01). No readiness percentage change. - **2026-10-10 (UI docking):** Tracks and Groups, Clips, MIDI Editor, Memory Locations, and Undo History use movable panels. Edit and Mix retain separate arrangements; Clips and MIDI Editor belong to Edit. Transport, plug-in, and specialist utility windows retain their existing hosts. Panel moves and reset are available as UI commands, and saved UI preferences retain arrangements. Common toolbar and track record-enable buttons share interaction, accessible labels and keyboard focus through `craft-ui`, retaining blue tool selection and red record-arm states. No readiness percentage change. - **2026-10-10** — Stage re-normalized to **pre-alpha** by the core-workflow gate (interface recording, MIDI recording and session interchange fail). Full re-measure against Pro Tools Ultimate 2026.4.1 and the standard progress-docs set (this page, target-app parity, gaps, roadmap, UI/format/hardware/plugin/ diff --git a/crates/playback/src/record.rs b/crates/playback/src/record.rs index 8072ada..519317b 100644 --- a/crates/playback/src/record.rs +++ b/crates/playback/src/record.rs @@ -188,6 +188,52 @@ where ) } +/// The input stream: device samples are converted to f32 in a scratch buffer allocated here (so +/// the callback never allocates), then feed the monitor ring and, while armed, the capture. +#[cfg(not(target_os = "freebsd"))] +fn build_input( + device: &cpal::Device, + config: &cpal::StreamConfig, + shared: &Arc, + monitor: &Arc, +) -> Result +where + T: cpal::SizedSample, + f32: cpal::FromSample, +{ + use cpal::Sample; + use cpal::traits::DeviceTrait; + let sh = Arc::clone(shared); + let mon = Arc::clone(monitor); + let mut scratch = vec![0.0f32; 8192 * usize::from(config.channels).max(1)]; + let chunk = scratch.len(); + let mut owed = 0; + device.build_input_stream( + config, + move |data: &[T], _: &cpal::InputCallbackInfo| { + crate::mark_audio_thread(); + for part in data.chunks(chunk) { + let Some(s) = scratch.get_mut(..part.len()) else { return }; + for (o, x) in s.iter_mut().zip(part) { + *o = f32::from_sample(*x); + } + mon.push(s); + if sh.armed.load(Ordering::Acquire) { + sh.capture(s, &mut owed); + } else { + owed = 0; + } + } + }, + |e| { + // Possibly the audio thread (see `crate::mark_audio_thread`). + crate::mark_audio_thread(); + log::warn!("input stream error: {e}"); + }, + None, + ) +} + impl Recorder { /// Open the default input device. Errors when there is none (the caller shows a message). pub fn open() -> Result {