cacophony 0.30.4 → 0.31.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 (444) hide show
  1. package/README.md +94 -8
  2. package/dist/_virtual/_rolldown/runtime.cjs +1 -0
  3. package/dist/assets/sh_hrir_order_1.wav_url.cjs +2 -0
  4. package/dist/assets/sh_hrir_order_1.wav_url.cjs.map +1 -0
  5. package/dist/assets/sh_hrir_order_1.wav_url.mjs +6 -0
  6. package/dist/assets/sh_hrir_order_1.wav_url.mjs.map +1 -0
  7. package/dist/audioSprite.cjs +2 -0
  8. package/dist/audioSprite.cjs.map +1 -0
  9. package/dist/audioSprite.d.ts +29 -0
  10. package/dist/audioSprite.mjs +26 -0
  11. package/dist/audioSprite.mjs.map +1 -0
  12. package/dist/autoplayUnlock.cjs +2 -0
  13. package/dist/autoplayUnlock.cjs.map +1 -0
  14. package/dist/autoplayUnlock.mjs +58 -0
  15. package/dist/autoplayUnlock.mjs.map +1 -0
  16. package/dist/basePlayback.cjs +2 -0
  17. package/dist/basePlayback.cjs.map +1 -0
  18. package/dist/basePlayback.d.ts +7 -4
  19. package/dist/basePlayback.mjs +157 -0
  20. package/dist/basePlayback.mjs.map +1 -0
  21. package/dist/bundles/barberpole-bundle.js_url.cjs +2 -0
  22. package/dist/bundles/barberpole-bundle.js_url.cjs.map +1 -0
  23. package/dist/bundles/barberpole-bundle.js_url.mjs +6 -0
  24. package/dist/bundles/barberpole-bundle.js_url.mjs.map +1 -0
  25. package/dist/bundles/bcc-encoder-bundle.js_url.cjs +2 -0
  26. package/dist/bundles/bcc-encoder-bundle.js_url.cjs.map +1 -0
  27. package/dist/bundles/bcc-encoder-bundle.js_url.mjs +6 -0
  28. package/dist/bundles/bcc-encoder-bundle.js_url.mjs.map +1 -0
  29. package/dist/bundles/dattorro-reverb-bundle.js_url.cjs +2 -0
  30. package/dist/bundles/dattorro-reverb-bundle.js_url.cjs.map +1 -0
  31. package/dist/bundles/dattorro-reverb-bundle.js_url.mjs +6 -0
  32. package/dist/bundles/dattorro-reverb-bundle.js_url.mjs.map +1 -0
  33. package/dist/bundles/dynamics-bundle.js_url.cjs +2 -0
  34. package/dist/bundles/dynamics-bundle.js_url.cjs.map +1 -0
  35. package/dist/bundles/dynamics-bundle.js_url.mjs +6 -0
  36. package/dist/bundles/dynamics-bundle.js_url.mjs.map +1 -0
  37. package/dist/bundles/fdn-reverb-bundle.js_url.cjs +2 -0
  38. package/dist/bundles/fdn-reverb-bundle.js_url.cjs.map +1 -0
  39. package/dist/bundles/fdn-reverb-bundle.js_url.mjs +6 -0
  40. package/dist/bundles/fdn-reverb-bundle.js_url.mjs.map +1 -0
  41. package/dist/bundles/frequency-shifter-bundle.js_url.cjs +2 -0
  42. package/dist/bundles/frequency-shifter-bundle.js_url.cjs.map +1 -0
  43. package/dist/bundles/frequency-shifter-bundle.js_url.mjs +6 -0
  44. package/dist/bundles/frequency-shifter-bundle.js_url.mjs.map +1 -0
  45. package/dist/bundles/harmonizer-bundle.js_url.cjs +2 -0
  46. package/dist/bundles/harmonizer-bundle.js_url.cjs.map +1 -0
  47. package/dist/bundles/harmonizer-bundle.js_url.mjs +6 -0
  48. package/dist/bundles/harmonizer-bundle.js_url.mjs.map +1 -0
  49. package/dist/bundles/loudness-meter-bundle.js_url.cjs +2 -0
  50. package/dist/bundles/loudness-meter-bundle.js_url.cjs.map +1 -0
  51. package/dist/bundles/loudness-meter-bundle.js_url.mjs +6 -0
  52. package/dist/bundles/loudness-meter-bundle.js_url.mjs.map +1 -0
  53. package/dist/bundles/modulated-delay-bundle.js_url.cjs +2 -0
  54. package/dist/bundles/modulated-delay-bundle.js_url.cjs.map +1 -0
  55. package/dist/bundles/modulated-delay-bundle.js_url.mjs +6 -0
  56. package/dist/bundles/modulated-delay-bundle.js_url.mjs.map +1 -0
  57. package/dist/bundles/pcm-stream-bundle.js_url.cjs +2 -0
  58. package/dist/bundles/pcm-stream-bundle.js_url.cjs.map +1 -0
  59. package/dist/bundles/pcm-stream-bundle.js_url.mjs +6 -0
  60. package/dist/bundles/pcm-stream-bundle.js_url.mjs.map +1 -0
  61. package/dist/bundles/phase-vocoder-bundle.js_url.cjs +2 -0
  62. package/dist/bundles/phase-vocoder-bundle.js_url.cjs.map +1 -0
  63. package/dist/bundles/phase-vocoder-bundle.js_url.mjs +6 -0
  64. package/dist/bundles/phase-vocoder-bundle.js_url.mjs.map +1 -0
  65. package/dist/bundles/phaser-bundle.js_url.cjs +2 -0
  66. package/dist/bundles/phaser-bundle.js_url.cjs.map +1 -0
  67. package/dist/bundles/phaser-bundle.js_url.mjs +6 -0
  68. package/dist/bundles/phaser-bundle.js_url.mjs.map +1 -0
  69. package/dist/bundles/spectral-freeze-bundle.js_url.cjs +2 -0
  70. package/dist/bundles/spectral-freeze-bundle.js_url.cjs.map +1 -0
  71. package/dist/bundles/spectral-freeze-bundle.js_url.mjs +6 -0
  72. package/dist/bundles/spectral-freeze-bundle.js_url.mjs.map +1 -0
  73. package/dist/bundles/stereo-to-bformat-bundle.js_url.cjs +2 -0
  74. package/dist/bundles/stereo-to-bformat-bundle.js_url.cjs.map +1 -0
  75. package/dist/bundles/stereo-to-bformat-bundle.js_url.mjs +6 -0
  76. package/dist/bundles/stereo-to-bformat-bundle.js_url.mjs.map +1 -0
  77. package/dist/bundles/stereo-widener-bundle.js_url.cjs +2 -0
  78. package/dist/bundles/stereo-widener-bundle.js_url.cjs.map +1 -0
  79. package/dist/bundles/stereo-widener-bundle.js_url.mjs +6 -0
  80. package/dist/bundles/stereo-widener-bundle.js_url.mjs.map +1 -0
  81. package/dist/bundles/tremolo-bundle.js_url.cjs +2 -0
  82. package/dist/bundles/tremolo-bundle.js_url.cjs.map +1 -0
  83. package/dist/bundles/tremolo-bundle.js_url.mjs +6 -0
  84. package/dist/bundles/tremolo-bundle.js_url.mjs.map +1 -0
  85. package/dist/bundles/waveshaper-bundle.js_url.cjs +2 -0
  86. package/dist/bundles/waveshaper-bundle.js_url.cjs.map +1 -0
  87. package/dist/bundles/waveshaper-bundle.js_url.mjs +6 -0
  88. package/dist/bundles/waveshaper-bundle.js_url.mjs.map +1 -0
  89. package/dist/bus.cjs +2 -0
  90. package/dist/bus.cjs.map +1 -0
  91. package/dist/bus.mjs +156 -0
  92. package/dist/bus.mjs.map +1 -0
  93. package/dist/cache.cjs +2 -0
  94. package/dist/cache.cjs.map +1 -0
  95. package/dist/cache.mjs +453 -0
  96. package/dist/cache.mjs.map +1 -0
  97. package/dist/cacophony.cjs +2 -0
  98. package/dist/cacophony.cjs.map +1 -0
  99. package/dist/cacophony.d.ts +16 -5
  100. package/dist/cacophony.mjs +791 -0
  101. package/dist/cacophony.mjs.map +1 -0
  102. package/dist/cli/audio-sink.cjs +2 -0
  103. package/dist/cli/audio-sink.cjs.map +1 -0
  104. package/dist/cli/audio-sink.mjs +8 -0
  105. package/dist/cli/audio-sink.mjs.map +1 -0
  106. package/dist/cli/commands.cjs +2 -0
  107. package/dist/cli/commands.cjs.map +1 -0
  108. package/dist/cli/commands.mjs +109 -0
  109. package/dist/cli/commands.mjs.map +1 -0
  110. package/dist/cli/effects-registry.cjs +2 -0
  111. package/dist/cli/effects-registry.cjs.map +1 -0
  112. package/dist/cli/effects-registry.mjs +221 -0
  113. package/dist/cli/effects-registry.mjs.map +1 -0
  114. package/dist/cli/index.cjs +8 -41
  115. package/dist/cli/index.cjs.map +1 -1
  116. package/dist/cli/index.mjs +98 -1053
  117. package/dist/cli/index.mjs.map +1 -1
  118. package/dist/cli/live.cjs +2 -0
  119. package/dist/cli/live.cjs.map +1 -0
  120. package/dist/cli/live.mjs +52 -0
  121. package/dist/cli/live.mjs.map +1 -0
  122. package/dist/cli/logging.cjs +2 -0
  123. package/dist/cli/logging.cjs.map +1 -0
  124. package/dist/cli/logging.mjs +15 -0
  125. package/dist/cli/logging.mjs.map +1 -0
  126. package/dist/cli/meter.cjs +2 -0
  127. package/dist/cli/meter.cjs.map +1 -0
  128. package/dist/cli/meter.mjs +44 -0
  129. package/dist/cli/meter.mjs.map +1 -0
  130. package/dist/cli/render.cjs +2 -0
  131. package/dist/cli/render.cjs.map +1 -0
  132. package/dist/cli/render.mjs +92 -0
  133. package/dist/cli/render.mjs.map +1 -0
  134. package/dist/cli/repl.cjs +41 -0
  135. package/dist/cli/repl.cjs.map +1 -0
  136. package/dist/cli/repl.mjs +317 -0
  137. package/dist/cli/repl.mjs.map +1 -0
  138. package/dist/cli/replay.cjs +2 -0
  139. package/dist/cli/replay.cjs.map +1 -0
  140. package/dist/cli/replay.mjs +86 -0
  141. package/dist/cli/replay.mjs.map +1 -0
  142. package/dist/cli/session.cjs +2 -0
  143. package/dist/cli/session.cjs.map +1 -0
  144. package/dist/cli/session.mjs +54 -0
  145. package/dist/cli/session.mjs.map +1 -0
  146. package/dist/cli/sprite.cjs +2 -0
  147. package/dist/cli/sprite.cjs.map +1 -0
  148. package/dist/cli/sprite.d.ts +21 -0
  149. package/dist/cli/sprite.mjs +68 -0
  150. package/dist/cli/sprite.mjs.map +1 -0
  151. package/dist/cli/wav.cjs +2 -0
  152. package/dist/cli/wav.cjs.map +1 -0
  153. package/dist/cli/wav.mjs +25 -0
  154. package/dist/cli/wav.mjs.map +1 -0
  155. package/dist/container.cjs +2 -0
  156. package/dist/container.cjs.map +1 -0
  157. package/dist/container.d.ts +2 -2
  158. package/dist/container.mjs +110 -0
  159. package/dist/container.mjs.map +1 -0
  160. package/dist/effectChain.cjs +2 -0
  161. package/dist/effectChain.cjs.map +1 -0
  162. package/dist/effectChain.mjs +151 -0
  163. package/dist/effectChain.mjs.map +1 -0
  164. package/dist/effects.cjs +2 -0
  165. package/dist/effects.cjs.map +1 -0
  166. package/dist/effects.mjs +249 -0
  167. package/dist/effects.mjs.map +1 -0
  168. package/dist/eventEmitter.cjs +2 -0
  169. package/dist/eventEmitter.cjs.map +1 -0
  170. package/dist/eventEmitter.mjs +42 -0
  171. package/dist/eventEmitter.mjs.map +1 -0
  172. package/dist/filters.cjs +2 -0
  173. package/dist/filters.cjs.map +1 -0
  174. package/dist/filters.mjs +25 -0
  175. package/dist/filters.mjs.map +1 -0
  176. package/dist/group.cjs +2 -0
  177. package/dist/group.cjs.map +1 -0
  178. package/dist/group.mjs +110 -0
  179. package/dist/group.mjs.map +1 -0
  180. package/dist/hlsAdapter.cjs +2 -0
  181. package/dist/hlsAdapter.cjs.map +1 -0
  182. package/dist/hlsAdapter.mjs +47 -0
  183. package/dist/hlsAdapter.mjs.map +1 -0
  184. package/dist/index.cjs +1 -1
  185. package/dist/index.d.ts +5 -1
  186. package/dist/index.mjs +21 -3
  187. package/dist/logger.cjs +2 -0
  188. package/dist/logger.cjs.map +1 -0
  189. package/dist/logger.mjs +14 -0
  190. package/dist/logger.mjs.map +1 -0
  191. package/dist/mediaStream.cjs +2 -0
  192. package/dist/mediaStream.cjs.map +1 -0
  193. package/dist/mediaStream.d.ts +3 -2
  194. package/dist/mediaStream.mjs +130 -0
  195. package/dist/mediaStream.mjs.map +1 -0
  196. package/dist/meters/loudness-core.cjs +2 -0
  197. package/dist/meters/loudness-core.cjs.map +1 -0
  198. package/dist/meters/loudness-core.mjs +177 -0
  199. package/dist/meters/loudness-core.mjs.map +1 -0
  200. package/dist/meters/loudness-meter.cjs +2 -0
  201. package/dist/meters/loudness-meter.cjs.map +1 -0
  202. package/dist/meters/loudness-meter.mjs +63 -0
  203. package/dist/meters/loudness-meter.mjs.map +1 -0
  204. package/dist/meters/truepeak-core.cjs +2 -0
  205. package/dist/meters/truepeak-core.cjs.map +1 -0
  206. package/dist/meters/truepeak-core.mjs +125 -0
  207. package/dist/meters/truepeak-core.mjs.map +1 -0
  208. package/dist/microphone.cjs +2 -0
  209. package/dist/microphone.cjs.map +1 -0
  210. package/dist/microphone.mjs +20 -0
  211. package/dist/microphone.mjs.map +1 -0
  212. package/dist/node.cjs +2 -2
  213. package/dist/node.cjs.map +1 -1
  214. package/dist/node.mjs +1 -1
  215. package/dist/oscillatorMixin.cjs +2 -0
  216. package/dist/oscillatorMixin.cjs.map +1 -0
  217. package/dist/oscillatorMixin.mjs +39 -0
  218. package/dist/oscillatorMixin.mjs.map +1 -0
  219. package/dist/pannerMixin.cjs +2 -0
  220. package/dist/pannerMixin.cjs.map +1 -0
  221. package/dist/pannerMixin.mjs +81 -0
  222. package/dist/pannerMixin.mjs.map +1 -0
  223. package/dist/pcmStream.cjs +2 -0
  224. package/dist/pcmStream.cjs.map +1 -0
  225. package/dist/pcmStream.d.ts +3 -3
  226. package/dist/pcmStream.mjs +179 -0
  227. package/dist/pcmStream.mjs.map +1 -0
  228. package/dist/playback.cjs +2 -0
  229. package/dist/playback.cjs.map +1 -0
  230. package/dist/playback.d.ts +9 -2
  231. package/dist/playback.mjs +274 -0
  232. package/dist/playback.mjs.map +1 -0
  233. package/dist/processors/dynamics-core.cjs +2 -0
  234. package/dist/processors/dynamics-core.cjs.map +1 -0
  235. package/dist/processors/dynamics-core.mjs +6 -0
  236. package/dist/processors/dynamics-core.mjs.map +1 -0
  237. package/dist/processors/modulated-delay-core.cjs +2 -0
  238. package/dist/processors/modulated-delay-core.cjs.map +1 -0
  239. package/dist/processors/modulated-delay-core.mjs +6 -0
  240. package/dist/processors/modulated-delay-core.mjs.map +1 -0
  241. package/dist/processors/timestretch-core.cjs +2 -0
  242. package/dist/processors/timestretch-core.cjs.map +1 -0
  243. package/dist/processors/timestretch-core.mjs +145 -0
  244. package/dist/processors/timestretch-core.mjs.map +1 -0
  245. package/dist/routableSource.cjs +2 -0
  246. package/dist/routableSource.cjs.map +1 -0
  247. package/dist/routableSource.mjs +124 -0
  248. package/dist/routableSource.mjs.map +1 -0
  249. package/dist/scheduler.cjs +2 -0
  250. package/dist/scheduler.cjs.map +1 -0
  251. package/dist/scheduler.d.ts +21 -0
  252. package/dist/scheduler.mjs +45 -0
  253. package/dist/scheduler.mjs.map +1 -0
  254. package/dist/sound.cjs +2 -0
  255. package/dist/sound.cjs.map +1 -0
  256. package/dist/sound.d.ts +10 -1
  257. package/dist/sound.mjs +206 -0
  258. package/dist/sound.mjs.map +1 -0
  259. package/dist/spatial/foa-encode.cjs +2 -0
  260. package/dist/spatial/foa-encode.cjs.map +1 -0
  261. package/dist/spatial/foa-encode.mjs +14 -0
  262. package/dist/spatial/foa-encode.mjs.map +1 -0
  263. package/dist/synth.cjs +2 -0
  264. package/dist/synth.cjs.map +1 -0
  265. package/dist/synth.d.ts +2 -2
  266. package/dist/synth.mjs +97 -0
  267. package/dist/synth.mjs.map +1 -0
  268. package/dist/synthGroup.cjs +2 -0
  269. package/dist/synthGroup.cjs.map +1 -0
  270. package/dist/synthGroup.mjs +92 -0
  271. package/dist/synthGroup.mjs.map +1 -0
  272. package/dist/synthPlayback.cjs +2 -0
  273. package/dist/synthPlayback.cjs.map +1 -0
  274. package/dist/synthPlayback.d.ts +2 -2
  275. package/dist/synthPlayback.mjs +55 -0
  276. package/dist/synthPlayback.mjs.map +1 -0
  277. package/dist/volumeMixin.cjs +2 -0
  278. package/dist/volumeMixin.cjs.map +1 -0
  279. package/dist/volumeMixin.d.ts +7 -2
  280. package/dist/volumeMixin.mjs +67 -0
  281. package/dist/volumeMixin.mjs.map +1 -0
  282. package/dist/webCodecsStream.cjs +2 -0
  283. package/dist/webCodecsStream.cjs.map +1 -0
  284. package/dist/webCodecsStream.mjs +220 -0
  285. package/dist/webCodecsStream.mjs.map +1 -0
  286. package/dist/worklets.cjs +2 -0
  287. package/dist/worklets.cjs.map +1 -0
  288. package/dist/worklets.d.ts +24 -18
  289. package/dist/worklets.mjs +75 -0
  290. package/dist/worklets.mjs.map +1 -0
  291. package/docs/assets/hierarchy.js +1 -1
  292. package/docs/assets/highlight.css +16 -2
  293. package/docs/assets/navigation.js +1 -1
  294. package/docs/assets/search.js +1 -1
  295. package/docs/classes/AudioCache.html +4 -4
  296. package/docs/classes/AudioSprite.html +143 -0
  297. package/docs/classes/BarberpoleEffect.html +7 -7
  298. package/docs/classes/BiquadEffect.html +3 -3
  299. package/docs/classes/Bus.html +21 -21
  300. package/docs/classes/Cacophony.html +112 -89
  301. package/docs/classes/DynamicsEffect.html +7 -7
  302. package/docs/classes/FdnReverbEffect.html +7 -7
  303. package/docs/classes/FoaDecoder.html +5 -5
  304. package/docs/classes/FoaDecoderEffect.html +3 -3
  305. package/docs/classes/FrequencyShifterEffect.html +7 -7
  306. package/docs/classes/Group.html +32 -32
  307. package/docs/classes/HarmonizerEffect.html +7 -7
  308. package/docs/classes/ImpulseResponseEffect.html +3 -3
  309. package/docs/classes/KWeightingFilter.html +4 -4
  310. package/docs/classes/LoudnessMeter.html +11 -11
  311. package/docs/classes/MediaStreamPlayback.html +86 -80
  312. package/docs/classes/MediaStreamSound.html +60 -56
  313. package/docs/classes/MicrophoneStream.html +55 -51
  314. package/docs/classes/ModulatedDelayEffect.html +7 -7
  315. package/docs/classes/PcmStreamPlayback.html +86 -80
  316. package/docs/classes/PcmStreamSound.html +63 -59
  317. package/docs/classes/PhaserEffect.html +7 -7
  318. package/docs/classes/Playback.html +99 -94
  319. package/docs/classes/ReverbEffect.html +7 -7
  320. package/docs/classes/Scheduler.html +91 -0
  321. package/docs/classes/ShareEffect.html +3 -3
  322. package/docs/classes/Sound.html +89 -67
  323. package/docs/classes/SpectralFreezeEffect.html +7 -7
  324. package/docs/classes/StereoWidenerEffect.html +3 -3
  325. package/docs/classes/Synth.html +65 -61
  326. package/docs/classes/SynthGroup.html +28 -28
  327. package/docs/classes/TremoloEffect.html +7 -7
  328. package/docs/classes/TruePeakDetector.html +8 -8
  329. package/docs/classes/WaveshaperEffect.html +7 -7
  330. package/docs/functions/encodeMonoToFoaSN3D.html +1 -1
  331. package/docs/functions/integratedLoudness.html +1 -1
  332. package/docs/functions/integratedUngatedLoudness.html +1 -1
  333. package/docs/functions/loudnessRange.html +1 -1
  334. package/docs/functions/timeStretch.html +1 -1
  335. package/docs/functions/timeStretchChannels.html +1 -1
  336. package/docs/functions/truePeakDb.html +1 -1
  337. package/docs/hierarchy.html +29 -29
  338. package/docs/index.html +47 -4
  339. package/docs/interfaces/AudioBuffer.html +8 -8
  340. package/docs/interfaces/AudioBufferSourceNode.html +22 -22
  341. package/docs/interfaces/AudioEventCallbacks.html +2 -2
  342. package/docs/interfaces/AudioListener.html +12 -12
  343. package/docs/interfaces/AudioNode.html +14 -14
  344. package/docs/interfaces/AudioParam.html +6 -6
  345. package/docs/interfaces/AudioWorklet.html +2 -2
  346. package/docs/interfaces/AudioWorkletNode.html +16 -16
  347. package/docs/interfaces/BarberpoleOptions.html +5 -5
  348. package/docs/interfaces/BaseContext.html +25 -25
  349. package/docs/interfaces/BaseSound.html +22 -18
  350. package/docs/interfaces/BiquadCoefficients.html +6 -6
  351. package/docs/interfaces/BiquadFilterNode.html +20 -20
  352. package/docs/interfaces/BuiltEffectGraph.html +6 -6
  353. package/docs/interfaces/CacheErrorEvent.html +5 -5
  354. package/docs/interfaces/CacheHitEvent.html +4 -4
  355. package/docs/interfaces/CacheMissEvent.html +4 -4
  356. package/docs/interfaces/CacophonyEffect.html +2 -2
  357. package/docs/interfaces/CacophonyLogger.html +4 -4
  358. package/docs/interfaces/ChannelMergerNode.html +14 -14
  359. package/docs/interfaces/ChannelSplitterNode.html +14 -14
  360. package/docs/interfaces/ConvolverNode.html +16 -16
  361. package/docs/interfaces/CreateSpriteOptions.html +64 -0
  362. package/docs/interfaces/DynamicsOptions.html +7 -7
  363. package/docs/interfaces/FadeStartEvent.html +4 -4
  364. package/docs/interfaces/FdnReverbOptions.html +6 -6
  365. package/docs/interfaces/FoaDecoderOptions.html +2 -2
  366. package/docs/interfaces/FrequencyShifterOptions.html +3 -3
  367. package/docs/interfaces/GainNode.html +15 -15
  368. package/docs/interfaces/GlobalPlaybackEvent.html +3 -3
  369. package/docs/interfaces/HarmonizerOptions.html +6 -6
  370. package/docs/interfaces/ImpulseResponseOptions.html +5 -5
  371. package/docs/interfaces/LoadingCompleteEvent.html +5 -5
  372. package/docs/interfaces/LoadingErrorEvent.html +5 -5
  373. package/docs/interfaces/LoadingProgressEvent.html +6 -6
  374. package/docs/interfaces/LoadingStartEvent.html +3 -3
  375. package/docs/interfaces/LoudnessChannelInput.html +3 -3
  376. package/docs/interfaces/LoudnessReading.html +5 -5
  377. package/docs/interfaces/MediaElementSourceNode.html +15 -15
  378. package/docs/interfaces/MediaStreamAudioSourceNode.html +15 -15
  379. package/docs/interfaces/MediaStreamSoundOptions.html +5 -5
  380. package/docs/interfaces/MicrophoneStreamOptions.html +8 -8
  381. package/docs/interfaces/ModulatedDelayOptions.html +8 -8
  382. package/docs/interfaces/OfflineOptions.html +5 -5
  383. package/docs/interfaces/OscillatorNode.html +20 -20
  384. package/docs/interfaces/PannerNode.html +28 -28
  385. package/docs/interfaces/PcmStreamBufferEvent.html +2 -2
  386. package/docs/interfaces/PcmStreamSoundOptions.html +6 -6
  387. package/docs/interfaces/PhaserOptions.html +7 -7
  388. package/docs/interfaces/PlayOptions.html +16 -8
  389. package/docs/interfaces/PlaybackErrorEvent.html +7 -7
  390. package/docs/interfaces/ReverbOptions.html +13 -13
  391. package/docs/interfaces/RuntimeOptions.html +7 -7
  392. package/docs/interfaces/ScheduledCallbackHandle.html +59 -0
  393. package/docs/interfaces/SoundCleanupHoldings.html +4 -4
  394. package/docs/interfaces/SoundErrorEvent.html +6 -6
  395. package/docs/interfaces/SpectralFreezeOptions.html +4 -4
  396. package/docs/interfaces/SpriteRegion.html +70 -0
  397. package/docs/interfaces/StereoPannerNode.html +15 -15
  398. package/docs/interfaces/StereoToBFormatOptions.html +60 -0
  399. package/docs/interfaces/StereoWidenerOptions.html +4 -4
  400. package/docs/interfaces/StreamCapabilities.html +5 -5
  401. package/docs/interfaces/TimeStretchOptions.html +5 -5
  402. package/docs/interfaces/TremoloOptions.html +5 -5
  403. package/docs/interfaces/WaveshaperOptions.html +5 -5
  404. package/docs/modules.html +6 -6
  405. package/docs/types/BaseAudioEvents.html +11 -11
  406. package/docs/types/BuiltEffect.html +1 -1
  407. package/docs/types/BusConnectionTarget.html +1 -1
  408. package/docs/types/CacheEventCallback.html +1 -1
  409. package/docs/types/CacophonyEvents.html +17 -17
  410. package/docs/types/ErrorEventCallback.html +1 -1
  411. package/docs/types/FadeType.html +1 -1
  412. package/docs/types/HrtfPannerOptions.html +1 -1
  413. package/docs/types/ImpulseResponseSource.html +1 -1
  414. package/docs/types/LoadingEventCallback.html +1 -1
  415. package/docs/types/LoopCount.html +1 -1
  416. package/docs/types/LoudnessChannel.html +1 -1
  417. package/docs/types/Orientation.html +3 -3
  418. package/docs/types/PanCloneOverrides.html +5 -5
  419. package/docs/types/PanType.html +1 -1
  420. package/docs/types/PcmStreamEvents.html +6 -6
  421. package/docs/types/PcmStreamState.html +1 -1
  422. package/docs/types/PlaybackEvents.html +1 -1
  423. package/docs/types/Position.html +1 -1
  424. package/docs/types/SoundEvents.html +1 -1
  425. package/docs/types/SoundType.html +1 -1
  426. package/docs/types/SourceNode.html +1 -1
  427. package/docs/types/SpriteMap.html +35 -0
  428. package/docs/types/SynthEvents.html +1 -1
  429. package/docs/types/ThreeDOptions.html +1 -1
  430. package/docs/types/WebCodecsStreamSound.html +1 -1
  431. package/docs/variables/CHANNEL_WEIGHTS.html +1 -1
  432. package/docs/variables/K_WEIGHTING_STAGE1_48K.html +1 -1
  433. package/docs/variables/K_WEIGHTING_STAGE2_48K.html +1 -1
  434. package/docs/variables/consoleLogger.html +1 -1
  435. package/docs/variables/noopLogger.html +1 -1
  436. package/package.json +7 -3
  437. package/dist/cacophony-PShY6dPK.cjs +0 -2
  438. package/dist/cacophony-PShY6dPK.cjs.map +0 -1
  439. package/dist/cacophony-o1zE5oDP.js +0 -3857
  440. package/dist/cacophony-o1zE5oDP.js.map +0 -1
  441. package/dist/src-Bss6ztQN.cjs +0 -2
  442. package/dist/src-Bss6ztQN.cjs.map +0 -1
  443. package/dist/src-CCQXsJcG.js +0 -400
  444. package/dist/src-CCQXsJcG.js.map +0 -1
package/README.md CHANGED
@@ -19,10 +19,36 @@ Cacophony is a powerful and intuitive audio library designed for modern web appl
19
19
  ## Installation
20
20
 
21
21
  ```bash
22
- npm install cacophony
23
- ```
24
-
25
- ## Quick Start
22
+ npm install cacophony
23
+ ```
24
+
25
+ ## Bundling and lazy loading
26
+
27
+ Use named ESM imports so your bundler can discard unused modules:
28
+
29
+ ```typescript
30
+ import { AudioCache } from 'cacophony';
31
+ ```
32
+
33
+ The package preserves its module boundaries and declares import side effects.
34
+ Importing `AudioCache` or an individual effect does not pull in the full
35
+ `Cacophony` class or the offline FFT implementation. The `Cacophony` class keeps
36
+ its complete factory API, so importing that class still includes the code its
37
+ methods reference.
38
+
39
+ `createStream()` loads MediaBunny on demand when using the WebCodecs transport.
40
+ HLS streams and browsers without `AudioDecoder` take their existing fallback
41
+ paths without loading it. Each AudioWorklet payload loads when its processor is
42
+ first needed. Call `await audio.loadWorklets()` to preload all processors.
43
+
44
+ Consumer bundlers must support code splitting to keep these imports in separate
45
+ downloadable chunks. Deploy all generated chunks with the application. MediaBunny
46
+ remains an installed dependency; lazy loading defers its runtime load.
47
+
48
+ Run `npm run build` followed by `npm run check:bundles -- --report` to inspect
49
+ initial bundle sizes for cache-only, full-factory, and single-effect consumers.
50
+
51
+ ## Quick Start
26
52
 
27
53
  ```typescript
