The previous release build failed in craft-common-actions, not in this
repo: riscv64 packaging got --formats deb,rpm,tar (fixed in
craft-common-actions#3), Linux jobs lacked the ALSA headers
(craft-common-actions#5), and Windows signing needed the AZURE_* secrets
listed in the caller.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- release.yml: new linux-riscv64 job, cross-compiled on ubuntu-24.04 against ports.ubuntu.com
riscv64 libs (the linux job's -dev packages incl. libasound2-dev:riscv64), CLI smoke-tested
under qemu-riscv64; wired into the release job's needs so SHA256SUMS covers it.
- packaging/linux/package.sh: CROSS_ARCH/CROSS_TARGET/CROSS_COMPILE/EMULATOR support.
- clap-host: c_char -> u8 without a cast that is a no-op (clippy error) where c_char is u8.
- Version 0.4.0 -> 0.5.0; docs list the riscv64 tarball.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The web build could not reach any file: File > Open Session…, Import > Audio… and Import > MIDI…
showed a text box for a path the browser can't read, and every save or export failed with
«operation not supported on this platform», so work was lost on close.
On the web now:
- Open Session…, Import Audio… and Import MIDI… show the browser's file picker; files dropped on
the page open (sessions) or import (audio, MIDI) by extension. Files travel as bytes; imports are
one undo step each, like the import commands.
- A session is saved as ONE file, a bundle `<name>.scraftz`: a zip (stored entries) holding the
`.scraft` and its `Audio Files/` as 32-bit float WAV — the same layout as a session folder, since
the browser has no folders. `io::open_session_bytes` opens a bundle or a bare `.scraft` (its audio
is then reported missing). Bundles are hostile input: entry count and size are capped, and
declared sizes are never read past.
- Every single-file output (save, Save As Template, bounce, MIDI/score/text export, track presets)
goes through `io::write_file`: a file natively, a download in the browser via a delivery hook
(`io::set_deliver`) that only the web app installs.
- In the browser Save As asks for the bundle's name (`<name>.scraftz`) instead of a folder path.
Native builds keep writing files and session folders as before. Folder outputs (stems, clip
exports) are still not available on the web.
Pairs with #157 (Save on a never-saved session opens Save As), which the browser needs too: the
web app always starts on the unsaved demo.
New dependency: `zip` (MIT), default features off (stored entries only).
Checked: engine tests for the bundle round trip (every sample identical), same-named sources,
bare sessions and hostile bundles; `cargo xtask ci`. In Chromium on the packaged web build:
⌘⇧I picks and imports a WAV; WAV, MP3, FLAC, OGG, M4A, AIFF and MIDI import by drop; Save As →
`Midnight Groove.scraftz` downloads with the imported audio inside; that bundle reopens in a fresh
page with all tracks and no missing media, and saves again with the same content.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On macOS, Heal Separation (Cmd+H) and Copy to Send (Cmd+Alt+H) never
ran (#140). The system menu bar used muda's predefined Hide and Hide
Others items, which carry those keys, and macOS offers a key press to
the menu bar's key equivalents before the window, so egui never saw
them: Cmd+H hid SoundCraft and Cmd+Alt+H hid the other apps.
Pro Tools uses the same keys for Heal Separation and Copy Automation to
Send, so the keys stay and Hide loses its shortcut instead. Hide
SoundCraft and Hide Others are now plain menu items that call
NSApplication's hide: and hideOtherApplications:. These are safe
objc2-app-kit calls, and both crates were already in the build through
muda. Show All keeps muda's item, which has no shortcut. Windows and
Linux have no such menu, so nothing changes there.
Resolve System appearance from egui on every frame and fall back to Dark when the integration cannot report a theme. Keep receiving OS changes during manual modes and apply the selected palette to both widget style branches and the current root UI.
Remove the cached detector and its unused dependency. Cover startup, live transitions, manual overrides, saved System preferences, and user colors with an application-frame regression. Add reproducible offscreen system-theme inputs and document the fallback.
* Add a selectable Light theme
* Apply the active theme to the menu bar
* Use the system theme by default
* Expose Appearance in the Setup menu
* Add Light theme screenshot
* Remove the Light theme screenshot
Repo policy keeps large binary assets out of the tree, and the PNG had no
ATTRIBUTION row.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Appearance: ui.theme command, Dark default, non-blocking system lookup
- ThemeMode derives Default with Dark as the default (fixes clippy's
derivable_impls); System and Light are opt-in. LIGHT_THEME starts false.
- New UI command `ui.theme {"mode": "system|light|dark"}` (label
"Appearance") in UI_COMMANDS; with no mode it reports the current one.
The UI Customization combo box dispatches it instead of writing state.
- The choice lives in UiState.theme, so it persists with the existing UI
prefs (ui.json) and is exposed through ui.set / ui.inspect. Restoring a
window configuration keeps the current theme.
- dark_light::detect() is only called in System mode, on a background
thread (an AtomicU8 holds the answer; dark until it arrives, then a
repaint). On the web it is the synchronous matchMedia lookup.
- theme::apply runs only when the effective palette changes, not every
frame.
- window.ui_customization keeps its catalog path (Window > UI
Customization) so parity is unchanged; Setup > Appearance still opens
it. The combo row is labelled "Theme" so it no longer repeats the title.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Light theme: move hard-coded colours to theme tokens
The Light palette left dark islands and unreadable text where colours
were Color32 literals. New tokens (Dark values are the old literals, so
the Dark theme renders pixel-identical to main):
- menu bar; toolbar group outline; edit-mode cells (no more dark block
around Shuffle/Spot/Slip/Grid); counter panel outlines, dividers and
off toggles; Smart-tool bracket
- selected rows in the Tracks/Groups/Clips lists, track-visible dot,
selected Edit track header, selected Mix strip
- marker names, alternate-playlist lanes, Universe background/outline,
Big Counter background
- meter background and clip lamp, pan knob body/ring/pointer, Mix insert
and send slots, Mix section captions
In Light, clip bodies are a paler tint and waveforms a deep shade of the
clip colour instead of black.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Light theme: instrument slot and plugin window text use the current tokens
The instrument picker (#23) landed with Tokens::DARK literals.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: t <t@t>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
The Mix window's insert menu listed each format's plugins as one flat column.
With many installed (53 VST3 and 95 Audio Units effects on a composer's Mac)
it ran past the bottom of the screen and egui menus don't scroll, so the lower
entries couldn't be reached. CLAP, VST3 and Audio Units now open one submenu
per vendor, as Pro Tools does when plug-in menus are organized by manufacturer,
and every list scrolls within the screen.
Choosing an Audio Unit did nothing: the engine's plugin lookup, which
mix.insert uses, covered built-in, CLAP and VST3 plugins only, so "au:" ids were
"unknown plugin" and the UI dropped the error. The lookup now includes Audio
Units (the engine depends on soundcraft-au-host, like the mixer and the UI), and
the menu shows a failed insert in the status bar.
Closes#21
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The vst3 bindings' enum constants use the C default enum type, which is i32 on
Windows and u32 elsewhere. The bus helpers took u32 and the process-context
flags were assigned to a u32 field directly, so the release build failed on all
three Windows targets. Type the helpers with the bindings' own aliases and cast
the flags once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* About: contributors compiled in from contributors.json (grab bag + table, sortable, name toggle)
Adds the craftrules standard (standards/contributors.md) to SoundCraft: the About window gets
About · Contributors · Models tabs. contributors/contributors.json is generated by
craftrules/scripts/contributors.py and baked into the binary by crates/ui-egui/build.rs as
static tables. Each contributor line: @username, opt-in display/real name, PRs, commits,
lines +/−/Δ, binary assets +/−, first/last commit. Sortable by every column; alphabetical
ignores case and the leading @. Sort arrows use ⏶/⏷ (egui's icon font) since the system UI
font has no ▲/▼.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Contributors: self-submitted names in contributors/people.toml; AGENTS.md credit-yourself section
build.rs reads contributors/people.toml next to the generated contributors.json and shows a name only
for entries the generator verified as written by that person (craftrules standards/contributors.md).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Contributors: regenerate (verified people.toml entries)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Video (new standalone crate soundcraft-video):
- Pure-Rust H.264 (Baseline/Main/High), ProRes (all flavours) and Motion JPEG decoding with
ISO-BMFF demux, adapted from FilmCraft's crates; fuzzed with mutated/truncated movies
- TrackKind::Video with ClipContent::Video referencing Session.videos; file.import_video adds
the picture track and the movie's audio; relinking on open; video.offset/online/list
- Video and Video Universe windows, thumbnails on the timeline, background decoding
Third-party plugins:
- Plugin state (CLAP state ext, VST3 component + controller state) saved in sessions
- Hosted instances created, state-loaded and dropped on the UI thread, never the audio thread
- Plugin editors: floating CLAP GUIs and VST3 views on macOS (verified with Melodyne)
- New isolated FFI crate soundcraft-au-host: Audio Units on macOS (effects and instruments,
parameters, latency, MIDI, ClassInfo state), wired into the mixer and plugin browser
UI: Window > Renderer (speaker layout with live levels and object positions), Window > UI
Customization (interface scale, reduce motion), Window > Configurations > Auto-Update.
Fix: saturating sample-index math in clip rendering (hostile stretch values overflowed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Surround:
- main and bus formats up to 9.1.6 and Ambisonics; pairwise constant-power
surround panner (divergence, centre, LFE, height) per track and send;
ITU fold-down; multichannel bounce with correct WAV channel masks;
multichannel device output; surround panner and multichannel meters in the
Mix window; setup.main_format, mix.surround_pan, mix.send_surround_pan
VST3:
- soundcraft-vst3-host: isolated unsafe crate (vst3 bindings, MIT), scans
standard folders, hosts components/processors/controllers, params,
latency, notes; VST3 menu; engine.vst3_plugins; e2e tests with a fixture
Hardening:
- positions from parameters clamped; offline renders capped and bounded to
track material; loop/transport limits; hostile-parameter property test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- soundcraft-clap-host: scans standard CLAP folders, loads plugins via
clap-sys/libloading, implements the Plugin trait (audio, params, latency,
notes); the only crate allowed unsafe, every block documented; stubs on wasm
- mixer, engine (mix.insert, engine.clap_plugins) and Mix window CLAP menu
- end-to-end tests against a Rust-built fixture plugin
- file.bounce_stems: one soloed file per track
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Workspace for SoundCraft, a clean-room pure-Rust Pro Tools-class DAW:
timebases and tempo maps, WAV/AIFF/FLAC/symphonia audio IO with peaks,
SMF and MIDI ops, 26 original DSP plugins, the session model, the mix
engine, ~180 registered commands with undo, a cpal player, and the
agent rules (AGENTS.md, ATTRIBUTION.md).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>