Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 [Earwurm] Various bug fixes #50

Merged
merged 56 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
28ddb14
:arrow_up: [Dependency] Minor and patch bumps
beefchimi Dec 20, 2023
d2f3945
:test_tube: [Tests] Update after vitest bump
beefchimi Dec 20, 2023
cc03bc4
:hammer_and_wrench: [VsCode] Update deprecated setting
beefchimi Dec 20, 2023
72d21ee
:speech_balloon: [Stack] TODO comment
beefchimi Nov 26, 2023
f065c94
:bug: [Sound] Do not call .stop() unless started
beefchimi Nov 26, 2023
6fc43cf
:label: [Sound] Include neverStarted prop on SoundEndedEvent
beefchimi Dec 20, 2023
0925bf7
:sparkles: [Sound] Manually emit ended event on .stop() but never sta…
beefchimi Dec 20, 2023
f548c40
:rewind: [Stack] Resolve the TODO comment
beefchimi Dec 20, 2023
8930670
:label: [Types] Add volume and mute events to all EventMap types
beefchimi Dec 21, 2023
e0d1f3d
:sparkles: [Earwurm] Emit volume and mute events
beefchimi Dec 21, 2023
bbf7a99
:sparkles: [Stack] Emit volume and mute events
beefchimi Dec 21, 2023
a40ce7f
:sparkles: [Sound] Emit volume and mute events
beefchimi Dec 21, 2023
e84967a
:test_tube: [Abstract] Add volume and mute event tests
beefchimi Dec 21, 2023
e7cd51f
:label: [Types] Add PrimitiveType
beefchimi Dec 21, 2023
5877b90
:wrench: [Utilities] Add arrayShallowEquals()
beefchimi Dec 21, 2023
059747a
:test_tube: [Earwurm] Reuse mockManager and reset after each test
beefchimi Dec 21, 2023
fc608c3
:bug: [Earwurm] Do not reinitialize an existing Stack on .add()
beefchimi Dec 21, 2023
d195086
:sparkles: [Earwurm] Add keys event
beefchimi Dec 21, 2023
a45a151
:label: [Types] Rename ManagerEventMap > statechange to state
beefchimi Dec 22, 2023
b6ffba3
:boom: [Earwurm] Rename statechange event to state
beefchimi Dec 22, 2023
0be554b
:art: [Abstract] Some test formatting
beefchimi Dec 22, 2023
eb45d4b
:boom: [Stack] Rename statechange event to state
beefchimi Dec 22, 2023
f4d08bb
:boom: [Sound] Rename statechange event to state
beefchimi Dec 22, 2023
55ebc1b
:recycle: [Stack] Update any references to Sound > statechange
beefchimi Dec 22, 2023
f66ef1e
:sparkles: [Earwurm] Move pre-defined error messages to static member
beefchimi Dec 22, 2023
fba8fa3
:books: [Docs] Update doc references to statechange
beefchimi Dec 22, 2023
c676d64
:fire: [Types] Remove LibraryKeys
beefchimi Dec 22, 2023
e7daa04
:books: [Docs] Replace reference to removed LibraryKeys
beefchimi Dec 22, 2023
abb78dc
:recycle: [Earwurm] Use StackId[] instead of LibraryKeys
beefchimi Dec 22, 2023
f888d21
:recycle: [Earwurm] Rename keys event to library
beefchimi Dec 22, 2023
eca87a1
:books: [Docs] Update API reference to keys event
beefchimi Dec 22, 2023
73556e8
:test_tube: [Stack] Update some tests to re-use mockStack reference
beefchimi Dec 22, 2023
fcee531
:sparkles: [Stack] Add queue event
beefchimi Dec 22, 2023
7b50b9c
:bug: [Sound] Disconnect and empty only after emitting ended event
beefchimi Dec 22, 2023
ace9b8f
:door: [Types] Export StackId and SoundId
beefchimi Dec 23, 2023
a9e0f70
:wrench: [Utilities] Simplify numbers arguments
beefchimi Dec 25, 2023
9e1ceaa
:recycle: [Earwurm] Update use of clamp()
beefchimi Dec 25, 2023
f3bdc64
:recycle: [Stack] Update use of clamp()
beefchimi Dec 25, 2023
52dbb50
:clown_face: [Mock] Default MockBaseAudioContext.currentTime to Date.…
beefchimi Dec 26, 2023
cac52f0
:rewind: [Mock] Return MockBaseAudioContext.currentTime to 0
beefchimi Dec 27, 2023
eb4691d
:wrench: [Helpers] New linearRamp() helper
beefchimi Dec 27, 2023
f037578
:recycle: [Earwurm] Now using linearRamp()
beefchimi Dec 27, 2023
0f782cb
:recycle: [Stack] Now using linearRamp()
beefchimi Dec 27, 2023
64e5610
:wrench: [Utilities] Add assertNumber() type-guard
beefchimi Dec 27, 2023
82b7300
:test_tube: [Tests] More consistent use of async for each test
beefchimi Dec 27, 2023
d352dfd
:speech_balloon: [Stack] Clarify comment
beefchimi Dec 27, 2023
6aafdcc
:sparkles: [Sound] Many changes to support new progress features
beefchimi Dec 27, 2023
f846f8a
:books: [Docs] Update API.md to cover some recent changes
beefchimi Dec 27, 2023
edacd78
:sparkles: [Sound] Better support for loop and progress
beefchimi Dec 28, 2023
d32a357
:speech_balloon: [Tokens] Clarify comment
beefchimi Dec 29, 2023
396cfb1
:sparkles: [Sound] Improve interaction of speed/loop/pause/progress
beefchimi Dec 29, 2023
4b56fcf
:bug: [Sound] Fix broken pause after speed change on FireFox
beefchimi Dec 29, 2023
005d06b
:door: [Tokens] Export for consumers
beefchimi Jan 2, 2024
769b102
:art: [Stack/Sound] Minor code formatting
beefchimi Jan 3, 2024
a2ead19
:memo: [Report] Add changeset
beefchimi Jan 4, 2024
de9c61d
:books: [Migration] Add a migration guide
beefchimi Jan 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .changeset/seven-taxis-sip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
'earwurm': minor
---

