Skip to content

Octatrack base: effect changes refused with NEEDS A BUFFER on a full core, and noise on Part switches #998

Open

Description

@repeat98

What a beta tester saw (USB beta base 5273cecd, 27 Oct 2026)

  • FX changes refused. Scrolling T1 FX1 from LOFI2 toward NONE showed MEMORY FULL T1 FX1 · FILTER NEEDS A BUFFER · FX1 BUFFERS T1-4 0/4, and the slot stayed on its effect. With effects that need delay buffers on all of T1–T4, the tester could not change FX1 to match two Parts.
  • Noise on Part switches. Patterns on different Parts with different effects gave short white-noise bursts when switching patterns. With the effects matched across the Parts, so no effect changes at the switch, there was no noise, and the DSP/MEMORY FULL warnings stopped too.
  • Ruled out:
    • the frame guard: the noise stayed after FM Synth was removed from the set;
    • the TSTR analysis gate (6e5c9af): no noise with matched effects and mismatched TSTR.

Likely cause (from reading the code; not yet run on a unit)

dl_buffers_prepare in sdk/octabam/platform/dsp-dynload-transport/buffers.c, unchanged since it was added:

  1. The swap needs a second block. When a slot changes to an effect that reads a Y buffer, the new effect must get a free block. The slot's own block stays in used, held by the outgoing effect until dl_buffers_retire. Each core has 4 blocks per kind (FX1 0x1000/0x1c00/0x2800/0x3400). So once all four slots of a kind on a core run buffer-reading effects, every change on that core to another buffer-reading effect returns DL_BUF_MEMORY. Stock gives each slot a fixed block and the new effect reuses it.
  2. Blocks move between effects and are never cleared. When a change does succeed, the new effect gets a block another slot's effect used, or one nothing has written since power-on. Nothing clears a block when it changes hands. An effect whose init does not clear its buffer would then play those leftovers, which fits the noise heard.
  3. FILTER may be wrongly marked as needing a buffer. FILTER (stock id 4, the default FX1) is reported that way. reads_buffer in dsp_loader.py also returns 1 when the init reaches no rts, which FILTER's init, running into its shared library, may hit. If so, every default FILTER holds a block and fills the core sooner.
  4. Refused picks may drop NONE. While scrolling toward NONE, refused effects along the way seem to leave the slot on its old effect. Check whether the queued final pick is dropped after a refusal (the later queue edits to manager.c in build_core.py).

Proposed fix

  1. Reuse the slot's own block. In the second loop of dl_buffers_prepare, a slot whose new effect reads a buffer takes its own live block first, as stock does. It searches for a free block only when it has none. The switch frame runs the outgoing effect's sub-block before the incoming init, so sharing the block is sequential, as on stock. Only a rollback after the new init could be audible.
  2. Check FILTER's flag. Compare FILTER's buffer flag with its init, and set it to 0 if the init never reads X:$213.
  3. Consider zeroing a block when its owner changes.

Apply the changes as build_core.py edits, like the existing manager.c and allocator.c ones. Add a host test: on a full core, changing one buffer-reading effect to another is admitted on the slot's own block.

To reproduce on a unit

  • Refusal: put buffer-reading FX1 effects on T1–T4 (the default FILTER may already count), set T1 FX1 to LOFI2 or CHORUS, then change T1 FX1. Expected today: refused.
  • Noise: use two Parts with different buffer-reading FX1/FX2 on T1–T4 and a pattern on each. Record MAIN while switching patterns: noise bursts. Then match the effects: clean.

Possibly related: #994 (Tape Echo blast when changing pattern).

Activity

  1. repeat98 commented on Oct 29, 2026

    @repeat98
    OwnerAuthor

    Part of this is fixed in the beta base since 28 Oct (#1017, now 9b7e0eb3): a slot whose effect changes keeps its own buffer block, as stock does, so changing one buffer-reading effect for another on a full core is no longer refused, on FX1 as well as FX2. A remaining refusal now reads NO ROOM / the effect / FX2 ON T1-4 FULL / CHANGE ONE FIRST.

    Still open: whether the Part-switch noise is gone too (blocks no longer change hands on a swap, but nothing clears a block yet), FILTER's buffer flag (point 3) and whether a refused pick drops the final NONE (point 4). Next: the reproduction steps above on a unit with the new base.

  2. repeat98 commented on Nov 10, 2026

    @repeat98
    OwnerAuthor

    Reproduced on a unit, 10 November 2026 (MKII, development twin of #1389's base with five effect modules installed, main output recorded over USB while switching Parts during play).

    Setup. Part 1: CHORUS on T1-T4 FX1, DELAY on FX2. Part 2: LOFI2 on T1-T4 FX1, Tape Echo on T1 FX2, PLATE REV on T2-T4 FX2. The first core is full there: BBD Delay, Mini Verb and E-Verb were refused on it with DSP FULL (105 %). Six Part switches a take, 2.5 s apart.

    Result.

    • Stock effects only (CHORUS against FLANGER, DELAY against PLATE REV, and a control with both Parts the same): 3 takes, 18 switches, clean.
    • With the module effects on Part 2: in 4 of 6 takes one audio frame at full scale on both main channels (16 samples, once 10), about 0.1 s after a switch to Part 2. It is a loud click, not a longer burst. In 3 of those 4 the switch itself took 1.9 s instead of 0.3 s.
    • During the same takes the DSP stalled once (stall record 40: frames stopped with a selection in flight on the full core, 77 selections requested, 74 completed, 3 refused). A RAM boot did not bring it back; a power cycle did.

    Not done yet. Which effect makes the frame (LOFI2 alone, Tape Echo alone), whether it comes with the long switch or without it, and whether the stall is the same event as findings 74 and 79. No fix yet; points 3 and 4 of the issue are untested.

    The takes and the analysis scripts are on the owner's computer (take998.sh, clip998.py).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions