Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 9 additions & 14 deletions TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ switches to that size, then audio comes back on its own. If it happens
once, there is nothing to do.

If it keeps happening, or audio plays too fast or too slow instead of
coming back (releases up to 2026.08.01.1 do this), clear the stuck buffer
coming back (releases up to 2026.08.04.1 do this), clear the stuck buffer
size and restart Live:

```bash
Expand All @@ -120,26 +120,21 @@ If you still have problems, try rebooting. If they come back after that,
run `./scripts/audio-report.sh` from a repository checkout and attach the
output to an issue.

## Live is slow and wineserver uses a full CPU core
## Live is slow and CPU use stays high

Without `/dev/ntsync`, every Windows synchronization wait becomes a
wineserver round trip: measured at about 45 percent of one core and 9,000
context switches per second with Live idle
([details](notes/ABLETON-WINE-NTSYNC-REGRESSION.md)). The launcher warns at
startup when the device is missing; `ls /dev/ntsync` checks by hand.

`ntsync` ships in Linux 6.14 and newer. On a 6.14+ kernel, load the module
and make the load permanent:
Live runs much slower without a Linux feature called ntsync. The launcher
warns at each startup while it is missing. Turn it on now and at every
boot:

```bash
sudo modprobe ntsync
echo ntsync | sudo tee /etc/modules-load.d/90-ableton-ntsync.conf
```

`setup-realtime.sh` installs the same drop-in. On kernels older than 6.14,
or built without `CONFIG_NTSYNC`, move to a distribution kernel that
provides the module. Relaunch Live to verify: the warning is gone. From a
repository checkout, `./scripts/check-ntsync.sh` runs the full probe.
Restart Live. The startup warning no longer appears.

If the first command reports that the module does not exist, move to a kernel
that provides ntsync (Linux 6.14 or newer) and run the commands again.

## Audio latency remains high

Expand Down
53 changes: 50 additions & 3 deletions notes/ABLETON-WINE-PIPEASIO-CRACKLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@ across every stream in the graph, which no buffer size corrects. The
`spa.alsa: hw:M2p: follower ... resync` line in #49 is that event. C8 governs
whether the follower copes.

*Corrected 2026-08-02: two devices in one graph are a supported
configuration and the resampling is silent when the follower has enough
buffer room. The crackle is C8's headroom shortfall, not the two-device
graph itself. See the status addendum below.*

### Working baseline

Taken on the build machine on 2026-07-26 with Live open:
Expand All @@ -158,7 +163,7 @@ pw-top: R 74 256 48000 alsa_input...analog-stereo (driver)
R 106 256 48000 = Ableton Live 12 Suite BUSY 270us B/Q 0.05
```

