Commit Graph
203 Commits
Author SHA1 Message Date
Brandon Thomas cf755b8cd2 Merge pull request #410 from Silvertree2010/fix/instrument-params-render
Engine: mix.instrument takes the instrument's parameters and refuses unknown fields (#265)
2026-10-13 06:53:58 -04:00
Brandon Thomas c2788c50d4 Merge pull request #415 from grovebit/tab-to-transient
Tab to Transient: every selected track, Alt+Tab back, Shift+Tab extends
2026-10-13 06:53:42 -04:00
Brandon ThomasandClaude Opus 5.5 b32d7bd926 Merge main into #410; put the mix.instrument note in the Instruments row's 'have' cell
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 06:45:33 -04:00
Brandon Thomas 00faedcbd0 Merge main into #334 2026-10-13 06:09:17 -04:00
Brandon Thomas 82eff0f561 Merge main into #219 2026-10-13 06:01:05 -04:00
Brandon Thomas e0deb3f4e5 Merge main into #335 2026-10-13 05:55:06 -04:00
Brandon Thomas 857882c740 Merge main into #332 2026-10-13 05:40:16 -04:00
Brandon Thomas 67f486d4c4 Merge main into #296 2026-10-13 05:34:50 -04:00
Brandon Thomas 056bc288c4 Merge main into #306 2026-10-13 05:31:14 -04:00
Brandon Thomas 468125aaf4 Merge main into #209 2026-10-13 05:27:22 -04:00
Brandon Thomas 3f3f64746f Merge main into #384 2026-10-13 05:21:33 -04:00
Brandon Thomas 2bba5c334d Merge main into #365 2026-10-13 05:17:58 -04:00
NetterSilver 1c2128ec37 Engine: mix.instrument takes the instrument's parameters and refuses unknown fields (#265)
mix.instrument only read `plugin` and `track` and ignored every other field, so a
synth setting written beside `plugin` (cutoff, amp_sustain, level…) came back
as success and the render never changed.

