Skip to content

Commit cdeaeb2

Browse files
fix: playhead/total reflect audible duration; stop kills lingering sounds
Playground bugs: - "aynı sürede göstermiyor" — block-edge time (UI construct) was driving the playhead and the Total label, but the underlying preset only sounds for its recipe duration. Counter ran past the audio. - "durma doğru çalışmıyor" — endPlayback() only stopped the pattern handle, leaving fire-and-forget sidebar previews and drop-blip plays running. Library: - PresetEntry gains an optional `durationMs` so consumers can size UI to actual audio length. Set on all 36 built-ins from each recipe's tail. - _player: don't manually fireEnded() in the fadeOut > 0 branch — the scheduled source.stop(now + tail) lets onended fire it later. The zero-fade branch keeps the manual fire (onended doesn't reliably run synchronously after stop()). Playground: - compose: derive `total` and the play span from max(step.at + presetEntries[id].durationMs) so playhead, counter and audio all end together. - compose: endPlayback() now also calls useSeslen.stopAll() so any lingering preview / drop-blip is killed when the user stops. Tooling: - .oxfmtrc.json: ignore web/src/routeTree.gen.ts (Tanstack-generated; oxfmt loops on it). Unblocks CI. - package.json: keyword reorder from oxfmt sweep. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 59196c7 commit cdeaeb2

41 files changed

Lines changed: 72 additions & 4 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.oxfmtrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"$schema": "https://unpkg.com/oxfmt/configuration_schema.json",
33
"semi": false,
4-
"ignorePatterns": ["CHANGELOG.md"]
4+
"ignorePatterns": ["CHANGELOG.md", "web/src/routeTree.gen.ts"]
55
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
"offline-audio",
2121
"oscillator",
2222
"polyphony",
23-
"preset",
2423
"prefers-reduced-motion",
24+
"preset",
2525
"react",
2626
"render-to-wav",
2727
"ses",

src/_player.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,17 @@ export function startBuffer(
9696
} catch {
9797
// already stopped
9898
}
99+
// `source.onended` will fire once the tail finishes — fireEnded()
100+
// is called from there, so don't fire here too.
99101
} else {
100102
try {
101103
source.stop()
102104
} catch {
103105
// already stopped
104106
}
107+
// `source.onended` may not fire synchronously after stop(); fire
108+
// ourselves so callers see ended immediately. The handler below
109+
// is idempotent (endedCb is nulled after the first call).
105110
fireEnded()
106111
}
107112
}

src/presets/_meta.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ export interface PresetEntry {
6060
* `createSeslen({ sources, defaults })`. Pure data — consumers can
6161
* override on a per-call basis with `play(name, opts)`. */
6262
readonly defaults?: SourceDefaults
63+
/** Approximate audible duration in milliseconds. Synthesised factories
64+
* don't expose `duration` on their `PlayHandle`, so this is the
65+
* metadata-side hint UIs need to show progress, sequence presets and
66+
* size waveform previews. Should match the recipe's tail. */
67+
readonly durationMs?: number
6368
/** The synthesis function. */
6469
readonly factory: SoundFactory
6570
}

src/presets/add.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const add: PresetEntry = {
88
description: "A quick rising blip for adding items, ticking todos and incrementing counters.",
99
tags: ["ui", "feedback", "chirp"],
1010
recipe: "sine 880→1480 Hz · 140 ms",
11+
durationMs: 160,
1112
motion: "bounce",
1213
accent: "teal",
1314
factory(ctx, master, opts) {

src/presets/alarm.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const alarm: PresetEntry = {
88
description: "Repeating two-tone siren for sustained alarms and timed warnings.",
99
tags: ["feedback", "warning"],
1010
recipe: "square 880↔660 Hz · 4 cycles · 800 ms",
11+
durationMs: 840,
1112
motion: "shake",
1213
accent: "red",
1314
factory(ctx, master, opts) {

src/presets/coin.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const coin: PresetEntry = {
88
description: "Two-note metallic ping for coin pickups, points and item collections.",
99
tags: ["game", "pickup"],
1010
recipe: "square 988 + 1320 Hz · 180 ms",
11+
durationMs: 200,
1112
motion: "flash",
1213
accent: "yellow",
1314
factory(ctx, master, opts) {

src/presets/collapse.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const collapse: PresetEntry = {
88
description: "Falling arc for accordions, drawers and panels collapsing.",
99
tags: ["ui", "transition"],
1010
recipe: "sine 990→330 Hz · 200 ms",
11+
durationMs: 220,
1112
motion: "pulse",
1213
accent: "teal",
1314
factory(ctx, master, opts) {

src/presets/copy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const copy: PresetEntry = {
88
description: "Bright two-tap blip for copy-to-clipboard confirmations.",
99
tags: ["ui", "feedback"],
1010
recipe: "sine 1480 + 1480 Hz · 90 ms",
11+
durationMs: 100,
1112
motion: "bounce",
1213
accent: "yellow",
1314
factory(ctx, master, opts) {

src/presets/delete.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const deletePreset: PresetEntry = {
88
description: "Filtered noise swoosh for removing items and dismissing dialogs.",
99
tags: ["ui", "noise", "sweep"],
1010
recipe: "noise sweep 4 kHz→400 Hz · 200 ms",
11+
durationMs: 220,
1112
motion: "swirl",
1213
accent: "purple",
1314
factory(ctx, master, opts) {

0 commit comments

Comments
 (0)