Commit Graph
12 Commits
Author SHA1 Message Date
NetterSilverandClaude Haiku 5.5 0224ca1e24 Reject CLAP port layouts beyond host limits instead of truncating
Fixes #435

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 04:07:58 +02:00
Brandon Thomas b0daf3213e Merge main into #315 2026-10-13 06:08:18 -04:00
Brandon Thomas bae80849dd Merge main into #338 2026-10-13 05:51:51 -04:00
Brandon Thomas 056bc288c4 Merge main into #306 2026-10-13 05:31:14 -04:00
grovebit 312315acb9 Type to search as soon as a plugin or bus menu opens
Finding a plugin for an insert took three submenus (format, vendor,
name). The send and I/O bus menus had a search field, but it had to be
clicked before typing, and it kept the last search.

- The send and I/O bus menus take typing as soon as they open, as Pro
  Tools' path selectors do. The search starts empty each time; Up/Down
  move through the matches, Enter picks one, Escape closes the menu.
- Insert and instrument menus start with the same search field. Typing
  lists the plugins whose name or vendor matches: built-in ones first,
  then Audio Units and whichever of CLAP and VST3 have been scanned,
  with a Scan button for each of the others. Typing never starts a scan
  (`cached()` in the CLAP and VST3 hosts returns the last scan without
  scanning); opening a format's submenu still scans it.
- A click inside the insert and instrument menus no longer closes them,
  so the field can be clicked; picking still does, and errors from
  Bypass and "no insert" now reach the status line. The send bus menu
  is no longer 600 points wide.
- Insert, send, instrument and I/O slots in the Mix window get
  accessibility labels, which the tests use.
2026-10-12 20:21:55 +01:00
Limestudio90andClaude Opus 5.5 434c60047d clap-host: host embedded plugin editors on Windows
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>
2026-10-12 17:44:36 +02:00
grovebit 793432bbfc Read plugin state on the UI thread, not the audio thread
Saving, bouncing and the two-minute autosave read every third-party
plugin's state through the audio callback: a command made the callback
call each plugin's save_state between two blocks and reply, while the
UI waited for up to 2 s. So:
- CLAP's clap.state and VST3's getState ran on the audio thread,
  although both formats want them on the main thread.
- The callback allocated and waited on the plugins; a plugin with a
  large state (a sampler) could make the audio drop out on every save
  and autosave.
- Without a running callback (a stalled or lost device), every save
  waited 2 s and then kept stale plugin states.

Each instance now hands Side::prepare a state reader before it leaves
for the audio thread, the way it hands over its editor handle. CLAP's
GuiLink and VST3's EditorLink (which now holds the component as well)
read the state under their lock; Audio Units get a StateLink that does
the same. Each instance cuts its link off before it is destroyed, so a
reader never calls into a dead plugin. Player::capture_states reads
them on the calling (UI) thread, and the CaptureStates command is gone.

Each host's tests read the state while another thread processes the
instance, and get nothing once it is dropped. Playback reads states
with no audio thread at all.
2026-10-12 15:50:58 +01:00
grovebit acd9e7d54e Play MIDI controllers through instruments
Imported MIDI keeps its controller events: sustain pedal and other CCs,
pitch bend, channel and poly pressure, program changes. Playback sent
instruments only note-ons and note-offs, so a piano part lost its pedal
and bends went flat.

- Plugin::midi takes any other MIDI 1.0 channel message at a sample
  offset. The mix engine sends each clip's controllers at their sample,
  after the Real-Time Properties delay (and transpose, for poly
  pressure), on channel 1 like the notes.
- After a seek, a stop or a loop wrap, an instrument first gets Reset All
  Controllers (CC 121), then the last value each controller had on its
  track before the playhead. A pedal held before the start point is
  still down.
- CLAP: raw MIDI events when the note port speaks the MIDI dialect.
- VST3: CCs, aftertouch and pitch bend become parameter changes at their
  offset, through the plugin's IMidiMapping. It is asked once in prepare,
  on the main thread, and there is one point per parameter per block.
  Poly pressure is a PolyPressureEvent. Program changes have no VST3
  mapping and are dropped.
- AU: MusicDeviceMIDIEvent for instruments and music effects.
- The built-in synth follows the sustain pedal, pitch bend (2 semitones
  each way), Reset All Controllers and All Notes Off.
- The sampler ignores the pedal, pitch bend and Reset All Controllers
  for now.

The AU check of MIDI volume lives inside the existing DLS test. Creating
two DLSMusicDevice instances at once on two threads crashes inside the
unit, with or without this change. Two instances created one after
another render in parallel fine.
2026-10-12 02:57:22 +01:00
grovebit 33ad8264c8 Give plugins the session's tempo and transport
Hosted plugins never learned the session's tempo or where the song was:
- CLAP got a null transport;
- VST3 got a fixed 120 BPM 4/4 context that never played and counted
  processed samples as the song position;
- Audio Units had no host callbacks.
Tempo-synced delays, LFOs and arpeggiators ran at 120 BPM and ignored
the transport.

Before each block the mix engine now hands every insert, instrument and
master-fader plugin a soundcraft_dsp::Transport (Plugin::set_transport):
play and record state, tempo and meter at the block start, and the
timeline position in samples, seconds and quarter notes, with the
current bar. Built-in plugins ignore it.
- CLAP: a clap_event_transport (fixed-point beats and seconds, bar start
  and number, time signature, play and record flags).
- VST3: ProcessContext tempo, time signature, project time in samples and
  quarter notes, bar position, kPlaying and kRecording. Continuous time
  stays the processed-sample count.
- AU: kAudioUnitProperty_HostCallbacks (beat and tempo, musical time
  location, transport state 1 and 2), read from atomics the instance
  owns and frees after disposing the unit.

Loop (cycle) ranges aren't reported yet: playback keeps the loop range
to itself.
2026-10-12 02:56:55 +01:00
Brandon ThomasandClaude Opus 5.5 4410486fc2 Release 0.5.0: linux-riscv64 tarball, version bump (#165)
- 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>
2026-10-10 19:37:37 -04:00
Brandon ThomasandClaude Opus 5.5 cdefc57c91 Video track, Audio Unit hosting, plugin state and editors, Renderer and UI Customization
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>
2026-10-06 01:41:05 -04:00
Brandon ThomasandClaude Opus 5.5 2fc8e2ecb8 CLAP plugin hosting (isolated unsafe crate), stem bouncing
- 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>
2026-10-05 23:44:22 -04:00