Phase 6: Add WAV clips, graph playback and bounded recording
This commit is contained in:
parent
65640c4aad
commit
8a37090b81
40 changed files with 1450 additions and 69 deletions
109
docs/AUDIO_FILES.md
Normal file
109
docs/AUDIO_FILES.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
# Audio clips and recording (Phase 6)
|
||||
|
||||
## Import and playback
|
||||
|
||||
File/Import WAV (Ctrl+I) loads a WAV into the selected track at the playhead.
|
||||
With no selected track it creates an Audio track. Add region still creates a
|
||||
silent placeholder. Imported clips use the existing move/trim controls.
|
||||
Import stops playback, validates a candidate project, and commits only after
|
||||
successful backend preparation (or locally when disconnected).
|
||||
|
||||
Supported input: little-endian RIFF/WAVE, PCM16/24/32 and IEEE float32, one or
|
||||
two channels, 1..768000 Hz. Stereo is averaged to mono. Compressed WAV, RF64,
|
||||
WAVE_FORMAT_EXTENSIBLE, PCM8, other containers and multichannel files are
|
||||
unsupported. Nonfinite float data and malformed/truncated files are rejected.
|
||||
There is no new dependency: the bounded C decoder/writer is covered by known
|
||||
sample, truncation and invalid-codec tests. See decision 0005.
|
||||
|
||||
Audio is preloaded before playback: maximum 64 distinct paths per plan,
|
||||
16777216 mono frames per asset (64 MiB), 67108864 total frames (256 MiB).
|
||||
Import rejects files over 256 MiB or over 4096 chunks. No streaming decoder,
|
||||
waveform cache, peak drawing or background load worker exists yet. Preloading
|
||||
can briefly block the GUI. Candidate compilation retains the old plan until
|
||||
success; temporary build memory can include both old and candidate buffers.
|
||||
|
||||
The callback renders only overlapping clip ranges from memory. Clips on all
|
||||
tracks are summed at unity gain into the graph's **Audio clips** source node.
|
||||
Import creates that source and connects it to an existing/new output if no
|
||||
audio source exists. Subsequent routing is explicit: disconnect it or route it
|
||||
through gain/meter nodes in Modular Graph. Removing the output silences editor
|
||||
graphs. This source does not monitor JACK input; unconnected ordinary graph
|
||||
inputs retain their earlier external-input behavior. Track faders/pan/mute
|
||||
and individual track routing belong to the mixer phase.
|
||||
|
||||
Linear interpolation converts source sample rate to backend rate. There is no
|
||||
antialiasing filter, time stretching, looping or fades. Musical durations round
|
||||
up to a tick on import; playback boundaries and trims use floor tick-to-sample
|
||||
conversion. A rounded tail pads with silence past the source, and a recording's
|
||||
placement can differ by less than one tick from the capture start sample.
|
||||
Changing tempo changes the musical span, not the source playback rate.
|
||||
|
||||
Arrange edits stop playback. Play preloads and adopts the current arrangement;
|
||||
Stop pauses the sample clock. Graph-only edits can still be submitted during
|
||||
playback. Graph recompilation can reset oscillator phase as before. Playback
|
||||
does not stop automatically at the arrangement end.
|
||||
|
||||
## Assets and recovery
|
||||
|
||||
Version 2 projects store external absolute canonical paths, not sample data.
|
||||
Save the project AND keep its referenced WAV files. Save As changes only the
|
||||
metadata path; it does not copy assets. Moving/deleting a WAV makes its regions
|
||||
silent, preserves their IDs/positions and reports the path and unique issue
|
||||
count on Open/Play. An already loaded plan keeps playing even if its file is
|
||||
removed; the next preparation detects it. Unreadable, malformed and unsupported
|
||||
assets are also reported, rather than substituted with unrelated files.
|
||||
Capacity/OOM is a preparation failure and retains the old plans.
|
||||
|
||||
Select the affected clip, then File/Relink selected audio to choose a replacement.
|
||||
Relinking retains its original timeline/source bounds. The replacement is
|
||||
validated on the next Play; a shorter replacement pads beyond its end with
|
||||
silence. Saving retains unresolved references for later repair. Missing assets
|
||||
are also checked on Open without a working backend, using a temporary plan.
|
||||
Automatic asset search, content hashes and portable project bundles are deferred.
|
||||
|
||||
## Recording
|
||||
|
||||
Record (or Audio/Record WAV, Shift+F5) opens a destination chooser, stops playback,
|
||||
prepares the project, opens a temporary mono float32 WAV and starts JACK.
|
||||
Connect a source to xtc's JACK input using an external patchbay; no physical or
|
||||
software route is created automatically. Without a route the take contains
|
||||
silence. Recording captures raw mono JACK input, not the output/effect mix.
|
||||
|
||||
A preallocated two-second SPSC ring transfers complete callback blocks to the
|
||||
GUI/control thread, which drains it every 100 ms. The producer uses verified
|
||||
lock-free atomics and bounded copies only. It never allocates, logs, takes a
|
||||
mutex, opens/writes files or calls FLTK. A slow disk/blocked GUI can overflow
|
||||
the ring; capture then stops accepting input with a sticky, visible capacity
|
||||
error rather than hiding gaps or compressing time.
|
||||
|
||||
Stop first synchronizes the callback, detaches the recorder, drains remaining
|
||||
samples, writes the final WAV header, flushes/fsyncs/closes and renames the
|
||||
same-directory temporary over the destination. A successful nonempty take is
|
||||
imported at its capture position on the selected track (or a new Recording
|
||||
track), then the document becomes unsaved. Save the project after Stop. Seeking
|
||||
back to the take and pressing Play auditions it. Recording continues existing
|
||||
arrangement playback, but there is no automatic input monitoring, punch, loop,
|
||||
latency compensation, multitrack arming or overdub alignment compensation.
|
||||
|
||||
Graph/arrangement edits, project file actions, reconnect and close are blocked
|
||||
until Stop finishes the take. Deactivation failure retains the recorder for a
|
||||
safe retry. On overflow a finalized partial WAV is retained for manual recovery
|
||||
and is not automatically added. On import/preparation failure the completed
|
||||
take remains at its chosen path with an explicit recovery message. I/O errors
|
||||
are reported; an unfinished temporary is removed on destruction. Recordings
|
||||
are RIFF-limited to 1073741814 frames, but the smaller playback/import asset
|
||||
limit still applies: longer takes may need external splitting before import.
|
||||
There is no crash-recovery journal. The file is mode 0600; parent-directory
|
||||
fsync and preservation of previous permissions are not implemented.
|
||||
|
||||
## Verification
|
||||
|
||||
make test includes deterministic WAV/graph samples, resampling/overlap/trim,
|
||||
malformed inputs, missing/relinked assets, SPSC concurrency/overflow/cleanup,
|
||||
and record -> save/reopen -> exact playback through the backend callback.
|
||||
make test-gui covers the workflow and rollback with a fake backend.
|
||||
make test-gui-jack records/reopens a silent take using real JACK callbacks.
|
||||
make test-jack-audio routes only two software clients: known source -> recorded
|
||||
WAV -> saved/reopened project -> graph playback -> capture assertion.
|
||||
Physical input/output, device latency, slow-disk endurance and server loss
|
||||
during a real recording remain unverified.
|
||||
Loading…
Add table
Add a link
Reference in a new issue