The submenu under Track › New... opens the same picker as the Mix window's
instrument slot for the first selected instrument track, and is greyed out
with a hint when none is selected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opening, creating, closing or reverting a session in the middle of a
take dropped the recorder: the take was written to disk but never added
to any session. Quitting mid-take did the same, and on_exit didn't
finish the take either.
New, Open, Close, Revert and Quit now wait for the take: the engine
refuses them with "stop recording first", and their menu items are
greyed out while recording, as is Recover in the recovery window. Any
exit that still happens mid-take (closing the window, the system
quitting the app, a remote quit) finishes the take first and keeps the
session, take included, in the autosave folder for the next launch.
Pro Tools has File › Open Recent; SoundCraft had no way back to a session but
browsing for it. The list (UiState.recent_sessions) records the engine's
session path whenever it changes, so opening or saving by any route (menu,
control channel, MCP, a dropped file) is covered by one rule.
- Under File › Open; each entry is "name — folder", full path on hover.
- A session that has moved or been deleted is greyed out "(missing)" instead
of failing on click; existence is re-checked at most every 3 s while the menu
is open, since a network share costs a round trip per file.
- Opening goes through the dialog layer, so unsaved changes are asked about.
- Clear Recent empties it.
- The desktop host saves ui.json as soon as the list changes, not only on a
clean exit: the list matters most after a crash.
- An older ui.json without the field still loads (serde default).
The macOS system menu bar (native_menu) does not show it yet; the egui menu
bar on Windows and Linux does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
midi.new_clip had no UI path, so an empty instrument/MIDI track could
never get a MIDI clip (#282). The menu bar is built from the catalog,
so the entry is added to menus::tree() and placed first in Clip.
The new test checks every mutating command is reachable from the GUI
(built menu tree, shortcut, or UI reference), with today's gaps listed.
Closes#282
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Commands that already worked but had no key get the ones Pro Tools uses,
on macOS, Windows and Linux alike (Alt is Option on macOS; Cmd is Ctrl
elsewhere):
- Shift+= and Shift+- step the Grid value to the next larger or smaller
one, and Alt+Shift+= and Alt+Shift+- the Nudge value, as the Pro Tools
Reference Guide gives them. `view.grid` and `view.nudge` take `step`.
`GridValue::stepped` walks the note values, keeping a dot or triplet, and
steps seconds, frames and samples by tens. macOS sends Alt+Shift+= as =
(the key under ±), so that arm takes = as well as +. Both commands list
the keys as descriptive shortcuts, like Nudge's Plus/Minus, so they show
wherever commands list their shortcuts; the strings don't parse, so the
registry never dispatches them and `shortcuts::fixed` handles the keys.
- Commands Focus: , and . nudge back and forward, M and / nudge by the next
larger Nudge value (`edit.nudge` takes `next`), 0 copies the Timeline
selection to the Edit selection and O the other way, [ and ] play the
Edit and Timeline selections, and Shift+Z redoes. Shift+P and Shift+;
add the track above or below the selection, keeping its range (P and ;
already move it). They run Extend Edit Up/Down, which now skip tracks
the Edit window doesn't show (hidden, or in a closed folder); before,
they could add an invisible track. Shift+; can arrive as :, so both are
matched.
- Playlists: Alt+Shift+Up and Alt+Shift+Down copy the selection to the
target playlist and to a new one, Alt+Shift+T and Alt+Shift+N move it
there, Shift+Right shows the target playlist and Cmd+Shift+Right
designates the shown one. The MIDI editor's piano roll moved notes on any
arrow key, whatever the modifiers; it now leaves Alt, Cmd and Ctrl arrows,
and Shift+Left/Right, to these shortcuts.
- F12 records, as in Pro Tools. Cmd+Space is Spotlight on macOS.
- Ctrl+Tab goes back to the previous clip boundary off macOS, where Windows,
GNOME and KDE take Alt+Tab; Pro Tools for Windows uses Ctrl+Tab too.
Cmd+Alt+Tab now toggles Tab to Transient: the Tab arm took it as Alt+Tab
and tabbed back instead.
- Windows: Alt+7 Universe, Alt+6 Clip Effects, Alt+= MIDI Event List,
Shift+K MIDI Keyboard, Cmd+Alt+J Window Configuration List, Alt+' Task
Manager, Alt+I Workspace, Alt+J Workspaces to Front.
Tests drive the keys through `shortcuts::handle` for each OS
(tests/pro_tools_keys.rs), plus the piano roll with modifier arrows held.
Window > Mix in Separate Window (window.mix_separate, kept with the UI
preferences) shows the Mix window in its own native window through an
egui immediate viewport, so Edit and Mix can be seen at once, e.g. one
per monitor. The main window then keeps Edit; Window > Mix and
Cmd/Ctrl+= bring the Mix window to the front; closing it puts Mix back
into the main window. Backends without multiple windows show it as a
floating egui window.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
Close Session, New, Open, Revert, Quit, the window's close button,
dropping a session file on the window and opening one from the Workspace
window all replaced or closed the session without asking, so unsaved
edits were lost (#136). They now ask first: Save, Don't Save or Cancel.
Save on a session that has never been saved goes through Save As, then
carries on. Revert asks for confirmation instead, and Revert to Saved is
unavailable until the session has a file. A take being recorded is
stopped first, so it counts as a change. The web build has nowhere to
save, so it offers only Don't Save and Cancel. Calls from the control
channel, MCP and the CLI never ask.
Selecting, locating, zooming and scrolling no longer mark the session
modified, so the question only comes after real edits. Undoing back to
the saved state makes the session clean again. The engine compares the
document with the one last opened or saved, ignoring the selection, the
playhead and the zoom, once per revision.
Fixes#136
The Window menu's keys never fired: Cmd+1 Transport, Cmd+3 Big Counter,
Cmd+4 Automation, Cmd+5 Memory Locations, Cmd+9 Video, Cmd+Alt+M Narrow
Mix, Cmd+W Close Window, Cmd+Ctrl+W Hide All Floating Windows and
Cmd+Ctrl+= Score Editor. The shortcut handler only looked at engine
commands, and these are window commands. It now falls back to them, and
the menus and the Keyboard Shortcuts window show their keys.
On a Mac, Cmd+Ctrl+= toggled Mix/Edit instead of opening the Score
Editor. The Mix/Edit toggle now needs Cmd+= without Control there.
The two Control chords still have no key on Windows and Linux.
The Edit menu always read "Can't Undo" and "Can't Redo", the incumbent's
labels for an empty history, even when there was something to undo. The
items now name the step they would take ("Undo Mute", "Redo Mute"), in
the in-window menu bar and the macOS system menu alike, and read "Can't
Undo" / "Can't Redo" only when there is nothing.
Clip > Rename... and Cmd+Alt+Shift+R ran clip.rename without a name, so
they only put "`name` required" in the status line. They now open the
Rename Clip dialog, which only the clip's right-click menu opened so
far, for the selected clip (or the first clip the edit selection
touches).
The dialog's name field, and Rename Track's, now opens with the old
name selected, so typing replaces it instead of adding to it.
Cmd+S and File > Save Session on an untitled session only left "no path
yet: pass `path` (Save As)" in the status line. From a menu, the command
palette or the keyboard, Save now opens the Save Session As prompt until
the session has a file. Calls from the control channel, MCP and the CLI
still need a `path`.
The prompt suggests ~/<name>/<name>.scraft, but saving a session without
audio there failed with "No such file or directory", because only
writing audio created the session folder. Saving now creates the folder.
engine.execute and app.run of ui.new_tracks_dialog and ui.bounce_dialog were opening modal dialogs, so a script could not create tracks or bounce without a window. Those ids now return an error unless the menu invokes them.
The menu bar rebuilt and leaked a fresh alias string for every mix-view section on each redraw. Those fifteen paths are now created the first time the menu catalog is asked for them.
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.
Nothing in the Clip List could be removed: neither its files nor its clips
had a delete action, so everything stayed listed.
- New `clip.clear` (Cmd+Shift+B, the Clip List Clear shortcut in Pro Tools),
also offered as Clear… on every Clip List row's right-click menu. A clip
leaves its track; a file leaves the session with its decoded audio and is
never deleted from disk. One undo step brings everything back.
- As in Pro Tools, Clear asks first. The dialog names what goes, including
the clips on any track or playlist that still play a file being removed:
they are removed too. Programmatic calls never open it; they pass
`with_clips: true` to remove a file still in use, and fail without
changing anything otherwise.
- File rows can be selected now (`edit.select {sources}`, kept in
`EditState::selected_sources`); with no ids, `clip.clear` acts on the
Clip List selection.
- Remove Warp and re-warping ignore a stored original whose file has been
cleared, so they never point a clip at a missing file.
* 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 window checks every playlist, including inactive takes, for missing audio, rate mismatches, empty buffers, and clips that extend past their source.
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>
- File › Export › Sibelius and File › Send To › Sibelius write MusicXML 4.0 (quantized,
chords, ties across bar lines, meter changes, treble or bass clef per part)
- File › Print Score engraves the MIDI tracks to a printable SVG page; File › Score Setup
sets title, composer, bars per system and track names
- File › Import › Clip Groups and Export Clip Groups (.scgrp with its audio)
- Edit › Paste Special › Merge Markers: copy carries the markers in the copied range
- The UI opens a path prompt for any command that needs a path or folder
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>