28
54
  import { Cacophony } from 'cacophony';
@@ -124,10 +150,49 @@ setTimeout(() => playback1.pause(), 1000);
124
150
  setTimeout(() => playback2.stop(), 2000);
125
151
 
126
152
  // Or control all playbacks through the Sound
127
- sound.stop(); // Stops all three playbacks
128
- ```
129
-
130
- ## Sound Types
153
+ sound.stop(); // Stops all three playbacks
154
+ ```
155
+
156
+ ### Audio Sprites for Games
157
+
158
+ Pack many short effects into one decoded WAV atlas while keeping each named
159
+ region as an ordinary, independently configurable `Sound`:
160
+
161
+ ```bash
162
+ cacophony sprite sfx/laser.wav sfx/engine.wav \
163
+ --out public/sfx-atlas.wav --map public/sfx-atlas.json --gap 10
164
+ ```
165
+
166
+ ```typescript
167
+ import { Cacophony, type SpriteMap } from 'cacophony';
168
+
169
+ const map = {
170
+ laser: { start: 0, duration: 0.35 },
171
+ engine: { start: 0.36, duration: 1.2, loopCount: 'infinite' },
172
+ } as const satisfies SpriteMap;
173
+
174
+ const cacophony = new Cacophony();
175
+ const sprite = await cacophony.createSprite('/sfx-atlas.wav', map);
176
+
177
+ // Literal keys stay typed. Each child uses the normal Sound API.
178
+ sprite.sounds.laser.volume = 0.7;
179
+ sprite.sounds.laser.play();
180
+
181
+ // Dynamic names use the checked lookup.
182
+ const selected: string = chooseEffectName();
183
+ if (sprite.has(selected)) sprite.get(selected).play();
184
+
185
+ // Child configuration is independent; the atlas has no shared play controls.
186
+ sprite.sounds.engine.loop('infinite');
187
+ sprite.sounds.engine.play();
188
+
189
+ sprite.cleanup();
190
+ ```
191
+
192
+ All child Sounds share the atlas `AudioBuffer`. `cleanup()` owns those children
193
+ but not clones created with `sound.clone()`, which remain independently usable.
194
+
195
+ ## Sound Types
131
196
 
132
197
  Cacophony supports three URL-backed sound labels:
133
198
 
@@ -551,6 +616,27 @@ FOA binaural decoding is available in both forms. Use
551
616
  `decoder.input` and `decoder.output`; use `createFoaDecoderEffect()` only on a
552
617
  dedicated 4-channel ACN/SN3D FOA bus, typically as the first and only filter
553
618
  that converts that bus to stereo binaural output.
