Skip to content

Buses#686

Merged
dpwe merged 10 commits into
mainfrom
buses
May 28, 2026
Merged

Buses#686
dpwe merged 10 commits into
mainfrom
buses

Conversation

@dpwe
Copy link
Copy Markdown
Collaborator

@dpwe dpwe commented Apr 18, 2026

Implements most of #114

This adds a new "bus" field to amy_event and struct synthinfo. amy_global now has an array of bus_state_t *bus[AMY_NUM_BUSES] each of which holds params (and pointers to private buffers) for EQ, reverb, chorus, and echo.

amy_render looks at the bus field of the "lead osc" for each note, and calls render_osc_wave with a pointer to the bus-specific buffer, thus collecting the output for each bus separately (we now have AMY_NUM_BUSES * AMY_MAX_CORES buffers).

amy_fill_buffer executes EQ, Chorus, Echo and Reverb separately for each active bus, then sums the results across buses, scaled by amy_global.volume[bus], before converting to the final output samples. So, volume=<bus0_level>,<bus1_level>,...'` is now a list.

Apart from converting all the global buffers for the FX into resources managed by a struct, the weirdest thing I had to do was to hijack the d->osc field in structure delta to hold the value of the bus (instead of the osc) for commands that are setting the params of a bus - otherwise, there's no way to combine both the parameter value with the bus to which it is meant to apply in a delta. So there's a big explicit conditional in amy_event_to_deltas_queue that treats all the EQ, echo, chorus, and reverb commands as a special-case. It's a bit clumsy, but not a bad solution. Maybe we should rename d->osc to be d->target since it's not always an osc now, but that's just to avoid misdirecting readers of the code.

This went so much more smoothly than I expected. One 4 hour session to move all the FX state into structures so they could be multiply-allocated, then another 4 hour session to actually implement the per-bus processing.

@dpwe dpwe mentioned this pull request May 26, 2026
@dpwe
Copy link
Copy Markdown
Collaborator Author

dpwe commented May 28, 2026

TESTED:

I reflashed AMYboard (with current tulipcc head) using this patch and everything seems OK. I tried directly manipulating buses to check it was working; after setting synth 2 to be a DX7 voice, I used the REPL (connecting via screen) to move it between bus 0 and bus 1, with reverb turned up for bus 0 but not bus 1, and verified that switching between buses caused the synth to render with and without reverb. I also tested that the multi-parameter volume command appropriately affected different buses differently:

>>> amy.send(bus=0, reverb=1)  # play notes (on MIDI channel 2), synth is on bus 0, hear reverb
>>> amy.send(synth=2, bus=1)  # play notes, synth is on bus 1 which has no reverb, hear no reverb
>>> amy.send(volume='5,1')  # Adjust volume of buses 0 and 1; synth is quieter
>>> amy.send(volume='1,5')  # Flip gains; synth is louder
>>> amy.send(volume='5,5')  # Make gains same
>>> amy.send(synth=2, bus=0)  # Move synth back to bus 0; still louder, now has reverb too.

@dpwe dpwe merged commit da6551d into main May 28, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant