@aura3d/audio 4.0.8 → 4.1.1

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/dist/index.d.ts CHANGED
@@ -47,4 +47,5 @@ export { VoicePool } from "./game-sound/Voice.js";
47
47
  export type { VoiceCueSpec, VoiceRecord, VoicePriority } from "./game-sound/Voice.js";
48
48
  export { syncListener } from "./game-sound/listenerSync.js";
49
49
  export type { ListenerLike } from "./game-sound/listenerSync.js";
50
+ export * from "./synth/index.js";
50
51
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../packages/audio/src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../packages/audio/src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -29,4 +29,5 @@ export { probeFormat, formatExtension } from "./game-sound/formatProbe.js";
29
29
  export { measureLoudness, gainForTarget, MASTERING_TARGETS } from "./game-sound/loudness.js";
30
30
  export { VoicePool } from "./game-sound/Voice.js";
31
31
  export { syncListener } from "./game-sound/listenerSync.js";
32
+ export * from "./synth/index.js";
32
33
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/audio/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAclF,OAAO,EAAE,8BAA8B,EAAE,8BAA8B,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAepJ,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAYjK,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAG5D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,EAAE,UAAU,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAE/F,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,0BAA0B,EAC1B,mBAAmB,EACnB,yBAAyB,EACzB,gBAAgB,EACjB,MAAM,qBAAqB,CAAC;AAU7B,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAUxF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,+EAA+E;AAC/E,2EAA2E;AAC3E,OAAO,EAAE,qBAAqB,IAAI,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAG3F,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1F,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/audio/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAclF,OAAO,EAAE,8BAA8B,EAAE,8BAA8B,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAepJ,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAYjK,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAG5D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,EAAE,UAAU,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAE/F,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,0BAA0B,EAC1B,mBAAmB,EACnB,yBAAyB,EACzB,gBAAgB,EACjB,MAAM,qBAAqB,CAAC;AAU7B,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAUxF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,+EAA+E;AAC/E,2EAA2E;AAC3E,OAAO,EAAE,qBAAqB,IAAI,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAG3F,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1F,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,cAAc,SAAS,CAAC"}
@@ -0,0 +1,88 @@
1
+ import type { SynthCueBank } from "./SynthCueBank.js";
2
+ import type { SynthBus, SynthContext } from "./types.js";
3
+ /** One sprite sheet holding several separately recorded takes of the same sound. */
4
+ export interface SampleSpriteSpec {
5
+ /** Where the sheet lives. `preload()` fetches it; `prepare()` decodes it once the bank is unlocked. */
6
+ readonly url?: string;
7
+ /** Start offset, in seconds, of each take inside the sheet. */
8
+ readonly offsets: readonly number[];
9
+ /** Length of every take, in seconds. */
10
+ readonly duration: number;
11
+ /** Procedural buffer played whole (no slicing) until the sheet decodes, or if it never does. */
12
+ readonly fallback?: (context: SynthContext) => AudioBuffer;
13
+ }
14
+ export interface SampleSlicePlayParams {
15
+ /** Linear gain on this play. Default 1. */
16
+ readonly gain?: number;
17
+ /** Stereo pan in -1..1. Omit for no panner. */
18
+ readonly pan?: number;
19
+ /** Playback rate multiplier. Default 1. */
20
+ readonly rate?: number;
21
+ /** Low-pass cutoff in Hz. Omit for no filter. */
22
+ readonly lowpass?: number;
23
+ /** Low-pass resonance. Default 0.5. */
24
+ readonly q?: number;
25
+ /** Which bus to play on. Default `sfx`. */
26
+ readonly bus?: SynthBus;
27
+ /** Force a take (tests). Skips the no-repeat pick and does not change the remembered take. */
28
+ readonly take?: number;
29
+ }
30
+ export interface SampleSlicesOptions<K extends string = string> {
31
+ readonly sprites: Readonly<Record<K, SampleSpriteSpec>>;
32
+ /** Uniform draw in [0, 1) used to pick the next take. Default: a seeded LCG (never `Math.random`). */
33
+ readonly random?: () => number;
34
+ /** Fetch used by `preload()`. Default `globalThis.fetch`. */
35
+ readonly fetch?: (url: string) => Promise<{
36
+ readonly ok: boolean;
37
+ arrayBuffer(): Promise<ArrayBuffer>;
38
+ }>;
39
+ }
40
+ /**
41
+ * Plays slices of recorded sprite sheets on a `SynthCueBank`'s buses.
42
+ *
43
+ * Several takes of one sound are recorded back to back in a sheet. Each play picks a take that is never the same as
44
+ * the previous one, plays only that slice, and runs it through an optional low-pass, gain and stereo panner. The
45
+ * sheet is fetched early, decoded after the bank unlocks, and until then (or if it never loads) a procedural
46
+ * fallback buffer stands in. The sound content and the way a game maps contacts to gain, pan and filter stay in
47
+ * the game.
48
+ */
49
+ export declare class SampleSlices<K extends string = string> {
50
+ private readonly bank;
51
+ private readonly sprites;
52
+ private readonly random;
53
+ private readonly fetchImpl;
54
+ private readonly downloads;
55
+ private readonly buffers;
56
+ private readonly fallbacks;
57
+ private readonly previous;
58
+ private readonly voices;
59
+ constructor(bank: SynthCueBank, options: SampleSlicesOptions<K>);
60
+ /** Start downloading every sheet. Safe to call before the context exists and repeatedly. A failed download is remembered as absent. */
61
+ preload(): Promise<void>;
62
+ /**
63
+ * Build the fallback buffers and decode the downloaded sheets. Call after `bank.unlock()`. Resolves when decoding
64
+ * is finished; plays before that use the fallback.
65
+ */
66
+ prepare(): Promise<void>;
67
+ /**
68
+ * Build the procedural fallback buffers now. Needs the bank's graph to exist (call right after `bank.unlock()` starts:
69
+ * the graph is created synchronously). `prepare()` calls it too; calling it earlier lets the very first play sound.
70
+ */
71
+ buildFallbacks(): void;
72
+ /** Supply a decoded sheet directly (tests, offline rendering, assets decoded elsewhere). */
73
+ setBuffer(name: K, buffer: AudioBuffer): void;
74
+ /** True once the sheet for `name` is decoded. */
75
+ has(name: K): boolean;
76
+ /** The take played last for `name`, or -1. */
77
+ lastTake(name: K): number;
78
+ /**
79
+ * Play one slice. Returns the take index played (-1 for the whole fallback buffer), or `null` when nothing sounded
80
+ * (bank locked, muted, not running, or no buffer yet and no fallback).
81
+ */
82
+ play(name: K, params?: SampleSlicePlayParams): number | null;
83
+ /** Stop every slice that is still sounding. */
84
+ stopAll(): void;
85
+ }
86
+ /** Convenience factory: `createSampleSlices(bank, { sprites })`. */
87
+ export declare function createSampleSlices<K extends string>(bank: SynthCueBank, options: SampleSlicesOptions<K>): SampleSlices<K>;
88
+ //# sourceMappingURL=SampleSlices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SampleSlices.d.ts","sourceRoot":"","sources":["../../../../../packages/audio/src/synth/SampleSlices.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,185 @@
1
+ const defaultRandom = () => {
2
+ let state = 0x1badf00d;
3
+ return () => {
4
+ state = (Math.imul(state, 1664525) + 1013904223) >>> 0;
5
+ return state / 0x100000000;
6
+ };
7
+ };
8
+ /**
9
+ * Plays slices of recorded sprite sheets on a `SynthCueBank`'s buses.
10
+ *
11
+ * Several takes of one sound are recorded back to back in a sheet. Each play picks a take that is never the same as
12
+ * the previous one, plays only that slice, and runs it through an optional low-pass, gain and stereo panner. The
13
+ * sheet is fetched early, decoded after the bank unlocks, and until then (or if it never loads) a procedural
14
+ * fallback buffer stands in. The sound content and the way a game maps contacts to gain, pan and filter stay in
15
+ * the game.
16
+ */
17
+ export class SampleSlices {
18
+ bank;
19
+ sprites;
20
+ random;
21
+ fetchImpl;
22
+ downloads = new Map();
23
+ buffers = new Map();
24
+ fallbacks = new Map();
25
+ previous = new Map();
26
+ voices = new Set();
27
+ constructor(bank, options) {
28
+ this.bank = bank;
29
+ this.sprites = options.sprites;
30
+ this.random = options.random ?? defaultRandom();
31
+ this.fetchImpl = options.fetch ?? (typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : undefined);
32
+ }
33
+ /** Start downloading every sheet. Safe to call before the context exists and repeatedly. A failed download is remembered as absent. */
34
+ preload() {
35
+ const pending = [];
36
+ for (const [name, sprite] of Object.entries(this.sprites)) {
37
+ if (!sprite.url || this.downloads.has(name))
38
+ continue;
39
+ const fetchImpl = this.fetchImpl;
40
+ const download = fetchImpl
41
+ ? fetchImpl(sprite.url)
42
+ .then((response) => {
43
+ if (!response.ok)
44
+ throw new Error("Audio unavailable");
45
+ return response.arrayBuffer();
46
+ })
47
+ .catch(() => null)
48
+ : Promise.resolve(null);
49
+ this.downloads.set(name, download);
50
+ pending.push(download);
51
+ }
52
+ return Promise.all(pending).then(() => undefined);
53
+ }
54
+ /**
55
+ * Build the fallback buffers and decode the downloaded sheets. Call after `bank.unlock()`. Resolves when decoding
56
+ * is finished; plays before that use the fallback.
57
+ */
58
+ async prepare() {
59
+ const ctx = this.bank.context;
60
+ if (!ctx)
61
+ return;
62
+ this.preload();
63
+ this.buildFallbacks();
64
+ const decoder = ctx;
65
+ await Promise.all(Object.keys(this.sprites).map(async (name) => {
66
+ try {
67
+ const bytes = await this.downloads.get(name);
68
+ if (!bytes || typeof decoder.decodeAudioData !== "function")
69
+ return;
70
+ const buffer = await decoder.decodeAudioData(bytes);
71
+ if (buffer)
72
+ this.buffers.set(name, buffer);
73
+ }
74
+ catch {
75
+ // A sheet that will not decode keeps using its fallback.
76
+ }
77
+ }));
78
+ }
79
+ /**
80
+ * Build the procedural fallback buffers now. Needs the bank's graph to exist (call right after `bank.unlock()` starts:
81
+ * the graph is created synchronously). `prepare()` calls it too; calling it earlier lets the very first play sound.
82
+ */
83
+ buildFallbacks() {
84
+ const ctx = this.bank.context;
85
+ if (!ctx)
86
+ return;
87
+ for (const [name, sprite] of Object.entries(this.sprites)) {
88
+ if (sprite.fallback && !this.fallbacks.has(name))
89
+ this.fallbacks.set(name, sprite.fallback(ctx));
90
+ }
91
+ }
92
+ /** Supply a decoded sheet directly (tests, offline rendering, assets decoded elsewhere). */
93
+ setBuffer(name, buffer) {
94
+ this.buffers.set(name, buffer);
95
+ }
96
+ /** True once the sheet for `name` is decoded. */
97
+ has(name) {
98
+ return this.buffers.has(name);
99
+ }
100
+ /** The take played last for `name`, or -1. */
101
+ lastTake(name) {
102
+ return this.previous.get(name) ?? -1;
103
+ }
104
+ /**
105
+ * Play one slice. Returns the take index played (-1 for the whole fallback buffer), or `null` when nothing sounded
106
+ * (bank locked, muted, not running, or no buffer yet and no fallback).
107
+ */
108
+ play(name, params = {}) {
109
+ const sprite = this.sprites[name];
110
+ const ctx = this.bank.context;
111
+ const bus = params.bus === "music" ? this.bank.musicDestination : this.bank.sfxDestination;
112
+ if (!sprite || !ctx || !bus || this.bank.muted || !this.bank.running)
113
+ return null;
114
+ const decoded = this.buffers.get(name);
115
+ const buffer = decoded ?? this.fallbacks.get(name);
116
+ if (!buffer)
117
+ return null;
118
+ const source = ctx.createBufferSource();
119
+ source.buffer = buffer;
120
+ source.playbackRate.value = params.rate ?? 1;
121
+ const nodes = [];
122
+ let tail = source;
123
+ if (params.lowpass !== undefined) {
124
+ const filter = ctx.createBiquadFilter();
125
+ filter.type = "lowpass";
126
+ filter.Q.value = params.q ?? 0.5;
127
+ filter.frequency.value = params.lowpass;
128
+ tail = tail.connect(filter);
129
+ nodes.push(filter);
130
+ }
131
+ const gain = ctx.createGain();
132
+ gain.gain.value = params.gain ?? 1;
133
+ tail = tail.connect(gain);
134
+ nodes.push(gain);
135
+ const withPanner = params.pan !== undefined && typeof ctx.createStereoPanner === "function";
136
+ if (withPanner) {
137
+ const pan = ctx.createStereoPanner();
138
+ pan.pan.value = params.pan;
139
+ tail = tail.connect(pan);
140
+ nodes.push(pan);
141
+ }
142
+ tail.connect(bus);
143
+ const voice = { source, nodes };
144
+ this.voices.add(voice);
145
+ source.onended = () => {
146
+ this.voices.delete(voice);
147
+ source.disconnect();
148
+ for (const node of nodes)
149
+ node.disconnect();
150
+ };
151
+ if (decoded && sprite.offsets.length > 0) {
152
+ const takes = sprite.offsets.length;
153
+ let index;
154
+ if (params.take !== undefined) {
155
+ index = ((params.take % takes) + takes) % takes;
156
+ }
157
+ else {
158
+ // Never repeat the previous take: step 1..takes-1 forward from it.
159
+ const previous = this.previous.get(name) ?? -1;
160
+ index = (previous + 1 + Math.floor(this.random() * Math.max(1, takes - 1))) % takes;
161
+ this.previous.set(name, index);
162
+ }
163
+ source.start(ctx.currentTime, sprite.offsets[index], sprite.duration);
164
+ return index;
165
+ }
166
+ source.start(ctx.currentTime);
167
+ return -1;
168
+ }
169
+ /** Stop every slice that is still sounding. */
170
+ stopAll() {
171
+ for (const voice of this.voices) {
172
+ try {
173
+ voice.source.stop();
174
+ }
175
+ catch {
176
+ // Already ended.
177
+ }
178
+ }
179
+ }
180
+ }
181
+ /** Convenience factory: `createSampleSlices(bank, { sprites })`. */
182
+ export function createSampleSlices(bank, options) {
183
+ return new SampleSlices(bank, options);
184
+ }
185
+ //# sourceMappingURL=SampleSlices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SampleSlices.js","sourceRoot":"","sources":["../../../../../packages/audio/src/synth/SampleSlices.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ import { AudioContextManager } from "../AudioContextManager.js";
2
+ import type { CuePlayParams, CueSpec, SynthContext, SynthVoice } from "./types.js";
3
+ export interface SynthCueBankOptions<K extends string = string> {
4
+ readonly cues: Readonly<Record<K, CueSpec>>;
5
+ /** The single `AudioContextManager` that owns the page's context. Default: a new manager (the kit never constructs a context itself). */
6
+ readonly manager?: AudioContextManager;
7
+ /** Inject a context directly (tests, offline rendering). */
8
+ readonly context?: SynthContext;
9
+ /** Master level when not muted. Default 0.9. */
10
+ readonly masterGain?: number;
11
+ readonly sfxGain?: number;
12
+ /** Music bus level before `setMusicLevel` is called. Default 0.0001 (silent). */
13
+ readonly musicGain?: number;
14
+ readonly muted?: boolean;
15
+ /** `KeyboardEvent.code` that toggles mute when `install()` is used. `false` disables. Default `"KeyM"`. */
16
+ readonly muteKey?: string | false;
17
+ /** Layers that may sound at once. Cues with `priority > 0` may use 1.5x. Default 24. */
18
+ readonly maxVoices?: number;
19
+ /** Noise generator seed (an LCG: `Math.random` is never used). */
20
+ readonly noiseSeed?: number;
21
+ /** Millisecond clock for cooldowns. Default `performance.now`/`Date.now`. */
22
+ readonly now?: () => number;
23
+ }
24
+ export interface InstallOptions {
25
+ /** Events that count as the first user gesture. Default pointerdown, keydown, touchstart. */
26
+ readonly unlockEvents?: readonly string[];
27
+ /** Called after every mute toggle made by the key binding. */
28
+ readonly onMuteChange?: (muted: boolean) => void;
29
+ }
30
+ interface EventTargetLike {
31
+ addEventListener(type: string, listener: (event: any) => void, options?: unknown): void;
32
+ removeEventListener(type: string, listener: (event: any) => void, options?: unknown): void;
33
+ }
34
+ /**
35
+ * A bank of procedurally synthesised sound cues on top of the page's one `AudioContextManager`.
36
+ *
37
+ * Nothing is sampled and no asset is loaded: a cue is a list of oscillator and filtered-noise layers with exponential
38
+ * envelopes and pitch glides. The bank adds what every game ended up hand-rolling: unlock on the first user gesture,
39
+ * a master mute (with a key binding), SFX and music buses, a voice budget with priorities, per-cue cooldown and
40
+ * concurrency limits, and music ducking.
41
+ */
42
+ export declare class SynthCueBank<K extends string = string> {
43
+ readonly manager: AudioContextManager;
44
+ private readonly injected;
45
+ private readonly cues;
46
+ private readonly masterLevel;
47
+ private readonly maxVoices;
48
+ private readonly muteKey;
49
+ private readonly now;
50
+ private readonly noise;
51
+ private ctx;
52
+ private master;
53
+ private sfxBus;
54
+ private musicBus;
55
+ private noiseBuffer;
56
+ private musicLevel;
57
+ private mutedValue;
58
+ private readonly sfxLevel;
59
+ private readonly voiceEnds;
60
+ private readonly cueEnds;
61
+ private readonly lastPlayed;
62
+ private readonly disposers;
63
+ constructor(options: SynthCueBankOptions<K>);
64
+ get muted(): boolean;
65
+ /** True once the context exists and is running. */
66
+ get running(): boolean;
67
+ /** The audio graph's context after `unlock()`, else null. */
68
+ get context(): SynthContext | null;
69
+ /** The music bus: connect a sequencer or loop here (the helpers in this kit do it for you). */
70
+ get musicDestination(): GainNode | null;
71
+ get sfxDestination(): GainNode | null;
72
+ /** Create the graph and resume the context. Call from a user gesture; safe to call repeatedly. */
73
+ unlock(): Promise<boolean>;
74
+ /**
75
+ * Wire the first-gesture unlock and the mute key onto `target` (default `globalThis`). Returns a function that
76
+ * removes every listener. Repeated mute key presses (`event.repeat`), modified presses and presses inside form
77
+ * fields are ignored.
78
+ */
79
+ install(target?: EventTargetLike, options?: InstallOptions): () => void;
80
+ setMuted(muted: boolean): void;
81
+ toggleMute(): boolean;
82
+ /** Music bus level (0..1) with a smooth transition. Remembered across `duck()`. */
83
+ setMusicLevel(level: number, timeConstant?: number): void;
84
+ /** Dip the music bus by `amount` (0..1) for `ms`, then recover. */
85
+ duck(amount?: number, ms?: number): void;
86
+ /** Trigger a cue. Returns true when it actually sounded (false when locked, muted, cooling down or over budget). */
87
+ play(name: K, params?: CuePlayParams): boolean;
88
+ /** Schedule one oscillator voice at an absolute time (used by sequencers). */
89
+ voice(voice: SynthVoice): void;
90
+ dispose(): void;
91
+ /** Lazily built looping noise buffer shared by noise layers and `createToneLoop`. */
92
+ getNoiseBuffer(): AudioBuffer | null;
93
+ private busNode;
94
+ private prune;
95
+ private tone;
96
+ private noiseHit;
97
+ private chain;
98
+ }
99
+ /** Convenience factory: `createCueBank({ cues })`. */
100
+ export declare function createCueBank<K extends string>(options: SynthCueBankOptions<K>): SynthCueBank<K>;
101
+ export {};
102
+ //# sourceMappingURL=SynthCueBank.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SynthCueBank.d.ts","sourceRoot":"","sources":["../../../../../packages/audio/src/synth/SynthCueBank.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,323 @@
1
+ import { AudioContextManager } from "../AudioContextManager.js";
2
+ import { createNoiseSource } from "./notes.js";
3
+ const isNoise = (layer) => layer.kind === "noise";
4
+ const MIN_GAIN = 0.0001;
5
+ /**
6
+ * A bank of procedurally synthesised sound cues on top of the page's one `AudioContextManager`.
7
+ *
8
+ * Nothing is sampled and no asset is loaded: a cue is a list of oscillator and filtered-noise layers with exponential
9
+ * envelopes and pitch glides. The bank adds what every game ended up hand-rolling: unlock on the first user gesture,
10
+ * a master mute (with a key binding), SFX and music buses, a voice budget with priorities, per-cue cooldown and
11
+ * concurrency limits, and music ducking.
12
+ */
13
+ export class SynthCueBank {
14
+ manager;
15
+ injected;
16
+ cues;
17
+ masterLevel;
18
+ maxVoices;
19
+ muteKey;
20
+ now;
21
+ noise;
22
+ ctx = null;
23
+ master = null;
24
+ sfxBus = null;
25
+ musicBus = null;
26
+ noiseBuffer = null;
27
+ musicLevel;
28
+ mutedValue;
29
+ sfxLevel;
30
+ voiceEnds = [];
31
+ cueEnds = new Map();
32
+ lastPlayed = new Map();
33
+ disposers = [];
34
+ constructor(options) {
35
+ this.injected = options.context;
36
+ this.manager = options.manager ?? new AudioContextManager(options.context ? { context: options.context } : {});
37
+ this.cues = options.cues;
38
+ this.masterLevel = options.masterGain ?? 0.9;
39
+ this.sfxLevel = options.sfxGain ?? 0.9;
40
+ this.musicLevel = options.musicGain ?? MIN_GAIN;
41
+ this.maxVoices = options.maxVoices ?? 24;
42
+ this.muteKey = options.muteKey === undefined ? "KeyM" : options.muteKey;
43
+ this.mutedValue = options.muted ?? false;
44
+ this.now = options.now ?? (() => (typeof performance !== "undefined" ? performance.now() : Date.now()));
45
+ this.noise = createNoiseSource(options.noiseSeed);
46
+ }
47
+ get muted() {
48
+ return this.mutedValue;
49
+ }
50
+ /** True once the context exists and is running. */
51
+ get running() {
52
+ return this.ctx !== null && this.ctx.state === "running";
53
+ }
54
+ /** The audio graph's context after `unlock()`, else null. */
55
+ get context() {
56
+ return this.ctx;
57
+ }
58
+ /** The music bus: connect a sequencer or loop here (the helpers in this kit do it for you). */
59
+ get musicDestination() {
60
+ return this.musicBus;
61
+ }
62
+ get sfxDestination() {
63
+ return this.sfxBus;
64
+ }
65
+ /** Create the graph and resume the context. Call from a user gesture; safe to call repeatedly. */
66
+ async unlock() {
67
+ try {
68
+ if (!this.ctx) {
69
+ const ctx = (this.injected ?? this.manager.context);
70
+ const master = ctx.createGain();
71
+ master.gain.value = this.mutedValue ? 0 : this.masterLevel;
72
+ master.connect(ctx.destination);
73
+ const music = ctx.createGain();
74
+ music.gain.value = Math.max(MIN_GAIN, this.musicLevel);
75
+ music.connect(master);
76
+ const sfx = ctx.createGain();
77
+ sfx.gain.value = this.sfxLevel;
78
+ sfx.connect(master);
79
+ this.ctx = ctx;
80
+ this.master = master;
81
+ this.musicBus = music;
82
+ this.sfxBus = sfx;
83
+ }
84
+ await this.manager.unlock();
85
+ return true;
86
+ }
87
+ catch {
88
+ this.ctx = null;
89
+ this.master = null;
90
+ this.musicBus = null;
91
+ this.sfxBus = null;
92
+ return false;
93
+ }
94
+ }
95
+ /**
96
+ * Wire the first-gesture unlock and the mute key onto `target` (default `globalThis`). Returns a function that
97
+ * removes every listener. Repeated mute key presses (`event.repeat`), modified presses and presses inside form
98
+ * fields are ignored.
99
+ */
100
+ install(target, options = {}) {
101
+ const host = target ?? (globalThis.addEventListener ? globalThis : undefined);
102
+ if (!host)
103
+ return () => undefined;
104
+ const events = options.unlockEvents ?? ["pointerdown", "keydown", "touchstart"];
105
+ const unlockOnce = () => {
106
+ void this.unlock();
107
+ };
108
+ for (const type of events)
109
+ host.addEventListener(type, unlockOnce, { passive: true });
110
+ const onKey = (event) => {
111
+ if (this.muteKey === false || event.code !== this.muteKey || event.repeat)
112
+ return;
113
+ if (event.ctrlKey || event.metaKey || event.altKey)
114
+ return;
115
+ const tag = event.target?.tagName?.toUpperCase();
116
+ if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT")
117
+ return;
118
+ // Toggle first: `options.onMuteChange?.(this.toggleMute())` would skip the toggle when no callback is given.
119
+ const muted = this.toggleMute();
120
+ options.onMuteChange?.(muted);
121
+ };
122
+ if (this.muteKey !== false)
123
+ host.addEventListener("keydown", onKey);
124
+ const remove = () => {
125
+ for (const type of events)
126
+ host.removeEventListener(type, unlockOnce);
127
+ host.removeEventListener("keydown", onKey);
128
+ };
129
+ this.disposers.push(remove);
130
+ return remove;
131
+ }
132
+ setMuted(muted) {
133
+ this.mutedValue = muted;
134
+ if (this.master && this.ctx)
135
+ this.master.gain.setTargetAtTime(muted ? 0 : this.masterLevel, this.ctx.currentTime, 0.05);
136
+ }
137
+ toggleMute() {
138
+ this.setMuted(!this.mutedValue);
139
+ return this.mutedValue;
140
+ }
141
+ /** Music bus level (0..1) with a smooth transition. Remembered across `duck()`. */
142
+ setMusicLevel(level, timeConstant = 0.4) {
143
+ this.musicLevel = Math.max(MIN_GAIN, level);
144
+ if (this.musicBus && this.ctx)
145
+ this.musicBus.gain.setTargetAtTime(this.musicLevel, this.ctx.currentTime, timeConstant);
146
+ }
147
+ /** Dip the music bus by `amount` (0..1) for `ms`, then recover. */
148
+ duck(amount = 0.5, ms = 300) {
149
+ if (!this.musicBus || !this.ctx)
150
+ return;
151
+ const t = this.ctx.currentTime;
152
+ const dipped = Math.max(MIN_GAIN, this.musicLevel * (1 - Math.min(1, Math.max(0, amount))));
153
+ this.musicBus.gain.setTargetAtTime(dipped, t, 0.03);
154
+ this.musicBus.gain.setTargetAtTime(this.musicLevel, t + ms / 1000, 0.25);
155
+ }
156
+ /** Trigger a cue. Returns true when it actually sounded (false when locked, muted, cooling down or over budget). */
157
+ play(name, params = {}) {
158
+ const spec = this.cues[name];
159
+ const ctx = this.ctx;
160
+ if (!spec || !ctx || !this.sfxBus || this.mutedValue || ctx.state !== "running")
161
+ return false;
162
+ const nowMs = this.now();
163
+ if (spec.cooldownMs !== undefined) {
164
+ const last = this.lastPlayed.get(name);
165
+ if (last !== undefined && nowMs - last < spec.cooldownMs)
166
+ return false;
167
+ }
168
+ const t0 = ctx.currentTime;
169
+ this.prune(t0);
170
+ const priority = spec.priority ?? 0;
171
+ const limit = priority > 0 ? Math.floor(this.maxVoices * 1.5) : this.maxVoices;
172
+ if (this.voiceEnds.length >= limit)
173
+ return false;
174
+ const mine = this.cueEnds.get(name) ?? [];
175
+ if (spec.maxConcurrent !== undefined && mine.length >= spec.maxConcurrent)
176
+ return false;
177
+ const resolved = { level: 0, ...params };
178
+ const layers = typeof spec.layers === "function" ? spec.layers(resolved) : spec.layers;
179
+ const pitch = params.pitch ?? 1;
180
+ const gain = params.gain ?? 1;
181
+ let end = t0;
182
+ for (const layer of layers) {
183
+ const finishes = isNoise(layer) ? this.noiseHit(layer, t0, gain) : this.tone(layer, t0, pitch, gain);
184
+ if (finishes > end)
185
+ end = finishes;
186
+ this.voiceEnds.push(finishes);
187
+ }
188
+ mine.push(end);
189
+ this.cueEnds.set(name, mine);
190
+ this.lastPlayed.set(name, nowMs);
191
+ if (spec.duckMusic !== undefined) {
192
+ if (typeof spec.duckMusic === "number")
193
+ this.duck(spec.duckMusic, 300);
194
+ else
195
+ this.duck(spec.duckMusic.amount, spec.duckMusic.ms);
196
+ }
197
+ return true;
198
+ }
199
+ /** Schedule one oscillator voice at an absolute time (used by sequencers). */
200
+ voice(voice) {
201
+ const ctx = this.ctx;
202
+ const bus = voice.bus === "sfx" ? this.sfxBus : this.musicBus;
203
+ if (!ctx || !bus)
204
+ return;
205
+ const osc = ctx.createOscillator();
206
+ const g = ctx.createGain();
207
+ osc.type = voice.type ?? "sine";
208
+ osc.frequency.value = voice.freq;
209
+ const attack = voice.attack ?? 0.02;
210
+ g.gain.setValueAtTime(MIN_GAIN, voice.at);
211
+ g.gain.exponentialRampToValueAtTime(Math.max(MIN_GAIN, voice.gain), voice.at + attack);
212
+ g.gain.exponentialRampToValueAtTime(MIN_GAIN, voice.at + Math.max(attack + 0.001, voice.dur));
213
+ this.chain(osc, g, bus, voice.filter, voice.at, voice.dur);
214
+ osc.start(voice.at);
215
+ osc.stop(voice.at + voice.dur + 0.05);
216
+ }
217
+ dispose() {
218
+ for (const remove of this.disposers.splice(0))
219
+ remove();
220
+ this.voiceEnds.length = 0;
221
+ this.cueEnds.clear();
222
+ void this.manager.dispose();
223
+ this.ctx = null;
224
+ this.master = null;
225
+ this.musicBus = null;
226
+ this.sfxBus = null;
227
+ }
228
+ /** Lazily built looping noise buffer shared by noise layers and `createToneLoop`. */
229
+ getNoiseBuffer() {
230
+ const ctx = this.ctx;
231
+ if (!ctx)
232
+ return null;
233
+ if (!this.noiseBuffer) {
234
+ const length = Math.floor(0.4 * ctx.sampleRate);
235
+ const buffer = ctx.createBuffer(1, length, ctx.sampleRate);
236
+ const data = buffer.getChannelData(0);
237
+ for (let i = 0; i < length; i++)
238
+ data[i] = this.noise();
239
+ this.noiseBuffer = buffer;
240
+ }
241
+ return this.noiseBuffer;
242
+ }
243
+ busNode(bus) {
244
+ return (bus === "music" ? this.musicBus : this.sfxBus);
245
+ }
246
+ prune(now) {
247
+ for (let i = this.voiceEnds.length - 1; i >= 0; i--)
248
+ if (this.voiceEnds[i] <= now)
249
+ this.voiceEnds.splice(i, 1);
250
+ for (const [name, ends] of this.cueEnds) {
251
+ const live = ends.filter((end) => end > now);
252
+ if (live.length > 0)
253
+ this.cueEnds.set(name, live);
254
+ else
255
+ this.cueEnds.delete(name);
256
+ }
257
+ }
258
+ tone(layer, t0, pitch, gainScale) {
259
+ const ctx = this.ctx;
260
+ const { freq, type = "sine", dur = 0.15, gain = 0.2, slideTo, delay = 0, attack = 0.008, detune } = layer;
261
+ const at = t0 + delay;
262
+ const osc = ctx.createOscillator();
263
+ const g = ctx.createGain();
264
+ osc.type = type;
265
+ osc.frequency.setValueAtTime(freq * pitch, at);
266
+ if (slideTo)
267
+ osc.frequency.exponentialRampToValueAtTime(Math.max(20, slideTo * pitch), at + dur);
268
+ if (detune !== undefined)
269
+ osc.detune.value = detune;
270
+ g.gain.setValueAtTime(MIN_GAIN, at);
271
+ g.gain.exponentialRampToValueAtTime(Math.max(MIN_GAIN, gain * gainScale), at + attack);
272
+ g.gain.exponentialRampToValueAtTime(MIN_GAIN, at + dur);
273
+ this.chain(osc, g, this.busNode(layer.bus), layer.filter, at, dur);
274
+ osc.start(at);
275
+ osc.stop(at + dur + 0.03);
276
+ return at + dur + 0.03;
277
+ }
278
+ noiseHit(layer, t0, gainScale) {
279
+ const ctx = this.ctx;
280
+ const { dur = 0.2, gain = 0.15, freq = 1200, q = 1, type = "bandpass", slideTo, delay = 0 } = layer;
281
+ const at = t0 + delay;
282
+ const src = ctx.createBufferSource();
283
+ src.buffer = this.getNoiseBuffer();
284
+ const filter = ctx.createBiquadFilter();
285
+ filter.type = type;
286
+ filter.frequency.setValueAtTime(freq, at);
287
+ filter.Q.value = q;
288
+ if (slideTo)
289
+ filter.frequency.exponentialRampToValueAtTime(Math.max(40, slideTo), at + dur);
290
+ const g = ctx.createGain();
291
+ g.gain.setValueAtTime(Math.max(MIN_GAIN, gain * gainScale), at);
292
+ g.gain.exponentialRampToValueAtTime(MIN_GAIN, at + dur);
293
+ src.connect(filter);
294
+ filter.connect(g);
295
+ g.connect(this.busNode(layer.bus));
296
+ src.start(at);
297
+ src.stop(at + dur + 0.02);
298
+ return at + dur + 0.02;
299
+ }
300
+ chain(osc, g, bus, filter, at, dur) {
301
+ const ctx = this.ctx;
302
+ if (!filter) {
303
+ osc.connect(g);
304
+ g.connect(bus);
305
+ return;
306
+ }
307
+ const f = ctx.createBiquadFilter();
308
+ f.type = filter.type;
309
+ f.frequency.setValueAtTime(filter.freq, at);
310
+ if (filter.q !== undefined)
311
+ f.Q.value = filter.q;
312
+ if (filter.slideTo)
313
+ f.frequency.exponentialRampToValueAtTime(Math.max(40, filter.slideTo), at + dur);
314
+ osc.connect(f);
315
+ f.connect(g);
316
+ g.connect(bus);
317
+ }
318
+ }
319
+ /** Convenience factory: `createCueBank({ cues })`. */
320
+ export function createCueBank(options) {
321
+ return new SynthCueBank(options);
322
+ }
323
+ //# sourceMappingURL=SynthCueBank.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SynthCueBank.js","sourceRoot":"","sources":["../../../../../packages/audio/src/synth/SynthCueBank.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import type { SynthCueBank } from "./SynthCueBank.js";
2
+ import type { SynthFilter, SynthVoice } from "./types.js";
3
+ /** Scheduler seam so tests can drive time without real timers. */
4
+ export interface SynthScheduler {
5
+ setInterval(handler: () => void, ms: number): unknown;
6
+ clearInterval(handle: unknown): void;
7
+ }
8
+ export interface StepSequencerOptions {
9
+ readonly bpm: number;
10
+ /** Steps per beat (2 = eighth notes). Default 2. */
11
+ readonly stepsPerBeat?: number;
12
+ /** Seconds scheduled ahead of the clock. Default 0.2. */
13
+ readonly lookahead?: number;
14
+ /** Timer period in ms. Default 40. */
15
+ readonly tickMs?: number;
16
+ readonly scheduler?: SynthScheduler;
17
+ /**
18
+ * Called once per step with the step index, its absolute start time and the step length in seconds.
19
+ * Schedule notes with `voice(...)` (they go to the music bus unless `bus: "sfx"`).
20
+ */
21
+ readonly step: (index: number, at: number, stepSeconds: number, voice: (v: Omit<SynthVoice, "at"> & {
22
+ at?: number;
23
+ }) => void) => void;
24
+ }
25
+ export interface StepSequencer {
26
+ start(): void;
27
+ stop(): void;
28
+ setBpm(bpm: number): void;
29
+ /** Schedule everything due within the lookahead window now (the timer calls this; tests call it directly). */
30
+ pump(): void;
31
+ readonly playing: boolean;
32
+ readonly stepIndex: number;
33
+ }
34
+ /** A lookahead music scheduler on the bank's music bus: one callback per step, sample-accurate start times. */
35
+ export declare function createStepSequencer(bank: SynthCueBank<string>, options: StepSequencerOptions): StepSequencer;
36
+ export interface ToneLoopVoice {
37
+ readonly type?: OscillatorType;
38
+ readonly freq: number;
39
+ /** Cents. */
40
+ readonly detune?: number;
41
+ readonly gain?: number;
42
+ }
43
+ export interface ToneLoopOptions {
44
+ /** Oscillators that run continuously (detune a few for a thicker engine or pad). */
45
+ readonly voices?: readonly ToneLoopVoice[];
46
+ /** Looping filtered noise (wind, surf, tyre hiss). */
47
+ readonly noise?: {
48
+ readonly gain: number;
49
+ readonly filter?: SynthFilter;
50
+ };
51
+ /** Low-pass (or other) filter on the tonal voices. */
52
+ readonly filter?: SynthFilter;
53
+ /** Loop level before `set`. Default 0 (silent until driven). */
54
+ readonly gain?: number;
55
+ /** Which bank bus the loop plays on. Default "sfx". */
56
+ readonly bus?: "sfx" | "music";
57
+ }
58
+ export interface ToneLoopParams {
59
+ /** Multiplies every voice's pitch (an engine's rev). */
60
+ readonly pitch?: number;
61
+ /** Tonal filter cutoff in Hz. */
62
+ readonly cutoff?: number;
63
+ /** Overall loop level. */
64
+ readonly gain?: number;
65
+ /** Noise level. */
66
+ readonly noiseGain?: number;
67
+ }
68
+ export interface ToneLoop {
69
+ start(): void;
70
+ stop(): void;
71
+ /** Smoothly move the loop toward new parameters (call every frame; cheap). */
72
+ set(params: ToneLoopParams, timeConstant?: number): void;
73
+ readonly running: boolean;
74
+ }
75
+ /** A continuous, parameter-driven bed: an engine drone, a wind layer, a quiet pad. */
76
+ export declare function createToneLoop(bank: SynthCueBank<string>, options?: ToneLoopOptions): ToneLoop;
77
+ //# sourceMappingURL=SynthLoops.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SynthLoops.d.ts","sourceRoot":"","sources":["../../../../../packages/audio/src/synth/SynthLoops.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ const realScheduler = {
2
+ setInterval: (handler, ms) => setInterval(handler, ms),
3
+ clearInterval: (handle) => clearInterval(handle)
4
+ };
5
+ /** A lookahead music scheduler on the bank's music bus: one callback per step, sample-accurate start times. */
6
+ export function createStepSequencer(bank, options) {
7
+ const scheduler = options.scheduler ?? realScheduler;
8
+ const lookahead = options.lookahead ?? 0.2;
9
+ let bpm = options.bpm;
10
+ let timer = null;
11
+ let index = 0;
12
+ let nextAt = 0;
13
+ const stepSeconds = () => 60 / bpm / (options.stepsPerBeat ?? 2);
14
+ const pump = () => {
15
+ const ctx = bank.context;
16
+ if (!ctx)
17
+ return;
18
+ while (nextAt < ctx.currentTime + lookahead) {
19
+ const at = nextAt;
20
+ options.step(index, at, stepSeconds(), (v) => bank.voice({ ...v, at: v.at ?? at }));
21
+ nextAt += stepSeconds();
22
+ index++;
23
+ }
24
+ };
25
+ return {
26
+ start() {
27
+ const ctx = bank.context;
28
+ if (!ctx || timer !== null)
29
+ return;
30
+ index = 0;
31
+ nextAt = ctx.currentTime + 0.1;
32
+ timer = scheduler.setInterval(pump, options.tickMs ?? 40);
33
+ },
34
+ stop() {
35
+ if (timer !== null)
36
+ scheduler.clearInterval(timer);
37
+ timer = null;
38
+ },
39
+ setBpm(next) {
40
+ bpm = Math.max(1, next);
41
+ },
42
+ pump,
43
+ get playing() {
44
+ return timer !== null;
45
+ },
46
+ get stepIndex() {
47
+ return index;
48
+ }
49
+ };
50
+ }
51
+ /** A continuous, parameter-driven bed: an engine drone, a wind layer, a quiet pad. */
52
+ export function createToneLoop(bank, options = {}) {
53
+ const voices = options.voices ?? [];
54
+ let oscillators = [];
55
+ let noiseSource = null;
56
+ let noiseGain = null;
57
+ let filter = null;
58
+ let out = null;
59
+ let running = false;
60
+ return {
61
+ get running() {
62
+ return running;
63
+ },
64
+ start() {
65
+ const ctx = bank.context;
66
+ const bus = options.bus === "music" ? bank.musicDestination : bank.sfxDestination;
67
+ if (!ctx || !bus || running)
68
+ return;
69
+ out = ctx.createGain();
70
+ out.gain.value = Math.max(0.0001, options.gain ?? 0);
71
+ out.connect(bus);
72
+ if (voices.length > 0) {
73
+ const tonalOut = ctx.createGain();
74
+ filter = ctx.createBiquadFilter();
75
+ const f = options.filter ?? { type: "lowpass", freq: 2000 };
76
+ filter.type = f.type;
77
+ filter.frequency.value = f.freq;
78
+ if (f.q !== undefined)
79
+ filter.Q.value = f.q;
80
+ filter.connect(tonalOut);
81
+ tonalOut.connect(out);
82
+ oscillators = voices.map((v) => {
83
+ const osc = ctx.createOscillator();
84
+ osc.type = v.type ?? "sawtooth";
85
+ osc.frequency.value = v.freq;
86
+ if (v.detune !== undefined)
87
+ osc.detune.value = v.detune;
88
+ const g = ctx.createGain();
89
+ g.gain.value = v.gain ?? 0.3;
90
+ osc.connect(g);
91
+ g.connect(filter);
92
+ osc.start();
93
+ return { osc, base: v.freq };
94
+ });
95
+ }
96
+ if (options.noise) {
97
+ const buffer = bank.getNoiseBuffer();
98
+ if (buffer) {
99
+ noiseSource = ctx.createBufferSource();
100
+ noiseSource.buffer = buffer;
101
+ noiseSource.loop = true;
102
+ const nf = ctx.createBiquadFilter();
103
+ nf.type = options.noise.filter?.type ?? "bandpass";
104
+ nf.frequency.value = options.noise.filter?.freq ?? 800;
105
+ if (options.noise.filter?.q !== undefined)
106
+ nf.Q.value = options.noise.filter.q;
107
+ noiseGain = ctx.createGain();
108
+ noiseGain.gain.value = Math.max(0.0001, options.noise.gain);
109
+ noiseSource.connect(nf);
110
+ nf.connect(noiseGain);
111
+ noiseGain.connect(out);
112
+ noiseSource.start();
113
+ }
114
+ }
115
+ running = true;
116
+ },
117
+ stop() {
118
+ if (!running)
119
+ return;
120
+ for (const { osc } of oscillators)
121
+ osc.stop();
122
+ noiseSource?.stop();
123
+ oscillators = [];
124
+ noiseSource = null;
125
+ noiseGain = null;
126
+ filter = null;
127
+ out = null;
128
+ running = false;
129
+ },
130
+ set(params, timeConstant = 0.08) {
131
+ const ctx = bank.context;
132
+ if (!ctx || !running)
133
+ return;
134
+ const t = ctx.currentTime;
135
+ if (params.pitch !== undefined)
136
+ for (const { osc, base } of oscillators)
137
+ osc.frequency.setTargetAtTime(base * params.pitch, t, timeConstant);
138
+ if (params.cutoff !== undefined && filter)
139
+ filter.frequency.setTargetAtTime(params.cutoff, t, timeConstant);
140
+ if (params.gain !== undefined && out)
141
+ out.gain.setTargetAtTime(Math.max(0.0001, params.gain), t, timeConstant);
142
+ if (params.noiseGain !== undefined && noiseGain)
143
+ noiseGain.gain.setTargetAtTime(Math.max(0.0001, params.noiseGain), t, timeConstant);
144
+ }
145
+ };
146
+ }
147
+ //# sourceMappingURL=SynthLoops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SynthLoops.js","sourceRoot":"","sources":["../../../../../packages/audio/src/synth/SynthLoops.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export { SynthCueBank, createCueBank } from "./SynthCueBank.js";
2
+ export type { InstallOptions, SynthCueBankOptions } from "./SynthCueBank.js";
3
+ export { SampleSlices, createSampleSlices } from "./SampleSlices.js";
4
+ export type { SampleSlicePlayParams, SampleSlicesOptions, SampleSpriteSpec } from "./SampleSlices.js";
5
+ export { createStepSequencer, createToneLoop } from "./SynthLoops.js";
6
+ export type { StepSequencer, StepSequencerOptions, SynthScheduler, ToneLoop, ToneLoopOptions, ToneLoopParams, ToneLoopVoice } from "./SynthLoops.js";
7
+ export { SCALES, createNoiseSource, midiToHz, noteFrom, scaleSemitones, semitoneHz } from "./notes.js";
8
+ export type { CueLayer, CuePlayParams, CueSpec, NoiseLayer, SynthBus, SynthContext, SynthFilter, SynthVoice, ToneLayer } from "./types.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/audio/src/synth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,cAAc,EAAE,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClJ,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpG,YAAY,EACV,QAAQ,EACR,aAAa,EACb,OAAO,EACP,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,UAAU,EACV,SAAS,EACV,MAAM,SAAS,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { SynthCueBank, createCueBank } from "./SynthCueBank.js";
2
+ export { SampleSlices, createSampleSlices } from "./SampleSlices.js";
3
+ export { createStepSequencer, createToneLoop } from "./SynthLoops.js";
4
+ export { SCALES, createNoiseSource, midiToHz, noteFrom, scaleSemitones, semitoneHz } from "./notes.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/audio/src/synth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnE,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,18 @@
1
+ /** Hz of a MIDI note number (69 = A4 = 440 Hz). */
2
+ export declare function midiToHz(midi: number): number;
3
+ /** Hz of a note `semitones` above (or below) `baseHz`. */
4
+ export declare function semitoneHz(baseHz: number, semitones: number): number;
5
+ /** Builds `(semitones) => Hz` rooted at `baseHz`, e.g. `const note = noteFrom(523.25)`. */
6
+ export declare function noteFrom(baseHz: number): (semitones: number) => number;
7
+ /** Semitone offsets of common scales, handy for pitch ladders that climb with a combo. */
8
+ export declare const SCALES: {
9
+ readonly major: readonly [0, 2, 4, 5, 7, 9, 11];
10
+ readonly minor: readonly [0, 2, 3, 5, 7, 8, 10];
11
+ readonly pentatonic: readonly [0, 2, 4, 7, 9];
12
+ readonly minorPentatonic: readonly [0, 3, 5, 7, 10];
13
+ };
14
+ /** Semitones for scale degree `degree` (may exceed the scale length: it wraps up by octaves, negative wraps down). */
15
+ export declare function scaleSemitones(scale: readonly number[], degree: number): number;
16
+ /** Linear congruential generator in [-1, 1): deterministic noise that never touches `Math.random`. */
17
+ export declare function createNoiseSource(seed?: number): () => number;
18
+ //# sourceMappingURL=notes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notes.d.ts","sourceRoot":"","sources":["../../../../../packages/audio/src/synth/notes.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,0DAA0D;AAC1D,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,2FAA2F;AAC3F,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAEtE;AAED,0FAA0F;AAC1F,eAAO,MAAM,MAAM;;;;;CAKT,CAAC;AAEX,sHAAsH;AACtH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAK/E;AAED,sGAAsG;AACtG,wBAAgB,iBAAiB,CAAC,IAAI,SAAY,GAAG,MAAM,MAAM,CAMhE"}
@@ -0,0 +1,35 @@
1
+ /** Hz of a MIDI note number (69 = A4 = 440 Hz). */
2
+ export function midiToHz(midi) {
3
+ return 440 * Math.pow(2, (midi - 69) / 12);
4
+ }
5
+ /** Hz of a note `semitones` above (or below) `baseHz`. */
6
+ export function semitoneHz(baseHz, semitones) {
7
+ return baseHz * Math.pow(2, semitones / 12);
8
+ }
9
+ /** Builds `(semitones) => Hz` rooted at `baseHz`, e.g. `const note = noteFrom(523.25)`. */
10
+ export function noteFrom(baseHz) {
11
+ return (semitones) => semitoneHz(baseHz, semitones);
12
+ }
13
+ /** Semitone offsets of common scales, handy for pitch ladders that climb with a combo. */
14
+ export const SCALES = {
15
+ major: [0, 2, 4, 5, 7, 9, 11],
16
+ minor: [0, 2, 3, 5, 7, 8, 10],
17
+ pentatonic: [0, 2, 4, 7, 9],
18
+ minorPentatonic: [0, 3, 5, 7, 10]
19
+ };
20
+ /** Semitones for scale degree `degree` (may exceed the scale length: it wraps up by octaves, negative wraps down). */
21
+ export function scaleSemitones(scale, degree) {
22
+ const len = scale.length;
23
+ const octave = Math.floor(degree / len);
24
+ const index = ((degree % len) + len) % len;
25
+ return scale[index] + 12 * octave;
26
+ }
27
+ /** Linear congruential generator in [-1, 1): deterministic noise that never touches `Math.random`. */
28
+ export function createNoiseSource(seed = 0x2f6e2b1) {
29
+ let state = seed >>> 0;
30
+ return () => {
31
+ state = (Math.imul(state, 1664525) + 1013904223) >>> 0;
32
+ return state / 0x80000000 - 1;
33
+ };
34
+ }
35
+ //# sourceMappingURL=notes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notes.js","sourceRoot":"","sources":["../../../../../packages/audio/src/synth/notes.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,SAAiB;IAC1D,OAAO,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AACtD,CAAC;AAED,0FAA0F;AAC1F,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC7B,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC7B,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3B,eAAe,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;CACzB,CAAC;AAEX,sHAAsH;AACtH,MAAM,UAAU,cAAc,CAAC,KAAwB,EAAE,MAAc;IACrE,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;IACzB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;IAC3C,OAAQ,KAAK,CAAC,KAAK,CAAY,GAAG,EAAE,GAAG,MAAM,CAAC;AAChD,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,iBAAiB,CAAC,IAAI,GAAG,SAAS;IAChD,IAAI,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC;IACvB,OAAO,GAAG,EAAE;QACV,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QACvD,OAAO,KAAK,GAAG,UAAU,GAAG,CAAC,CAAC;IAChC,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,84 @@
1
+ import type { AudioContextLike } from "../AudioContextManager.js";
2
+ /** The slice of `BaseAudioContext` the synth kit drives. A real `AudioContext` and a test fake both satisfy it. */
3
+ export interface SynthContext extends AudioContextLike {
4
+ readonly sampleRate: number;
5
+ createOscillator(): OscillatorNode;
6
+ createBuffer(numberOfChannels: number, length: number, sampleRate: number): AudioBuffer;
7
+ }
8
+ export type SynthBus = "sfx" | "music";
9
+ export interface SynthFilter {
10
+ readonly type: BiquadFilterType;
11
+ readonly freq: number;
12
+ readonly q?: number;
13
+ /** Exponentially sweep the cutoff to this frequency over the layer's duration. */
14
+ readonly slideTo?: number;
15
+ }
16
+ export interface ToneLayer {
17
+ readonly kind?: "tone";
18
+ readonly freq: number;
19
+ readonly type?: OscillatorType;
20
+ /** Seconds. Default 0.15. */
21
+ readonly dur?: number;
22
+ /** Peak gain. Default 0.2. */
23
+ readonly gain?: number;
24
+ /** Exponentially glide the pitch to this frequency over `dur`. */
25
+ readonly slideTo?: number;
26
+ /** Seconds after the cue is triggered. */
27
+ readonly delay?: number;
28
+ /** Attack seconds. Default 0.008. */
29
+ readonly attack?: number;
30
+ /** Cents. */
31
+ readonly detune?: number;
32
+ readonly filter?: SynthFilter;
33
+ readonly bus?: SynthBus;
34
+ }
35
+ export interface NoiseLayer {
36
+ readonly kind: "noise";
37
+ readonly dur?: number;
38
+ readonly gain?: number;
39
+ /** Filter cutoff in Hz. Default 1200. */
40
+ readonly freq?: number;
41
+ readonly q?: number;
42
+ /** Default `bandpass`. */
43
+ readonly type?: BiquadFilterType;
44
+ readonly slideTo?: number;
45
+ readonly delay?: number;
46
+ readonly bus?: SynthBus;
47
+ }
48
+ export type CueLayer = ToneLayer | NoiseLayer;
49
+ export interface CuePlayParams {
50
+ /** Free-form intensity the cue's layer function can read (a combo count, a speed...). */
51
+ readonly level?: number;
52
+ /** Multiplies every layer's pitch. */
53
+ readonly pitch?: number;
54
+ /** Multiplies every layer's gain. */
55
+ readonly gain?: number;
56
+ /** Free-form payload a layer function can read (a frequency list, a contact record...). Not interpreted by the bank. */
57
+ readonly data?: unknown;
58
+ }
59
+ export interface CueSpec {
60
+ readonly layers: readonly CueLayer[] | ((params: Required<Pick<CuePlayParams, "level">> & CuePlayParams) => readonly CueLayer[]);
61
+ /** Higher wins when the voice budget is exhausted. Default 0. */
62
+ readonly priority?: number;
63
+ /** Ignore a repeat trigger that arrives sooner than this. */
64
+ readonly cooldownMs?: number;
65
+ /** Most simultaneous instances of this cue. */
66
+ readonly maxConcurrent?: number;
67
+ /** Dip the music bus while the cue sounds: a fraction (0..1) or `{ amount, ms }`. */
68
+ readonly duckMusic?: number | {
69
+ readonly amount: number;
70
+ readonly ms: number;
71
+ };
72
+ }
73
+ export interface SynthVoice {
74
+ readonly type?: OscillatorType;
75
+ readonly freq: number;
76
+ /** Absolute context time. */
77
+ readonly at: number;
78
+ readonly dur: number;
79
+ readonly gain: number;
80
+ readonly attack?: number;
81
+ readonly filter?: SynthFilter;
82
+ readonly bus?: SynthBus;
83
+ }
84
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../packages/audio/src/synth/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../packages/audio/src/synth/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aura3d/audio",
3
- "version": "4.0.8",
3
+ "version": "4.1.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -11,7 +11,7 @@
11
11
  "main": "./dist/index.js",
12
12
  "types": "./dist/index.d.ts",
13
13
  "dependencies": {
14
- "@aura3d/scene": "4.0.8"
14
+ "@aura3d/scene": "4.1.1"
15
15
  },
16
16
  "description": "Browser audio lifecycle, clips, sources, buses, mixing, listener transforms, spatial attenuation, effects, and scene audio bridges for Aura3D.",
17
17
  "keywords": [