* Build: line tables only for workspace crates, no debug info for dependencies
Full debug info made most of the dev and test target size and link time. Line tables keep file and line numbers in backtraces; dependency frames lose them.
* Tests: build each crate's integration tests as one binary
Each tests/*.rs file was its own test binary: 98 binaries, each linking the crate and its dependencies. The files are now modules of tests/it/main.rs, one binary per crate, which cuts link time and target size. Filter by module: `cargo test -p <crate> --test it <module>::`.
Binaries with their own main (harness = false) in clap-host and vst3-host stay separate, as do the ui-egui tests that switch the process-wide Light/Dark palette and recovery.rs, whose autosave locks leak into child processes other tests start.
* Xtask: run tests with nextest, doctests apart, and no examples in the test build
cargo xtask ci runs the tests with cargo nextest when it is installed, else cargo test with a notice, and doctests with cargo test --doc. The test build leaves out examples (--lib --bins --tests); clippy --all-targets still compiles them. Test binaries with harness = false run under cargo test: their own main cannot answer nextest's --list. clippy and the wasm check keep going past a failing crate. cargo xtask test runs the test step alone.
Picking a plugin for an insert slot added it but opened nothing, so
every new plugin took an extra click on its slot. As in other DAWs, the
pick now opens it: a hosted plugin's own editor, else its plugin
window (built-in plugins, no audio engine, or an editor that can't open
here, such as CLAP plugins with only an embedded editor on macOS).
The insert menu's picks go through pick_insert, which remembers the
slot when mix.insert succeeds; SoundApp::open_inserted opens it on the
next logic pass, once the audio engine has the instance. Only the menu
opens it, so mix.insert from the CLI, MCP or control channel still
opens nothing. It covers empty and filled slots, in the Mix window and
the Edit window's Inserts column.
Tests: tests/open_on_insert.rs (empty slot, search and Enter,
replacing, Edit window column). menu_search closes the windows the
picks now open before it looks for the menu's Bypass.
Reject oversized batches before any side effects instead of reporting success after truncating calls.
Closes#460
Co-Authored-By: OpenAI Codex <noreply@openai.com>
With the marker present, ui.json, Autosave, Presets and logs go to
<exe dir>/SoundCraftData instead of the user profile. SOUNDCRAFT_CONFIG_DIR
still wins, and a data folder that can't be written falls back to the
profile with a warning in the log.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Press a checkbox and drag over its neighbours: each box the pointer
passes takes the state the first one switched to, until the button is
released. A click toggles one box, as before. Same design as VectorCraft
and PhotoCraft.
widgets::checkbox wraps egui's checkbox and adds the drag; every
ui.checkbox call in ui-egui uses it. Only boxes the pointer can see are
set, so rows scrolled out of a list or under another window stay as
they are.
Tests: widgets::tests (drag sets, drag unchecks and stops at release,
hidden rows untouched, a click toggles one) and tests/group_dialog.rs
(dragging down the Group dialog's track list groups every track).
A bounce rendered the whole mix (or bus) into memory and then encoded a
second copy, and the render silently stopped at 2^29 samples: about 93
minutes of stereo at 48 kHz, 31 of 5.1, 15 of 7.1.4. Longer bounces came
out cut short while file.bounce_mix still reported the requested length.
- audio-io: FileEncoder writes WAV/BWF (RF64 above 4 GiB), AIFF and FLAC
block by block into any Write + Seek, byte for byte what encode writes
for the whole buffer. check_room fails up front when an AIFF (4 GiB) or
a FLAC (2^36 frames) can't hold the bounce. AIFF and FLAC encode run on
the same writers; their output is unchanged.
- mix: RangeRender renders the main mix or one bus over a range of any
length, a block at a time; render_range and render_bus (in memory,
still capped) are built on it.
- engine: io::Bounce streams the main mix or a bus, or its stereo
fold-down, into "<name>.part" next to the target, syncs it and renames
it into place, so a failed bounce leaves no partial file and keeps the
old one. In the browser it encodes into memory (failing instead of
aborting when memory runs out) and delivers the file as before.
Normalize renders twice (peak, then the scaled write); levels are
measured as blocks are written. Stems stream the same way and share the
4-hour limit.
A 100-minute bounce of the demo session now writes all 288,000,000
frames with 83 MB peak memory.
Setup > Playback Engine now chooses the audio system (cpal host), output
and input device, device sample rate and buffer size, kept per machine
with the UI preferences and applied by reopening the devices (refused
while recording; the transport position is kept). ui.audio_device does
the same for agents and lists every system with its devices, channels,
rates and buffer range.
Player and recorder open the chosen device, fall back to the defaults
for anything unavailable (unplugged device, unsupported rate), retry
with the device's default buffer when the chosen one is refused, and
convert 32/16-bit integer devices from and to the f32 mix through
scratch buffers allocated up front (no allocation in the callbacks).
ASIO is behind an opt-in 'asio' feature (playback and app): building it
downloads Steinberg's ASIO SDK (proprietary licence or GPLv3) and needs
LLVM, so it stays off by default. Verified on Windows with an SSL 2+:
WASAPI output/input switching and buffer 256, ASIO duplex at 128.
Docs: G-01 shrunk, hardware-parity rows, roadmap log.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plugins that offer no floating editor (most CLAP plugins on Windows) now
get a host window of SoundCraft's: the GUI is created embedded, parented
to a top-level HWND owned by the app window, sized from get_size, resized
on request_resize (applied by the editor's idle on the main thread, then
set_size), and torn down when the user closes the window. Floating
editors work as before; other platforms still report embedded editors
as unsupported.
Docs: plugin-parity editor rows and the roadmap log.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>