Skip to content

Fold render_component and harness.py into one renderer core, with seams that keep a musician-facing tool possible #17

Description

@bdbarnett

Decision recorded, not scheduled. Brad: "build the core so that the product is possible later. We don't have to do it now, but we don't paint ourselves into a corner and build something that can't be built upon."

The duplication

Two scripts do the same three things — drive something that emits audio blocks, deliver timed events into it, stream the result to a WAV with a digest:

  • audiocomponents/tools/render_component.py — targets audioinstruments components by name; modes oneshots, kit, phrase, transitions. Runs under CPython and MicroPython, and is careful about memory because a whole render in RAM is a MemoryError on a board.
  • micropython-vst3/tools/harness.py — targets micropython-vst3 scripts through the vstaudio shim on the audioif CPython wheel. CPython only.

They differ only in what they drive. Every number the accuracy program has produced came from the first one.

The three seams, and what "not painting into a corner" means for each

Source. The core must not import audioinstruments. A source is anything that yields blocks — an audioinstruments component, a vst3 script, an effects chain — plugged in from outside. If the core knows about instruments, a MIDI-file front end or an effects-only render needs the core changed to exist.

Timeline — the one that actually decides whether the product is possible. Events must be data, not closures. render_component currently schedules lambda: inst.note_on(36, 100). A closure cannot be parsed from a MIDI file, serialised, inspected, diffed, or generated by a DAW export. Declarative records (time, kind, args) can be all of those, and executing them is trivial. This is the difference between a harness and something a musician could ever drive.

The timeline is also where note-offs, macro moves and program changes get modelled properly rather than being a list of note-ons — see #16.

Sink. Streaming, so length is not bounded by RAM, and the digest separable from the file so tests and users want the same code path.

Constraints to carry

  • MicroPython compatibility is not optional. render_component has it and harness.py does not; folding toward the latter's shape loses the ability to render on a board and breaks the cross-interpreter parity work, which is how the audioif envelope bug was found.
  • Dependency direction: the core depends on audioif's audiocore/synthio only. audiocomponents and micropython-vst3 consume it.
  • Blast radius: render_component is used by the tests, measure_hits, shared_circuits, the overlap gate and every listening capture. Changing its interface is not free.

What this is NOT, today

Not a musician-facing product. That would additionally need MIDI-file input, patches addressable by name, and CLI/docs/packaging — the fluidsynth -F out.wav font.sf2 in.mid shape, which is the obvious precedent. Deliberately deferred. The point of the seams above is that adding a MIDI-file source later is another source, not a rewrite.

Related

Activity

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

    parkedParked by ruling, with a named trigger

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions