@viji-dev/core 0.5.3 → 0.5.5

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.
@@ -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-CPrFAj59.js").then((n) => n.e);
1900
+ const wasmModule = await import("./essentia-wasm.web-C58CPq4U.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) {
@@ -6179,9 +6179,31 @@ class OnsetTapManager {
6179
6179
  modeChangeListeners = /* @__PURE__ */ new Set();
6180
6180
  sessionEndListeners = /* @__PURE__ */ new Set();
6181
6181
  muteChangeListeners = /* @__PURE__ */ new Set();
6182
- tap(instrument) {
6182
+ /**
6183
+ * Record a tap on `instrument`. Drives the visual envelope, advances
6184
+ * `lastTapTime`, flips mode to reflect activity, and (by default) feeds
6185
+ * the pattern-recognition pipeline.
6186
+ *
6187
+ * `options.skipRecognition: true` opts the tap out of the **recognition
6188
+ * pipeline only** — `tapIOIs` accumulation, `tryRecognizePattern`,
6189
+ * `applyPattern`, and `handlePatternTap` are skipped. Mode still flips
6190
+ * `'auto' → 'tapping'` on the first tap of a session (already-`'tapping'`
6191
+ * stays; already-`'pattern'` stays). This is load-bearing: `processFrame`'s
6192
+ * drain of `pendingTapEvents` and its audio-event filter both gate on
6193
+ * mode being non-`'auto'`, and downstream consumers (`onModeChange`
6194
+ * listeners, `broadcastOnsetState`) read mode as the signal that a tap
6195
+ * session is in progress. Suppressing the mode flip would silently break
6196
+ * all of them.
6197
+ *
6198
+ * Used for host-side relay of forwarded tap messages where another
6199
+ * instance owns the authoritative recognition (e.g. host receiving
6200
+ * controller taps over WebRTC). The `MIN_TAP_INTERVAL_MS` debounce still
6201
+ * applies regardless of `skipRecognition`.
6202
+ */
6203
+ tap(instrument, options) {
6183
6204
  const s = this.state[instrument];
6184
6205
  const now = performance.now();
6206
+ const skipRecognition = options?.skipRecognition === true;
6185
6207
  if (s.muted) {
6186
6208
  s.muted = false;
6187
6209
  s.mutedAt = 0;
@@ -6191,18 +6213,26 @@ class OnsetTapManager {
6191
6213
  if (s.lastTapTime > 0) {
6192
6214
  ioi = now - s.lastTapTime;
6193
6215
  if (ioi < MIN_TAP_INTERVAL_MS) return;
6194
- if (ioi > MAX_TAP_INTERVAL_MS) {
6195
- s.tapIOIs = [];
6196
- ioi = -1;
6197
- } else {
6198
- s.tapIOIs.push(ioi);
6199
- if (s.tapIOIs.length > MAX_TAP_HISTORY) s.tapIOIs.shift();
6216
+ if (!skipRecognition) {
6217
+ if (ioi > MAX_TAP_INTERVAL_MS) {
6218
+ s.tapIOIs = [];
6219
+ ioi = -1;
6220
+ } else {
6221
+ s.tapIOIs.push(ioi);
6222
+ if (s.tapIOIs.length > MAX_TAP_HISTORY) s.tapIOIs.shift();
6223
+ }
6200
6224
  }
6201
6225
  }
6202
6226
  s.lastTapTime = now;
6203
6227
  s.pendingTapEvents.push(now);
6204
6228
  s.sessionActive = true;
6205
6229
  this.scheduleSessionTimers(instrument);
6230
+ if (skipRecognition) {
6231
+ if (s.mode === "auto") {
6232
+ this.setMode(instrument, "tapping");
6233
+ }
6234
+ return;
6235
+ }
6206
6236
  if (s.mode === "auto") {
6207
6237
  this.setMode(instrument, "tapping");
6208
6238
  if (ioi > 0) {
@@ -6302,16 +6332,27 @@ class OnsetTapManager {
6302
6332
  /**
6303
6333
  * Serialize per-instrument onset state for cross-instance transfer.
6304
6334
  * Wall-clock fields are in this instance's `performance.now()` clock space.
6335
+ *
6336
+ * `options.instruments` scopes the output to the listed instruments only;
6337
+ * omitted instruments are absent from the payload (the receiver's
6338
+ * `applyInstrumentPayload` skips missing keys, leaving the receiver's
6339
+ * existing state for those instruments untouched). Default = all three —
6340
+ * the full-state-transfer used for same-process scene-switch.
6341
+ *
6342
+ * Cross-device commits should typically scope to the just-completed
6343
+ * instrument so an unrelated instrument's state on the receiver isn't
6344
+ * inadvertently overwritten.
6305
6345
  */
6306
- exportSessionState() {
6346
+ exportSessionState(options) {
6347
+ const list = options?.instruments ?? INSTRUMENTS;
6348
+ const instruments = {};
6349
+ for (const inst of list) {
6350
+ instruments[inst] = this.serializeInstrument(inst);
6351
+ }
6307
6352
  return {
6308
6353
  version: STATE_SCHEMA_VERSION,
6309
6354
  senderTime: performance.now(),
6310
- instruments: {
6311
- kick: this.serializeInstrument("kick"),
6312
- snare: this.serializeInstrument("snare"),
6313
- hat: this.serializeInstrument("hat")
6314
- }
6355
+ instruments
6315
6356
  };
6316
6357
  }
6317
6358
  /**
@@ -8497,10 +8538,16 @@ class AudioSystem {
8497
8538
  // Public API Methods for Audio Analysis Configuration
8498
8539
  // ═══════════════════════════════════════════════════════════
8499
8540
  /**
8500
- * Record a tap for the specified instrument onset
8541
+ * Record a tap for the specified instrument onset.
8542
+ * `options.skipRecognition` opts the tap out of the recognition pipeline
8543
+ * only (no IOI accumulation, no `tryRecognizePattern`, no `applyPattern`).
8544
+ * Mode still flips `'auto' → 'tapping'` so the visual envelope and
8545
+ * audio-event filter run; only the pattern-detection pipeline is bypassed.
8546
+ * Used by host-side relay of forwarded tap messages where another core
8547
+ * owns the authoritative recognition.
8501
8548
  */
8502
- tapOnset(instrument) {
8503
- this.onsetTapManager.tap(instrument);
8549
+ tapOnset(instrument, options) {
8550
+ this.onsetTapManager.tap(instrument, options);
8504
8551
  }
8505
8552
  /**
8506
8553
  * Clear tap pattern for an instrument, restoring auto-detection
@@ -8550,8 +8597,8 @@ class AudioSystem {
8550
8597
  // audio block is for same-process scene-switch transfer (sender's audio
8551
8598
  // analysis state would corrupt receiver's tracking on a different source).
8552
8599
  // ─────────────────────────────────────────────────────────────────────────
8553
- exportOnsetSessionState() {
8554
- return this.onsetTapManager.exportSessionState();
8600
+ exportOnsetSessionState(options) {
8601
+ return this.onsetTapManager.exportSessionState(options);
8555
8602
  }
8556
8603
  importOnsetSessionState(state, clockOffset) {
8557
8604
  this.onsetTapManager.importSessionState(state, clockOffset);
@@ -11108,10 +11155,25 @@ class VijiCore {
11108
11155
  * Tap an onset for a specific instrument.
11109
11156
  * First tap switches the instrument from auto to tapping mode.
11110
11157
  * If a repeating pattern is recognized, it continues after tapping stops.
11158
+ *
11159
+ * `options.skipRecognition: true` opts the tap out of the **recognition
11160
+ * pipeline only** — no `tapIOIs` accumulation, no `tryRecognizePattern`,
11161
+ * no `applyPattern`, no `handlePatternTap`. Mode still flips
11162
+ * `'auto' → 'tapping'` on the first tap of a session (and back to
11163
+ * `'auto'` on the 5s timeout). The mode flip is load-bearing for
11164
+ * `processFrame`'s drain of `pendingTapEvents`, the audio-event filter
11165
+ * that prevents music+tap doubling, and `onModeChange` consumers. Use
11166
+ * `skipRecognition` when relaying tap messages from another instance
11167
+ * that owns the authoritative recognition (e.g. host receiving
11168
+ * controller taps over WebRTC); the receiving core's pattern is then
11169
+ * driven only by `importSessionState` from the authoritative sender.
11170
+ *
11171
+ * The `MIN_TAP_INTERVAL_MS` debounce still applies regardless of the
11172
+ * `skipRecognition` flag.
11111
11173
  */
11112
- tap: (instrument) => {
11174
+ tap: (instrument, options) => {
11113
11175
  this.validateReady();
11114
- this.audioSystem?.tapOnset(instrument);
11176
+ this.audioSystem?.tapOnset(instrument, options);
11115
11177
  },
11116
11178
  /**
11117
11179
  * Clear the tap pattern for an instrument, restoring auto-detection
@@ -11214,10 +11276,22 @@ class VijiCore {
11214
11276
  * Cross-device-safe (no audio analysis state included). Pair with
11215
11277
  * `importSessionState` on a receiver. Wall-clock fields are in this
11216
11278
  * instance's `performance.now()` clock space.
11279
+ *
11280
+ * `options.instruments` scopes the snapshot to the listed instruments
11281
+ * only; omitted instruments are absent from the payload. The receiver
11282
+ * leaves its existing state for those instruments untouched (the
11283
+ * receiver's `applyInstrumentPayload` skips missing keys). Default =
11284
+ * all three.
11285
+ *
11286
+ * Cross-device commits should typically scope to the just-completed
11287
+ * instrument (e.g. `exportSessionState({ instruments: [ev.instrument] })`
11288
+ * inside an `onSessionEnd` handler) so the receiver's unrelated
11289
+ * instrument state isn't inadvertently overwritten by the sender's
11290
+ * default values.
11217
11291
  */
11218
- exportSessionState: () => {
11292
+ exportSessionState: (options) => {
11219
11293
  this.validateReady();
11220
- return this.audioSystem?.exportOnsetSessionState() ?? {
11294
+ return this.audioSystem?.exportOnsetSessionState(options) ?? {
11221
11295
  version: 1,
11222
11296
  senderTime: performance.now(),
11223
11297
  instruments: {}
@@ -11649,7 +11723,7 @@ function validateCoreStatePayload(state) {
11649
11723
  }
11650
11724
  return null;
11651
11725
  }
11652
- const VERSION = "0.5.3";
11726
+ const VERSION = "0.5.5";
11653
11727
  export {
11654
11728
  AudioSystem as A,
11655
11729
  VERSION as V,
@@ -11657,4 +11731,4 @@ export {
11657
11731
  VijiCoreError as b,
11658
11732
  getDefaultExportFromCjs as g
11659
11733
  };
11660
- //# sourceMappingURL=index-Bhq4eJe_.js.map
11734
+ //# sourceMappingURL=index-DsJxKERc.js.map