Commit Graph
20 Commits
Author SHA1 Message Date
Brandon Thomas 46399aa729 Merge main into #368 2026-10-13 04:50:04 -04:00
Brandon Thomas b764e299bc Merge pull request #326 from grovebit/long-renders
Refuse renders too long to finish instead of cutting the audio short
2026-10-13 04:42:56 -04:00
Brandon Thomas 6dfa00590b Merge pull request #304 from marcoarnulfo/fix/midi-track-offsets
Apply MIDI track offsets when scheduling notes
2026-10-13 04:29:40 -04:00
Brandon Thomas a307f767ba Merge pull request #212 from itrycodinganditsbad/consolidate-selection
Consolidate covers the whole edit selection (#164)
2026-10-13 04:28:45 -04:00
Brandon Thomas a89c0c4db5 Merge pull request #379 from webdevtodayjason/trim-to-selection-order
Keep clips in order after Trim to Selection
2026-10-13 04:28:26 -04:00
grovebit 62cb92c4df Never replace or quit a session while it records
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.
2026-10-12 23:33:48 +01:00
webdevtodayjason 950f3e7085 Keep clips in order after Trim to Selection 2026-10-12 16:09:01 -05:00
grovebit 3a702d9c6f Refuse renders too long to finish instead of cutting the audio short
One offline render holds MAX_RENDER_SAMPLES samples, about 93 minutes
of stereo at 48 kHz, and the offline time stretch, pitch shift and
resample stop at MAX_OFFLINE_SAMPLES frames. Longer audio was cut short
without a word: Render Clip Gain and Clip Effects Render left the end
of the clip silent, every AudioSuite process shortened the clip, the
track Commit made fell silent at the limit, and Export Clips wrote
shortened files. Above 74 kHz an hour no longer fits, so TCE, Elastic
Properties and Remove Pitch Shift padded the cut end with silence.

Each now checks the length before it renders and refuses with the
limit in seconds, as Consolidate does in #212. AudioSuite counts what
Time Stretch, Pitch Shift and Varispeed make, so a fourfold stretch is
refused at a quarter of the limit. Export Clips checks every clip
before it writes a file.
2026-10-12 17:35:33 +01:00
Marco Arnulfo 4bacfb13d5 Apply MIDI track offsets when scheduling notes (fixes #234)
event.midi_track_offsets stored midi.offset.<track> but the note
scheduler never read it, so the render was unchanged. schedule_notes
now looks that many samples back into the clips, which plays the track
exactly as if its MIDI had been moved by the offset. The scheduler is
shared by offline bounce and realtime playback.
2026-10-12 16:48:50 +02:00
Marco Arnulfo 5e7ca6de22 Apply the Feet+Frames reference to counters and typed positions (fixes #235)
Setup > Current Feet+Frames Position stored its origin in
feet_frames.start but nothing read it, so every Feet+Frames reading
still counted from sample 0. format_position/parse_position now take
the origin alongside the timecode start, and Session::format_position
and Session::parse_position pass both, so the counters, rulers,
session.format_time and typed positions share one reference.
2026-10-12 16:36:18 +02:00
Fabio LussiandClaude Opus 5.5 092b3cc890 Consolidate covers the whole edit selection
Consolidate clamped its range to the track's last clip end plus one
second, so on an empty track a 0-5 s selection made a 1 s clip and a
2-7 s selection made nothing. It now renders, clears and places exactly
the selection, and refuses a selection too long to render instead of
placing a shorter clip. Prepare DPE keeps the old per-track bound.

Fixes #164

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:02:56 +02:00
grovebit 992f60c79c Trackpad-friendly Edit window: smooth panning, pinch and Cmd+scroll zoom
- Pinch and Cmd+scroll zoom the timeline around the pointer. egui 0.36 turns
  both into zoom_delta, so the old Cmd+scroll branch never ran; Shift+wheel
  pans sideways again for the same reason.
- Two-finger panning keeps the sub-sample remainder, so slow motion still
  moves at the closest zoom; the scrollbar drag pans the same way (its range
  now takes in the view, so the thumb stays in the bar), and the rulers pan
  too. Panning stays open-ended to the right, as before.
- A swipe keeps to the axis it starts along, so panning doesn't drift between
  tracks and scrolling doesn't drift in time. The larger share of its first
  6 points decides until egui reports the scroll over: the fingers lift, or
  150 ms pass without wheel events.
- The MIDI editor scrolls by the point instead of rounding each frame's delta
  to whole rows (slow swipes did nothing), and its range fits the panel
  (pitch 0 could not be reached; a taller panel showed blank rows).
- Zoom and scroll write through `Engine::zoom_mut` (`view` commands): no
  playback resync (a session copy sent to the audio thread every frame), no
  copy of the whole session per frame, no journal entry per frame, and no
  end to an undo gesture (scrolling during an automation pass made each
  write its own undo step). New `view.zoom_by {factor, x?}`;
  `view.scroll` saturates; Fill Window and Zoom to Selection stay within the
  zoom range (zooming out after them on a long session zoomed in).
- Control channel: `ui.scroll` (trackpad swipe or wheel notches) and
  `ui.zoom` (pinch); `session.inspect` reports zoom.
2026-10-11 15:21:46 +01:00
reoniazx 0734281104 Stop playback when replacing the session 2026-10-10 12:44:01 +08: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 cc86842abe Surround mixing, VST3 hosting, and hardening against hostile inputs
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>
2026-10-06 00:39:59 -04:00
Brandon ThomasandClaude Opus 5.5 8269ca77f6 Property test: every command survives hostile parameters
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 00:15:26 -04:00
Brandon ThomasandClaude Opus 5.5 222273590e Property test: mutated session files load or fail cleanly and render without panicking
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 00:13:37 -04:00
Brandon ThomasandClaude Opus 5.5 7f9f9fff08 Random-edit property test covers the extended command set (400-case run clean)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 00:12:40 -04:00
Brandon ThomasandClaude Opus 5.5 daca626778 Fix fades outliving trimmed clips; property test of random edit sequences with full undo
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 00:10:53 -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