Thank you for the list, those are all excellent points, and for the kind words. Please indulge me a few comments/ideas for context/planning purposes
(hack: you could tie a GPIO to the BTN pin, leave it floating normally and pulse low/output and back to input to trigger pattern advancement)
I want to expose an API for that. I need to brainstorm some API concepts, open to ideas! The sequencers have the concept of play/pause/next, and playlists can be activated by index. Switching to a specific pattern requires the ID either directly or indirectly by scanning e.g. by name.
I think in many ways this API would be best served in global code/shared code with its own state, otherwise each pattern would need to use the API to make something that could implement programatic pattern control. Perhaps “custom sequencers” can be coded up that run much like a playlist does.
Alternatively, importing patterns and delegating to them through a coordinating main pattern could do much the same without actually switching which pattern PB was running at the time. e.g.:
import {render as render1, beforeRender as beforeRender1, sliderBar} from "awesome pattern"
import {render as render2, beforeRender as beforeRender2, sliderFoo} from "cool pattern"
export {sliderFoo} from "cool pattern" //re-export a slider
sliderAwesome(.5) //set a control from 'awesome pattern' programmatically
export function beforeRender(delta) {
beforeRender1(delta) // let 'awesome pattern' do it's thing
beforeRender2(delta) // let 'cool pattern' do it's thing
//set mode based on time, events, etc
mode == time(1) < .5 ? 1 : 2
}
export function render(index) {
if (mode == 1) {
render1(index) //we should run 'awesome pattern'
} else {
render2(index) //we should run 'cool pattern'
}
}
Sure, this is basically making you implement the sequencer and doesn’t interact with the UI sequencer stuff, but would give you a JS-like way of both code-reuse and compose/control patterns in any way you can imagine. Would allow code to implement sequencers, cross faders (with a little pixel composition support), segment mappers, libraries, etc.
I left the PI controller in pattern code since I wasn’t 100% sure it was the best, and wanted to allow for fixed gain since even the best AGC can cause problems if folks are using the line-in jack in a controlled environment.
If there is an auto-gain solution that is well-liked it could be added to PB (maybe a setting?), or even pushed down to the expander firmware.
There is no buffer (yet, but perhaps there could be). It was a core design goal of PB originally, mostly to allow lots of LEDs on APA102 without memory as things were tight on the ESP8266. The rendering architecture pipelines rendered pixels to a driver so that pixels can be rendered concurrently while sending data. I added an optional buffer for the WS2812 driver since the timing is tight on them, but the other LED types (and anything using output expanders) don’t buffer pixels on PB.
Obviously patterns are free to implement buffers in arrays, much as one would have to do when coding LEDs outside of PB. That said, I totally agree that a PB supported pixel buffer could make things easier + faster that arrays.
The intention here is to limit max brightness % in settings for power for a consistent appearance and static power management. Conversely, dynamic power management alters what appears on LEDs to stay within limits (often frame-by-frame before sending data to LEDs). I think both approaches have benefits/drawbacks and would ideally offer both options.
Implementation-wise since PB does not buffer the pixels, there is no way to limit total power draw dynamically in a holistic way - with only knowledge of power consumption from previously rendered and drawn pixels of the current frame, it would have to blank out future pixels once the power limit was reached. It would look very glitchy and so hasn’t been added yet.