cacophony 0.23.0 → 0.24.0

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.
Files changed (124) hide show
  1. package/dist/cacophony.d.ts +358 -1
  2. package/dist/context.d.ts +15 -0
  3. package/dist/effects.d.ts +428 -1
  4. package/dist/index.cjs +1 -1
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.ts +10 -2
  7. package/dist/index.mjs +2555 -1245
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/meters/loudness-core.d.ts +179 -0
  10. package/dist/meters/loudness-core.test.d.ts +1 -0
  11. package/dist/meters/loudness-meter.d.ts +60 -0
  12. package/dist/meters/loudness-meter.test.d.ts +1 -0
  13. package/dist/meters/truepeak-core.d.ts +104 -0
  14. package/dist/meters/truepeak-core.test.d.ts +1 -0
  15. package/dist/playback.d.ts +35 -0
  16. package/dist/sound.d.ts +41 -0
  17. package/dist/spatial/foa-encode.d.ts +37 -0
  18. package/docs/assets/navigation.js +1 -1
  19. package/docs/assets/search.js +1 -1
  20. package/docs/classes/AudioCache.html +7 -7
  21. package/docs/classes/BiquadEffect.html +2 -2
  22. package/docs/classes/Bus.html +15 -15
  23. package/docs/classes/Cacophony.html +300 -28
  24. package/docs/classes/DynamicsEffect.html +11 -0
  25. package/docs/classes/FdnReverbEffect.html +12 -0
  26. package/docs/classes/FoaDecoder.html +79 -0
  27. package/docs/classes/Group.html +13 -13
  28. package/docs/classes/KWeightingFilter.html +10 -0
  29. package/docs/classes/LoudnessMeter.html +39 -0
  30. package/docs/classes/MediaStreamPlayback.html +19 -19
  31. package/docs/classes/MediaStreamSound.html +19 -19
  32. package/docs/classes/MicrophonePlayback.html +3 -3
  33. package/docs/classes/ModulatedDelayEffect.html +12 -0
  34. package/docs/classes/PhaserEffect.html +11 -0
  35. package/docs/classes/Playback.html +58 -33
  36. package/docs/classes/ReverbEffect.html +2 -2
  37. package/docs/classes/ShareEffect.html +2 -2
  38. package/docs/classes/Sound.html +57 -28
  39. package/docs/classes/Synth.html +22 -22
  40. package/docs/classes/SynthGroup.html +2 -2
  41. package/docs/classes/TremoloEffect.html +11 -0
  42. package/docs/classes/TruePeakDetector.html +29 -0
  43. package/docs/classes/WaveshaperEffect.html +12 -0
  44. package/docs/functions/encodeMonoToFoaSN3D.html +31 -0
  45. package/docs/functions/integratedLoudness.html +12 -0
  46. package/docs/functions/integratedUngatedLoudness.html +7 -0
  47. package/docs/functions/loudnessRange.html +7 -0
  48. package/docs/functions/timeStretch.html +20 -0
  49. package/docs/functions/timeStretchChannels.html +4 -0
  50. package/docs/functions/truePeakDb.html +4 -0
  51. package/docs/hierarchy.html +1 -1
  52. package/docs/interfaces/AudioBuffer.html +2 -2
  53. package/docs/interfaces/AudioBufferSourceNode.html +4 -4
  54. package/docs/interfaces/AudioEventCallbacks.html +1 -1
  55. package/docs/interfaces/AudioListener.html +2 -2
  56. package/docs/interfaces/AudioNode.html +3 -3
  57. package/docs/interfaces/AudioParam.html +2 -2
  58. package/docs/interfaces/AudioWorklet.html +2 -2
  59. package/docs/interfaces/AudioWorkletNode.html +9 -4
  60. package/docs/interfaces/BaseContext.html +4 -2
  61. package/docs/interfaces/BaseSound.html +2 -2
  62. package/docs/interfaces/BiquadCoefficients.html +8 -0
  63. package/docs/interfaces/BiquadFilterNode.html +4 -4
  64. package/docs/interfaces/CacheErrorEvent.html +2 -2
  65. package/docs/interfaces/CacheHitEvent.html +2 -2
  66. package/docs/interfaces/CacheMissEvent.html +2 -2
  67. package/docs/interfaces/CacophonyEffect.html +2 -2
  68. package/docs/interfaces/ChannelMergerNode.html +3 -3
  69. package/docs/interfaces/ChannelSplitterNode.html +3 -3
  70. package/docs/interfaces/DynamicsOptions.html +21 -0
  71. package/docs/interfaces/FadeStartEvent.html +2 -2
  72. package/docs/interfaces/FdnReverbOptions.html +19 -0
  73. package/docs/interfaces/FoaDecoderOptions.html +10 -0
  74. package/docs/interfaces/GainNode.html +3 -3
  75. package/docs/interfaces/GlobalPlaybackEvent.html +2 -2
  76. package/docs/interfaces/LoadingCompleteEvent.html +2 -2
  77. package/docs/interfaces/LoadingErrorEvent.html +2 -2
  78. package/docs/interfaces/LoadingProgressEvent.html +2 -2
  79. package/docs/interfaces/LoadingStartEvent.html +2 -2
  80. package/docs/interfaces/LoudnessChannelInput.html +4 -0
  81. package/docs/interfaces/LoudnessReading.html +10 -0
  82. package/docs/interfaces/MediaElementSourceNode.html +3 -3
  83. package/docs/interfaces/MediaStreamAudioSourceNode.html +3 -3
  84. package/docs/interfaces/MediaStreamSoundOptions.html +2 -2
  85. package/docs/interfaces/ModulatedDelayOptions.html +27 -0
  86. package/docs/interfaces/OfflineOptions.html +2 -2
  87. package/docs/interfaces/OscillatorNode.html +4 -4
  88. package/docs/interfaces/PannerNode.html +3 -3
  89. package/docs/interfaces/PhaserOptions.html +23 -0
  90. package/docs/interfaces/PlayOptions.html +2 -2
  91. package/docs/interfaces/PlaybackErrorEvent.html +2 -2
  92. package/docs/interfaces/ReverbOptions.html +13 -13
  93. package/docs/interfaces/RuntimeOptions.html +2 -2
  94. package/docs/interfaces/SoundCleanupHoldings.html +2 -2
  95. package/docs/interfaces/SoundErrorEvent.html +2 -2
  96. package/docs/interfaces/StereoPannerNode.html +3 -3
  97. package/docs/interfaces/TimeStretchOptions.html +16 -0
  98. package/docs/interfaces/TremoloOptions.html +21 -0
  99. package/docs/interfaces/WaveshaperOptions.html +18 -0
  100. package/docs/modules.html +32 -0
  101. package/docs/types/BaseAudioEvents.html +1 -1
  102. package/docs/types/BusConnectionTarget.html +1 -1
  103. package/docs/types/CacheEventCallback.html +1 -1
  104. package/docs/types/CacophonyEvents.html +1 -1
  105. package/docs/types/ErrorEventCallback.html +1 -1
  106. package/docs/types/FadeType.html +1 -1
  107. package/docs/types/HrtfPannerOptions.html +1 -1
  108. package/docs/types/LoadingEventCallback.html +1 -1
  109. package/docs/types/LoopCount.html +1 -1
  110. package/docs/types/LoudnessChannel.html +4 -0
  111. package/docs/types/Orientation.html +1 -1
  112. package/docs/types/PanCloneOverrides.html +1 -1
  113. package/docs/types/PanType.html +1 -1
  114. package/docs/types/PlaybackEvents.html +1 -1
  115. package/docs/types/Position.html +1 -1
  116. package/docs/types/SoundEvents.html +1 -1
  117. package/docs/types/SoundType.html +1 -1
  118. package/docs/types/SourceNode.html +1 -1
  119. package/docs/types/SynthEvents.html +1 -1
  120. package/docs/types/ThreeDOptions.html +1 -1
  121. package/docs/variables/CHANNEL_WEIGHTS.html +4 -0
  122. package/docs/variables/K_WEIGHTING_STAGE1_48K.html +4 -0
  123. package/docs/variables/K_WEIGHTING_STAGE2_48K.html +3 -0
  124. package/package.json +5 -1