619
+
620
+ For physically correct mono positioning, use `encodeMonoToFoaSN3D()` and feed
621
+ its ACN/SN3D `[W, Y, Z, X]` output to the decoder. Stereo recordings can instead
622
+ be perceptually upmixed with `createStereoToBFormatNode()`. The default
623
+ `algorithm: 'perceptual'` path preserves the existing three-band front cue;
624
+ `algorithm: 'bcc'` uses frequency-domain coherence and pan analysis:
625
+
626
+ ```typescript
627
+ const upmixer = await cacophony.createStereoToBFormatNode({ algorithm: 'bcc' });
628
+ const decoder = await cacophony.createFoaDecoder();
629
+ stereoSource.connect(upmixer);
630
+ upmixer.connect(decoder.input);
631
+ decoder.output.connect(cacophony.context.destination);
632
+
633
+ // BCC analysis is stateful. Reset it after a seek or other discontinuity.
634
+ upmixer.port.postMessage({ type: 'reset' });
635
+ ```
636
+
637
+ Both stereo upmix algorithms emit ACN `[W, Y, Z, X]` but are perceptual
638
+ approximations, neither N3D nor SN3D. The BCC path produces W/Y only and keeps
639
+ Z/X at zero, trading the default path's front cue for per-band spatial analysis.
554
640
 
555
641
  ### Cleaning up
556
642
 