Fix issue "stopping" a `Sound` that was never "started".
Include a `neverStarted: boolean;` property in the `SoundEndedEvent`.
New `volume` change event for `Earwurm`, `Stack`, and `Sound`.
New `mute` change event for `Earwurm`, `Stack`, and `Sound`.
New `library` change event for `Earwurm`.
New `queue` change event for `Stack`.
New `speed` change event for `Sound`.
`speed` Setter now clamps the value between `0.25` and `4`.
New `progress` change event.
New `progress` Getter.
New `state > ending` value.
Renamed all `statechange` events to `state`.
No longer setting `mute = false` when "pausing".
Avoid re-initializing an existing `Stack` when `.add()` is passed an identical `id + path`.
Removed `LibraryKeys` type, instead using `StackIds[]` directly.
Now exporting `tokens` object with some usual values.
Updated `docs/api.md` to include details on all the newly added / changed code.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"editor.codeActionsOnSave": {
"source.fixAll": true
"source.fixAll": "explicit"
},
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# earwurm
# Earwurm Changelog

## 0.5.2

Expand Down
9 changes: 9 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Earwurm migration guide

## 0.6.0

For more details on the released changes, please see [🐛 Various bug fixes](https://github.com/beefchimi/earwurm/pull/50).

- Rename all instances of `statechange` to `state`.
- Example: `manager.on('statechange', () => {})`
- Replace any instances of `LibraryKeys` with the equivalent `StackIds[]`.
63 changes: 56 additions & 7 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,21 @@ manager.activeEvents;
// Returns the current `AudioContext > state`. This may trigger
// immediately upon `new Earwurm()` if the `AudioContext` is
// “unlocked” right away.
(event: 'statechange', listener: (state: ManagerState) => void)
(event: 'state', listener: (current: ManagerState) => void)

// Event called whenever the `keys` property changes. This is useful
// to subscribe to changes in the internal “stack library”.
(event: 'library', listener: (newKeys: StackId[], oldKeys: StackId[]) => void)

// Event called whenever the `volume` property changes.
(event: 'volume', listener: (level: number) => void)

// Event called whenever the `mute` property changes.
(event: 'mute', listener: (muted: boolean) => void)

// Event called whenever an error is occured on the `AudioContext`.
// This could be a result of: failed to resume, failed to close.
(event: 'error', listener: (error: CombinedErrorMessage) => void)
(event: 'error', listener: (messages: CombinedErrorMessage) => void)
```

**Static members:**
Expand Down Expand Up @@ -228,7 +238,17 @@ soundStack.activeEvents;
// the `Stack`. As sounds cycle through their various states, the
// `Stack` will determine if any `Sound` is currently `playing`.
// Possible `StackState` values are: `idle`, `loading`, `playing`.
(event: 'statechange', listener: (state: StackState) => void)
(event: 'state', listener: (current: StackState) => void)

// Event called whenever the `keys` property changes. This is useful
// to subscribe to changes in the internal “sound queue”.
(event: 'queue', listener: (newKeys: SoundId[], oldKeys: SoundId[]) => void)

// Event called whenever the `volume` property changes.
(event: 'volume', listener: (level: number) => void)

// Event called whenever the `mute` property changes.
(event: 'mute', listener: (muted: boolean) => void)

// Event called whenever an error is occured on the `Stack`.
// This could be a result of: failed to load the `path`.
Expand Down Expand Up @@ -288,6 +308,11 @@ sound.volume = 1;
// Mute / unmute this `Sound`.
sound.mute = true || false;

// Set the `playbackRate` for this `Sound.
// This value is a number used to multiply the speed of playback.
// Default is `1`. Min is `0.25`. Max is `4`.
sound.speed;

// Toggle the “repetition” of the `Sound`. Will
// repeat indefinitely if `true`, preventing the
// `ended` event from firing.
Expand All @@ -303,31 +328,55 @@ sound.volume;
// Get a `boolean` for whether or not this `Sound` is “mute”.
sound.mute;

// Get the current `playbackRate` for this `Sound.
sound.speed;

// Get a `boolean` for whether or not this `Sound` is
// to repeat indefinitely.
sound.loop;

// Get the “total play time” for this `Sound`.
sound.duration;

// Get the current `SoundProgressEvent` for this `Sound.
sound.progress;

// Get the current `state` for this `Sound`. Can be:
// `created`, `playing`, `paused`, or `stopping`.
sound.duration;
// `created`, `playing`, `paused`, `stopping`, or `ending`.
sound.state;

// Get an array of all the events for this instance
// that currently have listeners attached.
sound.activeEvents;
```

**Events:**

```ts
// Event called whenever `Sound > state` is changed.
// Possible `SoundState` values are:
// `created`, `playing`, `paused`, and `stopping`.
(event: 'statechange', listener: (state: SoundState) => void)
// `created`, `playing`, `paused`, `stopping`, and `ending`.
(event: 'state', listener: (current: SoundState) => void)

// Event called on the audio `source` node whenenver
// a `Sound` reaches either it’s “end duration”,
// or has been stopped / removed from the `Stack`.
// This will NOT get called each time a “loop” repeats.
(event: 'ended', listener: ({id, source}: SoundEndedEvent) => void)

// Event called whenever the `volume` property changes.
(event: 'volume', listener: (level: number) => void)

// Event called whenever the `mute` property changes.
(event: 'mute', listener: (muted: boolean) => void)

// Event called for every animation frame while `playing`.
// Returns data representing:
// elapsed: “seconds” into the current iteration of this `Sound`.
// remaining: “seconds” until the end of the current iteration of this `Sound`.
// percentage: “percentage progressed” into the current iteration of this `Sound`.
// iterations: number of times this `Sound` has looped.
(event: 'progress', listener: ({elapsed, remaining, percentage, iterations}: SoundProgressEvent) => void)
```

## Events API
Expand Down
6 changes: 3 additions & 3 deletions docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,14 @@ setTimeout(() => appleSound?.play(), appleSoundDuration + durationBuffer);

**Determining state values:**

While there is a dedicated `playing` property, you can obtain a more granular `state` by listening for the `statechange` event and checking the `state` property directly.
While there is a dedicated `playing` property, you can obtain a more granular `state` by listening for the `state` event and checking the `state` property directly.

```ts
let capturedState = sound.state;
let isPaused = capturedState === 'paused';

sound.on('statechange', (state) => {
capturedState = sound.state;
sound.on('state', (state) => {
capturedState = state;
isPaused = capturedState === 'paused';
});
```
Expand Down
Loading