Docs file normalization.

This commit is contained in:
Johannes Findeisen 2026-11-06 15:20:20 +01:00
commit 619c2d0808
46 changed files with 3587 additions and 2579 deletions

View file

@ -1,12 +1,12 @@
# Audio clips and recording
# Audio Clips and Recording
## Import and playback
## 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).
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,
@ -15,23 +15,22 @@ 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.
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 through their mix/automation settings 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
are implemented by the track mixer (see MIXER.md); individual
track graph routing remains deferred.
tracks are summed through their mix/automation settings 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 are implemented by the track mixer (see MIXER.md);
individual track graph routing remains deferred.
Linear interpolation converts source sample rate to backend rate. There is no
antialiasing filter, time stretching, looping or fades. Musical durations round
@ -45,7 +44,9 @@ 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
---
## 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
@ -56,20 +57,24 @@ 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.
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.
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
@ -80,53 +85,59 @@ 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 using an atomic no-clobber link; an existing destination is refused. 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.
same-directory temporary using an atomic no-clobber link; an existing
destination is refused. 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; failed temporary data is retained and its recovery path is reported. 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.
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; failed temporary data is retained and its recovery path is reported.
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.
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.
## Recording protection
---
## Recording Protection
The default recorder and GUI require a new destination, including rejecting
symlinks. Publication also refuses files created during recording. The explicit
`xtc_recorder_create_replace` API retains authorized replacement for callers
that deliberately need it; the GUI never uses it. After a failed finish, copy
`xtc_recorder_recovery_path` before destruction. Disk-write/finalization failures
retain the temporary. Destruction after producer quiescence attempts to drain
and finalize accepted data; normal code should call finish and inspect errors.
The GUI refuses closure while recording and prints the retained/finalized path
on exceptional destruction.
`xtc_recorder_recovery_path` before destruction. Disk-write/finalization
failures retain the temporary. Destruction after producer quiescence attempts to
drain and finalize accepted data; normal code should call finish and inspect
errors. The GUI refuses closure while recording and prints the
retained/finalized path on exceptional destruction.
Use `xtc-check --recover-recording TEMP NEW.wav` to copy complete float32 frames
from an interrupted xtc WAV into a new WAV. Source and existing destinations are
never modified. A trailing partial frame is ignored. This handles xtc's canonical
44-byte mono float32 header only, not arbitrary damaged WAVs. Recovery is explicit
and control-thread only; no orphan scan runs during playback.
never modified. A trailing partial frame is ignored. This handles xtc's
canonical 44-byte mono float32 header only, not arbitrary damaged WAVs. Recovery
is explicit and control-thread only; no orphan scan runs during playback.
`make test-recording` simulates 30 minutes at 8 kHz with repeated ring wrapping
and draining, destination races/symlinks, a child-local disk-size limit, prefix
@ -138,20 +149,22 @@ player still limits each asset to 16M frames. Longer valid takes may require
external splitting before import. No directory fsync/power-loss guarantee is
claimed. WAV destinations are chosen explicitly by the user.
## Non-destructive clip editing
---
## Non-Destructive Clip Editing
Move clips by dragging their body; drag the left/right edge to trim within the
existing source length. Ctrl+D duplicates adjacent to the selected clip. Delete
removes the reference. With an audio clip selected, click the ruler while stopped
to position the cursor strictly inside it, then choose **Edit / Split audio at
cursor**, press S with timeline focus, or use the clip context menu. The right
piece becomes selected. The four-pixel minimum draw width is also selectable for
very short clips; zoom in for precise edge gestures.
removes the reference. With an audio clip selected, click the ruler while
stopped to position the cursor strictly inside it, then choose **Edit / Split
audio at cursor**, press S with timeline focus, or use the clip context menu.
The right piece becomes selected. The four-pixel minimum draw width is also
selectable for very short clips; zoom in for precise edge gestures.
**Edit / Audio clip gain and fades** (A with timeline focus, also in the context
menu) takes three numbers: linear gain 0..4, fade-in ticks, fade-out ticks.
Defaults are `1 0 0`; 0 fade disables that explicit fade. Each duration can be up
to the original source length, even after trimming; overlapping long fades
Defaults are `1 0 0`; 0 fade disables that explicit fade. Each duration can be
up to the original source length, even after trimming; overlapping long fades
attenuate a short clip without extending it. MIDI clips reject these operations;
silent metadata regions support them for later audio relinking.
@ -165,9 +178,9 @@ No destructive audio processing or file deletion command is supplied.
A split retains the original source length/path/name/gain on both pieces. Its
right offset advances by the left length, keeping trims reversible within the
same source. Left keeps its ID and fade-in; right gets a fresh ID and fade-out.
Inner explicit fades are cleared. Gain/fades are retained on duplication.
Moving does not alter offsets; trimming changes only timeline/source bounds and
makes explicit fades follow the new audible boundaries.
Inner explicit fades are cleared. Gain/fades are retained on duplication. Moving
does not alter offsets; trimming changes only timeline/source bounds and makes
explicit fades follow the new audible boundaries.
The renderer maps tick boundaries by the existing absolute floor conversion,
linearly resamples the source and never reads beyond its samples. Its audible
@ -177,27 +190,27 @@ length up to a tick). A fade uses `age / fade_in_frames` at the start and
use the smaller value. The first/last audible samples are zero when their
respective fade has a positive sample duration. Durations rounding to zero
samples are disabled. A one-sample clip with any active fade is silent. Explicit
fade gain multiplies the existing optional safety envelope, then clip gain,
then track gain/pan/automation. No limiter is added; gains/overlaps may clip.
fade gain multiplies the existing optional safety envelope, then clip gain, then
track gain/pan/automation. No limiter is added; gains/overlaps may clip.
The GUI retains its 5 ms boundary safety fades, including new split edges, so
cuts can introduce a brief dip rather than an abrupt discontinuity. The raw C
plan still defaults to zero safety fade for exact-sample/offline consumers;
callers requesting raw cuts accept possible clicks. Tick quantization can place
an edit up to one output sample away from a separately rounded boundary; this
is not sample-resolution audio editing. Manual listening remains pending.
an edit up to one output sample away from a separately rounded boundary; this is
not sample-resolution audio editing. Manual listening remains pending.
Time-stretching, independent pitch shifting and crossfade tools are future work;
no suitable algorithm/quality target or new dependency has been selected.
### Cached waveform display
Timeline audio clips show mono min/max peaks from an immutable C summary,
shared by reference path across split/duplicated clips. Up to 64 paths each
cache at most 1024 bins (fewer for short files). It uses playback's WAV parser,
downmix and file/frame bounds; creation temporarily loads one WAV then frees
its sample storage. Bins cover every source sample, including a final partial
bin. The display follows source offsets and current tempo; it shows **raw source
peaks before clip/track gain and fades**, clamped visually to +/-1. It is an
Timeline audio clips show mono min/max peaks from an immutable C summary, shared
by reference path across split/duplicated clips. Up to 64 paths each cache at
most 1024 bins (fewer for short files). It uses playback's WAV parser, downmix
and file/frame bounds; creation temporarily loads one WAV then frees its sample
storage. Bins cover every source sample, including a final partial bin. The
display follows source offsets and current tempo; it shows **raw source peaks
before clip/track gain and fades**, clamped visually to +/-1. It is an
arrangement aid, not a sample editor or loudness meter.
Loading/rebuilding is synchronous on the GUI/control thread during project
@ -219,4 +232,5 @@ cover short-clip selection, shared previews, split/duplicate/delete and undo.
The modal audio source editor also provides frame selection, reversible
processing, selection export, copy adoption and transient slicing. See
[AUDIO_EDITOR.md](AUDIO_EDITOR.md) for commands, undo behavior and mono/size limits.
[AUDIO_EDITOR.md](AUDIO_EDITOR.md) for commands, undo behavior and mono/size
limits.