@@ -0,0 +1 @@
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));exports.__toESM=s;
@@ -0,0 +1,2 @@
1
+ var e=`data:audio/wav;base64,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`;exports.default=e;
2
+ //# sourceMappingURL=sh_hrir_order_1.wav_url.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sh_hrir_order_1.wav_url.cjs","names":[],"sources":["../../src/assets/sh_hrir_order_1.wav?url"],"sourcesContent":["export default \"data:audio/wav;base64,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\""],"mappings":"AAAA,IAAA,EAAe"}
@@ -0,0 +1,6 @@
1
+ //#region src/assets/sh_hrir_order_1.wav?url
2
+ var e = "data:audio/wav;base64,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";
3
+ //#endregion
4
+ export { e as default };
5
+
6
+ //# sourceMappingURL=sh_hrir_order_1.wav_url.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sh_hrir_order_1.wav_url.mjs","names":[],"sources":["../../src/assets/sh_hrir_order_1.wav?url"],"sourcesContent":["export default \"data:audio/wav;base64,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\""],"mappings":";AAAA,IAAA,IAAe"}
@@ -0,0 +1,2 @@
1
+ var e=class{sounds;names;cleanedUp=!1;constructor(e,t){this.sounds=Object.freeze(e),this.names=Object.freeze([...t])}get(e){if(!Object.hasOwn(this.sounds,e))throw Error(`Unknown audio sprite name: ${e}`);return this.sounds[e]}has(e){return Object.hasOwn(this.sounds,e)}cleanup(){if(!this.cleanedUp){this.cleanedUp=!0;for(let e of this.names)this.sounds[e].cleanup()}}};exports.AudioSprite=e;
2
+ //# sourceMappingURL=audioSprite.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioSprite.cjs","names":[],"sources":["../src/audioSprite.ts"],"sourcesContent":["import type { LoopCount } from \"./cacophony\";\nimport type { Sound } from \"./sound\";\n\n/** A named, immutable region of an audio atlas, expressed in seconds. */\nexport interface SpriteRegion {\n readonly start: number;\n readonly duration: number;\n readonly loopCount?: LoopCount;\n}\n\n/** Named regions used to construct an {@link AudioSprite}. */\nexport type SpriteMap = Readonly<Record<string, SpriteRegion>>;\n\n/** Options shared by every child Sound created for a sprite. */\nexport interface CreateSpriteOptions {\n panType?: import(\"./cacophony\").PanType;\n signal?: AbortSignal;\n}\n\n/**\n * A typed registry and lifetime owner for the ordinary Sounds in an atlas.\n * Playback and configuration remain child-Sound operations.\n */\nexport class AudioSprite<K extends string = string> {\n readonly sounds: Readonly<Record<K, Sound>>;\n readonly names: readonly K[];\n private cleanedUp = false;\n\n /** @internal Construct sprites through Cacophony.createSprite(). */\n constructor(sounds: Record<K, Sound>, names: readonly K[]) {\n this.sounds = Object.freeze(sounds);\n this.names = Object.freeze([...names]);\n }\n\n get(name: K): Sound {\n if (!Object.hasOwn(this.sounds, name)) {\n throw new Error(`Unknown audio sprite name: ${name}`);\n }\n return this.sounds[name];\n }\n\n has(name: string): name is K {\n return Object.hasOwn(this.sounds, name);\n }\n\n cleanup(): void {\n if (this.cleanedUp) return;\n this.cleanedUp = true;\n for (const name of this.names) {\n this.sounds[name].cleanup();\n }\n }\n}\n"],"mappings":"AAuBA,IAAa,EAAb,KAAoD,CAClD,OACA,MACA,UAAoB,GAGpB,YAAY,EAA0B,EAAqB,CACzD,KAAK,OAAS,OAAO,OAAO,CAAM,EAClC,KAAK,MAAQ,OAAO,OAAO,CAAC,GAAG,CAAK,CAAC,CACvC,CAEA,IAAI,EAAgB,CAClB,GAAI,CAAC,OAAO,OAAO,KAAK,OAAQ,CAAI,EAClC,MAAU,MAAM,8BAA8B,GAAM,EAEtD,OAAO,KAAK,OAAO,EACrB,CAEA,IAAI,EAAyB,CAC3B,OAAO,OAAO,OAAO,KAAK,OAAQ,CAAI,CACxC,CAEA,SAAgB,CACV,SAAK,UACT,MAAK,UAAY,GACjB,IAAK,IAAM,KAAQ,KAAK,MACtB,KAAK,OAAO,GAAM,QAAQ,CAFX,CAInB,CACF"}
@@ -0,0 +1,29 @@
1
+ import { LoopCount } from './cacophony';
2
+ import { Sound } from './sound';
3
+ /** A named, immutable region of an audio atlas, expressed in seconds. */
4
+ export interface SpriteRegion {
5
+ readonly start: number;
6
+ readonly duration: number;
7
+ readonly loopCount?: LoopCount;
8
+ }
9
+ /** Named regions used to construct an {@link AudioSprite}. */
10
+ export type SpriteMap = Readonly<Record<string, SpriteRegion>>;
11
+ /** Options shared by every child Sound created for a sprite. */
12
+ export interface CreateSpriteOptions {
13
+ panType?: import('./cacophony').PanType;
14
+ signal?: AbortSignal;
15
+ }
16
+ /**
17
+ * A typed registry and lifetime owner for the ordinary Sounds in an atlas.
18
+ * Playback and configuration remain child-Sound operations.
19
+ */
20
+ export declare class AudioSprite<K extends string = string> {
21
+ readonly sounds: Readonly<Record<K, Sound>>;
22
+ readonly names: readonly K[];
23
+ private cleanedUp;
24
+ /** @internal Construct sprites through Cacophony.createSprite(). */
25
+ constructor(sounds: Record<K, Sound>, names: readonly K[]);
26
+ get(name: K): Sound;
27
+ has(name: string): name is K;
28
+ cleanup(): void;
29
+ }
@@ -0,0 +1,26 @@
1
+ //#region src/audioSprite.ts
2
+ var e = class {
3
+ sounds;
4
+ names;
5
+ cleanedUp = !1;
6
+ constructor(e, t) {
7
+ this.sounds = Object.freeze(e), this.names = Object.freeze([...t]);
8
+ }
9
+ get(e) {
10
+ if (!Object.hasOwn(this.sounds, e)) throw Error(`Unknown audio sprite name: ${e}`);
11
+ return this.sounds[e];
12
+ }
13
+ has(e) {
14
+ return Object.hasOwn(this.sounds, e);
15
+ }
16
+ cleanup() {
17
+ if (!this.cleanedUp) {
18
+ this.cleanedUp = !0;
19
+ for (let e of this.names) this.sounds[e].cleanup();
20
+ }
21
+ }
22
+ };
23
+ //#endregion
24
+ export { e as AudioSprite };
25
+
26
+ //# sourceMappingURL=audioSprite.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioSprite.mjs","names":[],"sources":["../src/audioSprite.ts"],"sourcesContent":["import type { LoopCount } from \"./cacophony\";\nimport type { Sound } from \"./sound\";\n\n/** A named, immutable region of an audio atlas, expressed in seconds. */\nexport interface SpriteRegion {\n readonly start: number;\n readonly duration: number;\n readonly loopCount?: LoopCount;\n}\n\n/** Named regions used to construct an {@link AudioSprite}. */\nexport type SpriteMap = Readonly<Record<string, SpriteRegion>>;\n\n/** Options shared by every child Sound created for a sprite. */\nexport interface CreateSpriteOptions {\n panType?: import(\"./cacophony\").PanType;\n signal?: AbortSignal;\n}\n\n/**\n * A typed registry and lifetime owner for the ordinary Sounds in an atlas.\n * Playback and configuration remain child-Sound operations.\n */\nexport class AudioSprite<K extends string = string> {\n readonly sounds: Readonly<Record<K, Sound>>;\n readonly names: readonly K[];\n private cleanedUp = false;\n\n /** @internal Construct sprites through Cacophony.createSprite(). */\n constructor(sounds: Record<K, Sound>, names: readonly K[]) {\n this.sounds = Object.freeze(sounds);\n this.names = Object.freeze([...names]);\n }\n\n get(name: K): Sound {\n if (!Object.hasOwn(this.sounds, name)) {\n throw new Error(`Unknown audio sprite name: ${name}`);\n }\n return this.sounds[name];\n }\n\n has(name: string): name is K {\n return Object.hasOwn(this.sounds, name);\n }\n\n cleanup(): void {\n if (this.cleanedUp) return;\n this.cleanedUp = true;\n for (const name of this.names) {\n this.sounds[name].cleanup();\n }\n }\n}\n"],"mappings":";AAuBA,IAAa,IAAb,MAAoD;CAClD;CACA;CACA,YAAoB;CAGpB,YAAY,GAA0B,GAAqB;EAEzD,AADA,KAAK,SAAS,OAAO,OAAO,CAAM,GAClC,KAAK,QAAQ,OAAO,OAAO,CAAC,GAAG,CAAK,CAAC;CACvC;CAEA,IAAI,GAAgB;EAClB,IAAI,CAAC,OAAO,OAAO,KAAK,QAAQ,CAAI,GAClC,MAAU,MAAM,8BAA8B,GAAM;EAEtD,OAAO,KAAK,OAAO;CACrB;CAEA,IAAI,GAAyB;EAC3B,OAAO,OAAO,OAAO,KAAK,QAAQ,CAAI;CACxC;CAEA,UAAgB;EACV,UAAK,WACT;QAAK,YAAY;GACjB,KAAK,IAAM,KAAQ,KAAK,OACtB,KAAK,OAAO,GAAM,QAAQ;EAFX;CAInB;AACF"}
@@ -0,0 +1,2 @@
1
+ var e=[`touchend`,`click`,`keydown`],t={capture:!0,passive:!0};function n(n){let{context:r,onUnlock:i}=n;if(typeof document>`u`)return()=>{};let a=r.resume;if(typeof a!=`function`)return()=>{};let o=document,s=o.body??o,c=r,l=!1,u=!1,d=!1,f=()=>{if(l){for(let n of e)s.removeEventListener(n,p,t);l=!1}},p=()=>{if(!(d||u)){u=!0,f();try{let e=r.createBuffer(1,1,r.sampleRate),t=r.createBufferSource();t.buffer=e,t.connect(r.destination),t.start(0),t.stop(0)}catch(e){console.warn(`[cacophony/autoplayUnlock] primer failed:`,e)}a.call(r).then(()=>{if(u=!1,!d)try{i()}catch(e){console.error(`[cacophony/autoplayUnlock] onUnlock callback threw:`,e)}},e=>{u=!1,!d&&(console.warn(`[cacophony/autoplayUnlock] resume failed:`,e),h())})}},m=()=>{if(!(d||l||u)){for(let n of e)s.addEventListener(n,p,t);l=!0}};function h(){c.state===`suspended`||c.state===`interrupted`?m():f()}let g=()=>{d||h()};return c.addEventListener?.(`statechange`,g),h(),()=>{d||(d=!0,f(),c.removeEventListener?.(`statechange`,g))}}exports.installAutoplayUnlock=n;
2
+ //# sourceMappingURL=autoplayUnlock.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autoplayUnlock.cjs","names":[],"sources":["../src/autoplayUnlock.ts"],"sourcesContent":["import type { BaseContext } from \"./context\";\n\n/**\n * Autoplay unlock — Howler-parity automatic AudioContext resume on first\n * user gesture.\n *\n * On mobile browsers (especially iOS Safari) an `AudioContext` constructed\n * before any user interaction is created in `suspended` state. It will not\n * produce sound until BOTH:\n *\n * 1. `context.resume()` is called, AND\n * 2. an `AudioBufferSourceNode` is created and started inside the user\n * gesture's call stack (the iOS \"primer\").\n *\n * Many callers do (1) but not (2), and hear silence with no obvious cause.\n * This module watches the context for suspension and arms `touchend` / `click`\n * / `keydown` listeners on `document.body` (or `document` as fallback). A\n * gesture resumes the context, plays a 1-sample silent primer inside the\n * gesture call stack, removes all three listeners, and calls the `onUnlock`\n * callback. If the context suspends again, the listeners are re-armed.\n *\n * Design adapted (not copied) from Howler.js `_unlockAudio` — MIT licensed.\n */\n\nconst UNLOCK_EVENT_TYPES: ReadonlyArray<\"touchend\" | \"click\" | \"keydown\"> = [\"touchend\", \"click\", \"keydown\"];\nconst GESTURE_LISTENER_OPTIONS = { capture: true, passive: true } as const;\n\n/**\n * A `Document`-like type with the methods we need. Avoids a hard dependency\n * on DOM lib types so the package keeps building when `lib: [\"dom\"]` is off.\n */\ninterface DocumentLike {\n body?: EventTargetLike | null;\n addEventListener(type: string, listener: (ev: any) => void, options?: any): void;\n removeEventListener(type: string, listener: (ev: any) => void, options?: any): void;\n}\n\ninterface EventTargetLike {\n addEventListener(type: string, listener: (ev: any) => void, options?: any): void;\n removeEventListener(type: string, listener: (ev: any) => void, options?: any): void;\n}\n\n/**\n * Options for `installAutoplayUnlock`.\n */\nexport interface AutoplayUnlockOptions {\n /**\n * The audio context that should be resumed and primed.\n */\n context: BaseContext;\n\n /**\n * Called after the context has been resumed and the primer buffer has been\n * started. Used by `Cacophony` to emit the public `unlock` event.\n * Errors thrown by the callback are caught and logged so a faulty listener\n * cannot break the unlock flow.\n */\n onUnlock: () => void;\n}\n\n/**\n * Watch for context suspension and install unlock listeners while needed.\n * Returns a cleanup function that removes both the context watcher and any\n * armed gesture listeners (e.g. when a `Cacophony` instance is torn down).\n *\n * If the environment is non-browser (`document` is undefined), this is a\n * no-op and returns a no-op cleanup.\n *\n * @internal\n */\nexport function installAutoplayUnlock(opts: AutoplayUnlockOptions): () => void {\n const { context, onUnlock } = opts;\n\n // Server-side / non-browser: nothing to do.\n if (typeof document === \"undefined\") {\n return () => {};\n }\n\n // `BaseContext.resume` is optional. If this context has no resume() we\n // cannot actually unlock it — installing gesture listeners would be noise,\n // and firing the `unlock` event without a fulfilled resume() would violate\n // the contract (caller would see `unlock` while `Cacophony.locked` stays\n // true, since `locked` is derived from `context.state === \"suspended\"`).\n // Treat the absence as \"this context isn't ours to unlock\" and bail.\n const resume = (context as unknown as { resume?: () => Promise<void> }).resume;\n if (typeof resume !== \"function\") {\n return () => {};\n }\n\n const doc = document as unknown as DocumentLike;\n const target: EventTargetLike = (doc.body as EventTargetLike | null | undefined) ?? doc;\n const observableContext = context as unknown as {\n state?: string;\n addEventListener?: (type: string, listener: () => void) => void;\n removeEventListener?: (type: string, listener: () => void) => void;\n };\n\n let armed = false;\n let resumeInFlight = false;\n let disposed = false;\n\n const removeAll = () => {\n if (!armed) return;\n for (const type of UNLOCK_EVENT_TYPES) {\n target.removeEventListener(type, handler, GESTURE_LISTENER_OPTIONS);\n }\n armed = false;\n };\n\n const handler = () => {\n if (disposed || resumeInFlight) return;\n resumeInFlight = true;\n\n // Remove listeners FIRST so a re-entrant gesture cannot re-trigger us\n // while resume() is in flight.\n removeAll();\n\n // Play the iOS primer INSIDE the gesture call stack. iOS requires that\n // an AudioBufferSourceNode be created and started synchronously inside\n // the gesture handler for the context to truly unlock — calling\n // resume() alone is not sufficient. A 1-sample silent buffer is the\n // minimum that satisfies the requirement and is inaudible.\n try {\n // BaseContext doesn't declare createBuffer because Cacophony's normal\n // code path always feeds an AudioBuffer constructed externally; the\n // primer needs to construct a 1-sample buffer in-place, so we widen\n // the type locally here. Both AudioContext and OfflineAudioContext\n // expose createBuffer.\n const ctxWithCreateBuffer = context as unknown as {\n createBuffer(numberOfChannels: number, length: number, sampleRate: number): unknown;\n };\n const buffer = ctxWithCreateBuffer.createBuffer(1, 1, context.sampleRate);\n const source = context.createBufferSource();\n source.buffer = buffer as any;\n source.connect(context.destination);\n // The load-bearing iOS pattern is start(0); stop(0) on a silent buffer\n // INSIDE the gesture call stack. A 1-sample non-looping buffer would\n // end on its own, but the pair is what the platform contract names.\n source.start(0);\n source.stop(0);\n } catch (err) {\n // Primer failure should not block the rest of the unlock; the\n // context.resume() call below is still useful on platforms that do\n // not require the primer.\n console.warn(\"[cacophony/autoplayUnlock] primer failed:\", err);\n }\n\n // Resume the context, then emit unlock. The `unlock` event signals that\n // audio is actually playable, so we must wait for resume() to fulfill\n // before emitting. On rejection we surface the error and do NOT emit\n // unlock — a failed resume is not an unlock. `resume` is guaranteed to\n // be a function here (guarded at install time above).\n resume.call(context).then(\n () => {\n resumeInFlight = false;\n if (disposed) return;\n try {\n onUnlock();\n } catch (err) {\n console.error(\"[cacophony/autoplayUnlock] onUnlock callback threw:\", err);\n }\n },\n (err: unknown) => {\n resumeInFlight = false;\n if (disposed) return;\n console.warn(\"[cacophony/autoplayUnlock] resume failed:\", err);\n syncGestureListeners();\n },\n );\n };\n\n const armAll = () => {\n if (disposed || armed || resumeInFlight) return;\n for (const type of UNLOCK_EVENT_TYPES) {\n target.addEventListener(type, handler, GESTURE_LISTENER_OPTIONS);\n }\n armed = true;\n };\n\n function syncGestureListeners(): void {\n if (observableContext.state === \"suspended\" || observableContext.state === \"interrupted\") {\n armAll();\n } else {\n removeAll();\n }\n }\n\n const handleStateChange = () => {\n if (!disposed) syncGestureListeners();\n };\n\n observableContext.addEventListener?.(\"statechange\", handleStateChange);\n syncGestureListeners();\n\n return () => {\n if (disposed) return;\n disposed = true;\n removeAll();\n observableContext.removeEventListener?.(\"statechange\", handleStateChange);\n };\n}\n"],"mappings":"AAwBA,IAAM,EAAsE,CAAC,WAAY,QAAS,SAAS,EACrG,EAA2B,CAAE,QAAS,GAAM,QAAS,EAAK,EA6ChE,SAAgB,EAAsB,EAAyC,CAC7E,GAAM,CAAE,UAAS,YAAa,EAG9B,GAAI,OAAO,SAAa,IACtB,UAAa,CAAC,EAShB,IAAM,EAAU,EAAwD,OACxE,GAAI,OAAO,GAAW,WACpB,UAAa,CAAC,EAGhB,IAAM,EAAM,SACN,EAA2B,EAAI,MAA+C,EAC9E,EAAoB,EAMtB,EAAQ,GACR,EAAiB,GACjB,EAAW,GAET,MAAkB,CACjB,KACL,KAAK,IAAM,KAAQ,EACjB,EAAO,oBAAoB,EAAM,EAAS,CAAwB,EAEpE,EAAQ,EAF4D,CAGtE,EAEM,MAAgB,CAChB,QAAY,GAKhB,CAJA,EAAiB,GAIjB,EAAU,EAOV,GAAI,CASF,IAAM,EAAS,EAAoB,aAAa,EAAG,EAAG,EAAQ,UAAU,EAClE,EAAS,EAAQ,mBAAmB,EAC1C,EAAO,OAAS,EAChB,EAAO,QAAQ,EAAQ,WAAW,EAIlC,EAAO,MAAM,CAAC,EACd,EAAO,KAAK,CAAC,CACf,OAAS,EAAK,CAIZ,QAAQ,KAAK,4CAA6C,CAAG,CAC/D,CAOA,EAAO,KAAK,CAAO,EAAE,SACb,CACJ,KAAiB,GACb,GACJ,GAAI,CACF,EAAS,CACX,OAAS,EAAK,CACZ,QAAQ,MAAM,sDAAuD,CAAG,CAC1E,CACF,EACC,GAAiB,CAChB,EAAiB,GACb,KACJ,QAAQ,KAAK,4CAA6C,CAAG,EAC7D,EAAqB,EACvB,CACF,CArDU,CAsDZ,EAEM,MAAe,CACf,QAAY,GAAS,GACzB,KAAK,IAAM,KAAQ,EACjB,EAAO,iBAAiB,EAAM,EAAS,CAAwB,EAEjE,EAAQ,EAFyD,CAGnE,EAEA,SAAS,GAA6B,CAChC,EAAkB,QAAU,aAAe,EAAkB,QAAU,cACzE,EAAO,EAEP,EAAU,CAEd,CAEA,IAAM,MAA0B,CACzB,GAAU,EAAqB,CACtC,EAKA,OAHA,EAAkB,mBAAmB,cAAe,CAAiB,EACrE,EAAqB,MAER,CACP,IACJ,EAAW,GACX,EAAU,EACV,EAAkB,sBAAsB,cAAe,CAAiB,EAC1E,CACF"}
@@ -0,0 +1,58 @@
1
+ //#region src/autoplayUnlock.ts
2
+ var e = [
3
+ "touchend",
4
+ "click",
5
+ "keydown"
6
+ ], t = {
7
+ capture: !0,
8
+ passive: !0
9
+ };
10
+ function n(n) {
11
+ let { context: r, onUnlock: i } = n;
12
+ if (typeof document > "u") return () => {};
13
+ let a = r.resume;
14
+ if (typeof a != "function") return () => {};
15
+ let o = document, s = o.body ?? o, c = r, l = !1, u = !1, d = !1, f = () => {
16
+ if (l) {
17
+ for (let n of e) s.removeEventListener(n, p, t);
18
+ l = !1;
19
+ }
20
+ }, p = () => {
21
+ if (!(d || u)) {
22
+ u = !0, f();
23
+ try {
24
+ let e = r.createBuffer(1, 1, r.sampleRate), t = r.createBufferSource();
25
+ t.buffer = e, t.connect(r.destination), t.start(0), t.stop(0);
26
+ } catch (e) {
27
+ console.warn("[cacophony/autoplayUnlock] primer failed:", e);
28
+ }
29
+ a.call(r).then(() => {
30
+ if (u = !1, !d) try {
31
+ i();
32
+ } catch (e) {
33
+ console.error("[cacophony/autoplayUnlock] onUnlock callback threw:", e);
34
+ }
35
+ }, (e) => {
36
+ u = !1, !d && (console.warn("[cacophony/autoplayUnlock] resume failed:", e), h());
37
+ });
38
+ }
39
+ }, m = () => {
40
+ if (!(d || l || u)) {
41
+ for (let n of e) s.addEventListener(n, p, t);
42
+ l = !0;
43
+ }
44
+ };
45
+ function h() {
46
+ c.state === "suspended" || c.state === "interrupted" ? m() : f();
47
+ }
48
+ let g = () => {
49
+ d || h();
50
+ };
51
+ return c.addEventListener?.("statechange", g), h(), () => {
52
+ d || (d = !0, f(), c.removeEventListener?.("statechange", g));
53
+ };
54
+ }
55
+ //#endregion
56
+ export { n as installAutoplayUnlock };
57
+
58
+ //# sourceMappingURL=autoplayUnlock.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autoplayUnlock.mjs","names":[],"sources":["../src/autoplayUnlock.ts"],"sourcesContent":["import type { BaseContext } from \"./context\";\n\n/**\n * Autoplay unlock — Howler-parity automatic AudioContext resume on first\n * user gesture.\n *\n * On mobile browsers (especially iOS Safari) an `AudioContext` constructed\n * before any user interaction is created in `suspended` state. It will not\n * produce sound until BOTH:\n *\n * 1. `context.resume()` is called, AND\n * 2. an `AudioBufferSourceNode` is created and started inside the user\n * gesture's call stack (the iOS \"primer\").\n *\n * Many callers do (1) but not (2), and hear silence with no obvious cause.\n * This module watches the context for suspension and arms `touchend` / `click`\n * / `keydown` listeners on `document.body` (or `document` as fallback). A\n * gesture resumes the context, plays a 1-sample silent primer inside the\n * gesture call stack, removes all three listeners, and calls the `onUnlock`\n * callback. If the context suspends again, the listeners are re-armed.\n *\n * Design adapted (not copied) from Howler.js `_unlockAudio` — MIT licensed.\n */\n\nconst UNLOCK_EVENT_TYPES: ReadonlyArray<\"touchend\" | \"click\" | \"keydown\"> = [\"touchend\", \"click\", \"keydown\"];\nconst GESTURE_LISTENER_OPTIONS = { capture: true, passive: true } as const;\n\n/**\n * A `Document`-like type with the methods we need. Avoids a hard dependency\n * on DOM lib types so the package keeps building when `lib: [\"dom\"]` is off.\n */\ninterface DocumentLike {\n body?: EventTargetLike | null;\n addEventListener(type: string, listener: (ev: any) => void, options?: any): void;\n removeEventListener(type: string, listener: (ev: any) => void, options?: any): void;\n}\n\ninterface EventTargetLike {\n addEventListener(type: string, listener: (ev: any) => void, options?: any): void;\n removeEventListener(type: string, listener: (ev: any) => void, options?: any): void;\n}\n\n/**\n * Options for `installAutoplayUnlock`.\n */\nexport interface AutoplayUnlockOptions {\n /**\n * The audio context that should be resumed and primed.\n */\n context: BaseContext;\n\n /**\n * Called after the context has been resumed and the primer buffer has been\n * started. Used by `Cacophony` to emit the public `unlock` event.\n * Errors thrown by the callback are caught and logged so a faulty listener\n * cannot break the unlock flow.\n */\n onUnlock: () => void;\n}\n\n/**\n * Watch for context suspension and install unlock listeners while needed.\n * Returns a cleanup function that removes both the context watcher and any\n * armed gesture listeners (e.g. when a `Cacophony` instance is torn down).\n *\n * If the environment is non-browser (`document` is undefined), this is a\n * no-op and returns a no-op cleanup.\n *\n * @internal\n */\nexport function installAutoplayUnlock(opts: AutoplayUnlockOptions): () => void {\n const { context, onUnlock } = opts;\n\n // Server-side / non-browser: nothing to do.\n if (typeof document === \"undefined\") {\n return () => {};\n }\n\n // `BaseContext.resume` is optional. If this context has no resume() we\n // cannot actually unlock it — installing gesture listeners would be noise,\n // and firing the `unlock` event without a fulfilled resume() would violate\n // the contract (caller would see `unlock` while `Cacophony.locked` stays\n // true, since `locked` is derived from `context.state === \"suspended\"`).\n // Treat the absence as \"this context isn't ours to unlock\" and bail.\n const resume = (context as unknown as { resume?: () => Promise<void> }).resume;\n if (typeof resume !== \"function\") {\n return () => {};\n }\n\n const doc = document as unknown as DocumentLike;\n const target: EventTargetLike = (doc.body as EventTargetLike | null | undefined) ?? doc;\n const observableContext = context as unknown as {\n state?: string;\n addEventListener?: (type: string, listener: () => void) => void;\n removeEventListener?: (type: string, listener: () => void) => void;\n };\n\n let armed = false;\n let resumeInFlight = false;\n let disposed = false;\n\n const removeAll = () => {\n if (!armed) return;\n for (const type of UNLOCK_EVENT_TYPES) {\n target.removeEventListener(type, handler, GESTURE_LISTENER_OPTIONS);\n }\n armed = false;\n };\n\n const handler = () => {\n if (disposed || resumeInFlight) return;\n resumeInFlight = true;\n\n // Remove listeners FIRST so a re-entrant gesture cannot re-trigger us\n // while resume() is in flight.\n removeAll();\n\n // Play the iOS primer INSIDE the gesture call stack. iOS requires that\n // an AudioBufferSourceNode be created and started synchronously inside\n // the gesture handler for the context to truly unlock — calling\n // resume() alone is not sufficient. A 1-sample silent buffer is the\n // minimum that satisfies the requirement and is inaudible.\n try {\n // BaseContext doesn't declare createBuffer because Cacophony's normal\n // code path always feeds an AudioBuffer constructed externally; the\n // primer needs to construct a 1-sample buffer in-place, so we widen\n // the type locally here. Both AudioContext and OfflineAudioContext\n // expose createBuffer.\n const ctxWithCreateBuffer = context as unknown as {\n createBuffer(numberOfChannels: number, length: number, sampleRate: number): unknown;\n };\n const buffer = ctxWithCreateBuffer.createBuffer(1, 1, context.sampleRate);\n const source = context.createBufferSource();\n source.buffer = buffer as any;\n source.connect(context.destination);\n // The load-bearing iOS pattern is start(0); stop(0) on a silent buffer\n // INSIDE the gesture call stack. A 1-sample non-looping buffer would\n // end on its own, but the pair is what the platform contract names.\n source.start(0);\n source.stop(0);\n } catch (err) {\n // Primer failure should not block the rest of the unlock; the\n // context.resume() call below is still useful on platforms that do\n // not require the primer.\n console.warn(\"[cacophony/autoplayUnlock] primer failed:\", err);\n }\n\n // Resume the context, then emit unlock. The `unlock` event signals that\n // audio is actually playable, so we must wait for resume() to fulfill\n // before emitting. On rejection we surface the error and do NOT emit\n // unlock — a failed resume is not an unlock. `resume` is guaranteed to\n // be a function here (guarded at install time above).\n resume.call(context).then(\n () => {\n resumeInFlight = false;\n if (disposed) return;\n try {\n onUnlock();\n } catch (err) {\n console.error(\"[cacophony/autoplayUnlock] onUnlock callback threw:\", err);\n }\n },\n (err: unknown) => {\n resumeInFlight = false;\n if (disposed) return;\n console.warn(\"[cacophony/autoplayUnlock] resume failed:\", err);\n syncGestureListeners();\n },\n );\n };\n\n const armAll = () => {\n if (disposed || armed || resumeInFlight) return;\n for (const type of UNLOCK_EVENT_TYPES) {\n target.addEventListener(type, handler, GESTURE_LISTENER_OPTIONS);\n }\n armed = true;\n };\n\n function syncGestureListeners(): void {\n if (observableContext.state === \"suspended\" || observableContext.state === \"interrupted\") {\n armAll();\n } else {\n removeAll();\n }\n }\n\n const handleStateChange = () => {\n if (!disposed) syncGestureListeners();\n };\n\n observableContext.addEventListener?.(\"statechange\", handleStateChange);\n syncGestureListeners();\n\n return () => {\n if (disposed) return;\n disposed = true;\n removeAll();\n observableContext.removeEventListener?.(\"statechange\", handleStateChange);\n };\n}\n"],"mappings":";AAwBA,IAAM,IAAsE;CAAC;CAAY;CAAS;AAAS,GACrG,IAA2B;CAAE,SAAS;CAAM,SAAS;AAAK;AA6ChE,SAAgB,EAAsB,GAAyC;CAC7E,IAAM,EAAE,YAAS,gBAAa;CAG9B,IAAI,OAAO,WAAa,KACtB,aAAa,CAAC;CAShB,IAAM,IAAU,EAAwD;CACxE,IAAI,OAAO,KAAW,YACpB,aAAa,CAAC;CAGhB,IAAM,IAAM,UACN,IAA2B,EAAI,QAA+C,GAC9E,IAAoB,GAMtB,IAAQ,IACR,IAAiB,IACjB,IAAW,IAET,UAAkB;EACjB,OACL;QAAK,IAAM,KAAQ,GACjB,EAAO,oBAAoB,GAAM,GAAS,CAAwB;GAEpE,IAAQ;EAF4D;CAGtE,GAEM,UAAgB;EAChB,WAAY,IAKhB;GAJA,IAAiB,IAIjB,EAAU;GAOV,IAAI;IASF,IAAM,IAAS,EAAoB,aAAa,GAAG,GAAG,EAAQ,UAAU,GAClE,IAAS,EAAQ,mBAAmB;IAO1C,AANA,EAAO,SAAS,GAChB,EAAO,QAAQ,EAAQ,WAAW,GAIlC,EAAO,MAAM,CAAC,GACd,EAAO,KAAK,CAAC;GACf,SAAS,GAAK;IAIZ,QAAQ,KAAK,6CAA6C,CAAG;GAC/D;GAOA,EAAO,KAAK,CAAO,EAAE,WACb;IACJ,QAAiB,IACb,IACJ,IAAI;KACF,EAAS;IACX,SAAS,GAAK;KACZ,QAAQ,MAAM,uDAAuD,CAAG;IAC1E;GACF,IACC,MAAiB;IAChB,IAAiB,IACb,OACJ,QAAQ,KAAK,6CAA6C,CAAG,GAC7D,EAAqB;GACvB,CACF;EArDU;CAsDZ,GAEM,UAAe;EACf,WAAY,KAAS,IACzB;QAAK,IAAM,KAAQ,GACjB,EAAO,iBAAiB,GAAM,GAAS,CAAwB;GAEjE,IAAQ;EAFyD;CAGnE;CAEA,SAAS,IAA6B;EACpC,AAAI,EAAkB,UAAU,eAAe,EAAkB,UAAU,gBACzE,EAAO,IAEP,EAAU;CAEd;CAEA,IAAM,UAA0B;EAC9B,AAAK,KAAU,EAAqB;CACtC;CAKA,OAHA,EAAkB,mBAAmB,eAAe,CAAiB,GACrE,EAAqB,SAER;EACP,MACJ,IAAW,IACX,EAAU,GACV,EAAkB,sBAAsB,eAAe,CAAiB;CAC1E;AACF"}
@@ -0,0 +1,2 @@
1
+ const e=require("./effectChain.cjs"),t=require("./eventEmitter.cjs"),n=require("./filters.cjs"),r=require("./pannerMixin.cjs"),i=require("./volumeMixin.cjs");var a=class extends r.PannerMixin(i.VolumeMixin(n.FilterManager)){source;_effectChain;_effectContext;_sendGains=new Map;_state=`unplayed`;origin;eventEmitter=new t.TypedEventEmitter;constructor(e){super(),this.origin=e}setEffectChainEndpoints(t,n){if(this._effectContext=t.context??this.origin.context,this._effectChain){this._effectChain.setEndpoints(t,n);return}this._effectChain=new e.EffectChain(t,n,this.constructor.name)}addEffect(e){try{return this.materializeEffect(e)}catch(e){return Promise.reject(e)}}_addSourceEffect(e){return this.materializeEffect(e)}_addFilterEffect(e){return this.materializeEffect(e,e=>{this._filters.push(e)})}materializeEffect(e,t){if(!this._effectChain||!this._effectContext)throw Error(`Cannot add an effect before the playback effect chain is initialized`);let n=this._effectChain,r=n.reserve(),i;try{i=e.build(this._effectContext)}catch(e){throw n.cancel(r),e}if(i instanceof Promise||typeof i==`object`&&i&&`then`in i)return Promise.resolve(i).then(e=>{let i=n.resolve(r,e);return t?.(i),i},e=>{throw n.cancel(r),e});try{let e=n.resolve(r,i);return t?.(e),Promise.resolve(e)}catch(e){throw n.cancel(r),e}}rampEffectParam(e,t,n,r){if(!this._effectChain)throw Error(`Cannot automate an effect before the playback effect chain is initialized`);this._effectChain.rampParam(e,t,n,r)}addFilter(e){if(!this._effectChain)throw Error(`Cannot add a filter before the playback effect chain is initialized`);this._effectChain.add(e,this._filters.length),this._filters.push(e)}removeFilter(e){if(!this._effectChain)throw Error(`Cannot remove a filter before the playback effect chain is initialized`);this._effectChain.remove(e),this._filters=this._filters.filter(t=>t!==e)}setFilterOrder(e){if(!this._effectChain)throw Error(`Cannot reorder filters before the playback effect chain is initialized`);let t=this._effectChain.nodes.filter(e=>!this._filters.includes(e));this._effectChain.setOrder([...e,...t]),this._filters=[...e]}setFilterBypassed(e,t){if(!this._effectChain)throw Error(`Cannot bypass a filter before the playback effect chain is initialized`);this._effectChain.setBypassed(e,t)}isFilterBypassed(e){return this._effectChain?.isBypassed(e)??!1}rampFilterParam(e,t,n,r){if(!this._effectChain)throw Error(`Cannot automate a filter before the playback effect chain is initialized`);this._effectChain.rampParam(e,t,n,r)}get isPlaying(){return this._state===`playing`}get isPaused(){return this._state===`paused`}markPlaying(){this._state=`playing`}markPaused(){this._state=`paused`}markStopped(){this._state=`stopped`}emitPlayStarted(e){this.markPlaying(),this.emit(`play`,this),e&&this.emit(`resume`,void 0),this.origin.cacophony?.emit(`globalPlay`,{source:this.origin,timestamp:Date.now()})}emitPaused(){this.markPaused(),this.emit(`pause`,void 0),this.origin.cacophony?.emit(`globalPause`,{source:this.origin,timestamp:Date.now()})}emitStopped(){this.markStopped(),this.emit(`stop`,void 0),this.origin.cacophony?.emit(`globalStop`,{source:this.origin,timestamp:Date.now()})}on(e,t){return this.eventEmitter.on(e,t)}off(e,t){this.eventEmitter.off(e,t)}emit(e,t){this.eventEmitter.emit(e,t)}async emitAsync(e,t){return this.eventEmitter.emitAsync(e,t)}fadeTo(e,t,n=`linear`,r){return this.emit(`fadeStart`,{target:e,duration:t,type:n}),super.fadeTo(e,t,n,r).then(()=>{this.emit(`fadeEnd`,void 0)})}cancelFade(){let e=this._isFading;super.cancelFade(),e&&this.emit(`fadeCancel`,void 0)}cleanup(){for(let e of this._sendGains.values())try{e.disconnect()}catch{}this._sendGains.clear(),this._effectChain?.destroy(),this._effectChain=void 0,this._effectContext=void 0,this.eventEmitter.removeAllListeners(),super.cleanup()}};exports.BasePlayback=a;
2
+ //# sourceMappingURL=basePlayback.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"basePlayback.cjs","names":[],"sources":["../src/basePlayback.ts"],"sourcesContent":["import type { Bus } from \"./bus\";\nimport type { FadeType, PlayOptions } from \"./cacophony\";\nimport type { PlaybackContainer } from \"./container\";\nimport type { AudioNode, BaseContext, BiquadFilterNode, GainNode } from \"./context\";\nimport { EffectChain } from \"./effectChain\";\nimport type { CacophonyEffect } from \"./effects\";\nimport { TypedEventEmitter } from \"./eventEmitter\";\nimport type { PlaybackEvents } from \"./events\";\nimport { FilterManager } from \"./filters\";\nimport { PannerMixin } from \"./pannerMixin\";\nimport { VolumeMixin } from \"./volumeMixin\";\n\nexport type PlaybackState = \"unplayed\" | \"playing\" | \"paused\" | \"stopped\";\n\nexport abstract class BasePlayback extends /* @__PURE__ */ PannerMixin(/* @__PURE__ */ VolumeMixin(FilterManager)) {\n public source?: AudioNode;\n protected _effectChain?: EffectChain;\n private _effectContext?: BaseContext;\n /**\n * Per-playback send-gain allocations owned by the shared routing state\n * machine. Cleanup disconnects every allocation deterministically.\n */\n _sendGains: Map<Bus, GainNode> = new Map();\n protected _state: PlaybackState = \"unplayed\";\n public origin: PlaybackContainer;\n public eventEmitter: TypedEventEmitter<PlaybackEvents> = new TypedEventEmitter<PlaybackEvents>();\n\n constructor(origin: PlaybackContainer) {\n super();\n this.origin = origin;\n }\n\n protected setEffectChainEndpoints(input: AudioNode, output: AudioNode): void {\n this._effectContext =\n (input.context as BaseContext | undefined) ??\n (this.origin as PlaybackContainer & { context?: BaseContext }).context;\n if (this._effectChain) {\n this._effectChain.setEndpoints(input, output);\n return;\n }\n this._effectChain = new EffectChain(input, output, this.constructor.name);\n }\n\n /** Build and splice an effect into this live playback's pre-panner chain. */\n addEffect(effect: CacophonyEffect): Promise<AudioNode> {\n try {\n return this.materializeEffect(effect);\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n /** @internal Source preplay path that preserves synchronous native-build failures. */\n _addSourceEffect(effect: CacophonyEffect): Promise<AudioNode> {\n return this.materializeEffect(effect);\n }\n\n /** @internal Materialize a source-level biquad recipe and retain filter API compatibility. */\n _addFilterEffect(effect: CacophonyEffect): Promise<AudioNode> {\n return this.materializeEffect(effect, (handle) => {\n this._filters.push(handle as BiquadFilterNode);\n });\n }\n\n private materializeEffect(effect: CacophonyEffect, onBuilt?: (handle: AudioNode) => void): Promise<AudioNode> {\n if (!this._effectChain || !this._effectContext) {\n throw new Error(\"Cannot add an effect before the playback effect chain is initialized\");\n }\n const chain = this._effectChain;\n const reservation = chain.reserve();\n let built;\n try {\n built = effect.build(this._effectContext);\n } catch (error) {\n chain.cancel(reservation);\n throw error;\n }\n if (built instanceof Promise || (typeof built === \"object\" && built !== null && \"then\" in built)) {\n return Promise.resolve(built).then(\n (resolved) => {\n const handle = chain.resolve(reservation, resolved);\n onBuilt?.(handle);\n return handle;\n },\n (error) => {\n chain.cancel(reservation);\n throw error;\n },\n );\n }\n try {\n const handle = chain.resolve(reservation, built);\n onBuilt?.(handle);\n return Promise.resolve(handle);\n } catch (error) {\n chain.cancel(reservation);\n throw error;\n }\n }\n\n rampEffectParam(\n handle: AudioNode,\n paramName: string,\n value: number,\n options?: { duration?: number; type?: FadeType },\n ): void {\n if (!this._effectChain) {\n throw new Error(\"Cannot automate an effect before the playback effect chain is initialized\");\n }\n this._effectChain.rampParam(handle, paramName, value, options);\n }\n\n addFilter(filter: BiquadFilterNode): void {\n if (!this._effectChain) {\n throw new Error(\"Cannot add a filter before the playback effect chain is initialized\");\n }\n this._effectChain.add(filter, this._filters.length);\n this._filters.push(filter);\n }\n\n removeFilter(filter: BiquadFilterNode): void {\n if (!this._effectChain) {\n throw new Error(\"Cannot remove a filter before the playback effect chain is initialized\");\n }\n this._effectChain.remove(filter);\n this._filters = this._filters.filter((candidate) => candidate !== filter);\n }\n\n setFilterOrder(filters: readonly BiquadFilterNode[]): void {\n if (!this._effectChain) {\n throw new Error(\"Cannot reorder filters before the playback effect chain is initialized\");\n }\n const nonFilters = this._effectChain.nodes.filter((node) => !this._filters.includes(node as BiquadFilterNode));\n this._effectChain.setOrder([...filters, ...nonFilters]);\n this._filters = [...filters];\n }\n\n setFilterBypassed(filter: BiquadFilterNode, bypassed: boolean): void {\n if (!this._effectChain) {\n throw new Error(\"Cannot bypass a filter before the playback effect chain is initialized\");\n }\n this._effectChain.setBypassed(filter, bypassed);\n }\n\n isFilterBypassed(filter: BiquadFilterNode): boolean {\n return this._effectChain?.isBypassed(filter) ?? false;\n }\n\n rampFilterParam(\n filter: BiquadFilterNode,\n paramName: string,\n value: number,\n options?: { duration?: number; type?: FadeType },\n ): void {\n if (!this._effectChain) {\n throw new Error(\"Cannot automate a filter before the playback effect chain is initialized\");\n }\n this._effectChain.rampParam(filter, paramName, value, options);\n }\n\n abstract play(options?: PlayOptions): [this];\n abstract pause(): void;\n abstract stop(): void;\n\n /**\n * Checks if the audio is currently playing.\n */\n\n get isPlaying(): boolean {\n return this._state === \"playing\";\n }\n\n get isPaused(): boolean {\n return this._state === \"paused\";\n }\n\n protected markPlaying(): void {\n this._state = \"playing\";\n }\n\n protected markPaused(): void {\n this._state = \"paused\";\n }\n\n protected markStopped(): void {\n this._state = \"stopped\";\n }\n\n protected emitPlayStarted(isResume: boolean): void {\n this.markPlaying();\n this.emit(\"play\", this);\n if (isResume) {\n this.emit(\"resume\", undefined);\n }\n this.origin.cacophony?.emit(\"globalPlay\", {\n source: this.origin,\n timestamp: Date.now(),\n });\n }\n\n protected emitPaused(): void {\n this.markPaused();\n this.emit(\"pause\", undefined);\n this.origin.cacophony?.emit(\"globalPause\", {\n source: this.origin,\n timestamp: Date.now(),\n });\n }\n\n protected emitStopped(): void {\n this.markStopped();\n this.emit(\"stop\", undefined);\n this.origin.cacophony?.emit(\"globalStop\", {\n source: this.origin,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Register event listener.\n * @returns Cleanup function\n */\n on<K extends keyof PlaybackEvents>(event: K, listener: (data: PlaybackEvents[K]) => void): () => void {\n return this.eventEmitter.on(event, listener);\n }\n\n /**\n * Remove event listener.\n */\n off<K extends keyof PlaybackEvents>(event: K, listener: (data: PlaybackEvents[K]) => void): void {\n this.eventEmitter.off(event, listener);\n }\n\n public emit<K extends keyof PlaybackEvents>(event: K, data: PlaybackEvents[K]): void {\n this.eventEmitter.emit(event, data);\n }\n\n public async emitAsync<K extends keyof PlaybackEvents>(event: K, data: PlaybackEvents[K]): Promise<void> {\n return this.eventEmitter.emitAsync(event, data);\n }\n\n /**\n * Fades the volume to a target value, emitting fadeStart and fadeEnd events.\n */\n fadeTo(\n value: number,\n duration: number,\n type: FadeType = \"linear\",\n options?: { startTime?: number; startValue?: number },\n ): Promise<void> {\n this.emit(\"fadeStart\", { target: value, duration, type });\n return super.fadeTo(value, duration, type, options).then(() => {\n this.emit(\"fadeEnd\", undefined);\n });\n }\n\n /**\n * Cancels any in-progress fade, emitting fadeCancel if a fade was active.\n */\n cancelFade(): void {\n const wasFading = this._isFading;\n super.cancelFade();\n if (wasFading) {\n this.emit(\"fadeCancel\", undefined);\n }\n }\n\n cleanup(): void {\n for (const sendGain of this._sendGains.values()) {\n try {\n sendGain.disconnect();\n } catch {\n // The node may already have been disconnected externally.\n }\n }\n this._sendGains.clear();\n this._effectChain?.destroy();\n this._effectChain = undefined;\n this._effectContext = undefined;\n this.eventEmitter.removeAllListeners();\n super.cleanup();\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { Bus } from './bus';
2
- import { FadeType } from './cacophony';
2
+ import { FadeType, PlayOptions } from './cacophony';
3
3
  import { PlaybackContainer } from './container';
