@viji-dev/core 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/artist-dts-p5.js +1 -1
- package/dist/artist-dts.js +1 -1
- package/dist/artist-global-p5.d.ts +1 -1
- package/dist/artist-global.d.ts +1 -1
- package/dist/docs-api.js +47 -37
- package/dist/{essentia-wasm.web-x6zu4Vib.js → essentia-wasm.web-CPrFAj59.js} +2 -2
- package/dist/{essentia-wasm.web-x6zu4Vib.js.map → essentia-wasm.web-CPrFAj59.js.map} +1 -1
- package/dist/{index-Cqh1k_49.js → index-Bhq4eJe_.js} +101 -33
- package/dist/index-Bhq4eJe_.js.map +1 -0
- package/dist/index.d.ts +51 -10
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/index-Cqh1k_49.js.map +0 -1
|
@@ -1897,7 +1897,7 @@ class EssentiaOnsetDetection {
|
|
|
1897
1897
|
this.initPromise = (async () => {
|
|
1898
1898
|
try {
|
|
1899
1899
|
const essentiaModule = await import("./essentia.js-core.es-DnrJE0uR.js");
|
|
1900
|
-
const wasmModule = await import("./essentia-wasm.web-
|
|
1900
|
+
const wasmModule = await import("./essentia-wasm.web-CPrFAj59.js").then((n) => n.e);
|
|
1901
1901
|
const EssentiaClass = essentiaModule.Essentia || essentiaModule.default?.Essentia || essentiaModule.default;
|
|
1902
1902
|
let WASMModule = wasmModule.default || wasmModule.EssentiaWASM || wasmModule.default?.EssentiaWASM;
|
|
1903
1903
|
if (!WASMModule) {
|
|
@@ -6178,13 +6178,14 @@ class OnsetTapManager {
|
|
|
6178
6178
|
};
|
|
6179
6179
|
modeChangeListeners = /* @__PURE__ */ new Set();
|
|
6180
6180
|
sessionEndListeners = /* @__PURE__ */ new Set();
|
|
6181
|
-
|
|
6181
|
+
muteChangeListeners = /* @__PURE__ */ new Set();
|
|
6182
6182
|
tap(instrument) {
|
|
6183
6183
|
const s = this.state[instrument];
|
|
6184
6184
|
const now = performance.now();
|
|
6185
6185
|
if (s.muted) {
|
|
6186
6186
|
s.muted = false;
|
|
6187
6187
|
s.mutedAt = 0;
|
|
6188
|
+
this.fireMuteChange({ instrument, prevMuted: true, muted: false });
|
|
6188
6189
|
}
|
|
6189
6190
|
let ioi = -1;
|
|
6190
6191
|
if (s.lastTapTime > 0) {
|
|
@@ -6221,6 +6222,7 @@ class OnsetTapManager {
|
|
|
6221
6222
|
}
|
|
6222
6223
|
clear(instrument) {
|
|
6223
6224
|
const s = this.state[instrument];
|
|
6225
|
+
const prevMuted = s.muted;
|
|
6224
6226
|
this.cancelSessionTimers(s);
|
|
6225
6227
|
s.sessionActive = false;
|
|
6226
6228
|
this.setMode(instrument, "auto");
|
|
@@ -6236,6 +6238,9 @@ class OnsetTapManager {
|
|
|
6236
6238
|
s.pendingTapEvents = [];
|
|
6237
6239
|
s.envelope.reset();
|
|
6238
6240
|
s.envelopeSmoothed.reset();
|
|
6241
|
+
if (prevMuted) {
|
|
6242
|
+
this.fireMuteChange({ instrument, prevMuted: true, muted: false });
|
|
6243
|
+
}
|
|
6239
6244
|
}
|
|
6240
6245
|
getMode(instrument) {
|
|
6241
6246
|
return this.state[instrument].mode;
|
|
@@ -6252,6 +6257,7 @@ class OnsetTapManager {
|
|
|
6252
6257
|
setMuted(instrument, muted) {
|
|
6253
6258
|
const s = this.state[instrument];
|
|
6254
6259
|
if (s.muted === muted) return;
|
|
6260
|
+
const prevMuted = s.muted;
|
|
6255
6261
|
const now = performance.now();
|
|
6256
6262
|
if (muted) {
|
|
6257
6263
|
s.muted = true;
|
|
@@ -6264,6 +6270,7 @@ class OnsetTapManager {
|
|
|
6264
6270
|
s.lastTapTime += pauseDuration;
|
|
6265
6271
|
}
|
|
6266
6272
|
}
|
|
6273
|
+
this.fireMuteChange({ instrument, prevMuted, muted: s.muted });
|
|
6267
6274
|
}
|
|
6268
6275
|
isMuted(instrument) {
|
|
6269
6276
|
return this.state[instrument].muted;
|
|
@@ -6283,6 +6290,12 @@ class OnsetTapManager {
|
|
|
6283
6290
|
this.sessionEndListeners.delete(listener);
|
|
6284
6291
|
};
|
|
6285
6292
|
}
|
|
6293
|
+
onMuteChange(listener) {
|
|
6294
|
+
this.muteChangeListeners.add(listener);
|
|
6295
|
+
return () => {
|
|
6296
|
+
this.muteChangeListeners.delete(listener);
|
|
6297
|
+
};
|
|
6298
|
+
}
|
|
6286
6299
|
// ─────────────────────────────────────────────────────────────────────────
|
|
6287
6300
|
// State serialization
|
|
6288
6301
|
// ─────────────────────────────────────────────────────────────────────────
|
|
@@ -6312,22 +6325,22 @@ class OnsetTapManager {
|
|
|
6312
6325
|
* is older than one pattern period (phase-preserving — events still land on
|
|
6313
6326
|
* the original beat positions modulo `patternSum`).
|
|
6314
6327
|
*
|
|
6315
|
-
* Mutation is synchronous
|
|
6316
|
-
*
|
|
6317
|
-
*
|
|
6328
|
+
* Mutation is synchronous. Field-level events (`onModeChange`,
|
|
6329
|
+
* `onMuteChange`) fire when an imported value differs from the current one
|
|
6330
|
+
* — consumer-visible state is consistent with what polling would have
|
|
6331
|
+
* observed. Session-boundary events (`onSessionEnd`) do NOT fire on
|
|
6332
|
+
* import; imports are state replacement, not session boundaries.
|
|
6333
|
+
*
|
|
6334
|
+
* Throws nothing — malformed payloads should be filtered by the caller
|
|
6335
|
+
* via the `version` field.
|
|
6318
6336
|
*/
|
|
6319
6337
|
importSessionState(state, clockOffset) {
|
|
6320
6338
|
if (state.version !== STATE_SCHEMA_VERSION) return;
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
const
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
if (!payload) continue;
|
|
6327
|
-
this.applyInstrumentPayload(inst, payload, clockOffset, now);
|
|
6328
|
-
}
|
|
6329
|
-
} finally {
|
|
6330
|
-
this.suppressEmissions = false;
|
|
6339
|
+
const now = performance.now();
|
|
6340
|
+
for (const inst of INSTRUMENTS) {
|
|
6341
|
+
const payload = state.instruments[inst];
|
|
6342
|
+
if (!payload) continue;
|
|
6343
|
+
this.applyInstrumentPayload(inst, payload, clockOffset, now);
|
|
6331
6344
|
}
|
|
6332
6345
|
}
|
|
6333
6346
|
/**
|
|
@@ -6464,18 +6477,16 @@ class OnsetTapManager {
|
|
|
6464
6477
|
// Private helpers
|
|
6465
6478
|
// ---------------------------------------------------------------------------
|
|
6466
6479
|
/**
|
|
6467
|
-
* Single mutation point for `s.mode`. Fires `onModeChange`
|
|
6468
|
-
*
|
|
6469
|
-
*
|
|
6480
|
+
* Single mutation point for `s.mode`. Fires `onModeChange` so listeners
|
|
6481
|
+
* stay consistent regardless of which code path triggered the transition
|
|
6482
|
+
* (including imports, which fire via `applyInstrumentPayload` directly).
|
|
6470
6483
|
*/
|
|
6471
6484
|
setMode(instrument, newMode) {
|
|
6472
6485
|
const s = this.state[instrument];
|
|
6473
6486
|
const prevMode = s.mode;
|
|
6474
6487
|
if (prevMode === newMode) return;
|
|
6475
6488
|
s.mode = newMode;
|
|
6476
|
-
|
|
6477
|
-
this.fireModeChange({ instrument, prevMode, newMode });
|
|
6478
|
-
}
|
|
6489
|
+
this.fireModeChange({ instrument, prevMode, newMode });
|
|
6479
6490
|
}
|
|
6480
6491
|
fireModeChange(ev) {
|
|
6481
6492
|
for (const listener of this.modeChangeListeners) {
|
|
@@ -6495,6 +6506,15 @@ class OnsetTapManager {
|
|
|
6495
6506
|
}
|
|
6496
6507
|
}
|
|
6497
6508
|
}
|
|
6509
|
+
fireMuteChange(ev) {
|
|
6510
|
+
for (const listener of this.muteChangeListeners) {
|
|
6511
|
+
try {
|
|
6512
|
+
listener(ev);
|
|
6513
|
+
} catch (err) {
|
|
6514
|
+
console.error("Error in onMuteChange listener:", err);
|
|
6515
|
+
}
|
|
6516
|
+
}
|
|
6517
|
+
}
|
|
6498
6518
|
/**
|
|
6499
6519
|
* Schedule (or reschedule) the per-instrument session timers on every tap.
|
|
6500
6520
|
* 500ms timer fires `'pattern'` outcome if instrument is in pattern mode at
|
|
@@ -6585,6 +6605,8 @@ class OnsetTapManager {
|
|
|
6585
6605
|
}
|
|
6586
6606
|
applyInstrumentPayload(instrument, payload, clockOffset, now) {
|
|
6587
6607
|
const s = this.state[instrument];
|
|
6608
|
+
const prevMode = s.mode;
|
|
6609
|
+
const prevMuted = s.muted;
|
|
6588
6610
|
this.cancelSessionTimers(s);
|
|
6589
6611
|
s.sessionActive = false;
|
|
6590
6612
|
const translatedReplayLast = payload.replayLastEventTime !== null ? payload.replayLastEventTime + clockOffset : 0;
|
|
@@ -6601,7 +6623,6 @@ class OnsetTapManager {
|
|
|
6601
6623
|
}
|
|
6602
6624
|
}
|
|
6603
6625
|
}
|
|
6604
|
-
s.mode;
|
|
6605
6626
|
s.mode = payload.mode;
|
|
6606
6627
|
s.muted = payload.muted;
|
|
6607
6628
|
s.mutedAt = translatedMutedAt;
|
|
@@ -6615,6 +6636,12 @@ class OnsetTapManager {
|
|
|
6615
6636
|
s.pendingTapEvents = [];
|
|
6616
6637
|
s.envelope.reset();
|
|
6617
6638
|
s.envelopeSmoothed.reset();
|
|
6639
|
+
if (s.mode !== prevMode) {
|
|
6640
|
+
this.fireModeChange({ instrument, prevMode, newMode: s.mode });
|
|
6641
|
+
}
|
|
6642
|
+
if (s.muted !== prevMuted) {
|
|
6643
|
+
this.fireMuteChange({ instrument, prevMuted, muted: s.muted });
|
|
6644
|
+
}
|
|
6618
6645
|
}
|
|
6619
6646
|
/**
|
|
6620
6647
|
* Handle a tap that arrives while already in pattern mode.
|
|
@@ -8515,6 +8542,9 @@ class AudioSystem {
|
|
|
8515
8542
|
onOnsetSessionEnd(listener) {
|
|
8516
8543
|
return this.onsetTapManager.onSessionEnd(listener);
|
|
8517
8544
|
}
|
|
8545
|
+
onOnsetMuteChange(listener) {
|
|
8546
|
+
return this.onsetTapManager.onMuteChange(listener);
|
|
8547
|
+
}
|
|
8518
8548
|
// ─────────────────────────────────────────────────────────────────────────
|
|
8519
8549
|
// State serialization. Onset-only export is cross-device-safe; the full
|
|
8520
8550
|
// audio block is for same-process scene-switch transfer (sender's audio
|
|
@@ -10641,8 +10671,12 @@ class VijiCore {
|
|
|
10641
10671
|
/**
|
|
10642
10672
|
* Replace the audio analysis + onset state from a serialized payload.
|
|
10643
10673
|
* `clockOffset` is added to all sender-clocked fields (`0` for same-process,
|
|
10644
|
-
* NTP-derived for cross-device). Mutation is synchronous
|
|
10645
|
-
*
|
|
10674
|
+
* NTP-derived for cross-device). Mutation is synchronous.
|
|
10675
|
+
*
|
|
10676
|
+
* Field-level events (`onModeChange`, `onMuteChange`) fire when imported
|
|
10677
|
+
* values differ from current — consumer-visible state stays consistent
|
|
10678
|
+
* with what polling would have observed. Session-boundary events
|
|
10679
|
+
* (`onSessionEnd`) do NOT fire on import.
|
|
10646
10680
|
*
|
|
10647
10681
|
* Validates `version`; on mismatch, fires `onStateImportError` and leaves
|
|
10648
10682
|
* existing state intact.
|
|
@@ -11118,9 +11152,13 @@ class VijiCore {
|
|
|
11118
11152
|
},
|
|
11119
11153
|
/**
|
|
11120
11154
|
* Listen for instrument mode transitions (`'auto' | 'tapping' | 'pattern'`).
|
|
11121
|
-
* Fires
|
|
11122
|
-
*
|
|
11123
|
-
*
|
|
11155
|
+
* Fires whenever the underlying mode field actually changes, regardless
|
|
11156
|
+
* of which code path triggered it — first tap (`'auto' → 'tapping'`),
|
|
11157
|
+
* pattern recognition (`'tapping' → 'pattern'`), the 5s tap timeout
|
|
11158
|
+
* (`'tapping' → 'auto'`), explicit `clear()`, or `importSessionState`
|
|
11159
|
+
* landing a different mode value.
|
|
11160
|
+
*
|
|
11161
|
+
* Idempotent transitions (already in target mode) do not fire.
|
|
11124
11162
|
*
|
|
11125
11163
|
* @returns Unsubscribe function. Call to remove the listener.
|
|
11126
11164
|
*/
|
|
@@ -11130,14 +11168,20 @@ class VijiCore {
|
|
|
11130
11168
|
});
|
|
11131
11169
|
},
|
|
11132
11170
|
/**
|
|
11133
|
-
* Listen for natural session-end events. Fires
|
|
11171
|
+
* Listen for natural session-end events. Fires only on natural session
|
|
11172
|
+
* boundaries:
|
|
11134
11173
|
* - 500ms elapse since last tap with instrument in `'pattern'` mode
|
|
11135
11174
|
* (outcome `'pattern'`), or
|
|
11136
11175
|
* - 5s elapse in `'tapping'` mode without a recognized pattern
|
|
11137
11176
|
* (outcome `'cleared'`; instrument transitions to `'auto'`).
|
|
11138
11177
|
*
|
|
11139
|
-
*
|
|
11140
|
-
*
|
|
11178
|
+
* Does NOT fire on:
|
|
11179
|
+
* - Explicit `clear()` calls (caller-initiated; not a natural boundary).
|
|
11180
|
+
* - `importSessionState` (state replacement; not a session boundary).
|
|
11181
|
+
*
|
|
11182
|
+
* Field-change events (`onModeChange`, `onMuteChange`) fire on imports
|
|
11183
|
+
* when fields differ; this event does not because session-end is a
|
|
11184
|
+
* different category — about session lifecycle, not field state.
|
|
11141
11185
|
*
|
|
11142
11186
|
* @returns Unsubscribe function. Call to remove the listener.
|
|
11143
11187
|
*/
|
|
@@ -11146,6 +11190,25 @@ class VijiCore {
|
|
|
11146
11190
|
return this.audioSystem?.onOnsetSessionEnd(listener) ?? (() => {
|
|
11147
11191
|
});
|
|
11148
11192
|
},
|
|
11193
|
+
/**
|
|
11194
|
+
* Listen for instrument mute-state transitions (`true ↔ false`). Fires
|
|
11195
|
+
* whenever the underlying mute field actually changes, regardless of
|
|
11196
|
+
* which code path triggered it:
|
|
11197
|
+
* - `setMuted(instrument, muted)` when `prev !== next`.
|
|
11198
|
+
* - `tap(instrument)` auto-unmute on first tap of a muted instrument.
|
|
11199
|
+
* - `clear(instrument)` when the instrument was muted at call time.
|
|
11200
|
+
* - `importSessionState` landing a different muted value.
|
|
11201
|
+
*
|
|
11202
|
+
* Idempotent calls (e.g. `setMuted(true)` on an already-muted instrument)
|
|
11203
|
+
* do not fire.
|
|
11204
|
+
*
|
|
11205
|
+
* @returns Unsubscribe function. Call to remove the listener.
|
|
11206
|
+
*/
|
|
11207
|
+
onMuteChange: (listener) => {
|
|
11208
|
+
this.validateReady();
|
|
11209
|
+
return this.audioSystem?.onOnsetMuteChange(listener) ?? (() => {
|
|
11210
|
+
});
|
|
11211
|
+
},
|
|
11149
11212
|
/**
|
|
11150
11213
|
* Snapshot per-instrument onset state for cross-instance transfer.
|
|
11151
11214
|
* Cross-device-safe (no audio analysis state included). Pair with
|
|
@@ -11164,7 +11227,12 @@ class VijiCore {
|
|
|
11164
11227
|
* Replace per-instrument onset state from a serialized payload.
|
|
11165
11228
|
* `clockOffset` is added to all sender-clocked fields during import
|
|
11166
11229
|
* (use `0` for same-process transfer; NTP-derived offset for cross-device).
|
|
11167
|
-
* Mutation is synchronous
|
|
11230
|
+
* Mutation is synchronous.
|
|
11231
|
+
*
|
|
11232
|
+
* Field-level events fire when imported values differ from current:
|
|
11233
|
+
* `onModeChange` if the imported mode is different, `onMuteChange` if
|
|
11234
|
+
* the imported muted state is different. Session-boundary events
|
|
11235
|
+
* (`onSessionEnd`) do NOT fire — imports aren't session boundaries.
|
|
11168
11236
|
*
|
|
11169
11237
|
* Patterns are rebased forward by whole pattern cycles to eliminate
|
|
11170
11238
|
* the catch-up burst that would otherwise occur on stale payloads
|
|
@@ -11581,7 +11649,7 @@ function validateCoreStatePayload(state) {
|
|
|
11581
11649
|
}
|
|
11582
11650
|
return null;
|
|
11583
11651
|
}
|
|
11584
|
-
const VERSION = "0.5.
|
|
11652
|
+
const VERSION = "0.5.3";
|
|
11585
11653
|
export {
|
|
11586
11654
|
AudioSystem as A,
|
|
11587
11655
|
VERSION as V,
|
|
@@ -11589,4 +11657,4 @@ export {
|
|
|
11589
11657
|
VijiCoreError as b,
|
|
11590
11658
|
getDefaultExportFromCjs as g
|
|
11591
11659
|
};
|
|
11592
|
-
//# sourceMappingURL=index-
|
|
11660
|
+
//# sourceMappingURL=index-Bhq4eJe_.js.map
|