It now takes the built-in instrument's parameters in `params`, validated before
anything is changed (unknown ids and non-numbers are errors, values are
clamped into range), and refuses any other field with a message that points to
`params` and mix.instrument_param.
2026-10-13 11:17:57 +02:00
Brandon Thomas 5051b4a45f Merge main into #393 2026-10-13 05:12:31 -04:00
Brandon Thomas a47135b228 Merge main into #369 2026-10-13 05:08:26 -04:00
Brandon Thomas 0eee82a49c Merge main into #328 2026-10-13 04:59:30 -04:00
Brandon ThomasandClaude Opus 5.5 3cc0dc77cb Fix build after merging main into #368
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:56:26 -04:00
Brandon Thomas 46399aa729 Merge main into #368 2026-10-13 04:50:04 -04:00
Brandon Thomas 5495378d7a Merge pull request #309 from isaac-levine/mcp-automation-roots
MCP: confine file access with --automation-read-root and --automation-write-root
2026-10-13 04:43:44 -04:00
Brandon Thomas 9c7e5018b3 Merge pull request #333 from grovebit/strip-silence-long
Stop Strip Silence deleting clips late in long selections
2026-10-13 04:43:41 -04:00
Brandon Thomas 6c836b4389 Merge pull request #308 from grovebit/automation-overwrite
Automation passes replace the automation they play over, in one undo step
2026-10-13 04:43:21 -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 7347e98e79 Merge pull request #363 from grovebit/more-shortcuts
Pro Tools keys for nudging, Grid and Nudge values, playlists and windows
2026-10-13 04:42:25 -04:00
Brandon ThomasandClaude Opus 5.5 41c8561d51 Signal Generator refuses a selection longer than one render
It cut the new clip at MAX_RENDER_SAMPLES / channels without a word, after
allocating up to 2 GiB for it. Refuse such a selection up front, as #326
does for other renders, before anything is generated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:33:35 -04:00
Brandon Thomas bdff15defb Merge pull request #387 from itrycodinganditsbad/fix-250
Keep later meter changes on their bars when an earlier meter is edited
2026-10-13 04:32:53 -04:00
Brandon Thomas aa91e47073 Merge pull request #303 from marcoarnulfo/fix/restore-last-selection
Restore Last Selection brings back the previous selection
2026-10-13 04:32:49 -04:00
Brandon ThomasandClaude Opus 5.5 f4460e1ec7 Merge refs/pr/326 (refuse over-long renders) into fix328
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:31:59 -04:00
Brandon Thomas ba4c234344 Merge main into #387
# Conflicts:
#	crates/engine/src/cmd/event.rs
2026-10-13 04:30:17 -04:00
Brandon Thomas 0f6bd8a573 Merge main into #303
# Conflicts:
#	crates/engine/src/cmd/edit.rs
2026-10-13 04:30:17 -04:00
Brandon Thomas 52294bd4a3 Merge main into #291
# Conflicts:
#	crates/engine/src/cmd/event.rs
2026-10-13 04:30:17 -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 6bab8365e6 Merge pull request #289 from marcoarnulfo/fix/clear-trim-automation
fix(track): Clear Trim Automation removes the trim lane (#233)
2026-10-13 04:29:36 -04:00
Brandon Thomas cd1ddff0c0 Merge pull request #324 from iannitram/fix/gate-on-windows-and-rust-1.95
Make cargo xtask ci pass on Windows, and on Rust 1.95
2026-10-13 04:29:32 -04:00
Brandon Thomas e59f079a02 Merge pull request #342 from mroxso/t3code/76964692
fix(mix): mix.insert_params rejects unknown parameter names
2026-10-13 04:29:23 -04:00
Brandon Thomas b0339a418f Merge pull request #401 from Claudio911015/fix/273-clip-loop-unloop-consistency
Make clip.loop / clip.unloop self-consistent (loop_id tag)
2026-10-13 04:29:19 -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 ThomasandClaude Opus 5.5 dac86131ee Recovery repairs only take files in the folders recordings write to
recording.json names the take files whose headers recovery rewrites. Before
writing, check that each is a regular file (not a symlink) directly in the
Audio Files folder a recording of that session writes into (next to the
session file, or in its folder under the autosave root) and that it starts
with the float WAV header the recorder writes. Anything else is left
untouched, logged and listed with the media recovery couldn't load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:28:36 -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
Brandon Thomas 54254639cc Merge pull request #358 from sajibsrs/fix/282-new-midi-clip-menu
Add Clip › New MIDI Clip so an empty MIDI track can get a clip (#282)
2026-10-13 04:28:22 -04:00
Brandon Thomas 3c53d25413 Merge pull request #294 from marcoarnulfo/fix/feet-frames-reference
Apply the Feet+Frames reference to counters and typed positions
2026-10-13 04:27:47 -04:00
Brandon Thomas 3ef50746c8 Merge pull request #292 from marcoarnulfo/fix/trim-no-overlap
fix(edit): trims stop at the neighbouring clips instead of overlapping them (#228, #229)
2026-10-13 04:27:43 -04:00
Brandon Thomas 704ebc3c76 Merge pull request #288 from marcoarnulfo/fix/clip-gain-cut-clipboard
fix(edit): cut clip gain keeps the removed gain for paste (#230)
2026-10-13 04:27:37 -04:00
Brandon Thomas f58da8fe8a Merge pull request #284 from marcoarnulfo/fix/elastic-properties-ratio
fix(clip): Elastic Properties stretches the clip by the requested ratio (#227)
2026-10-13 04:27:14 -04:00
Brandon Thomas 99dbd4d628 Merge pull request #283 from marcoarnulfo/fix/marker-edit-name
fix(markers): markers.edit applies the documented name (#236)
2026-10-13 04:27:10 -04:00
Brandon ThomasandClaude Opus 5.5 165fa98a90 Count tracks, not lanes, in track.clear_trim_automation's result
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:21:20 -04:00
Claudio bee999584f Make clip.unloop recognise loops made by clip.loop, even after edits
clip.unloop found loop copies only by comparing content of back-to-back
clips. As soon as the source clip's notes were edited, its content no
longer matched the copies and unloop answered "the selection is not a
looped clip" for the very loop that clip.loop had just created.

clip.loop now tags the origin and its copies with a shared `loop_id`
(new optional Clip field, serde default so old sessions load), and
unloop treats equal-length adjacent clips with the same loop_id as one
loop. The content comparison stays as a fallback for loops without a
tag. unloop with mode=flatten clears the tag so the copies become
ordinary independent clips.

Propagating edits from the source to the copies is not part of this
change.
2026-10-12 23:54:33 -06:00
grovebit b9e4873ffa Tab to Transient: every selected track, Alt+Tab back, Shift+Tab extends
Tab found the next transient only on the first selected track, analysed
everything from the cursor to the end of the track on every press, and
Alt+Tab, Shift+Tab and Alt+Shift+Tab ignored Tab to Transient (Shift+Tab
did nothing at all). The toolbar button used the Selector tool's icon.

- A new command, edit.tab {back?, extend?}, does what the Tab keys do, as in
  Pro Tools: Tab and Alt+Tab (Option+Tab on a Mac, Ctrl+Tab on Windows and
  Linux) move the insertion point to the next or previous clip start, end or
  sync point on the selected tracks; Shift+Tab and Alt+Shift+Tab
  (Ctrl+Shift+Tab) extend the selection. Alt+Shift+Tab pulls the selection
  end back while a stop lies inside the selection, then grows its start.
- With Tab to Transient on, the stops also include the transients on every
  selected audio track and the note-ons and note-offs on MIDI and Instrument
  tracks. A transient within 10 ms of a clip boundary or note is that stop,
  not a second one.
- Transients are detected in fixed 10-second blocks of each clip, so Tab and
  Alt+Tab always find the same ones and a long clip costs one block per
  press. Analysed blocks are cached while their clips, clip effects and audio
  are unchanged: 0.5 ms a press across the demo's five audio tracks, 43 ms
  without the cache.
- The Tab to Transient button gets its own icon, an arrow into a transient.

Cmd+Alt+Tab still toggles Tab to Transient. On Windows and Linux the desktop
takes Ctrl+Alt+Tab, and Pro Tools' Ctrl+Alt+T is Thin Automation here too, so
the button and the Options menu are the way there.
2026-10-12 23:51:18 +01:00
grovebit 52e19a871a Keep the app responsive while bouncing
Bounce Mix rendered the whole file inside one UI frame: the window stopped
drawing and nothing could cancel the bounce until the file was written,
which takes minutes for long or plugin-heavy sessions.

- engine: io::Bounce renders a slice at a time (step) and reports its
  progress; dropping an unfinished one cancels it, removing the partial
  file and keeping any older one. cmd::bounce_job builds it from
  file.bounce_mix's params; the command and stems still run it to
  completion.
- ui: the Bounce dialog starts the job and logic() renders it for 30 ms
  per call (32 blocks in the browser, where Instant panics), requesting
  another call each time, so it carries on while the window is hidden
  (eframe then runs logic alone). A modal shows the file, a progress bar
  and Cancel (or Esc); the status line reports the result, and the Task
  Manager lists the running bounce.
- It stays on the UI thread because hosted plugins must be created there.
2026-10-12 23:47:00 +01:00
grovebit 5755795663 Stream bounces to disk instead of rendering them in memory
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.
2026-10-12 23:46:13 +01:00
grovebit 7f9b629964 Draw each take in the Edit window while it records
Pro Tools draws a take's waveform as it records; ours showed nothing
until Stop. Each record-enabled track now shows its take growing as a
red clip with its waveform, drawn from the take's live summary through
the same column grid and channel bands as clips (Peak view, as Pro Tools
always shows while recording).

- The take writer keeps, per take channel, the (min, max) of every 128
  frames it writes (at most 2^22 blocks, three hours at 48 kHz; the file
  records on regardless). Recorder::live_take hands the Edit window what
  a track's take holds so far, while the writer runs. The blocks sit
  behind a mutex the writer thread and the UI lock briefly; the input
  callback is untouched.
- io::live_span places the take as Stop will: from the record start,
  only the pass under way when loop recording, and within the punch
  range.

Tests: the take writer's summary (record.rs), live_span with loop and
punch (io.rs) and draw_live (tests/waveform.rs).
2026-10-12 23:43:58 +01:00