fix(cava): identical init re-uses the live plan

cava_init/destroy churn leaks the old plan's FFTW work buffers —
upstream frees only its own struct. init() now serializes the config
and no-ops when unchanged, so pipeline restarts (focus/episode churn)
keep the live plan instead of leaking a new one each cycle.
This commit is contained in:
2026-09-06 18:46:42 -04:00
parent 9e2f232d27
commit 09d5732b55
2 changed files with 73 additions and 3 deletions

View File

@@ -95,6 +95,8 @@ export class CavaCore {
private _bars = 0;
private _channels = 1;
private _destroyed = false;
/** Serialized last init config — identical init() calls are no-ops. */
private lastConfigKey = "";
/** Use loadCavaCore() instead of constructing directly. */
constructor(lib: CavaLib) {
@@ -112,15 +114,25 @@ export class CavaCore {
/**
* Initialize the cavacore engine with the given configuration.
* Must be called before execute(). Can be called again after destroy()
* to reinitialize with different parameters.
* Must be called before execute(). Identical configs are a no-op:
* cava_init/destroy churn leaks the old plan's FFTW work buffers
* (upstream frees only its own struct), so a pipeline restart with
* unchanged bars/rate/cutoffs must re-USE the live plan.
*/
init(config: CavaCoreConfig = {}): void {
const cfg = { ...DEFAULTS, ...config };
if (
this.plan !== null &&
!this._destroyed &&
this.lastConfigKey === JSON.stringify(cfg)
) {
return;
}
this.lastConfigKey = JSON.stringify(cfg);
if (this.plan) {
this.destroy();
}
const cfg = { ...DEFAULTS, ...config };
this._bars = cfg.bars;
this._channels = cfg.channels;