cacophony 0.33.0 → 0.34.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.
- package/CHANGELOG.md +1600 -0
- package/README.md +680 -484
- package/dist/automation.cjs +2 -0
- package/dist/automation.cjs.map +1 -0
- package/dist/automation.d.ts +8 -0
- package/dist/automation.mjs +15 -0
- package/dist/automation.mjs.map +1 -0
- package/dist/autoplayUnlock.cjs +1 -1
- package/dist/autoplayUnlock.cjs.map +1 -1
- package/dist/autoplayUnlock.d.ts +2 -0
- package/dist/autoplayUnlock.mjs +32 -26
- package/dist/autoplayUnlock.mjs.map +1 -1
- package/dist/basePlayback.cjs +1 -1
- package/dist/basePlayback.cjs.map +1 -1
- package/dist/basePlayback.d.ts +6 -18
- package/dist/basePlayback.mjs +5 -2
- package/dist/basePlayback.mjs.map +1 -1
- package/dist/bundles/dattorro-reverb-bundle.js_url.cjs +1 -1
- package/dist/bundles/dattorro-reverb-bundle.js_url.cjs.map +1 -1
- package/dist/bundles/dattorro-reverb-bundle.js_url.mjs +1 -1
- package/dist/bundles/dattorro-reverb-bundle.js_url.mjs.map +1 -1
- package/dist/bundles/fdn-reverb-bundle.js_url.cjs +1 -1
- package/dist/bundles/fdn-reverb-bundle.js_url.cjs.map +1 -1
- package/dist/bundles/fdn-reverb-bundle.js_url.mjs +1 -1
- package/dist/bundles/fdn-reverb-bundle.js_url.mjs.map +1 -1
- package/dist/bundles/modulated-delay-bundle.js_url.cjs +1 -1
- package/dist/bundles/modulated-delay-bundle.js_url.cjs.map +1 -1
- package/dist/bundles/modulated-delay-bundle.js_url.mjs +1 -1
- package/dist/bundles/modulated-delay-bundle.js_url.mjs.map +1 -1
- package/dist/cacophony.cjs +1 -1
- package/dist/cacophony.cjs.map +1 -1
- package/dist/cacophony.d.ts +60 -9
- package/dist/cacophony.mjs +157 -80
- package/dist/cacophony.mjs.map +1 -1
- package/dist/container.cjs +1 -1
- package/dist/container.cjs.map +1 -1
- package/dist/container.d.ts +7 -1
- package/dist/container.mjs +28 -21
- package/dist/container.mjs.map +1 -1
- package/dist/context.d.ts +6 -0
- package/dist/effectChain.cjs +1 -1
- package/dist/effectChain.cjs.map +1 -1
- package/dist/effectChain.mjs +22 -27
- package/dist/effectChain.mjs.map +1 -1
- package/dist/effects.cjs +1 -1
- package/dist/effects.cjs.map +1 -1
- package/dist/effects.d.ts +2 -1
- package/dist/effects.mjs +56 -47
- package/dist/effects.mjs.map +1 -1
- package/dist/events.d.ts +13 -3
- package/dist/group.cjs +1 -1
- package/dist/group.cjs.map +1 -1
- package/dist/group.d.ts +5 -2
- package/dist/group.mjs +13 -7
- package/dist/group.mjs.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/mediaStream.cjs +1 -1
- package/dist/mediaStream.cjs.map +1 -1
- package/dist/mediaStream.d.ts +1 -1
- package/dist/mediaStream.mjs +7 -7
- package/dist/mediaStream.mjs.map +1 -1
- package/dist/node.cjs +2 -2
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.ts +8 -7
- package/dist/node.mjs +49 -44
- package/dist/node.mjs.map +1 -1
- package/dist/occlusion.cjs +2 -0
- package/dist/occlusion.cjs.map +1 -0
- package/dist/occlusion.d.ts +19 -0
- package/dist/occlusion.mjs +41 -0
- package/dist/occlusion.mjs.map +1 -0
- package/dist/pannerMixin.cjs +1 -1
- package/dist/pannerMixin.cjs.map +1 -1
- package/dist/pannerMixin.d.ts +23 -50
- package/dist/pannerMixin.mjs +57 -29
- package/dist/pannerMixin.mjs.map +1 -1
- package/dist/pcmStream.cjs +1 -1
- package/dist/pcmStream.cjs.map +1 -1
- package/dist/pcmStream.d.ts +1 -1
- package/dist/pcmStream.mjs +8 -8
- package/dist/pcmStream.mjs.map +1 -1
- package/dist/playOptions.cjs +1 -1
- package/dist/playOptions.cjs.map +1 -1
- package/dist/playOptions.d.ts +5 -1
- package/dist/playOptions.mjs +27 -20
- package/dist/playOptions.mjs.map +1 -1
- package/dist/playback.cjs +1 -1
- package/dist/playback.cjs.map +1 -1
- package/dist/playback.d.ts +19 -1
- package/dist/playback.mjs +45 -23
- package/dist/playback.mjs.map +1 -1
- package/dist/routableSource.cjs +1 -1
- package/dist/routableSource.cjs.map +1 -1
- package/dist/routableSource.d.ts +26 -3
- package/dist/routableSource.mjs +69 -34
- package/dist/routableSource.mjs.map +1 -1
- package/dist/sessionLifecycle.cjs +2 -0
- package/dist/sessionLifecycle.cjs.map +1 -0
- package/dist/sessionLifecycle.d.ts +13 -0
- package/dist/sessionLifecycle.mjs +55 -0
- package/dist/sessionLifecycle.mjs.map +1 -0
- package/dist/sound.cjs +1 -1
- package/dist/sound.cjs.map +1 -1
- package/dist/sound.mjs +22 -18
- package/dist/sound.mjs.map +1 -1
- package/dist/spatialAutomation.cjs +2 -0
- package/dist/spatialAutomation.cjs.map +1 -0
- package/dist/spatialAutomation.d.ts +11 -0
- package/dist/spatialAutomation.mjs +53 -0
- package/dist/spatialAutomation.mjs.map +1 -0
- package/dist/synth.cjs +1 -1
- package/dist/synth.cjs.map +1 -1
- package/dist/synth.mjs +13 -9
- package/dist/synth.mjs.map +1 -1
- package/dist/synthGroup.cjs +1 -1
- package/dist/synthGroup.cjs.map +1 -1
- package/dist/synthGroup.mjs +2 -0
- package/dist/synthGroup.mjs.map +1 -1
- package/dist/synthPlayback.cjs +1 -1
- package/dist/synthPlayback.cjs.map +1 -1
- package/dist/synthPlayback.mjs +1 -6
- package/dist/synthPlayback.mjs.map +1 -1
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/highlight.css +4 -4
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/AudioCache.html +4 -4
- package/docs/classes/AudioSprite.html +7 -7
- package/docs/classes/BarberpoleEffect.html +7 -7
- package/docs/classes/BiquadEffect.html +3 -3
- package/docs/classes/Bus.html +21 -21
- package/docs/classes/Cacophony.html +186 -98
- package/docs/classes/DynamicsEffect.html +7 -7
- package/docs/classes/FdnReverbEffect.html +7 -7
- package/docs/classes/FoaDecoder.html +5 -5
- package/docs/classes/FoaDecoderEffect.html +3 -3
- package/docs/classes/FrequencyShifterEffect.html +7 -7
- package/docs/classes/Group.html +53 -36
- package/docs/classes/HarmonizerEffect.html +7 -7
- package/docs/classes/ImpulseResponseEffect.html +3 -3
- package/docs/classes/KWeightingFilter.html +4 -4
- package/docs/classes/LoudnessMeter.html +11 -11
- package/docs/classes/MediaStreamPlayback.html +146 -147
- package/docs/classes/MediaStreamSound.html +118 -54
- package/docs/classes/MicrophoneStream.html +119 -55
- package/docs/classes/ModulatedDelayEffect.html +7 -7
- package/docs/classes/PcmStreamPlayback.html +146 -147
- package/docs/classes/PcmStreamSound.html +128 -64
- package/docs/classes/PhaserEffect.html +7 -7
- package/docs/classes/Playback.html +218 -175
- package/docs/classes/ReverbEffect.html +7 -7
- package/docs/classes/Scheduler.html +3 -3
- package/docs/classes/ShareEffect.html +3 -3
- package/docs/classes/Sound.html +136 -78
- package/docs/classes/SpectralFreezeEffect.html +7 -7
- package/docs/classes/StereoWidenerEffect.html +3 -3
- package/docs/classes/Synth.html +126 -68
- package/docs/classes/SynthGroup.html +28 -28
- package/docs/classes/TremoloEffect.html +7 -7
- package/docs/classes/TruePeakDetector.html +8 -8
- package/docs/classes/WaveshaperEffect.html +7 -7
- package/docs/functions/encodeMonoToFoaSN3D.html +1 -1
- package/docs/functions/integratedLoudness.html +1 -1
- package/docs/functions/integratedUngatedLoudness.html +1 -1
- package/docs/functions/loudnessRange.html +1 -1
- package/docs/functions/timeStretch.html +1 -1
- package/docs/functions/timeStretchChannels.html +1 -1
- package/docs/functions/truePeakDb.html +1 -1
- package/docs/hierarchy.html +28 -28
- package/docs/index.html +165 -2
- package/docs/interfaces/AudioBuffer.html +8 -8
- package/docs/interfaces/AudioBufferSourceNode.html +22 -22
- package/docs/interfaces/AudioEventCallbacks.html +2 -2
- package/docs/interfaces/AudioListener.html +12 -12
- package/docs/interfaces/AudioNode.html +14 -14
- package/docs/interfaces/AudioParam.html +26 -8
- package/docs/interfaces/AudioWorklet.html +2 -2
- package/docs/interfaces/AudioWorkletNode.html +16 -16
- package/docs/interfaces/BarberpoleOptions.html +5 -5
- package/docs/interfaces/BaseContext.html +25 -25
- package/docs/interfaces/BaseSound.html +16 -16
- package/docs/interfaces/BiquadCoefficients.html +6 -6
- package/docs/interfaces/BiquadFilterNode.html +20 -20
- package/docs/interfaces/BuiltEffectGraph.html +6 -6
- package/docs/interfaces/CacheErrorEvent.html +5 -5
- package/docs/interfaces/CacheHitEvent.html +4 -4
- package/docs/interfaces/CacheMissEvent.html +4 -4
- package/docs/interfaces/CacophonyEffect.html +2 -2
- package/docs/interfaces/CacophonyLogger.html +4 -4
- package/docs/interfaces/ChannelMergerNode.html +14 -14
- package/docs/interfaces/ChannelSplitterNode.html +14 -14
- package/docs/interfaces/ConvolverNode.html +16 -16
- package/docs/interfaces/CreateSpriteOptions.html +3 -3
- package/docs/interfaces/DeviceChangeEvent.html +64 -0
- package/docs/interfaces/DynamicsOptions.html +7 -7
- package/docs/interfaces/FadeStartEvent.html +4 -4
- package/docs/interfaces/FdnReverbOptions.html +6 -6
- package/docs/interfaces/FoaDecoderOptions.html +2 -2
- package/docs/interfaces/FrequencyShifterOptions.html +3 -3
- package/docs/interfaces/GainNode.html +15 -15
- package/docs/interfaces/GlobalPlaybackEvent.html +3 -3
- package/docs/interfaces/HarmonizerOptions.html +6 -6
- package/docs/interfaces/ImpulseResponseOptions.html +5 -5
- package/docs/interfaces/LoadingCompleteEvent.html +5 -5
- package/docs/interfaces/LoadingErrorEvent.html +5 -5
- package/docs/interfaces/LoadingProgressEvent.html +6 -6
- package/docs/interfaces/LoadingStartEvent.html +3 -3
- package/docs/interfaces/LoudnessChannelInput.html +3 -3
- package/docs/interfaces/LoudnessReading.html +5 -5
- package/docs/interfaces/MediaElementSourceNode.html +15 -15
- package/docs/interfaces/MediaStreamAudioSourceNode.html +15 -15
- package/docs/interfaces/MediaStreamSoundOptions.html +5 -5
- package/docs/interfaces/MicrophoneStreamOptions.html +8 -8
- package/docs/interfaces/ModulatedDelayOptions.html +8 -8
- package/docs/interfaces/OfflineOptions.html +5 -5
- package/docs/interfaces/OscillatorNode.html +20 -20
- package/docs/interfaces/PannerNode.html +28 -28
- package/docs/interfaces/PcmStreamBufferEvent.html +2 -2
- package/docs/interfaces/PcmStreamSoundOptions.html +6 -6
- package/docs/interfaces/PhaserOptions.html +7 -7
- package/docs/interfaces/PlayOptions.html +13 -13
- package/docs/interfaces/PlaybackErrorEvent.html +5 -5
- package/docs/interfaces/ReverbOptions.html +13 -13
- package/docs/interfaces/RuntimeOptions.html +41 -15
- package/docs/interfaces/ScheduledCallbackHandle.html +2 -2
- package/docs/interfaces/SendGainOptions.html +68 -0
- package/docs/interfaces/SoundCleanupHoldings.html +4 -4
- package/docs/interfaces/SoundErrorEvent.html +6 -6
- package/docs/interfaces/SpectralFreezeOptions.html +4 -4
- package/docs/interfaces/SpriteRegion.html +4 -4
- package/docs/interfaces/StereoPannerNode.html +15 -15
- package/docs/interfaces/StereoToBFormatOptions.html +2 -2
- package/docs/interfaces/StereoWidenerOptions.html +4 -4
- package/docs/interfaces/StreamCapabilities.html +5 -5
- package/docs/interfaces/TimeStretchOptions.html +5 -5
- package/docs/interfaces/TremoloOptions.html +5 -5
- package/docs/interfaces/WaveshaperOptions.html +5 -5
- package/docs/modules.html +4 -4
- package/docs/types/AudioSinkId.html +35 -0
- package/docs/types/BaseAudioEvents.html +11 -11
- package/docs/types/BuiltEffect.html +1 -1
- package/docs/types/BusConnectionTarget.html +1 -1
- package/docs/types/CacheEventCallback.html +1 -1
- package/docs/types/CacophonyEvents.html +40 -20
- package/docs/types/ErrorEventCallback.html +1 -1
- package/docs/types/FadeType.html +1 -1
- package/docs/types/HrtfPannerOptions.html +1 -1
- package/docs/types/ImpulseResponseSource.html +1 -1
- package/docs/types/LoadingEventCallback.html +1 -1
- package/docs/types/LoopCount.html +1 -1
- package/docs/types/LoudnessChannel.html +1 -1
- package/docs/types/Orientation.html +3 -3
- package/docs/types/PanCloneOverrides.html +13 -7
- package/docs/types/PanType.html +1 -1
- package/docs/types/PcmStreamEvents.html +6 -6
- package/docs/types/PcmStreamState.html +1 -1
- package/docs/types/PlaybackEvents.html +1 -1
- package/docs/types/Position.html +1 -1
- package/docs/types/SoundEvents.html +1 -1
- package/docs/types/SoundType.html +1 -1
- package/docs/types/SourceNode.html +1 -1
- package/docs/types/SpriteMap.html +1 -1
- package/docs/types/SynthEvents.html +1 -1
- package/docs/types/ThreeDOptions.html +5 -15
- package/docs/types/WebCodecsStreamSound.html +1 -1
- package/docs/variables/CHANNEL_WEIGHTS.html +1 -1
- package/docs/variables/K_WEIGHTING_STAGE1_48K.html +1 -1
- package/docs/variables/K_WEIGHTING_STAGE2_48K.html +1 -1
- package/docs/variables/consoleLogger.html +1 -1
- package/docs/variables/noopLogger.html +1 -1
- package/package.json +6 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,1600 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to cacophony are recorded here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html). While cacophony is 0.x, a minor release
|
|
6
|
+
may contain breaking changes; they are always listed first under **⚠ Breaking** with a migration
|
|
7
|
+
note. Patch releases do not break.
|
|
8
|
+
|
|
9
|
+
Entries before 0.33.0 were reconstructed in September 2026 from the git history, pull requests,
|
|
10
|
+
and source diffs. Some versions were tagged but never published to npm; they are marked as such.
|
|
11
|
+
|
|
12
|
+
<!--
|
|
13
|
+
How to add an entry: put a bullet under "## [Unreleased]" in the same PR as the change, in the
|
|
14
|
+
right subsection (⚠ Breaking, Added, Changed, Deprecated, Removed, Fixed, Security). Write it for
|
|
15
|
+
someone upgrading, not as a commit message. `npm version` stamps the release; see CLAUDE.md.
|
|
16
|
+
-->
|
|
17
|
+
|
|
18
|
+
## [Unreleased]
|
|
19
|
+
|
|
20
|
+
## [0.34.0] - 2026-10-03
|
|
21
|
+
|
|
22
|
+
### ⚠ Breaking
|
|
23
|
+
- Spatial setters (`stereoPan`, `position`, `threeDOptions`) now reject incompatible panning modes, invalid values, or cleaned-up voices before changing any source defaults or voices. Group spatial setters preflight every member too. `ThreeDOptions` now describes HRTF configuration only; assigning it never switches modes. Migration: select the intended `panType` when creating a source or in `play({ panType, ... })`, and control mixed-mode voices individually. (#104)
|
|
24
|
+
- `Sound.clone`, `Synth.clone`, and `Playback.clone` reject invalid spatial overrides or overrides incompatible with the clone's target mode before allocation, instead of ignoring them or storing unusable defaults. Direct HRTF setters now share invocation constraints, including nonnegative cone angles. Migration: remove spatial overrides for the other mode and pass finite values within the documented bounds. (#104)
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- Group positions are validated even with no members, and position inputs and returned snapshots no longer share mutable arrays with the group. (#104)
|
|
28
|
+
- Reverb and delay tails no longer cut off when their input goes away. `createReverb`, `createFdnReverb`, and the `createDelay` family (delay, chorus, flanger, vibrato, doubling) keep rendering after the last source feeding them ends or is disconnected, for example a one-shot sending to a shared reverb bus. Before, the effect fell silent at that moment. (#255)
|
|
29
|
+
- `createFdnReverb` no longer follows the pan of its input. A source panned to one side used to produce reverb on that side only; the wet signal is now spread across both channels, which have different echo patterns and stay decorrelated at every `diffusion` setting, while the dry part of `mix` keeps its position. (#255)
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
- Browser audio-session recovery via `RuntimeOptions.autoRecover` (default `true`), platform `suspend`/`resume`/`interrupted` events, audio-output `devicechange` notifications, and `Cacophony.dispose()` for listener teardown. Visible-page recovery and gesture unlock preserve explicit user pauses. Recovery starts only after the context has first run, leaving autoplay unlock to the gesture path; a gesture unlock now also emits `resume`. Concurrent `pause()` calls settle with the pending suspension. (#209)
|
|
33
|
+
- Runtime `Cacophony.setOutputDevice()` and `outputDevice` for supporting browser and Node contexts, shared `AudioSinkId`, and `sinkChange` events for the active output. Platform permission errors propagate unchanged; offline selection is a no-op. (#203)
|
|
34
|
+
- Opt-in spatial motion smoothing via `RuntimeOptions.spatialSmoothingTau`, source/voice `spatialSmoothingTau`, and `Cacophony.listenerSmoothingTau` (seconds). Position, orientation and stereo pan retarget smoothly; initial and replayed poses remain immediate, getters report requested targets, and setting the constant to `0` snaps pending transitions. Legacy listener APIs remain immediate. (#201)
|
|
35
|
+
- Sources and Groups can remove an aux send with `removeSend(busOrName)` and ramp an existing send with `routeTo(busOrName, gain, { duration, type })`. Removal disconnects every voice's send and prevents future voices or bus drains from recreating it, while preserving primary routing. Ramps reuse existing nodes, interrupt smoothly, and take milliseconds; instant changes remain the default. (#241)
|
|
36
|
+
- `Playback.setOcclusion(amount, duration?)` renders per-voice obstruction with a dedicated pre-panner low-pass and attenuation stage, independently of volume and fades. Amounts clamp to `[0, 1]`; transitions default to 50 ms; resetting to `0` restores the clear path. `Playback.occlusion` reports the requested amount. The caller owns geometry, materials, and policy. (#221)
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
- `routeTo(busOrName, sendGain)` throws `RangeError` for a non-finite send gain instead of storing it, and `routeTo` throws `TypeError` when ramp options are passed without a send gain instead of ignoring them. (#241)
|
|
40
|
+
- `createReverb`, `createFdnReverb`, and the `createDelay` family now always take stereo in and give stereo out: a mono input is up-mixed and an input with more than two channels is down-mixed. A mono source through `createChorus`, `createFlanger`, `createVibrato`, or `createDoubling` therefore comes out as stereo, with the two channels modulated a quarter cycle apart; a plain `createDelay` is unchanged. An effect placed on a bus carrying more than two channels (for example first-order ambisonics ahead of a decoder) now folds it to stereo. (#255)
|
|
41
|
+
- `createFdnReverb` excites its wet path with the mono sum of the input, as `createReverb` already did. The wet level is unchanged for a centred source, about 3 dB lower for a hard-panned source or for wide stereo material, and zero for content that is out of phase between left and right. (#255)
|
|
42
|
+
|
|
43
|
+
## [0.33.0] - 2026-09-26
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
- `Playback.cleanup()` (and so `Sound.cleanup()`) stops started native buffer sources instead of only disconnecting them. Looping sources no longer keep running and holding decoded audio after cleanup. Shared buffers, sibling voices, and replay of stopped playbacks are unaffected. (#239)
|
|
47
|
+
|
|
48
|
+
## [0.32.1] - 2026-09-13
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
- `Playback.seek()` emits the `seek` event (with the new time) once after an accepted seek on buffer and media-element playbacks. Rejected seeks emit nothing. `Sound` does not relay a collective `seek` event. (#213, #237)
|
|
52
|
+
|
|
53
|
+
## [0.32.0] - 2026-09-13
|
|
54
|
+
|
|
55
|
+
### ⚠ Breaking
|
|
56
|
+
- `play(options)` validates its options before creating a voice and throws on invalid values: a `RangeError` for out-of-range numbers such as a negative `fadeIn` or `at`, and an `Error` for controls the source cannot honor. For example, `Synth` and live streams now reject `fadeOut`, `fadeInPerLoop`, `playbackRate`, and `loopCount` where they used to ignore them. Migration: drop the unsupported fields from those calls. (#232, #236)
|
|
57
|
+
- `AudioCache` follows HTTP caching rules (via `http-cache-semantics`) for both the in-memory decoded cache and the persistent Cache API store. Responses marked `no-store` are no longer retained, and stale memory hits get revalidated. `setCacheExpirationTime()` now only sets the fallback TTL for responses that have no cache directives, expiry, or validators, and it throws a `RangeError` for negative or non-finite values. Persistent entries written by older versions are ignored and fetched again once. Migration: for static audio, use versioned URLs or send `Cache-Control` headers, and expose `ETag`/`Age`/`Vary` through CORS where freshness depends on them. (#229, #234)
|
|
58
|
+
- `sound.playbacks` no longer keeps stopped playbacks: they are removed when the next voice is prepared. A reaped `Playback` you still hold can be replayed and gets re-attached to the Sound's current routing. Migration: keep your own references if you need stopped voices to stay in that list. (#212, #235)
|
|
59
|
+
|
|
60
|
+
### Added
|
|
61
|
+
- `PlayOptions` accepts per-voice `volume`, `playbackRate`, `loopCount`, `panType`, `stereoPan`, `position`, and `threeDOptions`. They apply to the new voice before its source starts and leave the Sound's defaults and other voices alone. `Group.play(options)` checks the options against every member first. (#232, #236)
|
|
62
|
+
- `BasePlayback.state`: a read-only lifecycle state for any playback. (#235)
|
|
63
|
+
- New runtime dependency `http-cache-semantics` (pinned to 4.1.1). Its license is included in `THIRD_PARTY_NOTICES.md`. (#234)
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
- `Sound.clone({ filters: [] })` clears the inherited filters. Before this, an empty array fell back to the source's filters. (#231, #233)
|
|
67
|
+
- `AudioCache` fixes: cross-origin audio is cached again. An unreadable or missing persistent body is evicted and fetched again. Aborting a `data:` URL load counts as an abort. A progress callback that throws no longer breaks a shared load for other subscribers. Progress stays capped when `Content-Length` underestimates the body. Abort notifications to loading-error callbacks work again. (#234)
|
|
68
|
+
- If `play()` fails partway, the voices it just created are stopped and removed. A reused stream voice survives a failed replay. (#236)
|
|
69
|
+
|
|
70
|
+
## [0.31.0] - 2026-09-08
|
|
71
|
+
|
|
72
|
+
### ⚠ Breaking
|
|
73
|
+
- `Cacophony.createStereoToBFormatNode(signal?)` is now `createStereoToBFormatNode(options?, signal?)`. Migration: change `createStereoToBFormatNode(signal)` to `createStereoToBFormatNode({}, signal)`. (#193, #220)
|
|
74
|
+
|
|
75
|
+
### Added
|
|
76
|
+
- Audio sprites: `cacophony.createSprite(sourceUrlOrBuffer, map)` returns an `AudioSprite` whose named regions are ordinary `Sound`s over one shared `AudioBuffer`. Playback, seeking, looping, cloning, and time-stretching stay inside each region. Exports `AudioSprite`, `SpriteMap`, `SpriteRegion`, and `CreateSpriteOptions`. (#196, #223)
|
|
77
|
+
- `cacophony sprite <file...> --out atlas.wav --map atlas.json [--gap ms]` CLI command that packs files into a WAV atlas and a matching `SpriteMap`. It runs headless, with no audio output device needed. (#223, #224)
|
|
78
|
+
- Sample-accurate scheduling: `play({ at })` starts a buffer sound at an absolute `AudioContext` time, and a scheduled `fadeIn` starts at that time too. Media, PCM, microphone, and synth sources throw if you pass `at`. (#195, #222)
|
|
79
|
+
- Exported `Scheduler` class (lookahead callback scheduler on `AudioContext` time, with `ScheduledCallbackHandle.cancel()`). (#195, #222)
|
|
80
|
+
- BCC stereo-to-FOA encoder: `createStereoToBFormatNode({ algorithm: "bcc" })`. The default stays `"perceptual"`. `StereoToBFormatOptions` is exported. (#193, #220)
|
|
81
|
+
- `fadeTo()`/`fadeIn()` accept an optional `startTime` option (plus `startValue` for `fadeTo`) for scheduled fades. (#222)
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
- MediaBunny (the WebCodecs streaming adapter) and each AudioWorklet bundle are loaded on demand instead of at import time. `package.json` declares `sideEffects` so bundlers can tree-shake unused modules. The PR reports a consumer bundle's initial gzip size dropping from about 275 KB to about 36 KB. `loadWorklets()` still preloads everything. Your bundler and host must serve the extra code-split chunks. (#225)
|
|
85
|
+
- `createWorkletNode()` accepts a worklet URL as a string or as an async loader (`() => Promise<string>`). A custom `resolveWorkletUrl` still receives a string. (#225)
|
|
86
|
+
|
|
87
|
+
### Fixed
|
|
88
|
+
- Autoplay unlock treats iOS Safari's `interrupted` context state like `suspended`, so audio comes back after the next gesture. (#215, #217)
|
|
89
|
+
- Setting `Bus.gain` cancels any scheduled gain ramps first, so a ramp no longer overrides a later direct assignment. (#214, #218)
|
|
90
|
+
|
|
91
|
+
## [0.30.4] - 2026-08-14
|
|
92
|
+
|
|
93
|
+
### Fixed
|
|
94
|
+
- The published TypeScript declarations include `BasePlayback`, `VolumeMixin`, and the public time-stretch types, which 0.30.3 was missing. (#192)
|
|
95
|
+
|
|
96
|
+
## [0.30.3] - 2026-08-14
|
|
97
|
+
|
|
98
|
+
_First npm release after 0.29.0 through 0.30.2, which were tagged but not published. Upgrading from an earlier npm version? Read those entries too._
|
|
99
|
+
|
|
100
|
+
### Fixed
|
|
101
|
+
- Firefox no longer crashes with `this.listener.forwardX is undefined`. Its native `AudioListener` has no position/orientation `AudioParam`s, so listener setters fall back to `setPosition()`/`setOrientation()` there (and on partial implementations), and getters return a cached pose. (#189, #190, #191)
|
|
102
|
+
|
|
103
|
+
### Changed
|
|
104
|
+
- The exported `AudioListener` type marks its `positionX`...`upZ` params as optional and adds optional `setPosition`/`setOrientation`. TypeScript code that reads those params directly may need a guard. (#190)
|
|
105
|
+
|
|
106
|
+
## [0.30.2] - 2026-08-14
|
|
107
|
+
|
|
108
|
+
_Tagged but not published to npm._
|
|
109
|
+
|
|
110
|
+
### Changed
|
|
111
|
+
- Failed release: the release workflow ran tests before building. Its contents were re-released as 0.30.3.
|
|
112
|
+
|
|
113
|
+
## [0.30.1] - 2026-08-13
|
|
114
|
+
|
|
115
|
+
_Tagged but not published to npm._
|
|
116
|
+
|
|
117
|
+
### Changed
|
|
118
|
+
- Version bump only. No code changes.
|
|
119
|
+
|
|
120
|
+
## [0.30.0] - 2026-08-11
|
|
121
|
+
|
|
122
|
+
_Tagged but not published to npm._
|
|
123
|
+
|
|
124
|
+
### ⚠ Breaking
|
|
125
|
+
- The public `applyFilters()` and `removeFilters()` methods are removed from `Sound`, `Playback`, and other `FilterManager` subclasses. Migration: call `removeFilter()` for each filter, and use `addFilter()`/`addFilters()` to build chains. (#161, #176)
|
|
126
|
+
- `Bus.addFilter()` throws synchronously when given a raw `AudioNode` (or a biquad from a different `AudioContext`) instead of returning a rejected Promise. Migration: wrap the call in `try`/`catch` as well as `.catch()`, or wrap the node with `cacophony.shareEffect()`. (#168, #170, #187, #188)
|
|
127
|
+
|
|
128
|
+
### Added
|
|
129
|
+
- Five new AudioWorklet effects: `createFrequencyShifter()`, `createBarberpole()`, `createHarmonizer()`, `createSpectralFreeze()`, and `createStereoWidener()`. Exports `FrequencyShifterEffect`, `BarberpoleEffect`, `HarmonizerEffect`, `SpectralFreezeEffect`, `StereoWidenerEffect`, and their `*Options` types. (#155)
|
|
130
|
+
- `MicrophoneStreamOptions.stopTracksOnStop` (default `true`). Set it to `false` to keep the microphone stream alive after stop or cleanup. (#160, #181)
|
|
131
|
+
- PCM and media-stream playbacks emit `resume` when resumed, like buffer and synth playbacks. (#173, #185)
|
|
132
|
+
|
|
133
|
+
### Changed
|
|
134
|
+
- Effect-chain guard errors have new messages, prefixed with the owning chain's scope. An effect whose `build()` returns something other than an `AudioNode` or `BuiltEffectGraph` is rejected with a clear error. (#168, #170)
|
|
135
|
+
- HLS errors say whether `hls.js` is not installed or Media Source Extensions are unsupported. Other import failures are re-thrown unchanged. hls.js errors are always reported with `recoverable: false`. (#162, #186)
|
|
136
|
+
- `FoaDecoder` rejects HRIR buffers with fewer than 4 channels and requires `createBuffer` support in the context. (#165, #184)
|
|
137
|
+
- Media-element streams: `seek()` throws when the element exposes no seekable range (for example, live streams). A loop setting made before playback applies to new playbacks. Cleanup clears and reloads the element's source. (#59, #154)
|
|
138
|
+
|
|
139
|
+
### Fixed
|
|
140
|
+
- Autoplay unlock re-arms whenever the context becomes suspended later on (not only at construction) and retries after a failed `resume()`. (#158, #179)
|
|
141
|
+
- `AudioCache`: one caller aborting a shared in-flight load no longer cancels it for other callers. The request is cancelled only after every caller aborts. (#159, #180)
|
|
142
|
+
- `MediaStreamPlayback` cleanup stops tracks it owns, and play/resume keep tracks you disabled on purpose disabled. (#160, #181)
|
|
143
|
+
- `Synth.clone()` produces independent oscillator options and position, and honors an empty `filters` override. (#156, #177)
|
|
144
|
+
- An effect graph rejected as a duplicate by `EffectChain` or `Bus` is disposed instead of leaked. (#157, #178)
|
|
145
|
+
- `Bus.addFilter()` keeps declaration order when several async effect builds are in flight at once. (#168, #187)
|
|
146
|
+
- WebCodecs streams report a seek during a decoder reopen separately from a disposed stream. (#163, #182)
|
|
147
|
+
- The WebCodecs streaming resampler writes into preallocated `Float32Array`s, so it no longer allocates boxed arrays for every chunk. (#164, #183)
|
|
148
|
+
|
|
149
|
+
## [0.29.0] - 2026-07-31
|
|
150
|
+
|
|
151
|
+
_Tagged but not published to npm._
|
|
152
|
+
|
|
153
|
+
### ⚠ Breaking
|
|
154
|
+
- `createStream()` now resolves to `Sound | WebCodecsStreamSound`. When `AudioDecoder` exists and the URL can be demuxed, the stream is decoded through WebCodecs into a PCM ring buffer instead of an `HTMLAudioElement`. Otherwise it falls back to the media-element `Sound`. Narrow the result before calling `Sound`-only methods. (#131, #137)
|
|
155
|
+
- Playback filters and pitch shifting now run before the panner (`source → effects → panner → gain`), not after it. There is no option to keep the old post-panner placement, so an effect chain on an HRTF-panned sound will sound different. (#140, #150)
|
|
156
|
+
- `Sound.resume()` and `Synth.resume()` only resume paused playbacks. Before this, they also restarted playbacks that had been stopped or never played. (#105, #123)
|
|
157
|
+
- `cacophony.volume = 0` no longer counts as muted. `muted` is now tracked separately from the gain value, and a later nonzero volume applies immediately. (#103, #139)
|
|
158
|
+
- `setGlobalVolume()` called while muted is deferred until `unmute()`, the same as the `volume` setter. Before, it unmuted the output. (#141, #149)
|
|
159
|
+
- `cacophony.master.destroy()` throws. Destroying the master bus used to silence the instance permanently. (#142, #147)
|
|
160
|
+
- The microphone was rebuilt on `MediaStreamSound`. `MicrophoneStream` now extends `MediaStreamSound`, `MicrophonePlayback` is an alias of `MediaStreamPlayback`, and microphone output goes through the master bus. `getMicrophoneStream(options?)` takes `constraints`, `panType`, `stereoPan` and `threeDOptions`, and acquisition failures reject the promise. (#102, #110, #153)
|
|
161
|
+
- `AudioCache` keeps decoded buffers and in-flight requests per audio context, and `clearMemoryCache()` clears only the instance it is called on. Before, one context could receive a buffer decoded at another context's sample rate. (#107, #124)
|
|
162
|
+
- `mediabunny` is a new required runtime dependency, used for WebCodecs demuxing. `node-web-audio-api` is a new `optionalDependency`, so npm installs it by default unless you pass `--omit=optional`.
|
|
163
|
+
|
|
164
|
+
### Added
|
|
165
|
+
- `cacophony/node` entry point with `createNodeCacophony()` and `createOfflineNodeCacophony()`, plus `decodeAudioFile()`, for running the engine headlessly on `node-web-audio-api`. The native backend is loaded lazily and needs Node 22 or later. (#93)
|
|
166
|
+
- `cacophony` CLI (`bin/cacophony.mjs`) with `render`, `play`, `synth`, `meter` and `repl` commands. Set `CACOPHONY_SINK=none` for machines with no audio device. (#93)
|
|
167
|
+
- `createPcmStreamSound()` / `PcmStreamSound`: a push-based PCM source backed by an AudioWorklet ring buffer, with backpressure, underrun/drain/ended events, pause/resume and `AbortSignal` teardown. (#130, #134)
|
|
168
|
+
- HLS: `.m3u8` URLs passed to `createStream()` use native HLS when the browser supports it. Otherwise they load the optional `hls.js` peer dependency. (#132, #138)
|
|
169
|
+
- `StreamCapabilities` (`transport`, `seekable`, `live`, `duration`) reported on streamed sounds. `createStream()` accepts a `panType` argument. (#137, #145)
|
|
170
|
+
- Per-source effects: `addEffect()` / `removeEffect()` on `Sound`, `Synth`, PCM streams and media streams. Each playback gets its own copy of the effect, in declaration order. (#113, #151)
|
|
171
|
+
- Playback effect chains support reordering, bypass and parameter automation (`setFilterOrder`, `setFilterBypassed`, `isFilterBypassed`), matching `Bus`. (#140, #150)
|
|
172
|
+
- `MediaStreamSound.routeTo()`, so live streams can be routed through buses like `Sound` and `Synth`. (#112, #127)
|
|
173
|
+
- `Group.resetOrder()` restarts ordered playback after a non-looping sequence runs out. `Group.play()`, `playRandom()` and `playOrdered()` accept `PlayOptions`. (#109, #136)
|
|
174
|
+
- `Playback.isPaused`, and one shared playback state machine across all playback types. (#106, #125)
|
|
175
|
+
- `Cacophony.createOffline()` takes a third `runtimeOptions` argument. (#108, #135)
|
|
176
|
+
- `RuntimeOptions.logger` (`CacophonyLogger`, `consoleLogger`, `noopLogger`), `RuntimeOptions.quiet` and `RuntimeOptions.resolveWorkletUrl`. (#93)
|
|
177
|
+
- `MicrophoneStream` and `MicrophoneStreamOptions` are exported. (#145, #153)
|
|
178
|
+
|
|
179
|
+
### Changed
|
|
180
|
+
- `AudioCache` falls back to fetch-only when the Cache API is unavailable, as in Node. (#93)
|
|
181
|
+
- The unused chunked-WAV `stream.ts` decoder was removed, and the docs now say that `"streaming"` sounds are backed by a media element. (#129, #133)
|
|
182
|
+
|
|
183
|
+
### Fixed
|
|
184
|
+
- Changing `panType` on a live playback, or cloning with a `panType` override, no longer leaves it silent. (#101, #122)
|
|
185
|
+
- `Playback.clone()` connects the clone to the origin's route, really starts clones of playing buffer playbacks, and registers them on `Sound.playbacks`. (#100, #121)
|
|
186
|
+
- `Playback.clone()` keeps fade-in/fade-out settings and pitch shift, with its own worklet node. (#143, #148)
|
|
187
|
+
- Group playback goes through `Sound.play()`, so member `play` events fire and fades apply. (#109, #136)
|
|
188
|
+
- `createSound(urls[])` format fallback works under Node, where there is no `Audio` global. (#144, #146)
|
|
189
|
+
- `SynthPlayback` inherits from `BasePlayback` directly. This removes the `OscillatorMixin` trap that restarted oscillators unconditionally. (#111, #120)
|
|
190
|
+
- `SynthPlayback` emits playback and global lifecycle events. An unset synth `detune` defaults to `0`. A failed send-gain allocation is disposed. (#145, #152)
|
|
191
|
+
- The first HTML/streaming playback reuses the media element already loaded for metadata, instead of fetching the media twice. (#114, #128)
|
|
192
|
+
- An empty `SynthGroup` returns `detune` `0`. (#114, #128)
|
|
193
|
+
- Offline fades resolve on context time, not wall-clock time. (#114, #128)
|
|
194
|
+
- A media stream whose tracks ended on `stop()` refuses to replay instead of reporting a dead replay as active. (#114, #128)
|
|
195
|
+
- Worklet effects load under Node. (#93)
|
|
196
|
+
|
|
197
|
+
## [0.28.0] - 2026-06-12
|
|
198
|
+
|
|
199
|
+
_First npm release after 0.26.0, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
200
|
+
|
|
201
|
+
### Added
|
|
202
|
+
- `createImpulseResponse(source, options?)` / `ImpulseResponseEffect`: native `ConvolverNode` convolution from an `AudioBuffer` or URL. URL impulse responses are fetched once per context and URL. `normalize` defaults to `false`, and optional `dry`/`wet` settings expose automatable params. (#94)
|
|
203
|
+
- `createFoaDecoderEffect()` / `FoaDecoderEffect`: an FOA-to-binaural decoder usable as a bus filter. (#94)
|
|
204
|
+
- `CacophonyEffect.build()` may return a `BuiltEffectGraph` (`input`, `output`, optional `params` and `dispose`) for multi-node effects. The new `BuiltEffect` and `BuiltEffectGraph` types are exported, along with the `ConvolverNode` type. (#94)
|
|
205
|
+
- `MediaStreamSoundOptions.primeWithMediaElement` (default `true`).
|
|
206
|
+
|
|
207
|
+
### Changed
|
|
208
|
+
- The return type of `CacophonyEffect.build()` widened from `AudioNode` to `BuiltEffect`. Code that calls `build()` on an effect directly and treats the result as an `AudioNode` must handle the graph form. (#94)
|
|
209
|
+
|
|
210
|
+
### Fixed
|
|
211
|
+
- Remote WebRTC streams in Chromium no longer play as silence through `MediaStreamSound`. Playback attaches the stream to a muted `HTMLAudioElement` to start decoding. Opt out with `primeWithMediaElement: false`.
|
|
212
|
+
- An aborted impulse-response load no longer breaks concurrent or later loads of the same URL. (#94)
|
|
213
|
+
- `Bus.destroy()` finishes cleanup even if an effect's `dispose()` throws. (#94)
|
|
214
|
+
|
|
215
|
+
## [0.26.0] - 2026-06-03
|
|
216
|
+
|
|
217
|
+
_Tagged but not published to npm._
|
|
218
|
+
|
|
219
|
+
### ⚠ Breaking
|
|
220
|
+
- Removed the per-worklet public methods on `Cacophony`: `loadPhaseVocoder`, `createPhaseVocoderNode`, `loadDattorroReverb`, `createDattorroReverbNode`, `loadDynamics`, `createDynamicsNode`, `loadFdnReverb`, `createFdnReverbNode`, `loadWaveshaper`, `createWaveshaperNode`, `loadModulatedDelay`, `createModulatedDelayNode`, `loadPhaser`, `createPhaserNode`, `loadTremolo`, `createTremoloNode`, `loadLoudnessMeter` and `createLoudnessMeterNode`. Use the effect factories (`createReverb()`, `createCompressor()`, ...) or `loadWorklets()` plus `buildWorkletEffect()`. (#92)
|
|
221
|
+
- Worklet effect classes (`ReverbEffect`, `DynamicsEffect`, `FdnReverbEffect`, `WaveshaperEffect`, `ModulatedDelayEffect`, `PhaserEffect`, `TremoloEffect`) now extend a shared `WorkletEffect` base with the constructor `(host: WorkletEffectHost, options)`. Build them through the `Cacophony` factory methods instead of calling the constructors. (#92)
|
|
222
|
+
|
|
223
|
+
## [0.25.1] - 2026-06-03
|
|
224
|
+
|
|
225
|
+
### Added
|
|
226
|
+
- `Bus.drainTo(target)` and `bus.destroy({ drainTo })` move live routed `Sound` and `Synth` instances to another bus before teardown. (#91)
|
|
227
|
+
- `Bus.setFilterOrder()`, `Bus.setFilterBypassed()` / `isFilterBypassed()` and `rampFilterParam()` for live effect-chain control. (#91)
|
|
228
|
+
- The `shape` option on waveshaper and tremolo effects and the `interpolation` option on modulated-delay effects accept string aliases as well as numeric indices. (#91)
|
|
229
|
+
|
|
230
|
+
### Changed
|
|
231
|
+
- `Bus.addFilter()` resolves to the built `AudioNode` instead of `void`. (#91)
|
|
232
|
+
- Bus filter-chain changes rewire only the edges that changed, instead of rebuilding the whole chain. (#91)
|
|
233
|
+
|
|
234
|
+
### Fixed
|
|
235
|
+
- Sounds routed to a bus only through sends are tracked correctly when that bus is drained. (#91)
|
|
236
|
+
- Synth routes are registered for bus draining. (#91)
|
|
237
|
+
|
|
238
|
+
## [0.25.0] - 2026-06-03
|
|
239
|
+
|
|
240
|
+
### Changed
|
|
241
|
+
- Version bump only. No code changes since 0.24.0.
|
|
242
|
+
|
|
243
|
+
## [0.24.0] - 2026-06-02
|
|
244
|
+
|
|
245
|
+
### Added
|
|
246
|
+
- DSP effects built on AudioWorklets, each with a `Cacophony` factory:
|
|
247
|
+
- dynamics: `createCompressor`, `createLimiter`, `createGate`
|
|
248
|
+
- reverb: `createFdnReverb`
|
|
249
|
+
- distortion: `createWaveshaper`, `createDistortion` (antialiased)
|
|
250
|
+
- modulated delay: `createDelay`, `createChorus`, `createFlanger`, `createVibrato`, `createDoubling`
|
|
251
|
+
- `createPhaser`
|
|
252
|
+
- tremolo: `createTremolo`, `createAutoPan`
|
|
253
|
+
|
|
254
|
+
The matching `*Effect` classes and `*Options` types are exported. (#88, #90)
|
|
255
|
+
- Pitch shifting through the phase vocoder: `Sound.setPitchShift(factor)` / `pitchShift`, also on playbacks. (#88)
|
|
256
|
+
- Offline time-stretching: `Sound.timeStretch(factor)`, `Cacophony.timeStretchBuffer()`, and the exported `timeStretch` / `timeStretchChannels`. (#88)
|
|
257
|
+
- ITU-R BS.1770-5 loudness metering: `createLoudnessMeter()` / `LoudnessMeter`, plus the exported `integratedLoudness`, `loudnessRange`, `KWeightingFilter`, `TruePeakDetector`, `truePeakDb` and related helpers. (#88)
|
|
258
|
+
- `createFoaDecoder()` / `FoaDecoder` for FOA-to-binaural decoding, and `encodeMonoToFoaSN3D()`. (#88)
|
|
259
|
+
- Per-worklet `load*()` / `create*Node()` methods. These were removed again in 0.26.0. (#88, #90)
|
|
260
|
+
|
|
261
|
+
### Changed
|
|
262
|
+
- `loadWorklets()` loads every bundled worklet: phase vocoder, stereo-to-B-format, Dattorro and FDN reverb, dynamics, waveshaper, modulated delay, phaser, tremolo and loudness meter. (#88, #90)
|
|
263
|
+
|
|
264
|
+
## [0.23.0] - 2026-05-30
|
|
265
|
+
|
|
266
|
+
### ⚠ Breaking
|
|
267
|
+
- `SoundType` is now a type-only string union, `"html" | "streaming" | "buffer" | "oscillator"`, instead of an enum. Replace `SoundType.HTML`, `SoundType.Streaming`, `SoundType.Buffer` and `SoundType.Oscillator` with the lowercase strings, and switch the import to `import type`. (#79)
|
|
268
|
+
- `Cacophony.pause()` and `Cacophony.resume()` are now `async` and return `Promise<void>`. (#79)
|
|
269
|
+
- The decoded-buffer memory cache is limited to 64 MiB, estimated from buffer size, instead of 100 entries.
|
|
270
|
+
- `stereoPan` on sound containers is typed `number` instead of `number | null`, and `threeDOptions` uses the new `ThreeDOptions` type instead of `any` or `PannerOptions`. (#79)
|
|
271
|
+
|
|
272
|
+
### Added
|
|
273
|
+
- Buses and sends: the `Bus` class, `cacophony.master`, `createBus()`, `getBus()`, `listBuses()`, and `routeTo(bus | name, sendGain?)` on `Sound`, `Synth` and `Group`. `bus.connect(target, gain?)` adds a gained send. (#83)
|
|
274
|
+
- An effect interface for bus chains: `CacophonyEffect`, `BiquadEffect`, `ShareEffect` (`shareEffect(node)`), and `createReverb()` / `ReverbEffect`, which uses the bundled Dattorro reverb worklet. (#83)
|
|
275
|
+
- `SynthPlayback` gains `outputNode`, `connect()` and `disconnect()`, matching `Playback`. (#83)
|
|
276
|
+
- Autoplay unlock: when the context starts suspended, the first touch, click or key press resumes it. Adds `cacophony.locked` and an `unlock` event. Opt out with `RuntimeOptions.autoUnlock: false`. (#81, #86)
|
|
277
|
+
- `createSound([url1, url2, ...])` picks the first URL whose format the browser can play, and falls back to the next one on a decode `EncodingError`. Only `"buffer"` sounds support this. (#82, #85)
|
|
278
|
+
- New type exports: `HrtfPannerOptions`, `PanCloneOverrides`, `ThreeDOptions` and `AudioWorklet`. The package entry now lists every export by name instead of re-exporting whole modules; no previously exported names were removed. (#79)
|
|
279
|
+
|
|
280
|
+
### Fixed
|
|
281
|
+
- The microphone stream's gain node is connected to the output (`context.destination`). Before, it was created but never connected, so microphone input that used to be silent is now audible (monitoring). (#80)
|
|
282
|
+
- `Cacophony.resume()` always calls through to the context. This fixes resuming after the context was suspended outside Cacophony. (#79)
|
|
283
|
+
- Media-element sources are cloned per playback. `loopEnded` waits for the source to be ready. A race in `stopWithFade` is fixed. (#79)
|
|
284
|
+
- `Sound` rolls back its preplay state when playback creation fails, and unregisters playback listeners on cleanup. (#79)
|
|
285
|
+
- A cancelled fade resolves its promise and snaps to the final value. (#79)
|
|
286
|
+
- The event emitter copies its listener list before emitting, so `once` listeners are removed correctly while an event is being emitted. (#79)
|
|
287
|
+
- Numeric options accept `0`: defaults use `??` instead of `||`. (#79)
|
|
288
|
+
- Phase vocoder options are no longer overwritten. (#79)
|
|
289
|
+
- `createSound(buffer, soundType)` honors the `soundType` argument instead of always creating a buffer sound. (#79)
|
|
290
|
+
- Worklet modules are tracked per `BaseContext`, so a second context loads its own copy. (#83)
|
|
291
|
+
- Cache metadata keys are handled consistently when entries are written, read and removed.
|
|
292
|
+
|
|
293
|
+
## [0.21.0] - 2026-05-11
|
|
294
|
+
|
|
295
|
+
### Added
|
|
296
|
+
- `MediaStreamSound` and `MediaStreamPlayback`, created with `cacophony.createMediaStreamSound(stream, { panType?, stopTracksOnStop? })`. They play a live `MediaStream`, such as WebRTC or a capture, through Cacophony's panning, volume and filters. `stopTracksOnStop` defaults to `true`. (#78)
|
|
297
|
+
|
|
298
|
+
### Changed
|
|
299
|
+
- `GlobalPlaybackEvent.source` is typed `BaseSound | Sound | Synth`, so `MediaStreamSound` can fire global play, pause and stop events. (#78)
|
|
300
|
+
|
|
301
|
+
## [0.20.8] - 2026-05-09
|
|
302
|
+
|
|
303
|
+
### Changed
|
|
304
|
+
- The `stereo-to-bformat` upmix worklet steers less high-frequency energy into the side (Y) channel: treble only moves sideways when the band is both off-center and side-dominant, so centered vocals stop drifting to the sides.
|
|
305
|
+
|
|
306
|
+
## [0.20.7] - 2026-05-09
|
|
307
|
+
|
|
308
|
+
### Changed
|
|
309
|
+
- The `stereo-to-bformat` upmix worklet gates direction with per-band stereo coherence: centered (in-phase) material feeds the front (X) cue and is kept out of the side (Y) cue, while hard-panned, anti-phase and diffuse material keeps its side cue.
|
|
310
|
+
|
|
311
|
+
## [0.20.6] - 2026-05-09
|
|
312
|
+
|
|
313
|
+
### Changed
|
|
314
|
+
- Internal changes only (dependency lockfile refresh).
|
|
315
|
+
|
|
316
|
+
## [0.20.5] - 2026-05-09
|
|
317
|
+
|
|
318
|
+
### Changed
|
|
319
|
+
- The `stereo-to-bformat` upmix worklet now writes a frontal cue to the X channel from mid and high-band center content. Before this, X was always silent.
|
|
320
|
+
|
|
321
|
+
## [0.20.4] - 2026-05-09
|
|
322
|
+
|
|
323
|
+
### Changed
|
|
324
|
+
- The `stereo-to-bformat` upmix worklet splits the signal into three bands (crossovers at 250 Hz and 2 kHz) and weights W and Y per band. Lows stay mostly omnidirectional and the upper bands carry the horizontal cue. This replaces the plain mid/side mapping, so the output sounds different.
|
|
325
|
+
|
|
326
|
+
## [0.20.3] - 2026-05-09
|
|
327
|
+
|
|
328
|
+
### Changed
|
|
329
|
+
- Internal changes only (version bump; no source changes).
|
|
330
|
+
|
|
331
|
+
## [0.20.2] - 2026-05-09
|
|
332
|
+
|
|
333
|
+
### ⚠ Breaking
|
|
334
|
+
- `createStereoToBFormatNode()` now outputs first-order ambisonics in ACN channel order (W, Y, Z, X) instead of W, X, Y, Z. If you route its four output channels by index, swap channel 1 and channel 3.
|
|
335
|
+
|
|
336
|
+
### Changed
|
|
337
|
+
- The `stereo-to-bformat` worklet logs per-channel peak statistics to the console with `console.info` about every 750 render quanta (roughly 2 seconds at 48 kHz).
|
|
338
|
+
|
|
339
|
+
## [0.20.1] - 2026-05-09
|
|
340
|
+
|
|
341
|
+
### Changed
|
|
342
|
+
- `createWorkletNode()` remembers which worklet modules it has already loaded and skips repeat `addModule()` calls. It now logs each construct and load step with `console.info`/`console.warn` under a `[cacophony/worklet]` prefix.
|
|
343
|
+
- `loadWorklets()` loads the `stereo-to-bformat` module without constructing a node.
|
|
344
|
+
|
|
345
|
+
## [0.20.0] - 2026-05-09
|
|
346
|
+
|
|
347
|
+
### Added
|
|
348
|
+
- `Cacophony.createStereoToBFormatNode()` returns an `AudioWorkletNode` that takes a stereo input and outputs a 4-channel first-order ambisonic (B-format) signal. `loadStereoToBFormatWorklet()` preloads its module, and `loadWorklets()` loads it too.
|
|
349
|
+
- `Cacophony.createSplitter(numChannels)` and `Cacophony.createMerger(numChannels)` create channel splitter and merger nodes. They throw if the context doesn't support those nodes.
|
|
350
|
+
- `createWorkletNode()` accepts an optional fourth argument of `AudioWorkletNodeOptions`. The `RuntimeOptions.createAudioWorkletNode` factory receives these options.
|
|
351
|
+
- The `AudioWorkletNode`, `ChannelSplitterNode` and `ChannelMergerNode` types are exported. `BaseContext` gains optional `createChannelSplitter`/`createChannelMerger` methods.
|
|
352
|
+
|
|
353
|
+
## [0.19.0] - 2026-04-15
|
|
354
|
+
|
|
355
|
+
### ⚠ Breaking
|
|
356
|
+
- `standardized-audio-context` is no longer a dependency. It is now an optional peer dependency, and `new Cacophony()` with no arguments creates the browser's native `AudioContext`. If you want the `standardized-audio-context` implementation, install it yourself and pass its `AudioContext` to the constructor. (#56)
|
|
357
|
+
- Public types now use structural interfaces (`BaseContext`, `AudioNode`, `GainNode`, `PannerNode`, ...) exported from the package root instead of `standardized-audio-context`'s `I*` types. `Cacophony.context` and `Sound.context` are typed as `BaseContext`. Code that relied on those properties having `standardized-audio-context` types may need casts or type updates. (#56)
|
|
358
|
+
- Setting `stereoPan` outside `-1..1` throws a `RangeError` instead of clamping silently. Clamp the value yourself before you assign it.
|
|
359
|
+
- `SynthGroup.setVolume(v)` is removed. Use `synthGroup.volume = v` instead. (#71)
|
|
360
|
+
- `createSound()` with `SoundType.HTML` or `SoundType.Streaming`, and `createStream()`, now wait for the media element's `loadedmetadata` event before resolving. They reject when the media fails to load or the `AbortSignal` fires. Before, they resolved immediately.
|
|
361
|
+
- Event payloads that were typed `void` (`stop`, `pause`, `resume`, `ended`, `loopEnd`, `fadeEnd`, `fadeCancel`, `mute`, `unmute`, `suspend`) are now typed `undefined`. This only matters for code that names these event types explicitly.
|
|
362
|
+
|
|
363
|
+
### Added
|
|
364
|
+
- Offline rendering: `Cacophony.createOffline({ numberOfChannels, length, sampleRate })`, `cacophony.isOffline`, and `cacophony.startRendering()`. (#56)
|
|
365
|
+
- The `Cacophony` constructor takes an optional third `RuntimeOptions` argument. Its `createAudioWorkletNode` factory lets non-native contexts build worklet nodes without the global `AudioWorkletNode`. (#56)
|
|
366
|
+
- `AudioCache` is exported from the package root.
|
|
367
|
+
- `on()` on `Cacophony`, `Sound`, `Synth` and playbacks returns an unsubscribe function.
|
|
368
|
+
- `Sound.resume()` and `Synth.resume()` resume paused playbacks. Synth playbacks now pause for real and resume from a fresh oscillator that keeps its settings. (#53, #68)
|
|
369
|
+
- `SynthGroup` has the same core controls as `Group`. `play()` returns the playbacks, and the group gains `pause()`, `resume()`, `isPlaying`, `addFilter()`/`removeFilter()`, fades, `stopWithFade()`, the `volume` getter/setter, and `stereoPan`, `position`, `frequency`, `detune` and `type` accessors. (#71)
|
|
370
|
+
- Events that were declared but never fired now fire: `ended` and `loopEnd` on `Sound`/`Playback`, `resume` on playbacks and sounds, and `mute`, `unmute`, `suspend`, `resume` and `volumeChange` on `Cacophony`. `volumeChange` also fires on `Playback` and `Synth`. (#53)
|
|
371
|
+
- Sounds are registered with a `FinalizationRegistry`, so if a `Sound` is garbage-collected without `cleanup()`, its source and gain nodes are disconnected and its media elements are released. (#74)
|
|
372
|
+
|
|
373
|
+
### Changed
|
|
374
|
+
- For HTML/media-element playbacks, `play()` sets `isPlaying` and emits `play`/`globalPlay` only after `HTMLMediaElement.play()` resolves. If it rejects (for example, because of autoplay policy), the state reverts and an `error` event is emitted. (#50)
|
|
375
|
+
- `Sound` emits `play` once for each playback, after that playback actually starts, not synchronously with the first playback. A rejected media playback no longer produces a false `play` event on the sound. (#70)
|
|
376
|
+
- Playbacks that end on their own (all loops done) are removed from `Sound.playbacks`. (#49)
|
|
377
|
+
- Revalidated cache hits (HTTP 304) report `cacheType: "conditional"` in `cacheHit` events instead of `"browser"`.
|
|
378
|
+
- `loadingComplete` reports the real decoded `duration` instead of `0`. `loadingError` events carry an `errorType` of `"network"`, `"decode"` or `"abort"`.
|
|
379
|
+
- `createStream()` no longer starts a hidden, uncontrollable background stream alongside the `Sound` it returns. The returned `Sound` is the only playback path. (#56)
|
|
380
|
+
- Creating media-element or media-stream sources on a context that doesn't support them (such as an `OfflineAudioContext`) throws a clear error. (#56)
|
|
381
|
+
|
|
382
|
+
### Fixed
|
|
383
|
+
- `cacophony.on('loadingError', ...)` fires on network and decode failures. Before, the callback was never invoked. (#47)
|
|
384
|
+
- `Group.playOrdered(false)` returns `undefined` after the last sound instead of crashing. (#48)
|
|
385
|
+
- The `Group.volume` getter returns `1` for an empty group instead of `NaN`. (#51)
|
|
386
|
+
- Oscillator `frequency: 0` and `detune: 0` are applied instead of being ignored, and the `frequency` getter no longer turns `0` into `440`. (#52)
|
|
387
|
+
- `getMicrophoneStream()` makes a single `getUserMedia` request (one permission prompt), and the first `play()` returns the playback instead of `[]`. (#54)
|
|
388
|
+
- `MicrophonePlayback` keeps its panner in the chain when filters are added or removed. (#55)
|
|
389
|
+
- `Playback.cleanup()` fully stops a media-backed playback (pauses and resets the element and detaches handlers) before it disconnects nodes. (#69)
|
|
390
|
+
- `setGlobalVolume()` with the current value no longer emits a `volumeChange` event.
|
|
391
|
+
|
|
392
|
+
## [0.18.3] - 2026-02-20
|
|
393
|
+
|
|
394
|
+
_First npm release after 0.18.0 through 0.18.2, which were tagged but not published. Upgrading from an earlier npm version? Read those entries too._
|
|
395
|
+
|
|
396
|
+
### Changed
|
|
397
|
+
- Internal changes only (release workflow moved to npm trusted publishing).
|
|
398
|
+
|
|
399
|
+
## [0.18.2] - 2026-02-20
|
|
400
|
+
|
|
401
|
+
_Tagged but not published to npm._
|
|
402
|
+
|
|
403
|
+
### Fixed
|
|
404
|
+
- `stop()` on a `Sound` or `Synth` also cleans up each playback it drops, so stopped playbacks no longer leave orphaned audio nodes.
|
|
405
|
+
|
|
406
|
+
## [0.18.1] - 2026-02-19
|
|
407
|
+
|
|
408
|
+
_Tagged but not published to npm._
|
|
409
|
+
|
|
410
|
+
### Changed
|
|
411
|
+
- Internal changes only (release workflow and dev-dependency updates).
|
|
412
|
+
|
|
413
|
+
## [0.18.0] - 2026-02-19
|
|
414
|
+
|
|
415
|
+
_Tagged but not published to npm._
|
|
416
|
+
|
|
417
|
+
### Added
|
|
418
|
+
- Fades on playbacks, sounds, synths and groups: `fadeTo(value, ms, type?)`, `fadeIn(ms, type?)`, `fadeOut(ms, type?)`, `stopWithFade(ms, type?)`, `cancelFade()`, and an `isFading` getter. `Playback.fadeIn()`/`fadeOut()` were last available in 0.8.7; these replace them. Each fade returns a promise that resolves when the fade finishes, and `type` is `"linear"` (the default) or `"exponential"`.
|
|
419
|
+
- `Sound.play(options?)` takes `PlayOptions`: `fadeIn`, `fadeOut` (applied when the last loop ends), `fadeType`, and `fadeInPerLoop` (fade in again on every loop).
|
|
420
|
+
- Playbacks emit `fadeStart` (`{ target, duration, type }`), `fadeEnd` and `fadeCancel` events.
|
|
421
|
+
- Event types from `events.ts` (such as `PlaybackEvents`, `SoundEvents` and `CacophonyEvents`) are exported from the package root.
|
|
422
|
+
|
|
423
|
+
### Changed
|
|
424
|
+
- Setting `volume` directly, or calling `stop()`, cancels any fade in progress.
|
|
425
|
+
|
|
426
|
+
## [0.17.1] - 2025-11-18
|
|
427
|
+
|
|
428
|
+
_First npm release after 0.17.0, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
429
|
+
|
|
430
|
+
### Fixed
|
|
431
|
+
- Type-checking fix for the filter cloning added in 0.17.0.
|
|
432
|
+
|
|
433
|
+
## [0.17.0] - 2025-11-18
|
|
434
|
+
|
|
435
|
+
_Tagged but not published to npm._
|
|
436
|
+
|
|
437
|
+
### ⚠ Breaking
|
|
438
|
+
- Filters added to a `Sound` or `Synth` are cloned into each new playback instead of being shared. Changing the original `BiquadFilterNode` no longer affects playbacks that already exist. To change the sound of a playback that is already playing, adjust that playback's own filters.
|
|
439
|
+
- `addFilter()`/`removeFilter()` on a `Sound`, `Synth` or `Group` only affect future playbacks, not ones already playing.
|
|
440
|
+
- `addFilter()` throws if the same filter instance is added twice. `removeFilter()` throws if the filter was never added. Guard those calls if you relied on them being no-ops.
|
|
441
|
+
|
|
442
|
+
## [0.16.1] - 2025-11-17
|
|
443
|
+
|
|
444
|
+
_First npm release after 0.16.0, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
445
|
+
|
|
446
|
+
### Fixed
|
|
447
|
+
- `removeFilter()` removes the exact filter instance you pass in. Before, it compared property values and could remove the wrong filters or fail to remove one.
|
|
448
|
+
- The package `exports` map lists `types` first, so TypeScript resolves the bundled type definitions correctly under `moduleResolution: "bundler"`/`"node16"`.
|
|
449
|
+
|
|
450
|
+
### Changed
|
|
451
|
+
- `emit()`, `emitAsync()` and `eventEmitter` on playbacks are now public.
|
|
452
|
+
|
|
453
|
+
## [0.16.0] - 2025-10-09
|
|
454
|
+
|
|
455
|
+
_Tagged but not published to npm._
|
|
456
|
+
|
|
457
|
+
### Added
|
|
458
|
+
- `Playback.outputNode`, `Playback.connect(destination)` and `Playback.disconnect(destination?)` let you route a playback's output into your own Web Audio graph.
|
|
459
|
+
|
|
460
|
+
## [0.15.3] - 2025-10-08
|
|
461
|
+
|
|
462
|
+
### Fixed
|
|
463
|
+
- `globalPlay`, `globalStop` and `globalPause` now fire from `Playback.play()`/`stop()`/`pause()`, so they also fire for sounds started through `Group.play()`, `Group.playOrdered()` and `Group.playRandom()`, not only through `Sound.play()`. `Synth` still emits them from `Synth.play()`/`stop()`/`pause()`.
|
|
464
|
+
- `Playback` emits its `pause` event. The event was declared in 0.15.0 but never fired.
|
|
465
|
+
|
|
466
|
+
## [0.15.2] - 2025-10-03
|
|
467
|
+
|
|
468
|
+
### Added
|
|
469
|
+
- Global playback events on `Cacophony`: `globalPlay`, `globalStop` and `globalPause`, each with a `{ source, timestamp }` payload where `source` is the `Sound` or `Synth`. In this release they fire only from `Sound.play()`/`stop()`/`pause()` and the matching `Synth` methods.
|
|
470
|
+
- `Cacophony.emit()` and `Cacophony.emitAsync()` are now public (previously `protected`).
|
|
471
|
+
- `Sound` and `Synth` constructors take an optional trailing `cacophony` argument, and `Sound.clone()`/`Synth.clone()` carry it over. The factory methods (`createSound`, `createStream`, `createOscillator`) pass it for you.
|
|
472
|
+
|
|
473
|
+
## [0.15.1] - 2025-10-02
|
|
474
|
+
|
|
475
|
+
### Changed
|
|
476
|
+
- Internal changes only (dev-dependency updates and a test fix).
|
|
477
|
+
|
|
478
|
+
## [0.15.0] - 2025-08-14
|
|
479
|
+
|
|
480
|
+
### Added
|
|
481
|
+
- Typed event system. `Cacophony`, `Sound`, `Synth` and every `Playback` expose `on(event, listener)` and `off(event, listener)`. (#23)
|
|
482
|
+
- `Cacophony`: `loadingStart`, `loadingProgress` (`{ url, loaded, total, progress }`, where `progress` is `-1` when the size is unknown), `loadingComplete`, `cacheHit` (`cacheType`: `memory` / `browser`), `cacheMiss` (`reason`: `not-found` / `expired`) and `cacheError`.
|
|
483
|
+
- `Sound`: `play` (receives the `Playback`), `stop`, `pause`, `volumeChange`, `rateChange` and `soundError`, which forwards playback errors.
|
|
484
|
+
- `Synth`: `play`, `stop`, `pause`, `frequencyChange`, `detuneChange` and `typeChange`.
|
|
485
|
+
- `Playback`: `play`, `stop` and `error`.
|
|
486
|
+
- `AbortSignal` support. `createSound(url, soundType, panType, signal)`, `createGroupFromUrls(urls, soundType, panType, signal)`, `createStream(url, signal)`, `loadWorklets(signal)` and `createWorkletNode(name, url, signal)` accept an optional signal that cancels the fetch, stream read or worklet load. (#22)
|
|
487
|
+
- Download progress reporting. `AudioCache` reads response bodies as a stream and reports progress to every caller waiting on the same URL.
|
|
488
|
+
- `AudioCache` honors `Cache-Control`. A cached entry within its `max-age` is served without a network request, and `no-cache`, `no-store` and `must-revalidate` force revalidation.
|
|
489
|
+
- `Sound.cleanup()` cleans up all of the sound's playbacks and removes its event listeners. `Playback.cleanup()` also disconnects the panner, gain node and filters and removes listeners.
|
|
490
|
+
|
|
491
|
+
### Changed
|
|
492
|
+
- `createSound(url, SoundType.Streaming)` returns a streaming `Sound` right away instead of downloading and decoding the whole file through the cache.
|
|
493
|
+
- `createStream()` again starts the internal chunked stream reader in the background, as in 0.13.0–0.13.2. That reader plays decoded chunks straight to `context.destination`, alongside the returned `Sound`.
|
|
494
|
+
- `Playback.addFilter()` inserts the filter node you pass instead of cloning it. `Sound` therefore reuses its own filter nodes in every playback it creates. `Playback.removeFilter()` now uses the shared `FilterManager` matching logic and no longer disconnects the removed node. `addFilter()`/`removeFilter()` throw on a cleaned-up playback.
|
|
495
|
+
- `createWorkletNode()` rethrows the original error (such as an `AbortError`) instead of a generic "Could not load worklet" error. It loads modules with `credentials: "same-origin"`.
|
|
496
|
+
- The custom-cache interface's `getAudioBuffer(context, url, signal?, callbacks?)` has two new optional parameters, so existing custom caches keep working.
|
|
497
|
+
|
|
498
|
+
### Fixed
|
|
499
|
+
- `AudioCache` recovers when metadata exists but the cached body is missing: it refetches from the network instead of failing.
|
|
500
|
+
- Streams that fail to fetch or read log the error instead of producing an unhandled rejection.
|
|
501
|
+
|
|
502
|
+
## [0.14.2] - 2025-07-02
|
|
503
|
+
|
|
504
|
+
### Changed
|
|
505
|
+
- `AudioCache` sends a conditional request (`If-None-Match` / `If-Modified-Since`) every time a URL is not in memory and its cached entry has an `ETag` or `Last-Modified`. The 24-hour TTL (`AudioCache.setCacheExpirationTime()`) applies only to entries with no validators. In 0.14.0, entries without validators were always refetched and entries with validators were only rechecked after the TTL.
|
|
506
|
+
|
|
507
|
+
### Fixed
|
|
508
|
+
- If the server returns `304 Not Modified` but the cached body has disappeared, the cache fetches the file again without validators instead of failing.
|
|
509
|
+
|
|
510
|
+
## [0.14.1] - 2025-05-13
|
|
511
|
+
|
|
512
|
+
### Fixed
|
|
513
|
+
- `Playback.pause()` stops the underlying `AudioBufferSourceNode` instead of only disconnecting it.
|
|
514
|
+
- A replaced source's `onended` handler is detached, so a stale source finishing after a pause or seek no longer triggers the loop/stop logic.
|
|
515
|
+
- Looping buffer-backed playbacks restart through `play()` at the loop boundary, which avoids calling `start()` twice on the same source node.
|
|
516
|
+
|
|
517
|
+
## [0.14.0] - 2025-02-11
|
|
518
|
+
|
|
519
|
+
### ⚠ Breaking
|
|
520
|
+
- Build output renamed and reduced. The package now ships only `dist/index.mjs` (ESM) and `dist/index.cjs` (CJS), declared through an `exports` map. The old `dist/cacophony.es.js`, `dist/cacophony.cjs.js`, `dist/cacophony.umd.js` and `dist/cacophony.iife.js` are gone. Import from `"cacophony"` instead of a file path. UMD and IIFE `<script>` users need a bundler or an ESM `<script type="module">`.
|
|
521
|
+
|
|
522
|
+
### Changed
|
|
523
|
+
- `AudioCache` revalidates cached entries with `ETag`/`Last-Modified` once the TTL has passed. Before, it reused them indefinitely. A `304` response refreshes the stored timestamp.
|
|
524
|
+
- Concurrent requests for the same URL share one in-flight load, whether it comes from the network or the browser cache.
|
|
525
|
+
|
|
526
|
+
### Fixed
|
|
527
|
+
- If writing to the browser cache fails, `AudioCache` deletes the partial body and metadata so a later load does not read a half-written entry.
|
|
528
|
+
|
|
529
|
+
## [0.13.5] - 2024-10-28
|
|
530
|
+
|
|
531
|
+
_First npm release after 0.13.4, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
532
|
+
|
|
533
|
+
### Fixed
|
|
534
|
+
- Fixes a TypeScript type error in `Playback.addFilter()` introduced in 0.13.4.
|
|
535
|
+
|
|
536
|
+
## [0.13.4] - 2024-10-28
|
|
537
|
+
|
|
538
|
+
_Tagged but not published to npm._
|
|
539
|
+
|
|
540
|
+
### ⚠ Breaking
|
|
541
|
+
- `Group.playRandom()`, `Group.preplayRandom()`, `Group.playOrdered()` and `Group.preplayOrdered()` return `Playback | undefined` and return `undefined` for an empty group. Before, `preplayOrdered()`/`playOrdered()` threw and the random variants failed. Add a check for `undefined`.
|
|
542
|
+
- Setting `Playback.playbackRate` to `0` or a negative value throws `"Playback rate must be greater than 0"`.
|
|
543
|
+
|
|
544
|
+
### Added
|
|
545
|
+
- `new Cacophony(context?, cache?)` accepts a custom cache object with `getAudioBuffer(context, url)` and `clearMemoryCache()`, for example to stub loading in tests.
|
|
546
|
+
|
|
547
|
+
### Fixed
|
|
548
|
+
- `Playback.addFilter()` appends to the filter chain again instead of replacing the existing filters (regression in 0.13.1).
|
|
549
|
+
- `Sound.clone()` applies the cloned volume, playback rate, loop count and panning through the public setters, so the values reach the clone correctly. It sets `position`/`threeDOptions` only for `HRTF` sounds and `stereoPan` only for `stereo` sounds, and it honors a `position` override even when it is falsy.
|
|
550
|
+
|
|
551
|
+
## [0.13.3] - 2024-10-14
|
|
552
|
+
|
|
553
|
+
### Fixed
|
|
554
|
+
- Replaying or seeking an HTML/streaming playback after it stops reuses its media element instead of swapping in an empty buffer source.
|
|
555
|
+
- `Playback.duration` no longer throws for media-element sources without a decoded buffer. It returns the element's duration, or `NaN` when the duration is unknown.
|
|
556
|
+
- `createStream()` no longer starts a second background fetch that played audio straight to the destination, bypassing volume and panning.
|
|
557
|
+
|
|
558
|
+
## [0.13.2] - 2024-10-14
|
|
559
|
+
|
|
560
|
+
_First npm release after 0.13.1, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
561
|
+
|
|
562
|
+
### Fixed
|
|
563
|
+
- `loop(n)` sets `loopCount` to `n` again (0.13.1 stored `n - 1`, so a playback repeated one time fewer than requested). Calling `loop(n)` on a playback that is already playing also stores `n` now; before 0.13.1 it stored `n - 1`.
|
|
564
|
+
|
|
565
|
+
## [0.13.1] - 2024-10-14
|
|
566
|
+
|
|
567
|
+
_Tagged but not published to npm._
|
|
568
|
+
|
|
569
|
+
### Changed
|
|
570
|
+
- `Playback` timing rewrite. `currentTime` accounts for `playbackRate`, changing the rate mid-play keeps the position, and `pause()`/`play()` resumes from the paused position.
|
|
571
|
+
- `Playback.seek()` keeps the current play/pause state and throws `"Invalid time value for seek"` for negative or non-finite times.
|
|
572
|
+
- `Playback.play()` does nothing on a playback that is already playing.
|
|
573
|
+
- Reading `playbackRate` no longer throws after cleanup, and setting it after cleanup is a silent no-op.
|
|
574
|
+
- `Playback.clone()` copies position, state, current loop, playback rate and filters (as fresh filter nodes). If the original is playing, the clone starts playing too.
|
|
575
|
+
- `loop(n)` stores `n - 1` (reverted in 0.13.2).
|
|
576
|
+
|
|
577
|
+
### Fixed
|
|
578
|
+
- Filter clones now copy `gain`, and removing a filter disconnects its node.
|
|
579
|
+
|
|
580
|
+
## [0.13.0] - 2024-10-08
|
|
581
|
+
|
|
582
|
+
### ⚠ Breaking
|
|
583
|
+
- `Sound.duration` returns `NaN` instead of `0` when the duration is unknown. When the sound has playbacks, it returns the first playback's duration, so HTML and streaming sounds report the media element's duration. Replace `duration === 0` checks with `Number.isNaN(duration)`.
|
|
584
|
+
|
|
585
|
+
### Added
|
|
586
|
+
- `Playback.duration` returns the media element's duration for HTML/streaming playbacks.
|
|
587
|
+
|
|
588
|
+
## [0.12.10] - 2024-09-23
|
|
589
|
+
|
|
590
|
+
### Fixed
|
|
591
|
+
- HTML and streaming sounds can be played again. Since 0.12.0 `Playback.play()` tried to rebuild a buffer source for every source type and threw "Cannot recreate source of a sound that has been cleaned up" for non-buffer sounds; now it only rebuilds buffered sources.
|
|
592
|
+
- `setPanType()` does nothing when the pan type is unchanged and a panner already exists. When the type does change, it disconnects the old panner first, so panners no longer pile up in the graph.
|
|
593
|
+
|
|
594
|
+
## [0.12.9] - 2024-08-22
|
|
595
|
+
|
|
596
|
+
### Fixed
|
|
597
|
+
- `stop()` on an infinitely looping playback now stops it. The playback is marked stopped before the source node is stopped, and the loop-end handler ignores `ended` events from playbacks that are not playing, so stopping no longer restarts the loop.
|
|
598
|
+
|
|
599
|
+
## [0.12.8] - 2024-08-22
|
|
600
|
+
|
|
601
|
+
### Changed
|
|
602
|
+
- `Playback.stop()` no longer wraps the source stop in `try`/`finally`. If the underlying node throws, the error propagates and the playback's state is left unchanged.
|
|
603
|
+
|
|
604
|
+
## [0.12.7] - 2024-08-21
|
|
605
|
+
|
|
606
|
+
### ⚠ Breaking
|
|
607
|
+
- `Playback.loop(count)` now returns the stored loop count (a number or `'infinite'`) instead of `'infinite'`/`0`. It sets the native `loop` flag only for `'infinite'`, so a finite count is handled by replaying the source. Calling it on a playing playback treats the current pass as the first. Code that compared the return value against `'infinite'`/`0` should read `loopCount` instead.
|
|
608
|
+
- `Playback.handleLoop` is renamed to `loopEnded`. Update any code that called or reassigned it.
|
|
609
|
+
|
|
610
|
+
### Fixed
|
|
611
|
+
- Looping works again. The loop handler still checked the `_playing` flag that 0.12.0 stopped updating, so loops did not repeat correctly in 0.12.0–0.12.6. A sound can now also switch from looping to non-looping (and back) while it plays.
|
|
612
|
+
- `Playback.stop()` no longer silently swallows errors thrown by the underlying source node.
|
|
613
|
+
|
|
614
|
+
## [0.12.6] - 2024-08-21
|
|
615
|
+
|
|
616
|
+
### Added
|
|
617
|
+
- `Group.randomSound()` returns a random `Sound` from the group without playing it. It throws on an empty group. `preplayRandom()` now uses it.
|
|
618
|
+
|
|
619
|
+
## [0.12.5] - 2024-08-19
|
|
620
|
+
|
|
621
|
+
### Changed
|
|
622
|
+
- Internal changes only (README updates).
|
|
623
|
+
|
|
624
|
+
## [0.12.4] - 2024-08-19
|
|
625
|
+
|
|
626
|
+
### Fixed
|
|
627
|
+
- Cache entries written by versions before 0.12.3 have no timestamp. These entries (when they also lack `ETag`/`Last-Modified`) are now treated as expired and refetched instead of being served indefinitely.
|
|
628
|
+
|
|
629
|
+
## [0.12.3] - 2024-08-19
|
|
630
|
+
|
|
631
|
+
### Changed
|
|
632
|
+
- The persistent audio cache now expires entries after 24 hours, but only entries that have no `ETag` or `Last-Modified` header. Entries that have one of those headers are served from the Cache API without a network request. The expiry is set through the internal `AudioCache.setCacheExpirationTime()`, which the package does not export.
|
|
633
|
+
|
|
634
|
+
## [0.12.2] - 2024-08-15
|
|
635
|
+
|
|
636
|
+
### Added
|
|
637
|
+
- `Group.preplayRandom()` and `Group.preplayOrdered(shouldLoop)` return a prepared, not-yet-started `Playback`. `playRandom()` and `playOrdered()` are now built on them.
|
|
638
|
+
|
|
639
|
+
### Changed
|
|
640
|
+
- Empty-group errors from the random and ordered methods now say "Cannot prepare …" instead of "Cannot play …".
|
|
641
|
+
|
|
642
|
+
## [0.12.1] - 2024-08-12
|
|
643
|
+
|
|
644
|
+
_First npm release after 0.12.0, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
645
|
+
|
|
646
|
+
### Changed
|
|
647
|
+
- Internal changes only (tests).
|
|
648
|
+
|
|
649
|
+
## [0.12.0] - 2024-08-12
|
|
650
|
+
|
|
651
|
+
_Tagged but not published to npm._
|
|
652
|
+
|
|
653
|
+
### ⚠ Breaking
|
|
654
|
+
- `Playback.resume()` (added in 0.11.1) is removed again. Call `play()` on a paused playback to continue from where it paused.
|
|
655
|
+
- The public `Playback.pauseTime` and `Playback.startTime` fields are removed. Read the new `currentTime` getter instead.
|
|
656
|
+
|
|
657
|
+
### Added
|
|
658
|
+
- `Playback.currentTime` getter returns the current position in seconds.
|
|
659
|
+
|
|
660
|
+
### Changed
|
|
661
|
+
- `Playback` now tracks an explicit state (unplayed, playing, paused, stopped). `isPlaying` is true only in the playing state, and `pause()` does nothing unless the playback is playing. `seek(time)` stores the offset and restarts playback only if it was playing, so a later `play()` starts from the seeked position.
|
|
662
|
+
|
|
663
|
+
## [0.11.1] - 2024-08-09
|
|
664
|
+
|
|
665
|
+
### Added
|
|
666
|
+
- `Playback.resume()` continues a paused playback from its pause position.
|
|
667
|
+
|
|
668
|
+
### Fixed
|
|
669
|
+
- Pausing and resuming buffered playbacks resumes at the right offset. `play()` and `seek()` now record the start time, which pause offsets are measured from. Pausing an HTML-backed playback also remembers its position.
|
|
670
|
+
|
|
671
|
+
## [0.11.0] - 2024-08-05
|
|
672
|
+
|
|
673
|
+
### ⚠ Breaking
|
|
674
|
+
- The `Playback` constructor is now `new Playback(origin: Sound, source, gainNode)`. Context, loop count and pan type come from the origin `Sound`. `SynthPlayback` likewise becomes `new SynthPlayback(origin: Synth, source, gainNode)`. Code that built playbacks directly must pass the owning `Sound`/`Synth` first.
|
|
675
|
+
|
|
676
|
+
### Added
|
|
677
|
+
- Playbacks have an `origin` property that points back to the `Sound` or `Synth` that created them.
|
|
678
|
+
|
|
679
|
+
### Fixed
|
|
680
|
+
- `Playback.clone()` copies the source playback's volume.
|
|
681
|
+
|
|
682
|
+
## [0.10.4] - 2024-07-15
|
|
683
|
+
|
|
684
|
+
### Added
|
|
685
|
+
- `createOscillator(options, panType)` accepts an optional `panType` (`'HRTF'` by default), so a synth can use stereo panning.
|
|
686
|
+
|
|
687
|
+
## [0.10.3] - 2024-07-12
|
|
688
|
+
|
|
689
|
+
### Changed
|
|
690
|
+
- `BasePlayback` moved to its own module and is no longer exported from the package entry point.
|
|
691
|
+
- Source formatting sweep across `playback.ts` and `container.ts` (no behavior change).
|
|
692
|
+
|
|
693
|
+
### Fixed
|
|
694
|
+
- Seeking a stopped or paused playback now takes effect: the next `play()` starts from the seeked time instead of from 0.
|
|
695
|
+
|
|
696
|
+
## [0.10.2] - 2024-07-02
|
|
697
|
+
|
|
698
|
+
_First npm release after 0.9.7 through 0.10.1, which were tagged but not published. Upgrading from an earlier npm version? Read those entries too._
|
|
699
|
+
|
|
700
|
+
### Fixed
|
|
701
|
+
- `MicrophonePlayback` is exported from the package entry point correctly (0.10.0 imported it from a bare `'microphone'` path).
|
|
702
|
+
|
|
703
|
+
## [0.10.1] - 2024-07-02
|
|
704
|
+
|
|
705
|
+
_Tagged but not published to npm._
|
|
706
|
+
|
|
707
|
+
### Fixed
|
|
708
|
+
- The internal `MicrophoneStream` import in `cacophony.ts` now uses a relative path.
|
|
709
|
+
|
|
710
|
+
## [0.10.0] - 2024-07-02
|
|
711
|
+
|
|
712
|
+
_Tagged but not published to npm._
|
|
713
|
+
|
|
714
|
+
### ⚠ Breaking
|
|
715
|
+
- The microphone classes moved to `microphone.ts`, and only `MicrophonePlayback` is exported from the package. `MicrophoneStream` is no longer importable from `cacophony`; get it from `Cacophony.getMicrophoneStream()` instead of importing the class.
|
|
716
|
+
|
|
717
|
+
## [0.9.7] - 2024-07-01
|
|
718
|
+
|
|
719
|
+
_Tagged but not published to npm._
|
|
720
|
+
|
|
721
|
+
### ⚠ Breaking
|
|
722
|
+
- `Sound.type` and `Synth.type` (the `SoundType`) are renamed to `soundType`. On `Synth`, `type` now means the oscillator waveform. Rename `.type` to `.soundType` wherever you read the source kind.
|
|
723
|
+
|
|
724
|
+
### Added
|
|
725
|
+
- `SynthGroup` (exported) for controlling several synths together: `addSynth()`, `removeSynth()`, `play()`, `stop()`, `setVolume()`, and `stereoPan`/`position` setters.
|
|
726
|
+
- `Synth` and `SynthPlayback` get `frequency`, `detune` and `type` accessors. On a `Synth`, setting one updates all of its active playbacks.
|
|
727
|
+
|
|
728
|
+
### Changed
|
|
729
|
+
- `play()`/`preplay()` on a container are typed to return that container's own playback type (e.g. `SynthPlayback[]` for a `Synth`).
|
|
730
|
+
|
|
731
|
+
## [0.9.6] - 2024-06-25
|
|
732
|
+
|
|
733
|
+
### Changed
|
|
734
|
+
- Internal changes only (the build now runs `tsc --noEmit` first).
|
|
735
|
+
|
|
736
|
+
## [0.9.5] - 2024-06-24
|
|
737
|
+
|
|
738
|
+
### Changed
|
|
739
|
+
- Members of the mixin-based classes (`playbacks`, `_volume`, `_position`, `panner`, `gainNode`, `_filters`, and others) are now public. TypeScript mixins cannot have private or protected members, and this let the type declarations be emitted. `Sound.playbacks` is accessible again.
|
|
740
|
+
- `index.ts` exports `Sound` and `Synth` by name instead of re-exporting their whole modules.
|
|
741
|
+
|
|
742
|
+
## [0.9.4] - 2024-06-24
|
|
743
|
+
|
|
744
|
+
### Changed
|
|
745
|
+
- Internal typing fixes (`Playback.source` is declared public on the base class).
|
|
746
|
+
|
|
747
|
+
## [0.9.3] - 2024-06-24
|
|
748
|
+
|
|
749
|
+
### Changed
|
|
750
|
+
- The npm package no longer ships the `src` directory, only `dist`, `docs` and `README.md`.
|
|
751
|
+
|
|
752
|
+
## [0.9.2] - 2024-06-24
|
|
753
|
+
|
|
754
|
+
### Fixed
|
|
755
|
+
- Several modules imported siblings through bare specifiers (`"pannerMixin"`, `"volumeMixin"`, `"oscillatorMixin"`). These are now relative imports, so builds and type resolution work in consuming projects.
|
|
756
|
+
|
|
757
|
+
## [0.9.1] - 2024-06-24
|
|
758
|
+
|
|
759
|
+
### Fixed
|
|
760
|
+
- Synth oscillator options (`frequency`, `detune`, `type`) are applied to the oscillator's `AudioParam` values. Before, they were `Object.assign`ed onto the node, which did not set them. (#7)
|
|
761
|
+
- `Synth.clone()` defaults `stereoPan` to `0` when the source has none.
|
|
762
|
+
|
|
763
|
+
## [0.9.0] - 2024-06-21
|
|
764
|
+
|
|
765
|
+
### ⚠ Breaking
|
|
766
|
+
- `Cacophony.createOscillator(options)` now returns a `Synth` (with `play()`, `stop()`, `volume`, `position`, filters, `clone()`, …) instead of a raw `OscillatorNode` connected to the output. Call `synth.play()` instead of `oscillator.start()`. (#6)
|
|
767
|
+
- `Playback.fadeIn()` and `Playback.fadeOut()` are removed, with no replacement in this release.
|
|
768
|
+
- `Sound.playbacks` became `protected` (it is public again in 0.9.5).
|
|
769
|
+
- The `BaseSound` interface no longer requires `playbackRate`, `loop` or `duration`, and gains optional `position` and `threeDOptions`.
|
|
770
|
+
|
|
771
|
+
### Added
|
|
772
|
+
- `Synth` class (exported) for oscillator-based sound with the same volume, panning, 3D-position and filter controls as `Sound`, plus `oscillatorOptions`. `SoundType.Oscillator` identifies it. (#6)
|
|
773
|
+
|
|
774
|
+
### Changed
|
|
775
|
+
- `Sound`, `Playback` and `Synth` are now composed from shared mixins (`PlaybackContainer`, `VolumeMixin`, `PannerMixin`). The existing volume, stereo pan, position and `threeDOptions` accessors behave the same. (#5)
|
|
776
|
+
|
|
777
|
+
## [0.8.7] - 2024-06-11
|
|
778
|
+
|
|
779
|
+
### Changed
|
|
780
|
+
- The in-memory decoded-buffer cache is capped at 100 entries (down from 500).
|
|
781
|
+
|
|
782
|
+
## [0.8.6] - 2024-06-11
|
|
783
|
+
|
|
784
|
+
### Added
|
|
785
|
+
- `Cacophony.clearMemoryCache()` empties the in-memory decoded-buffer cache and clears pending requests.
|
|
786
|
+
|
|
787
|
+
## [0.8.5] - 2024-06-11
|
|
788
|
+
|
|
789
|
+
### Changed
|
|
790
|
+
- The in-memory decoded-buffer cache is now an LRU with a size limit (500 entries) instead of growing without bound.
|
|
791
|
+
|
|
792
|
+
### Fixed
|
|
793
|
+
- A failed load now clears its pending request, so the next request for the same URL retries instead of getting the failed promise.
|
|
794
|
+
|
|
795
|
+
## [0.8.4] - 2024-05-23
|
|
796
|
+
|
|
797
|
+
### Changed
|
|
798
|
+
- Decoded `AudioBuffer`s are kept in memory by URL, so creating several sounds from the same URL decodes the audio only once. The data: URL path is cached the same way.
|
|
799
|
+
|
|
800
|
+
## [0.8.3] - 2024-04-01
|
|
801
|
+
|
|
802
|
+
### Added
|
|
803
|
+
- Loading audio from the network stores the `ETag`/`Last-Modified` headers and sends `If-None-Match`/`If-Modified-Since` on later fetches. A `304` reuses the cached body.
|
|
804
|
+
|
|
805
|
+
### Fixed
|
|
806
|
+
- Non-OK responses stored in the browser cache are no longer used as audio data.
|
|
807
|
+
|
|
808
|
+
## [0.8.2] - 2024-03-04
|
|
809
|
+
|
|
810
|
+
### Changed
|
|
811
|
+
- `Playback.addFilter()` adds a copy of the filter (type, frequency, Q), so the same filter node is never wired into more than one playback. `removeFilter()` matches filters by their parameter values instead of node identity, so the filter you passed in can still be removed.
|
|
812
|
+
|
|
813
|
+
## [0.8.1] - 2024-02-23
|
|
814
|
+
|
|
815
|
+
### Fixed
|
|
816
|
+
- Loop counting and `isPlaying` are correct when a sound finishes naturally: `isPlaying` becomes `false` at the end of the last loop.
|
|
817
|
+
- `stop()` ignores errors thrown by the underlying node (e.g. stopping a source that already ended).
|
|
818
|
+
- Seeking a buffered playback keeps its end-of-playback handler (so looping continues after a seek), and the source is no longer connected to the gain node twice.
|
|
819
|
+
|
|
820
|
+
## [0.8.0] - 2024-02-23
|
|
821
|
+
|
|
822
|
+
### Fixed
|
|
823
|
+
- Looping sounds can be stopped. Before this, the end-of-loop handler restarted the source after `stop()`. Stopping a sound twice and then playing it again also works.
|
|
824
|
+
|
|
825
|
+
## [0.7.0] - 2024-02-23
|
|
826
|
+
|
|
827
|
+
### ⚠ Breaking
|
|
828
|
+
- `resume()` is removed from `Sound`, `Playback`, `Group` and the `BaseSound` interface. Call `play()` on a paused playback to continue.
|
|
829
|
+
- `pause()` no longer suspends the whole `AudioContext` (which paused every sound). It now stops only that playback and records the position; `play()` restarts from there.
|
|
830
|
+
|
|
831
|
+
### Fixed
|
|
832
|
+
- Setting `threeDOptions` accepts `0` for numeric options (cone angles and gain, distances, rolloff, position and orientation). Before, `0` was ignored and the previous value kept.
|
|
833
|
+
|
|
834
|
+
## [0.6.2] - 2024-02-23
|
|
835
|
+
|
|
836
|
+
### Changed
|
|
837
|
+
- `isPlaying` is tracked by the playback itself instead of inferred from the node. It returns `false` rather than throwing after cleanup.
|
|
838
|
+
|
|
839
|
+
### Fixed
|
|
840
|
+
- `Sound.clone()` honors falsy overrides (`volume: 0`, `loopCount: 0`, `stereoPan: 0`) and copies `stereoPan` to the clone.
|
|
841
|
+
- `createSound()` accepts any `AudioBuffer`-like object, not only instances of the global `AudioBuffer` class (e.g. buffers from `standardized-audio-context`).
|
|
842
|
+
- `stop()` stops buffer-backed playbacks again. From 0.5.22 through 0.6.1, `isPlaying` was always `false` for them, so `Playback.stop()` and `Sound.stop()` returned without stopping anything.
|
|
843
|
+
- A finite loop count no longer plays one extra repetition.
|
|
844
|
+
|
|
845
|
+
## [0.6.1] - 2024-02-22
|
|
846
|
+
|
|
847
|
+
### Fixed
|
|
848
|
+
- `Playback.clone()` uses the newly created source node instead of reusing the original one.
|
|
849
|
+
|
|
850
|
+
## [0.6.0] - 2024-02-21
|
|
851
|
+
|
|
852
|
+
### ⚠ Breaking
|
|
853
|
+
- `isPlaying` is now a getter instead of a method on `Sound`, `Playback`, `Group`, `MicrophonePlayback`, `MicrophoneStream` and the `BaseSound` interface. Replace `x.isPlaying()` with `x.isPlaying`.
|
|
854
|
+
|
|
855
|
+
### Added
|
|
856
|
+
- `new Group(sounds)` accepts an initial array of sounds.
|
|
857
|
+
|
|
858
|
+
## [0.5.23] - 2024-02-21
|
|
859
|
+
|
|
860
|
+
### Changed
|
|
861
|
+
- `Playback.clone()` now builds a fresh source node (a new `AudioBufferSourceNode` sharing the same `AudioBuffer`, or a new media-element source). However, the clone is still constructed with the original's source node, so a cloned playback continues to share the source of the playback it was cloned from. Fixed in 0.6.1.
|
|
862
|
+
|
|
863
|
+
## [0.5.22] - 2024-02-21
|
|
864
|
+
|
|
865
|
+
### Changed
|
|
866
|
+
- `Playback.isPlaying()` inspects the underlying node instead of an internal flag: HTML-audio playbacks report `!mediaElement.paused`. Buffer playbacks check a `playbackState` property that Web Audio source nodes don't have, so they always report `false`. Because `Playback.stop()` returns early when `isPlaying()` is false, `stop()` (and `Sound.stop()`) no longer stops buffer-backed playbacks. This regression is fixed in 0.6.2.
|
|
867
|
+
- When a finite loop runs out, the playback calls `stop()` instead of just clearing its playing flag.
|
|
868
|
+
|
|
869
|
+
## [0.5.21] - 2024-02-21
|
|
870
|
+
|
|
871
|
+
### Changed
|
|
872
|
+
- `Sound.stop()` empties `sound.playbacks` after stopping them, so stopped playbacks are no longer tracked by (or updated through) the sound.
|
|
873
|
+
|
|
874
|
+
## [0.5.20] - 2024-02-21
|
|
875
|
+
|
|
876
|
+
### Fixed
|
|
877
|
+
- `Sound.clone()` and `Playback.clone()` can be called with no arguments again; `overrides` is optional and every field in it is optional.
|
|
878
|
+
|
|
879
|
+
## [0.5.19] - 2024-02-20
|
|
880
|
+
|
|
881
|
+
_First npm release after 0.5.18, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
882
|
+
|
|
883
|
+
### Changed
|
|
884
|
+
- Internal change only: reordered the loop-count condition in the loop-restart handler. No change in behavior.
|
|
885
|
+
|
|
886
|
+
## [0.5.18] - 2024-02-20
|
|
887
|
+
|
|
888
|
+
_Tagged but not published to npm._
|
|
889
|
+
|
|
890
|
+
### Changed
|
|
891
|
+
- Reworked the end-of-loop check in `Playback` so it compares `currentLoop > loopCount` and only restarts the source while repeats remain.
|
|
892
|
+
|
|
893
|
+
## [0.5.17] - 2024-02-20
|
|
894
|
+
|
|
895
|
+
### Added
|
|
896
|
+
- `Playback.clone({ loopCount?, panType? })` creates a new `Playback` with its own gain node.
|
|
897
|
+
|
|
898
|
+
### Changed
|
|
899
|
+
- `Sound.clone()` overrides are typed as a dedicated options shape (`panType`, `stereoPan`, `threeDOptions`, `loopCount`, `playbackRate`, `volume`, `position`, `filters`) instead of `Partial<Sound>`.
|
|
900
|
+
|
|
901
|
+
## [0.5.16] - 2024-02-20
|
|
902
|
+
|
|
903
|
+
_First npm release after 0.5.15, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
904
|
+
|
|
905
|
+
### ⚠ Breaking
|
|
906
|
+
- `Sound.clone(overrides)` takes a required `overrides` object (`panType`, `threeDOptions`, `loopCount`, `playbackRate`, `volume`, `position`, `filters`, ...). Calling `clone()` with no argument throws at runtime. Pass `{}` for a plain copy until 0.5.20 makes the argument optional.
|
|
907
|
+
|
|
908
|
+
### Fixed
|
|
909
|
+
- Cloned sounds get their own copy of the filter list instead of sharing the original's filter array.
|
|
910
|
+
|
|
911
|
+
## [0.5.15] - 2024-02-19
|
|
912
|
+
|
|
913
|
+
_Tagged but not published to npm._
|
|
914
|
+
|
|
915
|
+
### Changed
|
|
916
|
+
- First attempt at `Sound.clone(overrides)`. The constructor call passed arguments in the wrong positions, so this version's clone was broken; it was replaced in 0.5.16.
|
|
917
|
+
|
|
918
|
+
## [0.5.14] - 2024-02-16
|
|
919
|
+
|
|
920
|
+
### Added
|
|
921
|
+
- `filters` read-only getter on `Sound` and `Playback` exposes the current filter chain.
|
|
922
|
+
- `addFilters(filters)` and `removeFilters(filters)` add or remove several filters in one call.
|
|
923
|
+
|
|
924
|
+
## [0.5.13] - 2024-02-16
|
|
925
|
+
|
|
926
|
+
### Fixed
|
|
927
|
+
- Removed debug `console.log` output from the loop callback (added in 0.5.11).
|
|
928
|
+
|
|
929
|
+
## [0.5.12] - 2024-02-15
|
|
930
|
+
|
|
931
|
+
_First npm release after 0.5.11, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
932
|
+
|
|
933
|
+
### Fixed
|
|
934
|
+
- Looping buffer playbacks: when a finite loop restarts, the new source goes through the panner and filter chain only. It is no longer also wired straight to the gain node, which bypassed panning and filters.
|
|
935
|
+
- The loop callback does nothing after the playback has been cleaned up.
|
|
936
|
+
|
|
937
|
+
## [0.5.11] - 2024-02-15
|
|
938
|
+
|
|
939
|
+
_Tagged but not published to npm._
|
|
940
|
+
|
|
941
|
+
### Fixed
|
|
942
|
+
- Finite loop counts replay the sound: the loop callback connects the re-created buffer source, re-arms its `onended` handler, and starts it. Earlier versions re-created the source without connecting it. This version logs every loop iteration to the console.
|
|
943
|
+
|
|
944
|
+
## [0.5.10] - 2024-02-14
|
|
945
|
+
|
|
946
|
+
### Fixed
|
|
947
|
+
- `loop()` on a buffer-backed `Playback` works again. It no longer relies on an `instanceof AudioBufferSourceNode` check, which failed for standardized-audio-context nodes and threw `Unsupported source type`.
|
|
948
|
+
|
|
949
|
+
## [0.5.9] - 2024-02-14
|
|
950
|
+
|
|
951
|
+
### Fixed
|
|
952
|
+
- Attempted fix for looping broken by a type-only import in `Playback`. It did not work; see 0.5.10.
|
|
953
|
+
|
|
954
|
+
## [0.5.8] - 2024-02-13
|
|
955
|
+
|
|
956
|
+
### Added
|
|
957
|
+
- `seek()` works on HTML-audio (`SoundType.HTML`) playbacks by setting the media element's `currentTime`. Before, it only worked for buffer sounds.
|
|
958
|
+
|
|
959
|
+
### Changed
|
|
960
|
+
- Listener orientation and playback position set the `AudioParam.value` directly instead of using `setValueAtTime`, to avoid ordering races in calling code.
|
|
961
|
+
- `Position` is a labeled tuple (`[x, y, z]`). Added JSDoc for `Cacophony` and `Playback`.
|
|
962
|
+
|
|
963
|
+
## [0.5.7] - 2024-02-12
|
|
964
|
+
|
|
965
|
+
_First npm release after 0.5.6, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
966
|
+
|
|
967
|
+
### Changed
|
|
968
|
+
- Internal type-alias fixes for standardized-audio-context types.
|
|
969
|
+
|
|
970
|
+
## [0.5.6] - 2024-02-12
|
|
971
|
+
|
|
972
|
+
_Tagged but not published to npm._
|
|
973
|
+
|
|
974
|
+
### Fixed
|
|
975
|
+
- `Sound.loop(count)` applies the loop setting to active playbacks through `Playback.loop()` instead of only setting the native `loop` flag.
|
|
976
|
+
- The loop-restart handler is bound to its `Playback`.
|
|
977
|
+
|
|
978
|
+
## [0.5.5] - 2024-02-07
|
|
979
|
+
|
|
980
|
+
### Fixed
|
|
981
|
+
- Published type declarations include the shared context types. In 0.5.0–0.5.4 the `.d.ts` files imported a `./context` module that wasn't shipped, which broke type checking for TypeScript consumers.
|
|
982
|
+
|
|
983
|
+
## [0.5.4] - 2024-02-05
|
|
984
|
+
|
|
985
|
+
### Added
|
|
986
|
+
- `createGroupFromUrls(urls, soundType?, panType?)` passes the sound type and pan type through to each created sound.
|
|
987
|
+
|
|
988
|
+
## [0.5.3] - 2024-02-05
|
|
989
|
+
|
|
990
|
+
### Fixed
|
|
991
|
+
- `createBiquadFilter({ frequency: 0 })` and `createOscillator({ frequency: 0 })` honor a frequency of `0` instead of replacing it with the default (350 Hz and 440 Hz).
|
|
992
|
+
|
|
993
|
+
## [0.5.2] - 2024-02-05
|
|
994
|
+
|
|
995
|
+
### Changed
|
|
996
|
+
- `stereoPan` values outside −1..1 are clamped instead of throwing.
|
|
997
|
+
|
|
998
|
+
### Fixed
|
|
999
|
+
- `createOscillator()` without a `frequency` defaults to 440 Hz instead of setting an undefined frequency.
|
|
1000
|
+
|
|
1001
|
+
## [0.5.1] - 2024-02-05
|
|
1002
|
+
|
|
1003
|
+
### Fixed
|
|
1004
|
+
- Stereo panning (`panType: 'stereo'`) works: `stereoPan` no longer relies on an `instanceof StereoPannerNode` check, which always failed, so the getter returned `null` and the setter threw.
|
|
1005
|
+
- `createSound(url, SoundType.HTML, panType)` honors `panType` for HTML-audio sounds.
|
|
1006
|
+
|
|
1007
|
+
## [0.5.0] - 2024-02-05
|
|
1008
|
+
|
|
1009
|
+
### Changed
|
|
1010
|
+
- The library source is split into modules (`sound.ts`, `playback.ts`, `group.ts`, `filters.ts`). `index` now re-exports `Sound`, `Playback` and `Group` from their own modules. Public signatures are unchanged.
|
|
1011
|
+
- `BaseSound` is exported again (it was unexported in 0.4.2).
|
|
1012
|
+
|
|
1013
|
+
## [0.4.6] - 2024-02-05
|
|
1014
|
+
|
|
1015
|
+
### Changed
|
|
1016
|
+
- The `Playback` constructor throws `Invalid pan type` for a `panType` other than `'HRTF'` or `'stereo'`.
|
|
1017
|
+
|
|
1018
|
+
## [0.4.5] - 2024-02-05
|
|
1019
|
+
|
|
1020
|
+
### Changed
|
|
1021
|
+
- Internal changes only (redundant `panType` assignment and doc comments).
|
|
1022
|
+
|
|
1023
|
+
## [0.4.4] - 2024-02-05
|
|
1024
|
+
|
|
1025
|
+
### Added
|
|
1026
|
+
- `createSound()` accepts base64 `data:` URLs, which are decoded directly instead of fetched or cached.
|
|
1027
|
+
|
|
1028
|
+
### Changed
|
|
1029
|
+
- The second parameter of `createSound()` is renamed from `type` to `soundType`. This only affects the parameter name.
|
|
1030
|
+
|
|
1031
|
+
### Fixed
|
|
1032
|
+
- `createOscillator()` no longer throws when no `periodicWave` is given.
|
|
1033
|
+
|
|
1034
|
+
## [0.4.3] - 2024-02-05
|
|
1035
|
+
|
|
1036
|
+
### Added
|
|
1037
|
+
- `createSound(urlOrBuffer, soundType?, panType?)` takes a `panType` (`'HRTF'` or `'stereo'`), so buffer sounds can use stereo panning.
|
|
1038
|
+
|
|
1039
|
+
## [0.4.2] - 2024-02-05
|
|
1040
|
+
|
|
1041
|
+
### ⚠ Breaking
|
|
1042
|
+
- `BaseSound` is no longer exported, and it no longer requires `position` or `threeDOptions`. Code that imported it must use `Sound`, `Playback` or `Group` instead until 0.5.0 exports it again.
|
|
1043
|
+
- `Group.sounds` and `Group.addSound()` accept only `Sound` instances instead of any `BaseSound`.
|
|
1044
|
+
- The `Playback` constructor's fifth parameter changed from `hrtf: boolean` to `panType: PanType`. Pass `'HRTF'` or `'stereo'` instead of `true` or `false`.
|
|
1045
|
+
|
|
1046
|
+
### Added
|
|
1047
|
+
- `PanType` type (`'HRTF' | 'stereo'`) and `Sound.panType`. New playbacks get either a 3D panner or a stereo panner based on it.
|
|
1048
|
+
- `Sound.stereoPan` getter and setter, applied to the sound's current and future playbacks.
|
|
1049
|
+
|
|
1050
|
+
## [0.4.1] - 2024-02-01
|
|
1051
|
+
|
|
1052
|
+
### Added
|
|
1053
|
+
- Stereo panning: `Playback` can use a `StereoPannerNode` instead of an HRTF `PannerNode`, controlled with the `stereoPan` getter and setter (−1..1). On stereo playbacks, `position` and `threeDOptions` throw.
|
|
1054
|
+
|
|
1055
|
+
## [0.4.0] - 2024-01-22
|
|
1056
|
+
|
|
1057
|
+
_First npm release after 0.3.13, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
1058
|
+
|
|
1059
|
+
### Added
|
|
1060
|
+
- `Group.playRandom()` plays one random sound from the group and returns its `Playback`.
|
|
1061
|
+
- `Group.playOrdered(shouldLoop = true)` plays the group's sounds one at a time in order, one per call, and wraps around when `shouldLoop` is set.
|
|
1062
|
+
- JSDoc for most `Sound` and `Playback` methods.
|
|
1063
|
+
|
|
1064
|
+
### Changed
|
|
1065
|
+
- `Sound.pause()` and `Sound.resume()` delegate to each of the sound's playbacks instead of suspending or resuming the `AudioContext` directly. With no playbacks they now do nothing.
|
|
1066
|
+
|
|
1067
|
+
## [0.3.13] - 2024-01-22
|
|
1068
|
+
|
|
1069
|
+
_Tagged but not published to npm._
|
|
1070
|
+
|
|
1071
|
+
### Added
|
|
1072
|
+
- `Group.playRandom()` and `Group.playOrdered()` (first published in 0.4.0).
|
|
1073
|
+
|
|
1074
|
+
### Changed
|
|
1075
|
+
- This version imports an event-emitter module that isn't in the repository, so it doesn't build. 0.4.0 removed that import.
|
|
1076
|
+
|
|
1077
|
+
## [0.3.12] - 2024-01-02
|
|
1078
|
+
|
|
1079
|
+
### Added
|
|
1080
|
+
- `Sound.clone()` returns a new `Sound` with the same buffer, loop count, playback rate, volume, position, 3D options and filters.
|
|
1081
|
+
|
|
1082
|
+
## [0.3.11] - 2024-01-01
|
|
1083
|
+
|
|
1084
|
+
### Changed
|
|
1085
|
+
- The prebuilt AudioWorklet bundles (phase vocoder and overlap-add processors) are committed to the repository, and the phase-vocoder processing was restored to its original algorithm.
|
|
1086
|
+
|
|
1087
|
+
## [0.3.10] - 2024-01-01
|
|
1088
|
+
|
|
1089
|
+
### Added
|
|
1090
|
+
- `Cacophony.createWorkletNode(name, url)` creates an `AudioWorkletNode` and loads the module from `url` if the processor isn't registered yet.
|
|
1091
|
+
|
|
1092
|
+
### Changed
|
|
1093
|
+
- Audio worklets are built in a separate Rollup step and embedded in the package, so `loadWorklets()` can load the phase-vocoder worklet from the published build.
|
|
1094
|
+
|
|
1095
|
+
## [0.3.9] - 2023-12-28
|
|
1096
|
+
|
|
1097
|
+
### ⚠ Breaking
|
|
1098
|
+
- `createBiquadFilter()` takes an options object `{ type, frequency, gain, Q }` instead of a filter type string. Replace `createBiquadFilter('lowpass')` with `createBiquadFilter({ type: 'lowpass' })`. The defaults are `lowpass`, 350 Hz, gain 0 and Q 1.
|
|
1099
|
+
|
|
1100
|
+
### Added
|
|
1101
|
+
- `createPanner(options)` creates a `PannerNode` from a partial `IPannerOptions` object.
|
|
1102
|
+
|
|
1103
|
+
## [0.3.8] - 2023-12-28
|
|
1104
|
+
|
|
1105
|
+
### Added
|
|
1106
|
+
- `createOscillator({ frequency, type, periodicWave })` creates an `OscillatorNode` connected to the global output. It throws when `periodicWave` is omitted until 0.4.4.
|
|
1107
|
+
|
|
1108
|
+
## [0.3.7] - 2023-12-26
|
|
1109
|
+
|
|
1110
|
+
_First npm release after 0.3.6, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
1111
|
+
|
|
1112
|
+
### Added
|
|
1113
|
+
- `duration` on `Sound`, `Playback`, `Group` (the longest sound in the group) and the microphone classes (always `0`). `duration` is now a required member of `BaseSound`.
|
|
1114
|
+
|
|
1115
|
+
## [0.3.6] - 2023-12-26
|
|
1116
|
+
|
|
1117
|
+
_Tagged but not published to npm._
|
|
1118
|
+
|
|
1119
|
+
### Added
|
|
1120
|
+
- `duration` on `Sound`, `Playback`, `Group` and `MicrophoneStream` (first published in 0.3.7). HTML and streaming sounds report `0`.
|
|
1121
|
+
|
|
1122
|
+
## [0.3.5] - 2023-12-24
|
|
1123
|
+
|
|
1124
|
+
### Changed
|
|
1125
|
+
- Build changes to bundle the phase-vocoder AudioWorklet; no public API changes.
|
|
1126
|
+
|
|
1127
|
+
## [0.3.4] - 2023-12-24
|
|
1128
|
+
|
|
1129
|
+
### Changed
|
|
1130
|
+
- Worklet bundling change (the phase-vocoder URL is imported as a worker URL); no public API changes.
|
|
1131
|
+
|
|
1132
|
+
## [0.3.3] - 2023-12-23
|
|
1133
|
+
|
|
1134
|
+
_First npm release after 0.3.2, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
1135
|
+
|
|
1136
|
+
### Added
|
|
1137
|
+
- `Cacophony.loadWorklets()` registers the phase-vocoder AudioWorklet when the context supports AudioWorklet (first published here; added in 0.3.2). Nothing in the public API uses the worklet yet.
|
|
1138
|
+
- New runtime dependency: `fft.js`.
|
|
1139
|
+
|
|
1140
|
+
## [0.3.2] - 2023-12-23
|
|
1141
|
+
|
|
1142
|
+
_Tagged but not published to npm._
|
|
1143
|
+
|
|
1144
|
+
### Added
|
|
1145
|
+
- Initial AudioWorklet support: phase-vocoder and overlap-add processors plus `Cacophony.loadWorklets()`.
|
|
1146
|
+
|
|
1147
|
+
### Changed
|
|
1148
|
+
- The chunked WAV streaming helper moved to its own module.
|
|
1149
|
+
|
|
1150
|
+
## [0.3.1] - 2023-12-17
|
|
1151
|
+
|
|
1152
|
+
### Changed
|
|
1153
|
+
- Version bump only; no code changes.
|
|
1154
|
+
|
|
1155
|
+
## [0.3.0] - 2023-12-17
|
|
1156
|
+
|
|
1157
|
+
### Changed
|
|
1158
|
+
- Version bump only; no code changes since 0.2.1. The minor bump marks the switch to the Vite build and module format shipped in 0.2.1.
|
|
1159
|
+
|
|
1160
|
+
## [0.2.1] - 2023-12-17
|
|
1161
|
+
|
|
1162
|
+
### ⚠ Breaking
|
|
1163
|
+
- The package is built with Vite and declares `"type": "module"`. `main` changed from `dist/index.js` to `dist/cacophony.cjs.js`, a new `module` entry points to `dist/cacophony.es.js`, and UMD and IIFE bundles are also shipped. Deep imports of the old `dist/*.js` files no longer work. The CommonJS file uses a `.js` extension inside a `"type": "module"` package, so Node's `require()` treats it as ESM and fails; use `import` or a bundler. (#1)
|
|
1164
|
+
|
|
1165
|
+
### Changed
|
|
1166
|
+
- The TypeScript sources (`src/`) are included in the published package.
|
|
1167
|
+
|
|
1168
|
+
## [0.2.0] - 2023-12-16
|
|
1169
|
+
|
|
1170
|
+
### ⚠ Breaking
|
|
1171
|
+
- `playbackRate` is a required member of `BaseSound`. Custom `BaseSound` implementations must add it. `MicrophonePlayback` no longer declares that it implements `BaseSound`.
|
|
1172
|
+
|
|
1173
|
+
### Added
|
|
1174
|
+
- `playbackRate` getter and setter on `Sound`, `Playback` and `Group`. On a `Sound` it applies to current and future playbacks. It works for buffer and HTML-audio sources.
|
|
1175
|
+
- TypeDoc API docs are generated on build and shipped in the package (`docs/`), and the README links to https://cacophony.js.org.
|
|
1176
|
+
|
|
1177
|
+
## [0.1.39] - 2023-12-13
|
|
1178
|
+
|
|
1179
|
+
### ⚠ Breaking
|
|
1180
|
+
- Removed `Cacophony.stopAll()`, which closed the `AudioContext` permanently. Stop sounds individually, or call `pause()` to suspend the context.
|
|
1181
|
+
|
|
1182
|
+
## [0.1.38] - 2023-12-06
|
|
1183
|
+
|
|
1184
|
+
### ⚠ Breaking
|
|
1185
|
+
- `Cacophony.listenerOrientation` is an `Orientation` object `{ forward: Position, up: Position }` instead of a forward vector. Use the new `listenerForwardOrientation` for the old behavior.
|
|
1186
|
+
|
|
1187
|
+
### Added
|
|
1188
|
+
- `Orientation` type, plus `listenerForwardOrientation` and `listenerUpOrientation` getters and setters on `Cacophony`.
|
|
1189
|
+
|
|
1190
|
+
## [0.1.37] - 2023-12-06
|
|
1191
|
+
|
|
1192
|
+
### Added
|
|
1193
|
+
- `Cacophony.listenerPosition` and `Cacophony.listenerOrientation` getters and setters control the 3D audio listener.
|
|
1194
|
+
- Generated TypeDoc API documentation site; the README was rewritten to match the current API.
|
|
1195
|
+
|
|
1196
|
+
## [0.1.36] - 2023-12-06
|
|
1197
|
+
|
|
1198
|
+
### Fixed
|
|
1199
|
+
- 3D positioning works when filters are attached. Filters sit between the panner and the gain node; before, they replaced the panner in the chain.
|
|
1200
|
+
|
|
1201
|
+
## [0.1.35] - 2023-12-06
|
|
1202
|
+
|
|
1203
|
+
### Changed
|
|
1204
|
+
- The default `coneOuterAngle` for sounds is 360 instead of 0, so sounds are audible in all directions by default.
|
|
1205
|
+
- Updated `standardized-audio-context` to ^25.3.60.
|
|
1206
|
+
|
|
1207
|
+
## [0.1.34] - 2023-12-05
|
|
1208
|
+
|
|
1209
|
+
### Changed
|
|
1210
|
+
- `Playback.position` schedules the change with `setValueAtTime` instead of assigning `value` directly.
|
|
1211
|
+
|
|
1212
|
+
## [0.1.33] - 2023-12-05
|
|
1213
|
+
|
|
1214
|
+
### Fixed
|
|
1215
|
+
- New playbacks inherit the sound's `threeDOptions`.
|
|
1216
|
+
- The source is no longer connected straight to the gain node in addition to the panner, which had let the unpanned signal through.
|
|
1217
|
+
|
|
1218
|
+
## [0.1.32] - 2023-12-04
|
|
1219
|
+
|
|
1220
|
+
### Changed
|
|
1221
|
+
- `Playback.threeDOptions` assigns each panner property explicitly instead of using `Object.assign`. Falsy values such as `0` are ignored and keep the current setting.
|
|
1222
|
+
|
|
1223
|
+
## [0.1.31] - 2023-11-29
|
|
1224
|
+
|
|
1225
|
+
### Added
|
|
1226
|
+
- `Sound.threeDOptions` getter and setter (panner cone, distance model, rolloff and so on), merged into the sound's current playbacks. `Sound.position` is stored in these options.
|
|
1227
|
+
|
|
1228
|
+
## [0.1.30] - 2023-11-26
|
|
1229
|
+
|
|
1230
|
+
### Fixed
|
|
1231
|
+
- HTML-audio sounds set `crossOrigin = 'anonymous'` on the audio element that is actually played, so cross-origin media can be routed through Web Audio when the server allows CORS.
|
|
1232
|
+
|
|
1233
|
+
## [0.1.29] - 2023-11-26
|
|
1234
|
+
|
|
1235
|
+
### Changed
|
|
1236
|
+
- CORS adjustment to the HTML-audio path in `createSound()`. The element it touches isn't the one used for playback, so behavior is unchanged; see 0.1.30.
|
|
1237
|
+
|
|
1238
|
+
## [0.1.28] - 2023-11-25
|
|
1239
|
+
|
|
1240
|
+
### Changed
|
|
1241
|
+
- Sets `crossOrigin = 'anonymous'` on an audio element created in `createSound(url, SoundType.HTML)`. That element isn't the one used for playback, so this had no effect; see 0.1.30.
|
|
1242
|
+
|
|
1243
|
+
## [0.1.27] - 2023-11-25
|
|
1244
|
+
|
|
1245
|
+
### Added
|
|
1246
|
+
- `createSound(url, SoundType.HTML)` creates a sound backed by an HTML `<audio>` element instead of downloading and decoding the whole file.
|
|
1247
|
+
|
|
1248
|
+
### Fixed
|
|
1249
|
+
- `createSound(buffer, type)` always creates a buffer sound, whatever `type` is passed.
|
|
1250
|
+
|
|
1251
|
+
## [0.1.26] - 2023-11-25
|
|
1252
|
+
|
|
1253
|
+
### ⚠ Breaking
|
|
1254
|
+
- The `Sound` constructor's fifth parameter changed from `html: boolean` to `type: SoundType`, and the `Sound.html` property was replaced by `Sound.type`.
|
|
1255
|
+
|
|
1256
|
+
### Added
|
|
1257
|
+
- `SoundType` enum (`HTML`, `Streaming`, `Buffer`) and an optional `type` parameter on `createSound()`.
|
|
1258
|
+
- Experimental chunked streaming in `createStream()`: the URL is fetched and decoded chunk by chunk, assuming a 44-byte WAV header. This audio goes straight to the context destination and bypasses the global volume.
|
|
1259
|
+
|
|
1260
|
+
## [0.1.25] - 2023-11-22
|
|
1261
|
+
|
|
1262
|
+
### Fixed
|
|
1263
|
+
- Setting `Sound.volume` changes only that sound's playbacks. Before, it also set the global gain, so one sound's volume affected everything. New playbacks start at the sound's volume.
|
|
1264
|
+
- `Playback.cleanup()` is safe to call more than once.
|
|
1265
|
+
|
|
1266
|
+
## [0.1.24] - 2023-11-20
|
|
1267
|
+
|
|
1268
|
+
### Fixed
|
|
1269
|
+
- Setting `Cacophony.volume` while muted only stores the value to restore on unmute instead of unmuting.
|
|
1270
|
+
|
|
1271
|
+
## [0.1.23] - 2023-11-20
|
|
1272
|
+
|
|
1273
|
+
### Fixed
|
|
1274
|
+
- Setting `Cacophony.volume` while muted updates the volume that `unmute()` restores.
|
|
1275
|
+
|
|
1276
|
+
## [0.1.22] - 2023-11-20
|
|
1277
|
+
|
|
1278
|
+
### Fixed
|
|
1279
|
+
- Calling `mute()` twice no longer loses the volume to restore, and `unmute()` does nothing when not muted.
|
|
1280
|
+
|
|
1281
|
+
## [0.1.21] - 2023-11-20
|
|
1282
|
+
|
|
1283
|
+
### Added
|
|
1284
|
+
- `Cacophony.muted` getter and setter.
|
|
1285
|
+
|
|
1286
|
+
## [0.1.20] - 2023-11-19
|
|
1287
|
+
|
|
1288
|
+
### ⚠ Breaking
|
|
1289
|
+
- `createStream(url)` returns a `Sound` (backed by an HTML `<audio>` element) instead of a `Playback`. Call `sound.play()` to start it.
|
|
1290
|
+
- The `Sound` constructor takes an optional fifth `html` flag, and `buffer` may be `undefined`.
|
|
1291
|
+
|
|
1292
|
+
### Changed
|
|
1293
|
+
- `createSound()` is typed as returning `Promise<Sound>` again (it was `Promise<BaseSound>` since 0.1.13).
|
|
1294
|
+
|
|
1295
|
+
## [0.1.19] - 2023-11-19
|
|
1296
|
+
|
|
1297
|
+
### ⚠ Breaking
|
|
1298
|
+
- The `Sound` constructor takes the source `url` as its first parameter: `new Sound(url, buffer, context, globalGainNode)`.
|
|
1299
|
+
|
|
1300
|
+
### Changed
|
|
1301
|
+
- `Playback` tracks its own playing state. `isPlaying()` reflects `play()` and `stop()` instead of the context state, and it throws after `cleanup()`.
|
|
1302
|
+
- `stop()` on a playback that isn't playing does nothing, and `seek()` on a stopped playback moves the position without starting playback.
|
|
1303
|
+
- Loops restart only while the playback is still playing.
|
|
1304
|
+
|
|
1305
|
+
## [0.1.18] - 2023-11-19
|
|
1306
|
+
|
|
1307
|
+
_First npm release after 0.1.16 and 0.1.17, which were tagged but not published. Upgrading from an earlier npm version? Read those entries too._
|
|
1308
|
+
|
|
1309
|
+
### Changed
|
|
1310
|
+
- Internal changes only (release workflow permissions).
|
|
1311
|
+
|
|
1312
|
+
## [0.1.17] - 2023-11-19
|
|
1313
|
+
|
|
1314
|
+
_Tagged but not published to npm._
|
|
1315
|
+
|
|
1316
|
+
### Changed
|
|
1317
|
+
- Internal changes only (release workflow).
|
|
1318
|
+
|
|
1319
|
+
## [0.1.16] - 2023-11-19
|
|
1320
|
+
|
|
1321
|
+
_Tagged but not published to npm._
|
|
1322
|
+
|
|
1323
|
+
### Changed
|
|
1324
|
+
- Looping HTML-audio playbacks restart by seeking to 0; buffer playbacks re-create their source on each loop.
|
|
1325
|
+
- Added a GitHub Actions workflow that builds and publishes to npm on tag, and updated the README (microphone input, fades, `cleanup()`).
|
|
1326
|
+
|
|
1327
|
+
## [0.1.15] - 2023-11-19
|
|
1328
|
+
|
|
1329
|
+
### ⚠ Breaking
|
|
1330
|
+
- `isPlaying()` is a required member of `BaseSound`.
|
|
1331
|
+
|
|
1332
|
+
### Added
|
|
1333
|
+
- `Group.isPlaying()`, `MicrophoneStream.isPlaying()` and `MicrophonePlayback.isPlaying()`.
|
|
1334
|
+
|
|
1335
|
+
## [0.1.14] - 2023-11-19
|
|
1336
|
+
|
|
1337
|
+
_First npm release after 0.1.13, which was tagged but not published. Upgrading from an earlier npm version? Read that entry too._
|
|
1338
|
+
|
|
1339
|
+
### Changed
|
|
1340
|
+
- Internal changes only (tests).
|
|
1341
|
+
|
|
1342
|
+
## [0.1.13] - 2023-11-19
|
|
1343
|
+
|
|
1344
|
+
_Tagged but not published to npm._
|
|
1345
|
+
|
|
1346
|
+
### Changed
|
|
1347
|
+
- `createSound()` is typed as returning `Promise<BaseSound>` (reverted in 0.1.20).
|
|
1348
|
+
- `Group.addSound()` accepts any `BaseSound`, and `Group.resume()` calls each member's `resume()`.
|
|
1349
|
+
|
|
1350
|
+
## [0.1.12] - 2023-11-19
|
|
1351
|
+
|
|
1352
|
+
### Added
|
|
1353
|
+
- `Playback` is exported.
|
|
1354
|
+
|
|
1355
|
+
## [0.1.11] - 2023-11-19
|
|
1356
|
+
|
|
1357
|
+
### Changed
|
|
1358
|
+
- `createStream(url)` returns a single `Playback` again (reverting 0.1.10).
|
|
1359
|
+
|
|
1360
|
+
## [0.1.10] - 2023-11-19
|
|
1361
|
+
|
|
1362
|
+
### Changed
|
|
1363
|
+
- `createStream(url)` returns `Promise<Playback[]>`.
|
|
1364
|
+
|
|
1365
|
+
## [0.1.9] - 2023-11-19
|
|
1366
|
+
|
|
1367
|
+
### ⚠ Breaking
|
|
1368
|
+
- `StreamPlayback` is renamed to `MicrophonePlayback`.
|
|
1369
|
+
|
|
1370
|
+
### Added
|
|
1371
|
+
- `Cacophony.createStream(url)` plays audio through an HTML `<audio>` element routed into Web Audio. `Playback` supports media-element sources for play, stop, loop and seek.
|
|
1372
|
+
|
|
1373
|
+
### Fixed
|
|
1374
|
+
- Creating a `Playback` no longer starts its source immediately. `Sound.play()` had been starting the same source node twice.
|
|
1375
|
+
|
|
1376
|
+
## [0.1.8] - 2023-11-19
|
|
1377
|
+
|
|
1378
|
+
### Added
|
|
1379
|
+
- `isPlaying()` on `Sound` and `Playback`.
|
|
1380
|
+
- `Playback.threeDOptions` getter and setter for the underlying `PannerNode` settings; `threeDOptions` is an optional `BaseSound` member.
|
|
1381
|
+
|
|
1382
|
+
## [0.1.7] - 2023-11-18
|
|
1383
|
+
|
|
1384
|
+
### Fixed
|
|
1385
|
+
- The npm package includes the compiled library. Earlier tarballs (verified for 0.1.3–0.1.6) shipped only `dist/index.js`, which re-exported a module missing from the tarball, so the package could not be imported.
|
|
1386
|
+
|
|
1387
|
+
## [0.1.6] - 2023-11-18
|
|
1388
|
+
|
|
1389
|
+
### Added
|
|
1390
|
+
- `seek(time)` on `Sound`, `Playback` and `Group`.
|
|
1391
|
+
- Microphone input: `Cacophony.getMicrophoneStream()` returns a `MicrophoneStream`, played through a `StreamPlayback`, with volume, filters, pause and resume.
|
|
1392
|
+
- `Playback.sourceLoop` setter.
|
|
1393
|
+
|
|
1394
|
+
### Changed
|
|
1395
|
+
- `BaseSound.play()` returns `BaseSound[]`; `seek` and `loop` are optional `BaseSound` members.
|
|
1396
|
+
- `Sound.globalGainNode` and the internal nodes of `Playback` (`context`, `source`, `gainNode`, `panner`, `buffer`) are private.
|
|
1397
|
+
- `Sound.play()` starts playbacks through `Playback.play()`.
|
|
1398
|
+
|
|
1399
|
+
## [0.1.5] - 2023-11-18
|
|
1400
|
+
|
|
1401
|
+
### ⚠ Breaking
|
|
1402
|
+
- `moveTo(x, y, z)` is replaced by a `position` property on `Sound`, `Playback` and `Group`. Replace `sound.moveTo(x, y, z)` with `sound.position = [x, y, z]`.
|
|
1403
|
+
|
|
1404
|
+
### Added
|
|
1405
|
+
- `Position` and `LoopCount` types are exported.
|
|
1406
|
+
|
|
1407
|
+
### Changed
|
|
1408
|
+
- `Group.volume` returns the average volume of its sounds instead of the first sound's volume.
|
|
1409
|
+
|
|
1410
|
+
## [0.1.4] - 2023-11-18
|
|
1411
|
+
|
|
1412
|
+
### Added
|
|
1413
|
+
- `Playback.cleanup()` disconnects and releases a playback's nodes; later calls on the playback throw.
|
|
1414
|
+
|
|
1415
|
+
### Fixed
|
|
1416
|
+
- `Playback.fadeIn()` ramps from 0 to full volume using Web Audio automation and supports the `'exponential'` fade type. The old version used an interval timer that finished almost immediately.
|
|
1417
|
+
|
|
1418
|
+
## [0.1.3] - 2023-10-06
|
|
1419
|
+
|
|
1420
|
+
_0.1.0–0.1.2 were published to npm but not tagged; this block covers everything from the first commit to 0.1.3._
|
|
1421
|
+
|
|
1422
|
+
### Added
|
|
1423
|
+
- First release. `Cacophony` wraps a (standardized-audio-context) `AudioContext` with a global gain node and provides `createSound(url | AudioBuffer)`, `createGroup(sounds)`, `createGroupFromUrls(urls)`, `createBiquadFilter(type)`, `pause()`, `resume()`, `stopAll()`, `setGlobalVolume()`, a `volume` property, `mute()` and `unmute()`.
|
|
1424
|
+
- `Sound` holds a decoded buffer and creates a `Playback` for each `play()` call. It supports `stop()`, `pause()`, `resume()`, `loop(count | 'infinite')`, `volume`, `moveTo(x, y, z)` for 3D positioning, and `addFilter()`/`removeFilter()` for filters.
|
|
1425
|
+
- `Group` controls several sounds together.
|
|
1426
|
+
- Sounds loaded from URLs are cached with the browser Cache API (`CacheManager`), and concurrent loads of the same URL are de-duplicated.
|
|
1427
|
+
- `Playback.fadeIn()` and `Playback.fadeOut()` with `'linear'` or `'exponential'` fades.
|
|
1428
|
+
|
|
1429
|
+
[Unreleased]: https://github.com/ctoth/cacophony/compare/v0.34.0...HEAD
|
|
1430
|
+
[0.34.0]: https://github.com/ctoth/cacophony/compare/v0.33.0...v0.34.0
|
|
1431
|
+
[0.33.0]: https://github.com/ctoth/cacophony/compare/v0.32.1...v0.33.0
|
|
1432
|
+
[0.32.1]: https://github.com/ctoth/cacophony/compare/v0.32.0...v0.32.1
|
|
1433
|
+
[0.32.0]: https://github.com/ctoth/cacophony/compare/v0.31.0...v0.32.0
|
|
1434
|
+
[0.31.0]: https://github.com/ctoth/cacophony/compare/v0.30.4...v0.31.0
|
|
1435
|
+
[0.30.4]: https://github.com/ctoth/cacophony/compare/v0.30.3...v0.30.4
|
|
1436
|
+
[0.30.3]: https://github.com/ctoth/cacophony/compare/v0.30.2...v0.30.3
|
|
1437
|
+
[0.30.2]: https://github.com/ctoth/cacophony/compare/v0.30.1...v0.30.2
|
|
1438
|
+
[0.30.1]: https://github.com/ctoth/cacophony/compare/v0.30.0...v0.30.1
|
|
1439
|
+
[0.30.0]: https://github.com/ctoth/cacophony/compare/v0.29.0...v0.30.0
|
|
1440
|
+
[0.29.0]: https://github.com/ctoth/cacophony/compare/v0.28.0...v0.29.0
|
|
1441
|
+
[0.28.0]: https://github.com/ctoth/cacophony/compare/v0.26.0...v0.28.0
|
|
1442
|
+
[0.26.0]: https://github.com/ctoth/cacophony/compare/v0.25.1...v0.26.0
|
|
1443
|
+
[0.25.1]: https://github.com/ctoth/cacophony/compare/v0.25.0...v0.25.1
|
|
1444
|
+
[0.25.0]: https://github.com/ctoth/cacophony/compare/v0.24.0...v0.25.0
|
|
1445
|
+
[0.24.0]: https://github.com/ctoth/cacophony/compare/v0.23.0...v0.24.0
|
|
1446
|
+
[0.23.0]: https://github.com/ctoth/cacophony/compare/v0.21.0...v0.23.0
|
|
1447
|
+
[0.21.0]: https://github.com/ctoth/cacophony/compare/v0.20.8...v0.21.0
|
|
1448
|
+
[0.20.8]: https://github.com/ctoth/cacophony/compare/v0.20.7...v0.20.8
|
|
1449
|
+
[0.20.7]: https://github.com/ctoth/cacophony/compare/v0.20.6...v0.20.7
|
|
1450
|
+
[0.20.6]: https://github.com/ctoth/cacophony/compare/v0.20.5...v0.20.6
|
|
1451
|
+
[0.20.5]: https://github.com/ctoth/cacophony/compare/v0.20.4...v0.20.5
|
|
1452
|
+
[0.20.4]: https://github.com/ctoth/cacophony/compare/v0.20.3...v0.20.4
|
|
1453
|
+
[0.20.3]: https://github.com/ctoth/cacophony/compare/v0.20.2...v0.20.3
|
|
1454
|
+
[0.20.2]: https://github.com/ctoth/cacophony/compare/v0.20.1...v0.20.2
|
|
1455
|
+
[0.20.1]: https://github.com/ctoth/cacophony/compare/v0.20.0...v0.20.1
|
|
1456
|
+
[0.20.0]: https://github.com/ctoth/cacophony/compare/v0.19.0...v0.20.0
|
|
1457
|
+
[0.19.0]: https://github.com/ctoth/cacophony/compare/v0.18.3...v0.19.0
|
|
1458
|
+
[0.18.3]: https://github.com/ctoth/cacophony/compare/v0.18.2...v0.18.3
|
|
1459
|
+
[0.18.2]: https://github.com/ctoth/cacophony/compare/v0.18.1...v0.18.2
|
|
1460
|
+
[0.18.1]: https://github.com/ctoth/cacophony/compare/v0.18.0...v0.18.1
|
|
1461
|
+
[0.18.0]: https://github.com/ctoth/cacophony/compare/v0.17.1...v0.18.0
|
|
1462
|
+
[0.17.1]: https://github.com/ctoth/cacophony/compare/v0.17.0...v0.17.1
|
|
1463
|
+
[0.17.0]: https://github.com/ctoth/cacophony/compare/v0.16.1...v0.17.0
|
|
1464
|
+
[0.16.1]: https://github.com/ctoth/cacophony/compare/v0.16.0...v0.16.1
|
|
1465
|
+
[0.16.0]: https://github.com/ctoth/cacophony/compare/v0.15.3...v0.16.0
|
|
1466
|
+
[0.15.3]: https://github.com/ctoth/cacophony/compare/v0.15.2...v0.15.3
|
|
1467
|
+
[0.15.2]: https://github.com/ctoth/cacophony/compare/v0.15.1...v0.15.2
|
|
1468
|
+
[0.15.1]: https://github.com/ctoth/cacophony/compare/v0.15.0...v0.15.1
|
|
1469
|
+
[0.15.0]: https://github.com/ctoth/cacophony/compare/v0.14.2...v0.15.0
|
|
1470
|
+
[0.14.2]: https://github.com/ctoth/cacophony/compare/v0.14.1...v0.14.2
|
|
1471
|
+
[0.14.1]: https://github.com/ctoth/cacophony/compare/v0.14.0...v0.14.1
|
|
1472
|
+
[0.14.0]: https://github.com/ctoth/cacophony/compare/v0.13.5...v0.14.0
|
|
1473
|
+
[0.13.5]: https://github.com/ctoth/cacophony/compare/v0.13.4...v0.13.5
|
|
1474
|
+
[0.13.4]: https://github.com/ctoth/cacophony/compare/v0.13.3...v0.13.4
|
|
1475
|
+
[0.13.3]: https://github.com/ctoth/cacophony/compare/v0.13.2...v0.13.3
|
|
1476
|
+
[0.13.2]: https://github.com/ctoth/cacophony/compare/v0.13.1...v0.13.2
|
|
1477
|
+
[0.13.1]: https://github.com/ctoth/cacophony/compare/v0.13.0...v0.13.1
|
|
1478
|
+
[0.13.0]: https://github.com/ctoth/cacophony/compare/v0.12.10...v0.13.0
|
|
1479
|
+
[0.12.10]: https://github.com/ctoth/cacophony/compare/v0.12.9...v0.12.10
|
|
1480
|
+
[0.12.9]: https://github.com/ctoth/cacophony/compare/v0.12.8...v0.12.9
|
|
1481
|
+
[0.12.8]: https://github.com/ctoth/cacophony/compare/v0.12.7...v0.12.8
|
|
1482
|
+
[0.12.7]: https://github.com/ctoth/cacophony/compare/v0.12.6...v0.12.7
|
|
1483
|
+
[0.12.6]: https://github.com/ctoth/cacophony/compare/v0.12.5...v0.12.6
|
|
1484
|
+
[0.12.5]: https://github.com/ctoth/cacophony/compare/v0.12.4...v0.12.5
|
|
1485
|
+
[0.12.4]: https://github.com/ctoth/cacophony/compare/v0.12.3...v0.12.4
|
|
1486
|
+
[0.12.3]: https://github.com/ctoth/cacophony/compare/v0.12.2...v0.12.3
|
|
1487
|
+
[0.12.2]: https://github.com/ctoth/cacophony/compare/v0.12.1...v0.12.2
|
|
1488
|
+
[0.12.1]: https://github.com/ctoth/cacophony/compare/v0.12.0...v0.12.1
|
|
1489
|
+
[0.12.0]: https://github.com/ctoth/cacophony/compare/v0.11.1...v0.12.0
|
|
1490
|
+
[0.11.1]: https://github.com/ctoth/cacophony/compare/v0.11.0...v0.11.1
|
|
1491
|
+
[0.11.0]: https://github.com/ctoth/cacophony/compare/v0.10.4...v0.11.0
|
|
1492
|
+
[0.10.4]: https://github.com/ctoth/cacophony/compare/v0.10.3...v0.10.4
|
|
1493
|
+
[0.10.3]: https://github.com/ctoth/cacophony/compare/v0.10.2...v0.10.3
|
|
1494
|
+
[0.10.2]: https://github.com/ctoth/cacophony/compare/v0.10.1...v0.10.2
|
|
1495
|
+
[0.10.1]: https://github.com/ctoth/cacophony/compare/v0.10.0...v0.10.1
|
|
1496
|
+
[0.10.0]: https://github.com/ctoth/cacophony/compare/v0.9.7...v0.10.0
|
|
1497
|
+
[0.9.7]: https://github.com/ctoth/cacophony/compare/v0.9.6...v0.9.7
|
|
1498
|
+
[0.9.6]: https://github.com/ctoth/cacophony/compare/v0.9.5...v0.9.6
|
|
1499
|
+
[0.9.5]: https://github.com/ctoth/cacophony/compare/v0.9.4...v0.9.5
|
|
1500
|
+
[0.9.4]: https://github.com/ctoth/cacophony/compare/v0.9.3...v0.9.4
|
|
1501
|
+
[0.9.3]: https://github.com/ctoth/cacophony/compare/v0.9.2...v0.9.3
|
|
1502
|
+
[0.9.2]: https://github.com/ctoth/cacophony/compare/v0.9.1...v0.9.2
|
|
1503
|
+
[0.9.1]: https://github.com/ctoth/cacophony/compare/v0.9.0...v0.9.1
|
|
1504
|
+
[0.9.0]: https://github.com/ctoth/cacophony/compare/v0.8.7...v0.9.0
|
|
1505
|
+
[0.8.7]: https://github.com/ctoth/cacophony/compare/v0.8.6...v0.8.7
|
|
1506
|
+
[0.8.6]: https://github.com/ctoth/cacophony/compare/v0.8.5...v0.8.6
|
|
1507
|
+
[0.8.5]: https://github.com/ctoth/cacophony/compare/v0.8.4...v0.8.5
|
|
1508
|
+
[0.8.4]: https://github.com/ctoth/cacophony/compare/v0.8.3...v0.8.4
|
|
1509
|
+
[0.8.3]: https://github.com/ctoth/cacophony/compare/v0.8.2...v0.8.3
|
|
1510
|
+
[0.8.2]: https://github.com/ctoth/cacophony/compare/v0.8.1...v0.8.2
|
|
1511
|
+
[0.8.1]: https://github.com/ctoth/cacophony/compare/v0.8.0...v0.8.1
|
|
1512
|
+
[0.8.0]: https://github.com/ctoth/cacophony/compare/v0.7.0...v0.8.0
|
|
1513
|
+
[0.7.0]: https://github.com/ctoth/cacophony/compare/v0.6.2...v0.7.0
|
|
1514
|
+
[0.6.2]: https://github.com/ctoth/cacophony/compare/v0.6.1...v0.6.2
|
|
1515
|
+
[0.6.1]: https://github.com/ctoth/cacophony/compare/v0.6.0...v0.6.1
|
|
1516
|
+
[0.6.0]: https://github.com/ctoth/cacophony/compare/v0.5.23...v0.6.0
|
|
1517
|
+
[0.5.23]: https://github.com/ctoth/cacophony/compare/v0.5.22...v0.5.23
|
|
1518
|
+
[0.5.22]: https://github.com/ctoth/cacophony/compare/v0.5.21...v0.5.22
|
|
1519
|
+
[0.5.21]: https://github.com/ctoth/cacophony/compare/v0.5.20...v0.5.21
|
|
1520
|
+
[0.5.20]: https://github.com/ctoth/cacophony/compare/v0.5.19...v0.5.20
|
|
1521
|
+
[0.5.19]: https://github.com/ctoth/cacophony/compare/v0.5.18...v0.5.19
|
|
1522
|
+
[0.5.18]: https://github.com/ctoth/cacophony/compare/v0.5.17...v0.5.18
|
|
1523
|
+
[0.5.17]: https://github.com/ctoth/cacophony/compare/v0.5.16...v0.5.17
|
|
1524
|
+
[0.5.16]: https://github.com/ctoth/cacophony/compare/v0.5.15...v0.5.16
|
|
1525
|
+
[0.5.15]: https://github.com/ctoth/cacophony/compare/v0.5.14...v0.5.15
|
|
1526
|
+
[0.5.14]: https://github.com/ctoth/cacophony/compare/v0.5.13...v0.5.14
|
|
1527
|
+
[0.5.13]: https://github.com/ctoth/cacophony/compare/v0.5.12...v0.5.13
|
|
1528
|
+
[0.5.12]: https://github.com/ctoth/cacophony/compare/v0.5.11...v0.5.12
|
|
1529
|
+
[0.5.11]: https://github.com/ctoth/cacophony/compare/v0.5.10...v0.5.11
|
|
1530
|
+
[0.5.10]: https://github.com/ctoth/cacophony/compare/v0.5.9...v0.5.10
|
|
1531
|
+
[0.5.9]: https://github.com/ctoth/cacophony/compare/v0.5.8...v0.5.9
|
|
1532
|
+
[0.5.8]: https://github.com/ctoth/cacophony/compare/v0.5.7...v0.5.8
|
|
1533
|
+
[0.5.7]: https://github.com/ctoth/cacophony/compare/v0.5.6...v0.5.7
|
|
1534
|
+
[0.5.6]: https://github.com/ctoth/cacophony/compare/v0.5.5...v0.5.6
|
|
1535
|
+
[0.5.5]: https://github.com/ctoth/cacophony/compare/v0.5.4...v0.5.5
|
|
1536
|
+
[0.5.4]: https://github.com/ctoth/cacophony/compare/v0.5.3...v0.5.4
|
|
1537
|
+
[0.5.3]: https://github.com/ctoth/cacophony/compare/v0.5.2...v0.5.3
|
|
1538
|
+
[0.5.2]: https://github.com/ctoth/cacophony/compare/v0.5.1...v0.5.2
|
|
1539
|
+
[0.5.1]: https://github.com/ctoth/cacophony/compare/v0.5.0...v0.5.1
|
|
1540
|
+
[0.5.0]: https://github.com/ctoth/cacophony/compare/v0.4.6...v0.5.0
|
|
1541
|
+
[0.4.6]: https://github.com/ctoth/cacophony/compare/v0.4.5...v0.4.6
|
|
1542
|
+
[0.4.5]: https://github.com/ctoth/cacophony/compare/v0.4.4...v0.4.5
|
|
1543
|
+
[0.4.4]: https://github.com/ctoth/cacophony/compare/v0.4.3...v0.4.4
|
|
1544
|
+
[0.4.3]: https://github.com/ctoth/cacophony/compare/v0.4.2...v0.4.3
|
|
1545
|
+
[0.4.2]: https://github.com/ctoth/cacophony/compare/v0.4.1...v0.4.2
|
|
1546
|
+
[0.4.1]: https://github.com/ctoth/cacophony/compare/v0.4.0...v0.4.1
|
|
1547
|
+
[0.4.0]: https://github.com/ctoth/cacophony/compare/v0.3.13...v0.4.0
|
|
1548
|
+
[0.3.13]: https://github.com/ctoth/cacophony/compare/v0.3.12...v0.3.13
|
|
1549
|
+
[0.3.12]: https://github.com/ctoth/cacophony/compare/v0.3.11...v0.3.12
|
|
1550
|
+
[0.3.11]: https://github.com/ctoth/cacophony/compare/v0.3.10...v0.3.11
|
|
1551
|
+
[0.3.10]: https://github.com/ctoth/cacophony/compare/v0.3.9...v0.3.10
|
|
1552
|
+
[0.3.9]: https://github.com/ctoth/cacophony/compare/v0.3.8...v0.3.9
|
|
1553
|
+
[0.3.8]: https://github.com/ctoth/cacophony/compare/v0.3.7...v0.3.8
|
|
1554
|
+
[0.3.7]: https://github.com/ctoth/cacophony/compare/v0.3.6...v0.3.7
|
|
1555
|
+
[0.3.6]: https://github.com/ctoth/cacophony/compare/v0.3.5...v0.3.6
|
|
1556
|
+
[0.3.5]: https://github.com/ctoth/cacophony/compare/v0.3.4...v0.3.5
|
|
1557
|
+
[0.3.4]: https://github.com/ctoth/cacophony/compare/v0.3.3...v0.3.4
|
|
1558
|
+
[0.3.3]: https://github.com/ctoth/cacophony/compare/v0.3.2...v0.3.3
|
|
1559
|
+
[0.3.2]: https://github.com/ctoth/cacophony/compare/v0.3.1...v0.3.2
|
|
1560
|
+
[0.3.1]: https://github.com/ctoth/cacophony/compare/v0.3.0...v0.3.1
|
|
1561
|
+
[0.3.0]: https://github.com/ctoth/cacophony/compare/v0.2.1...v0.3.0
|
|
1562
|
+
[0.2.1]: https://github.com/ctoth/cacophony/compare/v0.2.0...v0.2.1
|
|
1563
|
+
[0.2.0]: https://github.com/ctoth/cacophony/compare/v0.1.39...v0.2.0
|
|
1564
|
+
[0.1.39]: https://github.com/ctoth/cacophony/compare/v0.1.38...v0.1.39
|
|
1565
|
+
[0.1.38]: https://github.com/ctoth/cacophony/compare/v0.1.37...v0.1.38
|
|
1566
|
+
[0.1.37]: https://github.com/ctoth/cacophony/compare/v0.1.36...v0.1.37
|
|
1567
|
+
[0.1.36]: https://github.com/ctoth/cacophony/compare/v0.1.35...v0.1.36
|
|
1568
|
+
[0.1.35]: https://github.com/ctoth/cacophony/compare/v0.1.34...v0.1.35
|
|
1569
|
+
[0.1.34]: https://github.com/ctoth/cacophony/compare/v0.1.33...v0.1.34
|
|
1570
|
+
[0.1.33]: https://github.com/ctoth/cacophony/compare/v0.1.32...v0.1.33
|
|
1571
|
+
[0.1.32]: https://github.com/ctoth/cacophony/compare/v0.1.31...v0.1.32
|
|
1572
|
+
[0.1.31]: https://github.com/ctoth/cacophony/compare/v0.1.30...v0.1.31
|
|
1573
|
+
[0.1.30]: https://github.com/ctoth/cacophony/compare/v0.1.29...v0.1.30
|
|
1574
|
+
[0.1.29]: https://github.com/ctoth/cacophony/compare/v0.1.28...v0.1.29
|
|
1575
|
+
[0.1.28]: https://github.com/ctoth/cacophony/compare/v0.1.27...v0.1.28
|
|
1576
|
+
[0.1.27]: https://github.com/ctoth/cacophony/compare/v0.1.26...v0.1.27
|
|
1577
|
+
[0.1.26]: https://github.com/ctoth/cacophony/compare/v0.1.25...v0.1.26
|
|
1578
|
+
[0.1.25]: https://github.com/ctoth/cacophony/compare/v0.1.24...v0.1.25
|
|
1579
|
+
[0.1.24]: https://github.com/ctoth/cacophony/compare/v0.1.23...v0.1.24
|
|
1580
|
+
[0.1.23]: https://github.com/ctoth/cacophony/compare/v0.1.22...v0.1.23
|
|
1581
|
+
[0.1.22]: https://github.com/ctoth/cacophony/compare/v0.1.21...v0.1.22
|
|
1582
|
+
[0.1.21]: https://github.com/ctoth/cacophony/compare/v0.1.20...v0.1.21
|
|
1583
|
+
[0.1.20]: https://github.com/ctoth/cacophony/compare/v0.1.19...v0.1.20
|
|
1584
|
+
[0.1.19]: https://github.com/ctoth/cacophony/compare/v0.1.18...v0.1.19
|
|
1585
|
+
[0.1.18]: https://github.com/ctoth/cacophony/compare/v0.1.17...v0.1.18
|
|
1586
|
+
[0.1.17]: https://github.com/ctoth/cacophony/compare/v0.1.16...v0.1.17
|
|
1587
|
+
[0.1.16]: https://github.com/ctoth/cacophony/compare/v0.1.15...v0.1.16
|
|
1588
|
+
[0.1.15]: https://github.com/ctoth/cacophony/compare/v0.1.14...v0.1.15
|
|
1589
|
+
[0.1.14]: https://github.com/ctoth/cacophony/compare/v0.1.13...v0.1.14
|
|
1590
|
+
[0.1.13]: https://github.com/ctoth/cacophony/compare/v0.1.12...v0.1.13
|
|
1591
|
+
[0.1.12]: https://github.com/ctoth/cacophony/compare/v0.1.11...v0.1.12
|
|
1592
|
+
[0.1.11]: https://github.com/ctoth/cacophony/compare/v0.1.10...v0.1.11
|
|
1593
|
+
[0.1.10]: https://github.com/ctoth/cacophony/compare/v0.1.9...v0.1.10
|
|
1594
|
+
[0.1.9]: https://github.com/ctoth/cacophony/compare/v0.1.8...v0.1.9
|
|
1595
|
+
[0.1.8]: https://github.com/ctoth/cacophony/compare/v0.1.7...v0.1.8
|
|
1596
|
+
[0.1.7]: https://github.com/ctoth/cacophony/compare/v0.1.6...v0.1.7
|
|
1597
|
+
[0.1.6]: https://github.com/ctoth/cacophony/compare/v0.1.5...v0.1.6
|
|
1598
|
+
[0.1.5]: https://github.com/ctoth/cacophony/compare/v0.1.4...v0.1.5
|
|
1599
|
+
[0.1.4]: https://github.com/ctoth/cacophony/compare/v0.1.3...v0.1.4
|
|
1600
|
+
[0.1.3]: https://github.com/ctoth/cacophony/releases/tag/v0.1.3
|