@@ -1,12 +1,14 @@
1
1
  import { Bus } from './bus';
2
2
  import { ICache } from './cache';
3
3
  import { AudioBuffer, AudioListener, AudioNode, AudioWorkletNode, BaseContext, BiquadFilterNode, ChannelMergerNode, ChannelSplitterNode, GainNode, PannerNode } from './context';
4
- import { CacophonyEffect, ReverbEffect, ReverbOptions } from './effects';
4
+ import { CacophonyEffect, DynamicsEffect, DynamicsOptions, FdnReverbEffect, FdnReverbOptions, FoaDecoder, FoaDecoderOptions, ModulatedDelayEffect, ModulatedDelayOptions, PhaserEffect, PhaserOptions, ReverbEffect, ReverbOptions, TremoloEffect, TremoloOptions, WaveshaperEffect, WaveshaperOptions } from './effects';
5
5
  import { CacophonyEvents } from './events';
6
6
  import { Group } from './group';
7
7
  import { MediaStreamSound, MediaStreamSoundOptions } from './mediaStream';
8
+ import { LoudnessMeter } from './meters/loudness-meter';
8
9
  import { MicrophoneStream } from './microphone';
9
10
  import { ThreeDOptions } from './pannerMixin';
11
+ import { TimeStretchOptions } from './processors/timestretch-core';
10
12
  import { Sound } from './sound';
11
13
  import { Synth } from './synth';
12
14
  export type SoundType = "html" | "streaming" | "buffer" | "oscillator";