Note two things even here. The capture device drives the graph, which is C9
Even this baseline shows two things. The capture device drives the graph, which is C9
in its harmless form because both devices are the same card. And
`clock.quantum` reads 512 while the graph runs at 256, so the settings
metadata reports the configured default rather than the running quantum.
Expand Down Expand Up @@ -371,8 +376,50 @@ it was written 2026-07-26. State of the plan as of this addendum:
telemetry running throughout; clearing the pin left the graph stable at
the re-established node force. G1 is answered yes by the observed
rebuild: Live 12.4.3 services kAsioResetRequest while running. C1 is
closed. One instrumentation note: the driver's unix-side messages reach
closed. Instrumentation: the driver's unix-side messages reach
the session log with their own `[pipeasio]` prefix, and its wine TRACE
class did not surface even with `trace+asio`, so the G1 log line is
invisible in the field; the behavioural answer stands.
- Next per the Order section: F8. G2 through G4 stay open.
- F8 landed 2026-08-02 as pipeasio patch 0006, in the conservative reading
the risk table asks for. The node cache carries `device.id`, so the
driver can tell when two nodes share a card. The preference change is
confined to the fallback tier: only when the capture direction has no
usable default does the driver prefer a source on the playback card over
the first-discovered one, logging the choice when it diverges. A default
the user set is never overridden, because recording from a device the
user did not pick is a worse failure than resampling; when the two
directions resolve to different devices, the driver logs the pair once,
naming both nodes and the `input_device`/`output_device` keys (marker
`pipeasio-clock-domains`). Runtime verification needs a container
build. The seeded input-count question (whether the seed keeps
`inputs = 2`) stays open, decided separately per the risk table.
- C9 correction and fix, 2026-08-02: two devices only crackle when the
second device runs out of buffer room while PipeWire adjusts its pace
to match the first device's clock; with enough room the adjustment is
silent (C8). Pipeasio patch 0007 supplies the room. While Live runs on
two devices, the driver raises the second device's buffer room to 512
frames (the ALSA property `api.alsa.headroom`, applied live through
the node's Props parameter), logs the change, and puts the old value
back when the session ends, the devices change, or that device starts
setting the graph's timing itself. Single-device sessions are never
touched. One limit is inherent to the approach. The restore runs only
on the driver's normal paths, so if the process dies without a clean
exit (a crash or a kill), the added room stays on the device node
until PipeWire recreates it, and every client of that device keeps
the added latency meanwhile. A later session does not undo it
either: the driver probes the raised value, sees nothing to raise,
and never records the original. On PipeWire 1.5.85 the Props
enumeration yields multiple objects behind the audio adapter, and
all of them must be enumerated, otherwise `clock.name` stays empty
and the feature never engages. `PIPEASIO_FOLLOWER_HEADROOM` accepts
a frame count from 16 to 8192; smaller positive values rise to 16 and
larger values come down to 8192. `off`, `0`, a value below 1, or text
that is not a number turns this off. The live property path is verified
against PipeWire
1.6.8 on the build machine. Open: a listening run on a real rig (USB
microphone plus a separate USB interface, no crackle over a long
session), the oldest supported PipeWire (the driver does nothing when
the property is refused), and reporting the added room to Live as
latency, which recording alignment needs.
- Next per the Order section: the reply to #49, then the
three-distribution verification matrix. G2 through G4 stay open.
22 changes: 19 additions & 3 deletions notes/performance-moonshot/MOONSHOT-ROADMAP-TRACKER.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ entry.
| # | Item | Certainty | Invasiveness | Projected result | Chance | Status |
|---|---|---|---|---|---|---|
| P0 | Bench baselines + harness automation | certain | none | evidence floor for everything | high | in progress |
| P1 | Host `/dev/ntsync` launch gate | high | minimal | recovers a silently lost ~1 core / 4-50x sync on affected hosts | very high | in progress |
| P1 | Host `/dev/ntsync` launch gate | high | minimal | recovers a silently lost ~1 core / 4-50x sync on affected hosts | very high | done |
| P2 | Run the written scheduling A/B | n/a (measurement) | none | decides the RR default, quantifies the inversion | high | in progress |
| P3 | Audio hardening F0-F8 + PipeWire host arm | high | medium | fixes the audible defect classes (issue 49, crackle, recording offsets) | high | in progress |
| P4 | Thread-priority chain (avrt de-stub, server RT band, retire whole-process RR, RTKit) | high problem / medium gain | high | audio outranks UI per thread; biggest dropout-margin lever at 64-128 frames | medium-high | not started |
Expand Down Expand Up @@ -67,8 +67,24 @@ entry.
with PIPEASIO_ALLOW_QUANTUM_MISMATCH=on as the escape hatch, and port
buffers sized to the quantum limit; verified in production the same day
(pre-launch pin 384 predicted cleanly, mid-run pin 768 converged with
one mute episode; G1 answered yes). Next: F8. Driver patches need a
container build to ship.
one mute episode; G1 answered yes). F8 landed 2026-08-02 as pipeasio
patches 0006 and 0007. 0006: device.id cache, fallback capture
anchored to the playback card, user choices never overridden, neutral
two-device log line. 0007: while Live runs on two devices, the driver
gives the device that is not setting the graph's timing 512 frames of
buffer room (`api.alsa.headroom`, applied live) so PipeWire's pace
matching stays silent, and restores the old value afterwards;
`PIPEASIO_FOLLOWER_HEADROOM` adjusts or disables it; single-device
sessions are untouched. Verified: the live property path on PipeWire
1.6.8. Open: the two-device listening run (USB microphone plus a
separate USB interface, no crackle over a long session), reporting
the added room to Live as latency, the container build that carries
the driver stack, and the seeded input-count question. Next: the
issue 49 reply, the latency reporting, then the three-distribution
verification matrix before any release carries these patches.
- P1 shipped 2026-08-02 (commit 96b043f, in the production launcher): the
warning branches are verified against faked kernels; a run on a host
that really lacks `/dev/ntsync` is the one open check.
- Wine patches from moonshot items land in `patches/performance/`;
apply-order wiring in `container-build.sh` and build-audit fingerprint
entries land with the first such patch. P1 produced no patch (launcher,
Expand Down
Loading