4
4
  import { AudioNode, BaseContext, BiquadFilterNode, GainNode } from './context';
5
5
  import { EffectChain } from './effectChain';
@@ -26,7 +26,7 @@ declare const BasePlayback_base: (abstract new (...args: any[]) => {
26
26
  readonly filters: BiquadFilterNode[];
27
27
  addFilters(filters: BiquadFilterNode[]): void;
28
28
  }) & typeof FilterManager & (abstract new (...args: any[]) => import('./volumeMixin').VolumeControls);
29
- export declare abstract class BasePlayback extends BasePlayback_base {
29
+ export declare abstract class BasePlayback extends /* @__PURE__ */ BasePlayback_base {
30
30
  source?: AudioNode;
31
31
  protected _effectChain?: EffectChain;
32
32
  private _effectContext?;
@@ -60,7 +60,7 @@ export declare abstract class BasePlayback extends BasePlayback_base {
60
60
  duration?: number;
61
61
  type?: FadeType;
62
62
  }): void;
63
- abstract play(): [this];
63
+ abstract play(options?: PlayOptions): [this];
64
64
  abstract pause(): void;
65
65
  abstract stop(): void;
66
66
  /**
@@ -88,7 +88,10 @@ export declare abstract class BasePlayback extends BasePlayback_base {
88
88
  /**
89
89
  * Fades the volume to a target value, emitting fadeStart and fadeEnd events.
90
90
  */
91
- fadeTo(value: number, duration: number, type?: FadeType): Promise<void>;
91
+ fadeTo(value: number, duration: number, type?: FadeType, options?: {
92
+ startTime?: number;
93
+ startValue?: number;
94
+ }): Promise<void>;
92
95
  /**
93
96
  * Cancels any in-progress fade, emitting fadeCancel if a fade was active.
94
97
  */
@@ -0,0 +1,157 @@
1
+ import { EffectChain as e } from "./effectChain.mjs";
2
+ import { TypedEventEmitter as t } from "./eventEmitter.mjs";
3
+ import { FilterManager as n } from "./filters.mjs";
4
+ import { PannerMixin as r } from "./pannerMixin.mjs";
5
+ import { VolumeMixin as i } from "./volumeMixin.mjs";
6
+ //#region src/basePlayback.ts
7
+ var a = class extends r(/* @__PURE__ */ i(n)) {
8
+ source;
9
+ _effectChain;
10
+ _effectContext;
11
+ _sendGains = /* @__PURE__ */ new Map();
12
+ _state = "unplayed";
13
+ origin;
14
+ eventEmitter = new t();
15
+ constructor(e) {
16
+ super(), this.origin = e;
17
+ }
18
+ setEffectChainEndpoints(t, n) {
19
+ if (this._effectContext = t.context ?? this.origin.context, this._effectChain) {
20
+ this._effectChain.setEndpoints(t, n);
21
+ return;
22
+ }
23
+ this._effectChain = new e(t, n, this.constructor.name);
24
+ }
25
+ addEffect(e) {
26
+ try {
27
+ return this.materializeEffect(e);
28
+ } catch (e) {
29
+ return Promise.reject(e);
30
+ }
31
+ }
32
+ _addSourceEffect(e) {
33
+ return this.materializeEffect(e);
34
+ }
35
+ _addFilterEffect(e) {
36
+ return this.materializeEffect(e, (e) => {
37
+ this._filters.push(e);
38
+ });
39
+ }
40
+ materializeEffect(e, t) {
41
+ if (!this._effectChain || !this._effectContext) throw Error("Cannot add an effect before the playback effect chain is initialized");
42
+ let n = this._effectChain, r = n.reserve(), i;
43
+ try {
44
+ i = e.build(this._effectContext);
45
+ } catch (e) {
46
+ throw n.cancel(r), e;
47
+ }
48
+ if (i instanceof Promise || typeof i == "object" && i && "then" in i) return Promise.resolve(i).then((e) => {
49
+ let i = n.resolve(r, e);
50
+ return t?.(i), i;
51
+ }, (e) => {
52
+ throw n.cancel(r), e;
53
+ });
54
+ try {
55
+ let e = n.resolve(r, i);
56
+ return t?.(e), Promise.resolve(e);
57
+ } catch (e) {
58
+ throw n.cancel(r), e;
59
+ }
60
+ }
61
+ rampEffectParam(e, t, n, r) {
62
+ if (!this._effectChain) throw Error("Cannot automate an effect before the playback effect chain is initialized");
63
+ this._effectChain.rampParam(e, t, n, r);
64
+ }
65
+ addFilter(e) {
66
+ if (!this._effectChain) throw Error("Cannot add a filter before the playback effect chain is initialized");
67
+ this._effectChain.add(e, this._filters.length), this._filters.push(e);
68
+ }
69
+ removeFilter(e) {
70
+ if (!this._effectChain) throw Error("Cannot remove a filter before the playback effect chain is initialized");
71
+ this._effectChain.remove(e), this._filters = this._filters.filter((t) => t !== e);
72
+ }
73
+ setFilterOrder(e) {
74
+ if (!this._effectChain) throw Error("Cannot reorder filters before the playback effect chain is initialized");
75
+ let t = this._effectChain.nodes.filter((e) => !this._filters.includes(e));
76
+ this._effectChain.setOrder([...e, ...t]), this._filters = [...e];
77
+ }
78
+ setFilterBypassed(e, t) {
79
+ if (!this._effectChain) throw Error("Cannot bypass a filter before the playback effect chain is initialized");
80
+ this._effectChain.setBypassed(e, t);
81
+ }
82
+ isFilterBypassed(e) {
83
+ return this._effectChain?.isBypassed(e) ?? !1;
84
+ }
85
+ rampFilterParam(e, t, n, r) {
86
+ if (!this._effectChain) throw Error("Cannot automate a filter before the playback effect chain is initialized");
87
+ this._effectChain.rampParam(e, t, n, r);
88
+ }
89
+ get isPlaying() {
90
+ return this._state === "playing";
91
+ }
92
+ get isPaused() {
93
+ return this._state === "paused";
94
+ }
95
+ markPlaying() {
96
+ this._state = "playing";
97
+ }
98
+ markPaused() {
99
+ this._state = "paused";
100
+ }
101
+ markStopped() {
102
+ this._state = "stopped";
103
+ }
104
+ emitPlayStarted(e) {
105
+ this.markPlaying(), this.emit("play", this), e && this.emit("resume", void 0), this.origin.cacophony?.emit("globalPlay", {
106
+ source: this.origin,
107
+ timestamp: Date.now()
108
+ });
109
+ }
110
+ emitPaused() {
111
+ this.markPaused(), this.emit("pause", void 0), this.origin.cacophony?.emit("globalPause", {
112
+ source: this.origin,
113
+ timestamp: Date.now()
114
+ });
115
+ }
116
+ emitStopped() {
117
+ this.markStopped(), this.emit("stop", void 0), this.origin.cacophony?.emit("globalStop", {
118
+ source: this.origin,
119
+ timestamp: Date.now()
120
+ });
121
+ }
122
+ on(e, t) {
123
+ return this.eventEmitter.on(e, t);
124
+ }
125
+ off(e, t) {
126
+ this.eventEmitter.off(e, t);
127
+ }
128
+ emit(e, t) {
129
+ this.eventEmitter.emit(e, t);
130
+ }
131
+ async emitAsync(e, t) {
132
+ return this.eventEmitter.emitAsync(e, t);
133
+ }
134
+ fadeTo(e, t, n = "linear", r) {
135
+ return this.emit("fadeStart", {
136
+ target: e,
137
+ duration: t,
138
+ type: n
139
+ }), super.fadeTo(e, t, n, r).then(() => {
140
+ this.emit("fadeEnd", void 0);
141
+ });
142
+ }
143
+ cancelFade() {
144
+ let e = this._isFading;
145
+ super.cancelFade(), e && this.emit("fadeCancel", void 0);
146
+ }
147
+ cleanup() {
148
+ for (let e of this._sendGains.values()) try {
149
+ e.disconnect();
150
+ } catch {}
151
+ this._sendGains.clear(), this._effectChain?.destroy(), this._effectChain = void 0, this._effectContext = void 0, this.eventEmitter.removeAllListeners(), super.cleanup();
152
+ }
153
+ };
154
+ //#endregion
155
+ export { a as BasePlayback };
156
+
157
+ //# sourceMappingURL=basePlayback.mjs.map