@@ -137,6 +139,15 @@ export declare class Cacophony {
137
139
  * the second construct would throw with no module registered.
138
140
  */
139
141
  private loadedAudioWorklets;
142
+ /**
143
+ * Per-context cache of the decoded order-1 SH-HRIR `AudioBuffer` used by
144
+ * {@link FoaDecoder}. Keyed on the context (like
145
+ * {@link loadedAudioWorklets}) because `decodeAudioData` produces a buffer
146
+ * bound to ONE context's sample rate; a buffer decoded on context A must not
147
+ * be reused on context B. Stores the in-flight Promise so concurrent
148
+ * `loadFoaHrir` calls share a single fetch/decode.
149
+ */
150
+ private foaHrirCache;
140
151
  private finalizationRegistry;
141
152
  private eventEmitter;
142
153
  private cache;
@@ -205,6 +216,32 @@ export declare class Cacophony {
205
216
  * @throws Error if the context does not support offline rendering
206
217
  */
207
218
  startRendering(): Promise<AudioBuffer>;
219
+ /**
220
+ * OFFLINE independent time-stretch: change an AudioBuffer's tempo WITHOUT
221
+ * changing its pitch, returning a NEW AudioBuffer of length ≈
222
+ * `round(buffer.length · factor)` at the same sample rate.
223
+ *
224
+ * Algorithm: Phase Gradient Heap Integration (PGHI) per Zdeněk Průša & Nicki
225
+ * Holighaus, "Phase Vocoder Done Right" (EUSIPCO 2017 / arXiv:2202.07382).
226
+ * The signal is STFT'd, the synthesis phase is reconstructed by integrating
227
+ * the analysis-phase time/frequency gradients along the magnitude ridges
228
+ * (max-heap), then overlap-added at the stretched synthesis hop. No peak
229
+ * picking and no transient detection. Each channel is processed independently.
230
+ *
231
+ * This is an OFFLINE buffer transform, NOT a real-time worklet: the project's
232
+ * OLA worklet base is unity-rate (analysis hop == synthesis hop, fixed to the
233
+ * 128-sample render quantum) and cannot change the time base in real time. A
234
+ * genuine independent stretch needs analysis hop ≠ synthesis hop, which only
235
+ * the whole-buffer offline path provides.
236
+ *
237
+ * @param buffer The source AudioBuffer to time-stretch.
238
+ * @param factor Stretch factor (`> 0`). `> 1` lengthens (slower tempo), `< 1`
239
+ * shortens (faster tempo); pitch is preserved either way.
240
+ * @param options Optional PGHI parameters (fftSize, analysisHop, tol, seed).
241
+ * @returns A new, time-stretched AudioBuffer.
242
+ * @throws If the context cannot create buffers, or `factor <= 0`.
243
+ */
244
+ timeStretchBuffer(buffer: AudioBuffer, factor: number, options?: TimeStretchOptions): AudioBuffer;
208
245
  /**
209
246
  * Register event listener.
210
247
  * @returns Cleanup function
@@ -218,6 +255,21 @@ export declare class Cacophony {
218
255
  emitAsync<K extends keyof CacophonyEvents>(event: K, data: CacophonyEvents[K]): Promise<void>;
219
256
  loadWorklets(signal?: AbortSignal): Promise<void>;
220
257
  loadStereoToBFormatWorklet(signal?: AbortSignal): Promise<void>;
258
+ /**
259
+ * Idempotently registers the `phase-vocoder` AudioWorkletProcessor (peak-based
260
+ * pitch-shifter with Identity Phase-Locking, Laroche & Dolson 1999 WASPAA) on
261
+ * this context. Safe to call repeatedly — subsequent calls short-circuit via
262
+ * the per-context {@link loadedAudioWorklets} set. Cross-context: pass
263
+ * `context` so a node built against a bus on a different context loads there.
264
+ */
265
+ loadPhaseVocoder(signal?: AbortSignal, context?: BaseContext): Promise<void>;
266
+ /**
267
+ * Constructs a `phase-vocoder` AudioWorkletNode. Caller is expected to have
268
+ * loaded the module already (via {@link loadPhaseVocoder} or {@link loadWorklets}).
269
+ * Uses the same construct/fallback path as {@link createWorkletNode}. The
270
+ * returned node carries a single `pitchFactor` AudioParam (1 = no shift).
271
+ */
272
+ createPhaseVocoderNode(options?: AudioWorkletNodeOptions, context?: BaseContext): Promise<AudioWorkletNode>;
221
273
  /**
222
274
  * Idempotently registers the DattorroReverb AudioWorkletProcessor on this
223
275
  * context. Safe to call repeatedly — subsequent calls short-circuit via
@@ -243,6 +295,137 @@ export declare class Cacophony {
243
295
  * for the cross-context rationale.
244
296
  */
245
297
  createDattorroReverbNode(options: AudioWorkletNodeOptions, context?: BaseContext): Promise<AudioWorkletNode>;
298
+ /**
299
+ * Idempotently registers the `dynamics` AudioWorkletProcessor (feed-forward
300
+ * compressor/limiter/expander/gate, Giannoulis 2012) on this context. Safe to
301
+ * call repeatedly — subsequent calls short-circuit via the per-context
302
+ * {@link loadedAudioWorklets} set. Cross-context: pass `context` so a
303
+ * {@link DynamicsEffect} added to a bus on a different context loads there.
304
+ */
305
+ loadDynamics(signal?: AbortSignal, context?: BaseContext): Promise<void>;
306
+ /**
307
+ * Constructs a `dynamics` AudioWorkletNode. Caller is expected to have loaded
308
+ * the module already (via {@link loadDynamics} or by reaching here through
309
+ * {@link DynamicsEffect.build}). Uses the same construct/fallback path as
310
+ * {@link createWorkletNode}.
311
+ */
312
+ createDynamicsNode(options: AudioWorkletNodeOptions, context?: BaseContext): Promise<AudioWorkletNode>;
313
+ /**
314
+ * Idempotently registers the `fdn-reverb` AudioWorkletProcessor (Feedback
315
+ * Delay Network reverb — lossless paraunitary Hadamard feedback per Schlecht
316
+ * & Habets 2019, per-line absorption T60 per Jot 1991, velvet-noise diffusion
317
+ * per Fagerström 2020) on this context. Safe to call repeatedly — subsequent
318
+ * calls short-circuit via the per-context {@link loadedAudioWorklets} set.
319
+ * Cross-context: pass `context` so an {@link FdnReverbEffect} added to a bus
320
+ * on a different context loads there.
321
+ */
322
+ loadFdnReverb(signal?: AbortSignal, context?: BaseContext): Promise<void>;
323
+ /**
324
+ * Constructs an `fdn-reverb` AudioWorkletNode. Caller is expected to have
325
+ * loaded the module already (via {@link loadFdnReverb} or by reaching here
326
+ * through {@link FdnReverbEffect.build}). Uses the same construct/fallback
327
+ * path as {@link createWorkletNode}.
328
+ */
329
+ createFdnReverbNode(options: AudioWorkletNodeOptions, context?: BaseContext): Promise<AudioWorkletNode>;
330
+ /**
331
+ * Idempotently registers the `waveshaper` AudioWorkletProcessor (antialiased
332
+ * distortion/waveshaper via first-order Antiderivative Antialiasing, Parker,
333
+ * Zavalishin & Le Bivic 2016, DAFx-16) on this context. Safe to call
334
+ * repeatedly — subsequent calls short-circuit via the per-context
335
+ * {@link loadedAudioWorklets} set. Cross-context: pass `context` so a
336
+ * {@link WaveshaperEffect} added to a bus on a different context loads there.
337
+ */
338
+ loadWaveshaper(signal?: AbortSignal, context?: BaseContext): Promise<void>;
339
+ /**
340
+ * Constructs a `waveshaper` AudioWorkletNode. Caller is expected to have
341
+ * loaded the module already (via {@link loadWaveshaper} or by reaching here
342
+ * through {@link WaveshaperEffect.build}). Uses the same construct/fallback
343
+ * path as {@link createWorkletNode}.
344
+ */
345
+ createWaveshaperNode(options: AudioWorkletNodeOptions, context?: BaseContext): Promise<AudioWorkletNode>;
346
+ /**
347
+ * Idempotently registers the `modulated-delay` AudioWorkletProcessor —
348
+ * Dattorro's unified modulated-delay circuit (JAES 1997, Fig. 36) backing
349
+ * delay/chorus/flanger/vibrato/doubling, with Lagrange FIR fractional-delay
350
+ * interpolation (Laakso 1996) — on this context. Safe to call repeatedly —
351
+ * subsequent calls short-circuit via the per-context {@link loadedAudioWorklets}
352
+ * set. Cross-context: pass `context` so a {@link ModulatedDelayEffect} added to
353
+ * a bus on a different context loads there.
354
+ */
355
+ loadModulatedDelay(signal?: AbortSignal, context?: BaseContext): Promise<void>;
356
+ /**
357
+ * Constructs a `modulated-delay` AudioWorkletNode. Caller is expected to have
358
+ * loaded the module already (via {@link loadModulatedDelay} or by reaching here
359
+ * through {@link ModulatedDelayEffect.build}). Uses the same construct/fallback
360
+ * path as {@link createWorkletNode}.
361
+ */
362
+ createModulatedDelayNode(options: AudioWorkletNodeOptions, context?: BaseContext): Promise<AudioWorkletNode>;
363
+ /**
364
+ * Idempotently registers the `phaser` AudioWorkletProcessor — a classic
365
+ * MXR/Univibe-style allpass-cascade phase shifter (Smith STAN-M-21; PASP §8.9:
366
+ * a cascade of first-order allpass sections at a common LFO-swept break
367
+ * frequency, summed additively with the dry signal to sweep notches) on this
368
+ * context. Safe to call repeatedly — subsequent calls short-circuit via the
369
+ * per-context {@link loadedAudioWorklets} set. Cross-context: pass `context` so
370
+ * a {@link PhaserEffect} added to a bus on a different context loads there.
371
+ */
372
+ loadPhaser(signal?: AbortSignal, context?: BaseContext): Promise<void>;
373
+ /**
374
+ * Constructs a `phaser` AudioWorkletNode. Caller is expected to have loaded the
375
+ * module already (via {@link loadPhaser} or by reaching here through
376
+ * {@link PhaserEffect.build}). Uses the same construct/fallback path as
377
+ * {@link createWorkletNode}.
378
+ */
379
+ createPhaserNode(options: AudioWorkletNodeOptions, context?: BaseContext): Promise<AudioWorkletNode>;
380
+ /**
381
+ * Idempotently registers the `tremolo` AudioWorkletProcessor — LFO-driven
382
+ * amplitude modulation (a VCA swung by a low-frequency oscillator; standard AM
383
+ * theory + Dattorro 1997 p.776 quadrature stereo LFO + Mitcheltree et al.
384
+ * DAFx23 LFO framing) on this context. Safe to call repeatedly — subsequent
385
+ * calls short-circuit via the per-context {@link loadedAudioWorklets} set.
386
+ * Cross-context: pass `context` so a {@link TremoloEffect} added to a bus on a
387
+ * different context loads there.
388
+ */
389
+ loadTremolo(signal?: AbortSignal, context?: BaseContext): Promise<void>;
390
+ /**
391
+ * Constructs a `tremolo` AudioWorkletNode. Caller is expected to have loaded the
392
+ * module already (via {@link loadTremolo} or by reaching here through
393
+ * {@link TremoloEffect.build}). Uses the same construct/fallback path as
394
+ * {@link createWorkletNode}.
395
+ */
396
+ createTremoloNode(options: AudioWorkletNodeOptions, context?: BaseContext): Promise<AudioWorkletNode>;
397
+ /**
398
+ * Idempotently registers the `loudness-meter` AudioWorkletProcessor (ITU-R
399
+ * BS.1770-5 momentary / short-term / integrated loudness + true-peak) on this
400
+ * context. Safe to call repeatedly — subsequent calls short-circuit via the
401
+ * per-context {@link loadedAudioWorklets} set. Cross-context: pass `context`
402
+ * so a meter tapping a bus on a different context loads there.
403
+ */
404
+ loadLoudnessMeter(signal?: AbortSignal, context?: BaseContext): Promise<void>;
405
+ /**
406
+ * Constructs a `loudness-meter` AudioWorkletNode. Caller is expected to have
407
+ * loaded the module already (via {@link loadLoudnessMeter} or {@link createLoudnessMeter}).
408
+ * The node is a PASS-THROUGH metering tap (1 input, 1 output) that posts
409
+ * momentary/short-term/integrated loudness and true-peak back over its port.
410
+ */
411
+ createLoudnessMeterNode(options?: AudioWorkletNodeOptions, context?: BaseContext): Promise<AudioWorkletNode>;
412
+ /**
413
+ * Fetches and decodes the bundled order-1 SH-HRIR
414
+ * (`sh_hrir_order_1.wav`, from Omnitone, Apache-2.0 — see
415
+ * `src/assets/NOTICE`) into an `AudioBuffer`, memoized per context. The
416
+ * buffer is the 4-channel (ACN rows W,Y,Z,X) SH-domain HRIR consumed by
417
+ * {@link FoaDecoder} to drive its WY/ZX stereo ConvolverNodes
418
+ * (Ahrens 2022 eq.31 decode).
419
+ *
420
+ * The WAV is 48 kHz; `decodeAudioData` resamples it to the context's sample
421
+ * rate automatically when they differ (standard Web Audio behavior, which
422
+ * Omnitone relies on).
423
+ *
424
+ * @param context Optional BaseContext to decode on. Defaults to this host's
425
+ * own `context`. Supplied so a {@link FoaDecoder} added to a bus on
426
+ * a different context decodes the HRIR on the right context.
427
+ */
428
+ loadFoaHrir(context?: BaseContext): Promise<AudioBuffer>;
246
429
  createWorkletNode(name: string, url: string, signal?: AbortSignal, options?: AudioWorkletNodeOptions, context?: BaseContext): Promise<AudioWorkletNode>;
247
430
  createStereoToBFormatNode(signal?: AbortSignal): Promise<AudioWorkletNode>;
248
431
  /**
@@ -346,6 +529,180 @@ export declare class Cacophony {
346
529
  * chain via `bus.addFilter(effect)`.
347
530
  */
348
531
  createReverb(options?: ReverbOptions): ReverbEffect;
532
+ /**
533
+ * Creates a Feedback Delay Network (FDN) {@link CacophonyEffect} — an
534
+ * algorithmic reverb with a lossless degree-0 paraunitary Hadamard feedback
535
+ * matrix (Schlecht & Habets 2019), per-delay-line absorption filters setting
536
+ * the reverberation time T60 (Jot & Chaigne 1991), and multiplication-free
537
+ * velvet-noise input diffusion (Fagerström et al. 2020). The effect's
538
+ * `build` lazily registers the worklet module (no-op if already loaded) and
539
+ * constructs the AudioWorkletNode with the supplied {@link FdnReverbOptions}
540
+ * as `parameterData`. Add the returned effect to a {@link Bus} via
541
+ * `bus.addFilter(effect)`.
542
+ */
543
+ createFdnReverb(options?: FdnReverbOptions): FdnReverbEffect;
544
+ /**
545
+ * Creates a dynamics {@link CacophonyEffect} configured as a COMPRESSOR
546
+ * (ratio > 1 reduces the level of signals above threshold). Implements the
547
+ * feed-forward design of Giannoulis, Massberg & Reiss 2012. Add the returned
548
+ * effect to a {@link Bus} via `bus.addFilter(effect)`. The same machinery
549
+ * (gain computer + log-domain smooth-branching detector) backs the limiter
550
+ * and gate presets below.
551
+ */
552
+ createCompressor(options?: DynamicsOptions): DynamicsEffect;
553
+ /**
554
+ * Creates a dynamics {@link CacophonyEffect} preset as a LIMITER — a
555
+ * compressor with an effectively infinite ratio so output is clamped at the
556
+ * threshold (Giannoulis 2012 eqs 18-19). The ratio is fixed to the worklet's
557
+ * limiter sentinel; caller-supplied `ratio` is ignored. Other params
558
+ * (threshold, knee, attack, release, makeup) remain configurable.
559
+ */
560
+ createLimiter(options?: Omit<DynamicsOptions, "ratio">): DynamicsEffect;
561
+ /**
562
+ * Creates a dynamics {@link CacophonyEffect} preset as a downward EXPANDER /
563
+ * GATE — ratio < 1 so signals BELOW the threshold are pushed further down
564
+ * (Giannoulis 2012 p.403). The default `ratio` of 0.1 gives gate-like
565
+ * downward expansion; pass a `ratio` closer to 1 for gentler expansion.
566
+ */
567
+ createGate(options?: DynamicsOptions): DynamicsEffect;
568
+ /**
569
+ * Creates a {@link WaveshaperEffect} — an antialiased distortion/waveshaper
570
+ * implementing first-order Antiderivative Antialiasing (Parker, Zavalishin &
571
+ * Le Bivic 2016, DAFx-16): y[n] = (F0(x_n) - F0(x_{n-1}))/(x_n - x_{n-1})
572
+ * (eq.9), with an f(midpoint) fallback at the 0/0 singularity (eq.10). Ships
573
+ * two nonlinearities — `shape: 0` hard clip (polynomial F0, eq.25), `shape: 1`
574
+ * tanh soft clip (F0 = log cosh, eq.20). Carries an inherent 0.5-sample group
575
+ * delay (eq.17). Add the returned effect to a {@link Bus} via
576
+ * `bus.addFilter(effect)`.
577
+ */
578
+ createWaveshaper(options?: WaveshaperOptions): WaveshaperEffect;
579
+ /**
580
+ * Creates a {@link WaveshaperEffect} preset as a DISTORTION — the tanh soft
581
+ * clipper (`shape: 1`, F0 = log cosh, Parker 2016 eq.20) with a default drive
582
+ * of 4 for an audible saturated tone. A convenience wrapper over
583
+ * {@link createWaveshaper}; caller-supplied options override the defaults.
584
+ */
585
+ createDistortion(options?: WaveshaperOptions): WaveshaperEffect;
586
+ /**
587
+ * Creates a {@link ModulatedDelayEffect} preset as a DELAY / ECHO — Dattorro's
588
+ * unified modulated-delay circuit (JAES 1997, Fig. 36) with the modulation OFF
589
+ * (`depth: 0`, `rate: 0`). Echo knobs (Table 6): full dry `blend: 1` plus a
590
+ * unity wet tap `feedforward: 1`; feedback defaults to 0 (a single tap) but is
591
+ * caller-configurable for a regenerating echo (|feedback| < 1, Table 6). The
592
+ * 250 ms tap sits in the echo range (Table 7). All knobs are exposed.
593
+ */
594
+ createDelay(options?: ModulatedDelayOptions): ModulatedDelayEffect;
595
+ /**
596
+ * Creates a {@link ModulatedDelayEffect} preset as a (white) CHORUS — Dattorro
597
+ * Table 6 white-chorus knobs `blend: 0.7071`, `feedforward: 1`,
598
+ * `feedback: 0.7071` (blend = feedback, feedforward = 1, the negative-feedback
599
+ * path that minimizes the spectral aberration of a plain dry+wet chorus). A
600
+ * 9 ms tap modulated 4 ms at 0.5 Hz sits in the chorus range (Table 7).
601
+ *
602
+ * NOTE: Dattorro's white chorus (p.776) combines this negative-feedback path
603
+ * with ALLPASS fractional-delay interpolation. This implementation uses the
604
+ * white-chorus knob settings but substitutes cubic-Lagrange interpolation
605
+ * (Laakso 1996) — transient-safe under modulation (Laakso p.52), trading some
606
+ * high-frequency trough depth versus a true allpass-interpolated white chorus.
607
+ */
608
+ createChorus(options?: ModulatedDelayOptions): ModulatedDelayEffect;
609
+ /**
610
+ * Creates a {@link ModulatedDelayEffect} preset as a FLANGER — Dattorro Table 6
611
+ * flanger knobs `blend: 0.7071`, `feedforward: 0.7071` (blend = feedforward for
612
+ * the deepest comb trough), `feedback: -0.7071` (negative feedback deepens the
613
+ * troughs). A short 5 ms tap swept 4 ms at 0.25 Hz gives the classic flange
614
+ * (Table 7).
615
+ */
616
+ createFlanger(options?: ModulatedDelayOptions): ModulatedDelayEffect;
617
+ /**
618
+ * Creates a {@link ModulatedDelayEffect} preset as a VIBRATO — Dattorro Table 6
619
+ * vibrato knobs `blend: 0`, `feedforward: 1`, `feedback: 0` (100% wet, no dry
620
+ * path, no feedback), so only the pitch-modulated delayed signal is heard. A
621
+ * 5 ms tap swept 3 ms at 5 Hz (Table 7).
622
+ */
623
+ createVibrato(options?: ModulatedDelayOptions): ModulatedDelayEffect;
624
+ /**
625
+ * Creates a {@link ModulatedDelayEffect} preset as DOUBLING ("double tracking")
626
+ * — Dattorro Table 6 doubling knobs `blend: 0.7071`, `feedforward: 0.7071`,
627
+ * `feedback: 0` (no feedback). A ~20 ms tap (Table 7 doubling nominal) with a
628
+ * gentle 1 ms / 0.4 Hz wobble fattens a single take into two.
629
+ */
630
+ createDoubling(options?: ModulatedDelayOptions): ModulatedDelayEffect;
631
+ /**
632
+ * Creates a {@link PhaserEffect} — a classic MXR/Univibe-style phase shifter: a
633
+ * cascade of first-order allpass sections at a common LFO-swept break frequency
634
+ * summed additively with the dry signal to sweep notches through the spectrum
635
+ * (Smith STAN-M-21; PASP §8.9). Two allpass sections per notch (default 4
636
+ * sections = 2 notches). Add the returned effect to a {@link Bus} via
637
+ * `bus.addFilter(effect)`.
638
+ */
639
+ createPhaser(options?: PhaserOptions): PhaserEffect;
640
+ /**
641
+ * Creates a {@link TremoloEffect} — LFO-driven amplitude modulation (a VCA
642
+ * swung by a low-frequency oscillator). The gain swings between (1 - depth)
643
+ * and 1, never inverting (a true tremolo, not ring modulation). Anchored to
644
+ * standard AM theory, Dattorro 1997 (p.776) for the quadrature stereo LFO, and
645
+ * Mitcheltree et al. (DAFx23) for the LFO-driven-effect framing. `shape` selects
646
+ * the LFO waveform (0 = sine, 1 = triangle, 2 = square); `stereoPhase` offsets
647
+ * the per-channel LFO. Add the returned effect to a {@link Bus} via
648
+ * `bus.addFilter(effect)`.
649
+ */
650
+ createTremolo(options?: TremoloOptions): TremoloEffect;
651
+ /**
652
+ * Creates a {@link TremoloEffect} preset as an AUTO-PAN — a tremolo with
653
+ * `stereoPhase: 180`, so the left and right channel gains modulate in
654
+ * anti-phase (the sound swings hard between the speakers). The 180-deg
655
+ * per-channel LFO offset is Dattorro's stereo-modulation convention (p.776). A
656
+ * convenience wrapper over {@link createTremolo}; caller options override the
657
+ * preset.
658
+ */
659
+ createAutoPan(options?: TremoloOptions): TremoloEffect;
660
+ /** The default audio context for this Cacophony instance (used by
661
+ * {@link FoaDecoder} when no explicit context is supplied). */
662
+ defaultContext(): BaseContext;
663
+ /**
664
+ * Creates a {@link FoaDecoder} — a standalone first-order ambisonic (FOA) ->
665
+ * binaural FORMAT CONVERTER built from native Web Audio nodes (no worklet).
666
+ * It decodes a 4-channel ACN/SN3D `[W, Y, Z, X]` signal to headphone stereo
667
+ * via the per-SH-channel HRIR decode of Ahrens 2022 (eq.31), using
668
+ * Omnitone's WY/ZX 2-stereo-ConvolverNode packing and the bundled order-1
669
+ * SH-HRIR.
670
+ *
671
+ * It is 4-channel-in / 2-channel-out, so it is NOT a `CacophonyEffect` and is
672
+ * NOT added via `bus.addFilter`. Wire it EXPLICITLY using its two endpoints:
673
+ * feed FOA into `decoder.input` (4-ch) and route `decoder.output` (2-ch
674
+ * stereo) downstream:
675
+ * ```ts
676
+ * const decoder = await cacophony.createFoaDecoder();
677
+ * foaSource.connect(decoder.input);
678
+ * decoder.output.connect(bus.input); // or context.destination
679
+ * ```
680
+ * Build is async (the bundled HRIR is fetched + decoded). Pair it with
681
+ * {@link encodeMonoToFoaSN3D} (clean, physically correct) or with
682
+ * `createStereoToBFormatNode` (the perceptual, approximate stereo-upmix path).
683
+ */
684
+ createFoaDecoder(options?: FoaDecoderOptions, context?: BaseContext): Promise<FoaDecoder>;
685
+ /**
686
+ * Creates an ITU-R BS.1770-5 {@link LoudnessMeter} that TAPS the output of a
687
+ * target node without altering the audible path. The meter reports momentary
688
+ * (400 ms), short-term (3 s), and gated integrated loudness in LKFS/LUFS, plus
689
+ * true-peak level in dBTP (Annex 2 4× oversampling).
690
+ *
691
+ * The tap is a BRANCH: the target's output is connected to the metering
692
+ * worklet in ADDITION to its existing forward edge, and the worklet's output
693
+ * is routed through an owned zero-gain sink to keep the branch silent and live.
694
+ * By default the target is the
695
+ * master bus output (`master.output`), measuring everything that reaches the
696
+ * destination — the integrated-loudness target. Pass a {@link Bus} to meter
697
+ * one bus's output, or any {@link AudioNode} to meter that node.
698
+ *
699
+ * Lazily registers the `loudness-meter` worklet module (no-op if already
700
+ * loaded) on the target's context, then constructs the node and branch-taps.
701
+ *
702
+ * @param target Node or bus whose output to meter. Defaults to the master bus.
703
+ * @returns A {@link LoudnessMeter} handle exposing the live readings.
704
+ */
705
+ createLoudnessMeter(target?: Bus | AudioNode): Promise<LoudnessMeter>;
349
706
  /**
350
707
  * Creates a new {@link Bus}. If `name` is provided, the bus is registered
351
708
  * so {@link getBus} can look it up by name. Anonymous buses (no name) are
package/dist/context.d.ts CHANGED
@@ -62,8 +62,21 @@ export interface ChannelSplitterNode extends AudioNode {
62
62
  }
63
63
  export interface ChannelMergerNode extends AudioNode {
64
64
  }
65
+ export interface ConvolverNode extends AudioNode {
66
+ buffer: AudioBuffer | null;
67
+ normalize: boolean;
68
+ }
65
69
  export interface AudioWorkletNode extends AudioNode {
66
70
  readonly port: MessagePort;
71
+ /**
72
+ * The node's AudioParam map (Web Audio `AudioParamMap`). Modelled as the
73
+ * minimal `get(name)` surface this library uses to drive worklet params
74
+ * (e.g. the phase-vocoder `pitchFactor`). Optional because test/mock
75
+ * contexts may not synthesise the param map.
76
+ */
77
+ readonly parameters?: {
78
+ get(name: string): AudioParam | undefined;
79
+ };
67
80
  }
68
81
  export interface AudioBufferSourceNode extends AudioNode {
69
82
  buffer: AudioBuffer | null;
@@ -125,6 +138,8 @@ export interface BaseContext {
125
138
  createStereoPanner(): StereoPannerNode;
126
139
  createChannelSplitter?(numberOfOutputs?: number): ChannelSplitterNode;
127
140
  createChannelMerger?(numberOfInputs?: number): ChannelMergerNode;
141
+ createConvolver?(): ConvolverNode;
142
+ createBuffer?(numberOfChannels: number, length: number, sampleRate: number): AudioBuffer;
128
143
  createOscillator(): OscillatorNode;
129
144
  decodeAudioData(audioData: ArrayBuffer): Promise<AudioBuffer>;
130
145
  decodeAudioData(audioData: ArrayBuffer, successCallback: (buffer: AudioBuffer) => void, errorCallback?: (error: DOMException) => void): Promise<AudioBuffer>;