@sharpee/media 0.9.100
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/audio/audio-registry.d.ts +249 -0
- package/audio/audio-registry.d.ts.map +1 -0
- package/audio/audio-registry.js +250 -0
- package/audio/audio-registry.js.map +1 -0
- package/audio/capabilities.d.ts +49 -0
- package/audio/capabilities.d.ts.map +1 -0
- package/audio/capabilities.js +11 -0
- package/audio/capabilities.js.map +1 -0
- package/audio/events.d.ts +176 -0
- package/audio/events.d.ts.map +1 -0
- package/audio/events.js +24 -0
- package/audio/events.js.map +1 -0
- package/audio/index.d.ts +18 -0
- package/audio/index.d.ts.map +1 -0
- package/audio/index.js +20 -0
- package/audio/index.js.map +1 -0
- package/audio/registry-merge.d.ts +81 -0
- package/audio/registry-merge.d.ts.map +1 -0
- package/audio/registry-merge.js +13 -0
- package/audio/registry-merge.js.map +1 -0
- package/audio/types.d.ts +42 -0
- package/audio/types.d.ts.map +1 -0
- package/audio/types.js +11 -0
- package/audio/types.js.map +1 -0
- package/index.d.ts +14 -0
- package/index.d.ts.map +1 -0
- package/index.js +30 -0
- package/index.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AudioRegistry — central registration system for all audio in a story.
|
|
3
|
+
*
|
|
4
|
+
* Public interface: AudioCue, VariationPool, DuckingConfig, RoomAtmosphere,
|
|
5
|
+
* AtmosphereBuilder, and AudioRegistry class. Stories create one AudioRegistry
|
|
6
|
+
* in initializeWorld() and populate it with cues, pools, and atmospheres.
|
|
7
|
+
* Actions and handlers reference registered names only — never raw audio
|
|
8
|
+
* parameters.
|
|
9
|
+
*
|
|
10
|
+
* Owner context: @sharpee/media (ADR-138)
|
|
11
|
+
*/
|
|
12
|
+
import type { ISemanticEvent } from "../../core/index";
|
|
13
|
+
import type { AudioAssetPath, AmbientChannel, Volume, DurationMs, DuckPriority, AudioEffectType, AudioTarget } from './types';
|
|
14
|
+
import './registry-merge';
|
|
15
|
+
/**
|
|
16
|
+
* An audio cue factory — returns a fresh event each invocation.
|
|
17
|
+
* Factories (not constants) because each call needs a unique event id/timestamp.
|
|
18
|
+
*/
|
|
19
|
+
export type AudioCue = () => ISemanticEvent;
|
|
20
|
+
/**
|
|
21
|
+
* A variation pool — multiple audio files for the same logical sound.
|
|
22
|
+
* The registry picks one at random each time and applies jitter to
|
|
23
|
+
* prevent repetition fatigue.
|
|
24
|
+
*/
|
|
25
|
+
export interface VariationPool {
|
|
26
|
+
/** Audio files to choose from (at least one required) */
|
|
27
|
+
readonly sources: readonly AudioAssetPath[];
|
|
28
|
+
/** Base volume before jitter. Default: 1.0 */
|
|
29
|
+
readonly volume?: Volume;
|
|
30
|
+
/** Random volume jitter range: +/-jitter. e.g., 0.1 means volume varies +/-10%. Default: 0 */
|
|
31
|
+
readonly volumeJitter?: number;
|
|
32
|
+
/** Random pitch jitter range: +/-jitter applied to playback rate. e.g., 0.05 means +/-5%. Default: 0 */
|
|
33
|
+
readonly pitchJitter?: number;
|
|
34
|
+
/** Ducking priority. Default: 0 */
|
|
35
|
+
readonly duck?: DuckPriority;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Ducking configuration — how the client reduces background audio
|
|
39
|
+
* when a high-priority sound fires.
|
|
40
|
+
*/
|
|
41
|
+
export interface DuckingConfig {
|
|
42
|
+
/** Volume multiplier applied to ducked audio (0.0-1.0). Default: 0.3 */
|
|
43
|
+
readonly duckVolume: Volume;
|
|
44
|
+
/** How quickly ducked audio fades down (ms). Default: 100 */
|
|
45
|
+
readonly attackMs: DurationMs;
|
|
46
|
+
/** How quickly ducked audio recovers after the SFX ends (ms). Default: 500 */
|
|
47
|
+
readonly releaseMs: DurationMs;
|
|
48
|
+
/**
|
|
49
|
+
* Which categories get ducked. Default: ['music', 'ambient']
|
|
50
|
+
* SFX never duck other SFX.
|
|
51
|
+
*/
|
|
52
|
+
readonly targets: readonly ('music' | 'ambient')[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Atmosphere definition for a room or region.
|
|
56
|
+
* Describes the ambient soundscape, optional music track, and optional effect.
|
|
57
|
+
*/
|
|
58
|
+
export interface RoomAtmosphere {
|
|
59
|
+
readonly ambient: ReadonlyArray<{
|
|
60
|
+
readonly src: AudioAssetPath;
|
|
61
|
+
readonly channel: AmbientChannel;
|
|
62
|
+
readonly volume: Volume;
|
|
63
|
+
}>;
|
|
64
|
+
readonly music?: {
|
|
65
|
+
readonly src: AudioAssetPath;
|
|
66
|
+
readonly volume: Volume;
|
|
67
|
+
};
|
|
68
|
+
readonly effect?: {
|
|
69
|
+
readonly effect: AudioEffectType;
|
|
70
|
+
readonly target: AudioTarget;
|
|
71
|
+
readonly params: Readonly<Record<string, number>>;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** Default fade durations for atmosphere transitions */
|
|
75
|
+
export interface FadeDefaults {
|
|
76
|
+
/** Ambient channel fade-in duration (ms). Default: 2000 */
|
|
77
|
+
readonly ambientIn: DurationMs;
|
|
78
|
+
/** Ambient channel fade-out duration (ms). Default: 2000 */
|
|
79
|
+
readonly ambientOut: DurationMs;
|
|
80
|
+
/** Music track fade-in duration (ms). Default: 1000 */
|
|
81
|
+
readonly musicIn: DurationMs;
|
|
82
|
+
/** Audio effect transition duration (ms). Default: 2000 */
|
|
83
|
+
readonly effectTransition: DurationMs;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Central registry for all audio in a story.
|
|
87
|
+
* Stories populate this during initializeWorld(). Actions and handlers
|
|
88
|
+
* reference registered names — never raw audio parameters.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const audio = new AudioRegistry();
|
|
93
|
+
*
|
|
94
|
+
* // Register a simple cue
|
|
95
|
+
* audio.registerCue('skin.activate', () =>
|
|
96
|
+
* createTypedEvent('audio.sfx', { src: 'sfx/skin-activate.mp3', volume: 0.8 })
|
|
97
|
+
* );
|
|
98
|
+
*
|
|
99
|
+
* // Register a variation pool (multiple files, random selection + jitter)
|
|
100
|
+
* audio.registerPool('footstep.metal', {
|
|
101
|
+
* sources: ['sfx/step-metal-1.mp3', 'sfx/step-metal-2.mp3', 'sfx/step-metal-3.mp3'],
|
|
102
|
+
* volume: 0.6,
|
|
103
|
+
* volumeJitter: 0.1,
|
|
104
|
+
* pitchJitter: 0.05,
|
|
105
|
+
* });
|
|
106
|
+
*
|
|
107
|
+
* // Register a room atmosphere using the fluent builder
|
|
108
|
+
* audio.atmosphere('entropy.room.bridge')
|
|
109
|
+
* .ambient('ambient/ship-hum.mp3', 'environment', 0.3)
|
|
110
|
+
* .ambient('ambient/console-beeps.mp3', 'machinery', 0.15)
|
|
111
|
+
* .music('music/bridge-theme.mp3', 0.4)
|
|
112
|
+
* .effect('lowpass', 'ambient:environment', { frequency: 2000, q: 1 })
|
|
113
|
+
* .build();
|
|
114
|
+
*
|
|
115
|
+
* // In an action or handler — just use the name
|
|
116
|
+
* const events = audio.cue('skin.activate');
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export declare class AudioRegistry {
|
|
120
|
+
private cues;
|
|
121
|
+
private pools;
|
|
122
|
+
private atmospheres;
|
|
123
|
+
private fadeDefaultValues;
|
|
124
|
+
private duckingConfig;
|
|
125
|
+
/**
|
|
126
|
+
* Register a named audio cue (single sound, full control).
|
|
127
|
+
*
|
|
128
|
+
* @param name - Unique cue identifier (e.g., 'skin.activate', 'door.open')
|
|
129
|
+
* @param cue - Factory function that returns a fresh ISemanticEvent
|
|
130
|
+
*/
|
|
131
|
+
registerCue(name: string, cue: AudioCue): void;
|
|
132
|
+
/**
|
|
133
|
+
* Register a variation pool — multiple files for one logical sound.
|
|
134
|
+
* When fired, the registry picks a random source and applies jitter.
|
|
135
|
+
*
|
|
136
|
+
* @param name - Unique pool identifier (e.g., 'footstep.metal')
|
|
137
|
+
* @param pool - Pool configuration with sources and jitter parameters
|
|
138
|
+
*/
|
|
139
|
+
registerPool(name: string, pool: VariationPool): void;
|
|
140
|
+
/**
|
|
141
|
+
* Fire a registered cue or pool by name. Returns empty array if not registered.
|
|
142
|
+
*
|
|
143
|
+
* Resolution order:
|
|
144
|
+
* 1. Check cues (exact factory)
|
|
145
|
+
* 2. Check pools (random selection + jitter -> AudioSfxEvent)
|
|
146
|
+
* 3. Return [] (silent degradation)
|
|
147
|
+
*
|
|
148
|
+
* @param name - Registered cue or pool name
|
|
149
|
+
* @returns Array of events to emit (empty if name is not registered)
|
|
150
|
+
*/
|
|
151
|
+
cue(name: string): ISemanticEvent[];
|
|
152
|
+
private resolvePool;
|
|
153
|
+
/**
|
|
154
|
+
* Override the default ducking behavior.
|
|
155
|
+
*
|
|
156
|
+
* @param config - Partial ducking configuration to merge with defaults
|
|
157
|
+
*/
|
|
158
|
+
setDucking(config: Partial<DuckingConfig>): void;
|
|
159
|
+
/**
|
|
160
|
+
* Get the current ducking configuration.
|
|
161
|
+
*
|
|
162
|
+
* @returns Read-only ducking config
|
|
163
|
+
*/
|
|
164
|
+
getDucking(): Readonly<DuckingConfig>;
|
|
165
|
+
/**
|
|
166
|
+
* Register a room atmosphere by room ID (raw object).
|
|
167
|
+
*
|
|
168
|
+
* @param roomId - Entity ID of the room
|
|
169
|
+
* @param atmosphere - Complete atmosphere definition
|
|
170
|
+
*/
|
|
171
|
+
registerAtmosphere(roomId: string, atmosphere: RoomAtmosphere): void;
|
|
172
|
+
/**
|
|
173
|
+
* Start a fluent atmosphere builder for a room.
|
|
174
|
+
*
|
|
175
|
+
* @param roomId - Entity ID of the room
|
|
176
|
+
* @returns AtmosphereBuilder instance — call .build() to register
|
|
177
|
+
*/
|
|
178
|
+
atmosphere(roomId: string): AtmosphereBuilder;
|
|
179
|
+
/**
|
|
180
|
+
* Get the registered atmosphere for a room.
|
|
181
|
+
*
|
|
182
|
+
* @param roomId - Entity ID of the room
|
|
183
|
+
* @returns The atmosphere definition, or undefined if none registered
|
|
184
|
+
*/
|
|
185
|
+
getAtmosphere(roomId: string): RoomAtmosphere | undefined;
|
|
186
|
+
/**
|
|
187
|
+
* Override default fade durations (ms).
|
|
188
|
+
*
|
|
189
|
+
* @param defaults - Partial fade defaults to merge
|
|
190
|
+
*/
|
|
191
|
+
setFadeDefaults(defaults: Partial<FadeDefaults>): void;
|
|
192
|
+
/**
|
|
193
|
+
* Get the current fade defaults.
|
|
194
|
+
*
|
|
195
|
+
* @returns Read-only fade defaults
|
|
196
|
+
*/
|
|
197
|
+
getFadeDefaults(): Readonly<FadeDefaults>;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Fluent builder for room atmospheres.
|
|
201
|
+
* Avoids verbose JSON object literals in registration code.
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```typescript
|
|
205
|
+
* registry.atmosphere('entropy.room.bridge')
|
|
206
|
+
* .ambient('ambient/ship-hum.mp3', 'environment', 0.3)
|
|
207
|
+
* .music('music/bridge-theme.mp3', 0.4)
|
|
208
|
+
* .build();
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
export declare class AtmosphereBuilder {
|
|
212
|
+
private registry;
|
|
213
|
+
private roomId;
|
|
214
|
+
private _ambient;
|
|
215
|
+
private _music;
|
|
216
|
+
private _effect;
|
|
217
|
+
constructor(registry: AudioRegistry, roomId: string);
|
|
218
|
+
/**
|
|
219
|
+
* Add an ambient channel to the atmosphere.
|
|
220
|
+
*
|
|
221
|
+
* @param src - Audio file path
|
|
222
|
+
* @param channel - Named channel identifier
|
|
223
|
+
* @param volume - Playback volume (0.0-1.0)
|
|
224
|
+
* @returns this (for chaining)
|
|
225
|
+
*/
|
|
226
|
+
ambient(src: AudioAssetPath, channel: AmbientChannel, volume: Volume): this;
|
|
227
|
+
/**
|
|
228
|
+
* Set the music track for the atmosphere.
|
|
229
|
+
*
|
|
230
|
+
* @param src - Audio file path
|
|
231
|
+
* @param volume - Playback volume (0.0-1.0)
|
|
232
|
+
* @returns this (for chaining)
|
|
233
|
+
*/
|
|
234
|
+
music(src: AudioAssetPath, volume: Volume): this;
|
|
235
|
+
/**
|
|
236
|
+
* Set an audio effect for the atmosphere.
|
|
237
|
+
*
|
|
238
|
+
* @param effect - Effect type (e.g., 'reverb', 'lowpass')
|
|
239
|
+
* @param target - Mix target to apply the effect to
|
|
240
|
+
* @param params - Effect-specific parameters
|
|
241
|
+
* @returns this (for chaining)
|
|
242
|
+
*/
|
|
243
|
+
effect(effect: AudioEffectType, target: AudioTarget, params: Record<string, number>): this;
|
|
244
|
+
/**
|
|
245
|
+
* Register the atmosphere with the registry.
|
|
246
|
+
*/
|
|
247
|
+
build(): void;
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=audio-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio-registry.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/media/src/audio/audio-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* AudioRegistry — central registration system for all audio in a story.
|
|
4
|
+
*
|
|
5
|
+
* Public interface: AudioCue, VariationPool, DuckingConfig, RoomAtmosphere,
|
|
6
|
+
* AtmosphereBuilder, and AudioRegistry class. Stories create one AudioRegistry
|
|
7
|
+
* in initializeWorld() and populate it with cues, pools, and atmospheres.
|
|
8
|
+
* Actions and handlers reference registered names only — never raw audio
|
|
9
|
+
* parameters.
|
|
10
|
+
*
|
|
11
|
+
* Owner context: @sharpee/media (ADR-138)
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.AtmosphereBuilder = exports.AudioRegistry = void 0;
|
|
15
|
+
const core_1 = require("../../core/index.js");
|
|
16
|
+
// Ensure declaration merging is active
|
|
17
|
+
require("./registry-merge");
|
|
18
|
+
/**
|
|
19
|
+
* Central registry for all audio in a story.
|
|
20
|
+
* Stories populate this during initializeWorld(). Actions and handlers
|
|
21
|
+
* reference registered names — never raw audio parameters.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const audio = new AudioRegistry();
|
|
26
|
+
*
|
|
27
|
+
* // Register a simple cue
|
|
28
|
+
* audio.registerCue('skin.activate', () =>
|
|
29
|
+
* createTypedEvent('audio.sfx', { src: 'sfx/skin-activate.mp3', volume: 0.8 })
|
|
30
|
+
* );
|
|
31
|
+
*
|
|
32
|
+
* // Register a variation pool (multiple files, random selection + jitter)
|
|
33
|
+
* audio.registerPool('footstep.metal', {
|
|
34
|
+
* sources: ['sfx/step-metal-1.mp3', 'sfx/step-metal-2.mp3', 'sfx/step-metal-3.mp3'],
|
|
35
|
+
* volume: 0.6,
|
|
36
|
+
* volumeJitter: 0.1,
|
|
37
|
+
* pitchJitter: 0.05,
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // Register a room atmosphere using the fluent builder
|
|
41
|
+
* audio.atmosphere('entropy.room.bridge')
|
|
42
|
+
* .ambient('ambient/ship-hum.mp3', 'environment', 0.3)
|
|
43
|
+
* .ambient('ambient/console-beeps.mp3', 'machinery', 0.15)
|
|
44
|
+
* .music('music/bridge-theme.mp3', 0.4)
|
|
45
|
+
* .effect('lowpass', 'ambient:environment', { frequency: 2000, q: 1 })
|
|
46
|
+
* .build();
|
|
47
|
+
*
|
|
48
|
+
* // In an action or handler — just use the name
|
|
49
|
+
* const events = audio.cue('skin.activate');
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
class AudioRegistry {
|
|
53
|
+
cues = new Map();
|
|
54
|
+
pools = new Map();
|
|
55
|
+
atmospheres = new Map();
|
|
56
|
+
fadeDefaultValues = {
|
|
57
|
+
ambientIn: 2000,
|
|
58
|
+
ambientOut: 2000,
|
|
59
|
+
musicIn: 1000,
|
|
60
|
+
effectTransition: 2000,
|
|
61
|
+
};
|
|
62
|
+
duckingConfig = {
|
|
63
|
+
duckVolume: 0.3,
|
|
64
|
+
attackMs: 100,
|
|
65
|
+
releaseMs: 500,
|
|
66
|
+
targets: ['music', 'ambient'],
|
|
67
|
+
};
|
|
68
|
+
// ── Cues ────────────────────────────────────────────────────────────
|
|
69
|
+
/**
|
|
70
|
+
* Register a named audio cue (single sound, full control).
|
|
71
|
+
*
|
|
72
|
+
* @param name - Unique cue identifier (e.g., 'skin.activate', 'door.open')
|
|
73
|
+
* @param cue - Factory function that returns a fresh ISemanticEvent
|
|
74
|
+
*/
|
|
75
|
+
registerCue(name, cue) {
|
|
76
|
+
this.cues.set(name, cue);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Register a variation pool — multiple files for one logical sound.
|
|
80
|
+
* When fired, the registry picks a random source and applies jitter.
|
|
81
|
+
*
|
|
82
|
+
* @param name - Unique pool identifier (e.g., 'footstep.metal')
|
|
83
|
+
* @param pool - Pool configuration with sources and jitter parameters
|
|
84
|
+
*/
|
|
85
|
+
registerPool(name, pool) {
|
|
86
|
+
this.pools.set(name, pool);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Fire a registered cue or pool by name. Returns empty array if not registered.
|
|
90
|
+
*
|
|
91
|
+
* Resolution order:
|
|
92
|
+
* 1. Check cues (exact factory)
|
|
93
|
+
* 2. Check pools (random selection + jitter -> AudioSfxEvent)
|
|
94
|
+
* 3. Return [] (silent degradation)
|
|
95
|
+
*
|
|
96
|
+
* @param name - Registered cue or pool name
|
|
97
|
+
* @returns Array of events to emit (empty if name is not registered)
|
|
98
|
+
*/
|
|
99
|
+
cue(name) {
|
|
100
|
+
const factory = this.cues.get(name);
|
|
101
|
+
if (factory)
|
|
102
|
+
return [factory()];
|
|
103
|
+
const pool = this.pools.get(name);
|
|
104
|
+
if (pool)
|
|
105
|
+
return [this.resolvePool(pool)];
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
resolvePool(pool) {
|
|
109
|
+
const src = pool.sources[Math.floor(Math.random() * pool.sources.length)];
|
|
110
|
+
const baseVolume = pool.volume ?? 1.0;
|
|
111
|
+
const volumeJitter = pool.volumeJitter ?? 0;
|
|
112
|
+
const pitchJitter = pool.pitchJitter ?? 0;
|
|
113
|
+
const volume = Math.max(0, Math.min(1, baseVolume + (Math.random() * 2 - 1) * volumeJitter));
|
|
114
|
+
const rate = 1.0 + (Math.random() * 2 - 1) * pitchJitter;
|
|
115
|
+
return (0, core_1.createTypedEvent)('audio.sfx', { src, volume, rate, duck: pool.duck });
|
|
116
|
+
}
|
|
117
|
+
// ── Ducking ─────────────────────────────────────────────────────────
|
|
118
|
+
/**
|
|
119
|
+
* Override the default ducking behavior.
|
|
120
|
+
*
|
|
121
|
+
* @param config - Partial ducking configuration to merge with defaults
|
|
122
|
+
*/
|
|
123
|
+
setDucking(config) {
|
|
124
|
+
this.duckingConfig = { ...this.duckingConfig, ...config };
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get the current ducking configuration.
|
|
128
|
+
*
|
|
129
|
+
* @returns Read-only ducking config
|
|
130
|
+
*/
|
|
131
|
+
getDucking() {
|
|
132
|
+
return this.duckingConfig;
|
|
133
|
+
}
|
|
134
|
+
// ── Atmospheres ─────────────────────────────────────────────────────
|
|
135
|
+
/**
|
|
136
|
+
* Register a room atmosphere by room ID (raw object).
|
|
137
|
+
*
|
|
138
|
+
* @param roomId - Entity ID of the room
|
|
139
|
+
* @param atmosphere - Complete atmosphere definition
|
|
140
|
+
*/
|
|
141
|
+
registerAtmosphere(roomId, atmosphere) {
|
|
142
|
+
this.atmospheres.set(roomId, atmosphere);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Start a fluent atmosphere builder for a room.
|
|
146
|
+
*
|
|
147
|
+
* @param roomId - Entity ID of the room
|
|
148
|
+
* @returns AtmosphereBuilder instance — call .build() to register
|
|
149
|
+
*/
|
|
150
|
+
atmosphere(roomId) {
|
|
151
|
+
return new AtmosphereBuilder(this, roomId);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get the registered atmosphere for a room.
|
|
155
|
+
*
|
|
156
|
+
* @param roomId - Entity ID of the room
|
|
157
|
+
* @returns The atmosphere definition, or undefined if none registered
|
|
158
|
+
*/
|
|
159
|
+
getAtmosphere(roomId) {
|
|
160
|
+
return this.atmospheres.get(roomId);
|
|
161
|
+
}
|
|
162
|
+
// ── Fade defaults ───────────────────────────────────────────────────
|
|
163
|
+
/**
|
|
164
|
+
* Override default fade durations (ms).
|
|
165
|
+
*
|
|
166
|
+
* @param defaults - Partial fade defaults to merge
|
|
167
|
+
*/
|
|
168
|
+
setFadeDefaults(defaults) {
|
|
169
|
+
this.fadeDefaultValues = { ...this.fadeDefaultValues, ...defaults };
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get the current fade defaults.
|
|
173
|
+
*
|
|
174
|
+
* @returns Read-only fade defaults
|
|
175
|
+
*/
|
|
176
|
+
getFadeDefaults() {
|
|
177
|
+
return this.fadeDefaultValues;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
exports.AudioRegistry = AudioRegistry;
|
|
181
|
+
/**
|
|
182
|
+
* Fluent builder for room atmospheres.
|
|
183
|
+
* Avoids verbose JSON object literals in registration code.
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* registry.atmosphere('entropy.room.bridge')
|
|
188
|
+
* .ambient('ambient/ship-hum.mp3', 'environment', 0.3)
|
|
189
|
+
* .music('music/bridge-theme.mp3', 0.4)
|
|
190
|
+
* .build();
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
class AtmosphereBuilder {
|
|
194
|
+
registry;
|
|
195
|
+
roomId;
|
|
196
|
+
_ambient = [];
|
|
197
|
+
_music;
|
|
198
|
+
_effect;
|
|
199
|
+
constructor(registry, roomId) {
|
|
200
|
+
this.registry = registry;
|
|
201
|
+
this.roomId = roomId;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Add an ambient channel to the atmosphere.
|
|
205
|
+
*
|
|
206
|
+
* @param src - Audio file path
|
|
207
|
+
* @param channel - Named channel identifier
|
|
208
|
+
* @param volume - Playback volume (0.0-1.0)
|
|
209
|
+
* @returns this (for chaining)
|
|
210
|
+
*/
|
|
211
|
+
ambient(src, channel, volume) {
|
|
212
|
+
this._ambient = [...this._ambient, { src, channel, volume }];
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Set the music track for the atmosphere.
|
|
217
|
+
*
|
|
218
|
+
* @param src - Audio file path
|
|
219
|
+
* @param volume - Playback volume (0.0-1.0)
|
|
220
|
+
* @returns this (for chaining)
|
|
221
|
+
*/
|
|
222
|
+
music(src, volume) {
|
|
223
|
+
this._music = { src, volume };
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Set an audio effect for the atmosphere.
|
|
228
|
+
*
|
|
229
|
+
* @param effect - Effect type (e.g., 'reverb', 'lowpass')
|
|
230
|
+
* @param target - Mix target to apply the effect to
|
|
231
|
+
* @param params - Effect-specific parameters
|
|
232
|
+
* @returns this (for chaining)
|
|
233
|
+
*/
|
|
234
|
+
effect(effect, target, params) {
|
|
235
|
+
this._effect = { effect, target, params };
|
|
236
|
+
return this;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Register the atmosphere with the registry.
|
|
240
|
+
*/
|
|
241
|
+
build() {
|
|
242
|
+
this.registry.registerAtmosphere(this.roomId, {
|
|
243
|
+
ambient: this._ambient,
|
|
244
|
+
music: this._music,
|
|
245
|
+
effect: this._effect,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
exports.AtmosphereBuilder = AtmosphereBuilder;
|
|
250
|
+
//# sourceMappingURL=audio-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio-registry.js","sourceRoot":"","sources":["../../../../../../../repos/sharpee/packages/media/src/audio/audio-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio capability negotiation and player preference types.
|
|
3
|
+
*
|
|
4
|
+
* Public interface: AudioCapabilities (declared by clients at session start)
|
|
5
|
+
* and AudioPreferences (player settings persisted by clients).
|
|
6
|
+
*
|
|
7
|
+
* Owner context: @sharpee/media (ADR-138)
|
|
8
|
+
*/
|
|
9
|
+
import type { Volume, AudioFormat } from './types';
|
|
10
|
+
/**
|
|
11
|
+
* Audio capabilities declared by the client at session start.
|
|
12
|
+
* Stories can check these before emitting audio events to avoid
|
|
13
|
+
* sending events the client cannot render.
|
|
14
|
+
*/
|
|
15
|
+
export interface AudioCapabilities {
|
|
16
|
+
/** Can play sound effects (AudioSfxEvent) */
|
|
17
|
+
readonly sfx: boolean;
|
|
18
|
+
/** Can play background music (AudioMusicPlayEvent/StopEvent) */
|
|
19
|
+
readonly music: boolean;
|
|
20
|
+
/** Can layer ambient channels (AudioAmbientPlayEvent/StopEvent) */
|
|
21
|
+
readonly ambient: boolean;
|
|
22
|
+
/** Can synthesize procedural sounds (AudioProceduralEvent) */
|
|
23
|
+
readonly procedural: boolean;
|
|
24
|
+
/** Can apply audio effects (AudioEffectEvent) */
|
|
25
|
+
readonly effects: boolean;
|
|
26
|
+
/** Maximum simultaneous audio sources. 0 = unlimited. */
|
|
27
|
+
readonly maxChannels?: number;
|
|
28
|
+
/** Supported audio file formats */
|
|
29
|
+
readonly formats: readonly AudioFormat[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Player audio preferences, persisted to localStorage by the client.
|
|
33
|
+
* Player settings override story-specified volumes.
|
|
34
|
+
*/
|
|
35
|
+
export interface AudioPreferences {
|
|
36
|
+
/** Master audio enabled/disabled */
|
|
37
|
+
enabled: boolean;
|
|
38
|
+
/** Master volume (multiplied against all event volumes). Default: 1.0 */
|
|
39
|
+
masterVolume: Volume;
|
|
40
|
+
/** Per-category volume multipliers */
|
|
41
|
+
sfxVolume: Volume;
|
|
42
|
+
musicVolume: Volume;
|
|
43
|
+
ambientVolume: Volume;
|
|
44
|
+
/** Per-category mute toggles (independent of volume) */
|
|
45
|
+
sfxMuted: boolean;
|
|
46
|
+
musicMuted: boolean;
|
|
47
|
+
ambientMuted: boolean;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/media/src/audio/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEnD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,6CAA6C;IAC7C,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IAEtB,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAExB,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAE7B,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B,yDAAyD;IACzD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAE9B,mCAAmC;IACnC,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;CAC1C;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IAEjB,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;IAErB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IAEtB,wDAAwD;IACxD,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACvB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Audio capability negotiation and player preference types.
|
|
4
|
+
*
|
|
5
|
+
* Public interface: AudioCapabilities (declared by clients at session start)
|
|
6
|
+
* and AudioPreferences (player settings persisted by clients).
|
|
7
|
+
*
|
|
8
|
+
* Owner context: @sharpee/media (ADR-138)
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../../../../../../repos/sharpee/packages/media/src/audio/capabilities.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio event interfaces for the Sharpee media subsystem.
|
|
3
|
+
*
|
|
4
|
+
* Public interface: All audio event shapes, the AudioEvent discriminated
|
|
5
|
+
* union, and the isAudioEvent() type guard.
|
|
6
|
+
*
|
|
7
|
+
* Owner context: @sharpee/media (ADR-138). These events flow through the
|
|
8
|
+
* engine's event pipeline unchanged — clients that support audio render
|
|
9
|
+
* them; others ignore them.
|
|
10
|
+
*/
|
|
11
|
+
import type { Volume, DurationMs, StereoPan, PlaybackRate, AudioAssetPath, AmbientChannel, DuckPriority, AudioTarget, AudioEffectType, ProceduralRecipeName } from './types';
|
|
12
|
+
/**
|
|
13
|
+
* Base interface for all audio events.
|
|
14
|
+
* Audio events flow through the engine's event pipeline unchanged.
|
|
15
|
+
* Clients that support audio render them; others ignore them.
|
|
16
|
+
*/
|
|
17
|
+
export interface AudioEventBase {
|
|
18
|
+
readonly type: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Play a sound effect.
|
|
22
|
+
*
|
|
23
|
+
* Use cases: door opening, item pickup, skin activation, weapon fire,
|
|
24
|
+
* system alert, puzzle solve chime.
|
|
25
|
+
*/
|
|
26
|
+
export interface AudioSfxEvent extends AudioEventBase {
|
|
27
|
+
readonly type: 'audio.sfx';
|
|
28
|
+
/** Audio file path (relative to assets/audio/) */
|
|
29
|
+
readonly src: AudioAssetPath;
|
|
30
|
+
/** Playback volume. Default: 1.0 */
|
|
31
|
+
readonly volume?: Volume;
|
|
32
|
+
/** Playback speed. Default: 1.0 */
|
|
33
|
+
readonly rate?: PlaybackRate;
|
|
34
|
+
/** Stereo position. Default: 0.0 (center) */
|
|
35
|
+
readonly pan?: StereoPan;
|
|
36
|
+
/**
|
|
37
|
+
* Ducking priority. Higher values duck lower-priority audio.
|
|
38
|
+
* When this SFX fires, ambient and music temporarily reduce volume
|
|
39
|
+
* so the SFX cuts through the mix. Default: 0 (no ducking).
|
|
40
|
+
*
|
|
41
|
+
* Suggested values:
|
|
42
|
+
* - 0: ambient/background SFX (no ducking)
|
|
43
|
+
* - 1: normal gameplay SFX (subtle duck)
|
|
44
|
+
* - 2: important feedback (moderate duck)
|
|
45
|
+
* - 3: critical alerts, combat hits (aggressive duck)
|
|
46
|
+
*/
|
|
47
|
+
readonly duck?: DuckPriority;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Start playing a music track, or crossfade to a new one.
|
|
51
|
+
* If music is already playing, the current track fades out while
|
|
52
|
+
* the new one fades in over the fadeIn duration.
|
|
53
|
+
*
|
|
54
|
+
* Use cases: exploration theme, tension/combat music, victory stinger.
|
|
55
|
+
*/
|
|
56
|
+
export interface AudioMusicPlayEvent extends AudioEventBase {
|
|
57
|
+
readonly type: 'audio.music.play';
|
|
58
|
+
/** Audio file path (relative to assets/audio/) */
|
|
59
|
+
readonly src: AudioAssetPath;
|
|
60
|
+
/** Playback volume. Default: 0.5 */
|
|
61
|
+
readonly volume?: Volume;
|
|
62
|
+
/** Fade-in duration. Default: 1000ms */
|
|
63
|
+
readonly fadeIn?: DurationMs;
|
|
64
|
+
/** Whether to loop the track. Default: true */
|
|
65
|
+
readonly loop?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Stop the current music track.
|
|
69
|
+
*/
|
|
70
|
+
export interface AudioMusicStopEvent extends AudioEventBase {
|
|
71
|
+
readonly type: 'audio.music.stop';
|
|
72
|
+
/** Fade-out duration. Default: 1000ms */
|
|
73
|
+
readonly fadeOut?: DurationMs;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Start or replace an ambient channel.
|
|
77
|
+
*
|
|
78
|
+
* Use cases: wind, rain, cave dripping, engine hum, distant explosions,
|
|
79
|
+
* electrical buzz, crowd murmur.
|
|
80
|
+
*/
|
|
81
|
+
export interface AudioAmbientPlayEvent extends AudioEventBase {
|
|
82
|
+
readonly type: 'audio.ambient.play';
|
|
83
|
+
/** Audio file path (relative to assets/audio/) */
|
|
84
|
+
readonly src: AudioAssetPath;
|
|
85
|
+
/** Named channel. Reusing a channel name replaces the current source. */
|
|
86
|
+
readonly channel: AmbientChannel;
|
|
87
|
+
/** Playback volume. Default: 0.3 */
|
|
88
|
+
readonly volume?: Volume;
|
|
89
|
+
/** Fade-in duration. Default: 2000ms */
|
|
90
|
+
readonly fadeIn?: DurationMs;
|
|
91
|
+
/** Whether to loop. Default: true */
|
|
92
|
+
readonly loop?: boolean;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Stop a single ambient channel.
|
|
96
|
+
*/
|
|
97
|
+
export interface AudioAmbientStopEvent extends AudioEventBase {
|
|
98
|
+
readonly type: 'audio.ambient.stop';
|
|
99
|
+
/** Channel to stop */
|
|
100
|
+
readonly channel: AmbientChannel;
|
|
101
|
+
/** Fade-out duration. Default: 2000ms */
|
|
102
|
+
readonly fadeOut?: DurationMs;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Stop all ambient channels at once (e.g., on scene change).
|
|
106
|
+
*/
|
|
107
|
+
export interface AudioAmbientStopAllEvent extends AudioEventBase {
|
|
108
|
+
readonly type: 'audio.ambient.stop_all';
|
|
109
|
+
/** Fade-out duration for all channels. Default: 1000ms */
|
|
110
|
+
readonly fadeOut?: DurationMs;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Play a procedural sound from a named recipe.
|
|
114
|
+
*
|
|
115
|
+
* Recipes are registered by the client, not defined by the story.
|
|
116
|
+
* The story says *what* conceptual sound it wants; the client decides
|
|
117
|
+
* how to synthesize it. Clients without procedural support can map
|
|
118
|
+
* recipe names to fallback audio files, or skip the event.
|
|
119
|
+
*
|
|
120
|
+
* Use cases: system beeps, alerts, electrical hum, static bursts,
|
|
121
|
+
* tonal feedback for puzzle state.
|
|
122
|
+
*/
|
|
123
|
+
export interface AudioProceduralEvent extends AudioEventBase {
|
|
124
|
+
readonly type: 'audio.procedural';
|
|
125
|
+
/** Named recipe identifier */
|
|
126
|
+
readonly recipe: ProceduralRecipeName;
|
|
127
|
+
/** Recipe-specific parameters (override recipe defaults) */
|
|
128
|
+
readonly params?: Readonly<Record<string, number>>;
|
|
129
|
+
/** Playback volume. Default: 1.0 */
|
|
130
|
+
readonly volume?: Volume;
|
|
131
|
+
/** Duration override. Uses recipe default if omitted. */
|
|
132
|
+
readonly duration?: DurationMs;
|
|
133
|
+
/** Ducking priority. See AudioSfxEvent.duck. Default: 0 */
|
|
134
|
+
readonly duck?: DuckPriority;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Apply an audio effect to a mix target.
|
|
138
|
+
*
|
|
139
|
+
* Use cases: reverb in caves, muffled sound behind walls,
|
|
140
|
+
* distortion during damage, lowpass for flashback sequences.
|
|
141
|
+
*/
|
|
142
|
+
export interface AudioEffectEvent extends AudioEventBase {
|
|
143
|
+
readonly type: 'audio.effect';
|
|
144
|
+
/** Which part of the audio mix to affect */
|
|
145
|
+
readonly target: AudioTarget;
|
|
146
|
+
/** Effect to apply */
|
|
147
|
+
readonly effect: AudioEffectType;
|
|
148
|
+
/** Effect-specific parameters */
|
|
149
|
+
readonly params: Readonly<Record<string, number>>;
|
|
150
|
+
/** Transition time to reach new effect state. Default: 0 (instant) */
|
|
151
|
+
readonly transition?: DurationMs;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Remove all effects from a mix target.
|
|
155
|
+
*/
|
|
156
|
+
export interface AudioEffectClearEvent extends AudioEventBase {
|
|
157
|
+
readonly type: 'audio.effect.clear';
|
|
158
|
+
/** Which part of the audio mix to clear effects from */
|
|
159
|
+
readonly target: AudioTarget;
|
|
160
|
+
/** Transition time to remove effects. Default: 0 (instant) */
|
|
161
|
+
readonly transition?: DurationMs;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Union of all audio events. Clients switch on the `type` discriminant.
|
|
165
|
+
*/
|
|
166
|
+
export type AudioEvent = AudioSfxEvent | AudioMusicPlayEvent | AudioMusicStopEvent | AudioAmbientPlayEvent | AudioAmbientStopEvent | AudioAmbientStopAllEvent | AudioProceduralEvent | AudioEffectEvent | AudioEffectClearEvent;
|
|
167
|
+
/**
|
|
168
|
+
* Returns true if the event is any audio event.
|
|
169
|
+
*
|
|
170
|
+
* @param event - Any object with a `type` string field
|
|
171
|
+
* @returns Type predicate narrowing to AudioEvent
|
|
172
|
+
*/
|
|
173
|
+
export declare function isAudioEvent(event: {
|
|
174
|
+
type: string;
|
|
175
|
+
}): event is AudioEvent;
|
|
176
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/media/src/audio/events.ts"],"names":[],"mappings":"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"}
|
package/audio/events.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Audio event interfaces for the Sharpee media subsystem.
|
|
4
|
+
*
|
|
5
|
+
* Public interface: All audio event shapes, the AudioEvent discriminated
|
|
6
|
+
* union, and the isAudioEvent() type guard.
|
|
7
|
+
*
|
|
8
|
+
* Owner context: @sharpee/media (ADR-138). These events flow through the
|
|
9
|
+
* engine's event pipeline unchanged — clients that support audio render
|
|
10
|
+
* them; others ignore them.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.isAudioEvent = isAudioEvent;
|
|
14
|
+
// ── Type Guards ───────────────────────────────────────────────────────
|
|
15
|
+
/**
|
|
16
|
+
* Returns true if the event is any audio event.
|
|
17
|
+
*
|
|
18
|
+
* @param event - Any object with a `type` string field
|
|
19
|
+
* @returns Type predicate narrowing to AudioEvent
|
|
20
|
+
*/
|
|
21
|
+
function isAudioEvent(event) {
|
|
22
|
+
return event.type.startsWith('audio.');
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../../../../../repos/sharpee/packages/media/src/audio/events.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;AA0PH,oCAEC;AAVD,yEAAyE;AAEzE;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,KAAuB;IAClD,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AACzC,CAAC"}
|
package/audio/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio module barrel — re-exports all audio types, events, capabilities,
|
|
3
|
+
* registry merging, and the AudioRegistry class.
|
|
4
|
+
*
|
|
5
|
+
* Public interface: Everything needed by stories and clients to work
|
|
6
|
+
* with Sharpee audio.
|
|
7
|
+
*
|
|
8
|
+
* Owner context: @sharpee/media (ADR-138)
|
|
9
|
+
*/
|
|
10
|
+
export type { Volume, DurationMs, StereoPan, PlaybackRate, AudioAssetPath, AmbientChannel, DuckPriority, AudioTarget, AudioEffectType, AudioFormat, BuiltinRecipeName, ProceduralRecipeName, } from './types';
|
|
11
|
+
export type { AudioEventBase, AudioSfxEvent, AudioMusicPlayEvent, AudioMusicStopEvent, AudioAmbientPlayEvent, AudioAmbientStopEvent, AudioAmbientStopAllEvent, AudioProceduralEvent, AudioEffectEvent, AudioEffectClearEvent, AudioEvent, } from './events';
|
|
12
|
+
export { isAudioEvent } from './events';
|
|
13
|
+
export type { AudioCapabilities, AudioPreferences, } from './capabilities';
|
|
14
|
+
export type { AudioSfxData, AudioMusicPlayData, AudioMusicStopData, AudioAmbientPlayData, AudioAmbientStopData, AudioAmbientStopAllData, AudioProceduralData, AudioEffectData, AudioEffectClearData, } from './registry-merge';
|
|
15
|
+
import './registry-merge';
|
|
16
|
+
export type { AudioCue, VariationPool, DuckingConfig, RoomAtmosphere, FadeDefaults, } from './audio-registry';
|
|
17
|
+
export { AudioRegistry, AtmosphereBuilder } from './audio-registry';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/media/src/audio/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EACV,MAAM,EACN,UAAU,EACV,SAAS,EACT,YAAY,EACZ,cAAc,EACd,cAAc,EACd,YAAY,EACZ,WAAW,EACX,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,UAAU,GACX,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,YAAY,EACV,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,kBAAkB,CAAC;AAE1B,YAAY,EACV,QAAQ,EACR,aAAa,EACb,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/audio/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Audio module barrel — re-exports all audio types, events, capabilities,
|
|
4
|
+
* registry merging, and the AudioRegistry class.
|
|
5
|
+
*
|
|
6
|
+
* Public interface: Everything needed by stories and clients to work
|
|
7
|
+
* with Sharpee audio.
|
|
8
|
+
*
|
|
9
|
+
* Owner context: @sharpee/media (ADR-138)
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AtmosphereBuilder = exports.AudioRegistry = exports.isAudioEvent = void 0;
|
|
13
|
+
var events_1 = require("./events");
|
|
14
|
+
Object.defineProperty(exports, "isAudioEvent", { enumerable: true, get: function () { return events_1.isAudioEvent; } });
|
|
15
|
+
// Side-effect import: activates declaration merging for audio event keys
|
|
16
|
+
require("./registry-merge");
|
|
17
|
+
var audio_registry_1 = require("./audio-registry");
|
|
18
|
+
Object.defineProperty(exports, "AudioRegistry", { enumerable: true, get: function () { return audio_registry_1.AudioRegistry; } });
|
|
19
|
+
Object.defineProperty(exports, "AtmosphereBuilder", { enumerable: true, get: function () { return audio_registry_1.AtmosphereBuilder; } });
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../repos/sharpee/packages/media/src/audio/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AA+BH,mCAAwC;AAA/B,sGAAA,YAAY,OAAA;AAmBrB,yEAAyE;AACzE,4BAA0B;AAU1B,mDAAoE;AAA3D,+GAAA,aAAa,OAAA;AAAE,mHAAA,iBAAiB,OAAA"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventDataRegistry declaration merging for audio events.
|
|
3
|
+
*
|
|
4
|
+
* Public interface: Nine *Data interfaces and the declaration merging
|
|
5
|
+
* block that extends @sharpee/core's EventDataRegistry with audio event
|
|
6
|
+
* keys. Importing this module (or any re-export of it) activates
|
|
7
|
+
* compile-time type checking for createTypedEvent('audio.*', ...).
|
|
8
|
+
*
|
|
9
|
+
* Owner context: @sharpee/media (ADR-138)
|
|
10
|
+
*/
|
|
11
|
+
import type { AudioAssetPath, Volume, DurationMs, StereoPan, PlaybackRate, AmbientChannel, DuckPriority, AudioTarget, AudioEffectType, ProceduralRecipeName } from './types';
|
|
12
|
+
/** Data for audio.sfx events */
|
|
13
|
+
export interface AudioSfxData {
|
|
14
|
+
readonly src: AudioAssetPath;
|
|
15
|
+
readonly volume?: Volume;
|
|
16
|
+
readonly rate?: PlaybackRate;
|
|
17
|
+
readonly pan?: StereoPan;
|
|
18
|
+
readonly duck?: DuckPriority;
|
|
19
|
+
}
|
|
20
|
+
/** Data for audio.music.play events */
|
|
21
|
+
export interface AudioMusicPlayData {
|
|
22
|
+
readonly src: AudioAssetPath;
|
|
23
|
+
readonly volume?: Volume;
|
|
24
|
+
readonly fadeIn?: DurationMs;
|
|
25
|
+
readonly loop?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/** Data for audio.music.stop events */
|
|
28
|
+
export interface AudioMusicStopData {
|
|
29
|
+
readonly fadeOut?: DurationMs;
|
|
30
|
+
}
|
|
31
|
+
/** Data for audio.ambient.play events */
|
|
32
|
+
export interface AudioAmbientPlayData {
|
|
33
|
+
readonly src: AudioAssetPath;
|
|
34
|
+
readonly channel: AmbientChannel;
|
|
35
|
+
readonly volume?: Volume;
|
|
36
|
+
readonly fadeIn?: DurationMs;
|
|
37
|
+
readonly loop?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Data for audio.ambient.stop events */
|
|
40
|
+
export interface AudioAmbientStopData {
|
|
41
|
+
readonly channel: AmbientChannel;
|
|
42
|
+
readonly fadeOut?: DurationMs;
|
|
43
|
+
}
|
|
44
|
+
/** Data for audio.ambient.stop_all events */
|
|
45
|
+
export interface AudioAmbientStopAllData {
|
|
46
|
+
readonly fadeOut?: DurationMs;
|
|
47
|
+
}
|
|
48
|
+
/** Data for audio.procedural events */
|
|
49
|
+
export interface AudioProceduralData {
|
|
50
|
+
readonly recipe: ProceduralRecipeName;
|
|
51
|
+
readonly params?: Readonly<Record<string, number>>;
|
|
52
|
+
readonly volume?: Volume;
|
|
53
|
+
readonly duration?: DurationMs;
|
|
54
|
+
readonly duck?: DuckPriority;
|
|
55
|
+
}
|
|
56
|
+
/** Data for audio.effect events */
|
|
57
|
+
export interface AudioEffectData {
|
|
58
|
+
readonly target: AudioTarget;
|
|
59
|
+
readonly effect: AudioEffectType;
|
|
60
|
+
readonly params: Readonly<Record<string, number>>;
|
|
61
|
+
readonly transition?: DurationMs;
|
|
62
|
+
}
|
|
63
|
+
/** Data for audio.effect.clear events */
|
|
64
|
+
export interface AudioEffectClearData {
|
|
65
|
+
readonly target: AudioTarget;
|
|
66
|
+
readonly transition?: DurationMs;
|
|
67
|
+
}
|
|
68
|
+
declare module '@sharpee/core' {
|
|
69
|
+
interface EventDataRegistry {
|
|
70
|
+
'audio.sfx': AudioSfxData;
|
|
71
|
+
'audio.music.play': AudioMusicPlayData;
|
|
72
|
+
'audio.music.stop': AudioMusicStopData;
|
|
73
|
+
'audio.ambient.play': AudioAmbientPlayData;
|
|
74
|
+
'audio.ambient.stop': AudioAmbientStopData;
|
|
75
|
+
'audio.ambient.stop_all': AudioAmbientStopAllData;
|
|
76
|
+
'audio.procedural': AudioProceduralData;
|
|
77
|
+
'audio.effect': AudioEffectData;
|
|
78
|
+
'audio.effect.clear': AudioEffectClearData;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=registry-merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-merge.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/media/src/audio/registry-merge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* EventDataRegistry declaration merging for audio events.
|
|
4
|
+
*
|
|
5
|
+
* Public interface: Nine *Data interfaces and the declaration merging
|
|
6
|
+
* block that extends @sharpee/core's EventDataRegistry with audio event
|
|
7
|
+
* keys. Importing this module (or any re-export of it) activates
|
|
8
|
+
* compile-time type checking for createTypedEvent('audio.*', ...).
|
|
9
|
+
*
|
|
10
|
+
* Owner context: @sharpee/media (ADR-138)
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
//# sourceMappingURL=registry-merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-merge.js","sourceRoot":"","sources":["../../../../../../../repos/sharpee/packages/media/src/audio/registry-merge.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG"}
|
package/audio/types.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common audio primitive types for the Sharpee media subsystem.
|
|
3
|
+
*
|
|
4
|
+
* Public interface: Type aliases used throughout all audio event interfaces,
|
|
5
|
+
* the AudioRegistry, and capability negotiation.
|
|
6
|
+
*
|
|
7
|
+
* Owner context: @sharpee/media (ADR-138)
|
|
8
|
+
*/
|
|
9
|
+
/** Volume level: 0.0 (silent) to 1.0 (full) */
|
|
10
|
+
export type Volume = number;
|
|
11
|
+
/** Duration in milliseconds */
|
|
12
|
+
export type DurationMs = number;
|
|
13
|
+
/** Stereo pan: -1.0 (hard left) to 1.0 (hard right), 0.0 = center */
|
|
14
|
+
export type StereoPan = number;
|
|
15
|
+
/** Playback rate: 1.0 = normal, 0.5 = half speed, 2.0 = double speed */
|
|
16
|
+
export type PlaybackRate = number;
|
|
17
|
+
/** Asset path relative to the story's assets/audio/ directory */
|
|
18
|
+
export type AudioAssetPath = string;
|
|
19
|
+
/** Named ambient channel identifier (e.g., 'wind', 'machinery', 'dripping') */
|
|
20
|
+
export type AmbientChannel = string;
|
|
21
|
+
/** Ducking priority: 0 (none) to 3 (aggressive). See AudioSfxEvent.duck. */
|
|
22
|
+
export type DuckPriority = 0 | 1 | 2 | 3;
|
|
23
|
+
/**
|
|
24
|
+
* Audio mix target — identifies where an effect or volume change applies.
|
|
25
|
+
* - 'master': affects all audio output
|
|
26
|
+
* - 'sfx': affects all sound effects
|
|
27
|
+
* - 'music': affects the music track
|
|
28
|
+
* - 'ambient:{channel}': affects a specific ambient channel
|
|
29
|
+
*/
|
|
30
|
+
export type AudioTarget = 'master' | 'sfx' | 'music' | `ambient:${string}`;
|
|
31
|
+
/** Effect types that map to Web Audio API nodes */
|
|
32
|
+
export type AudioEffectType = 'reverb' | 'lowpass' | 'highpass' | 'distortion' | 'delay';
|
|
33
|
+
/** Audio file formats */
|
|
34
|
+
export type AudioFormat = 'mp3' | 'ogg' | 'wav' | 'aac' | 'opus' | 'webm';
|
|
35
|
+
/**
|
|
36
|
+
* Built-in recipe names that clients SHOULD support.
|
|
37
|
+
* Stories may use any string — unknown recipes are silently skipped.
|
|
38
|
+
*/
|
|
39
|
+
export type BuiltinRecipeName = 'beep' | 'alert' | 'sweep-up' | 'sweep-down' | 'static' | 'hum';
|
|
40
|
+
/** Recipe name: built-in or story-defined */
|
|
41
|
+
export type ProceduralRecipeName = BuiltinRecipeName | (string & {});
|
|
42
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/media/src/audio/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,+CAA+C;AAC/C,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAE5B,+BAA+B;AAC/B,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC,qEAAqE;AACrE,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B,wEAAwE;AACxE,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC,iEAAiE;AACjE,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC,+EAA+E;AAC/E,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC,4EAA4E;AAC5E,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,WAAW,MAAM,EAAE,CAAC;AAE3E,mDAAmD;AACnD,MAAM,MAAM,eAAe,GACvB,QAAQ,GACR,SAAS,GACT,UAAU,GACV,YAAY,GACZ,OAAO,CAAC;AAEZ,yBAAyB;AACzB,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1E;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,OAAO,GACP,UAAU,GACV,YAAY,GACZ,QAAQ,GACR,KAAK,CAAC;AAEV,6CAA6C;AAC7C,MAAM,MAAM,oBAAoB,GAAG,iBAAiB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC"}
|
package/audio/types.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Common audio primitive types for the Sharpee media subsystem.
|
|
4
|
+
*
|
|
5
|
+
* Public interface: Type aliases used throughout all audio event interfaces,
|
|
6
|
+
* the AudioRegistry, and capability negotiation.
|
|
7
|
+
*
|
|
8
|
+
* Owner context: @sharpee/media (ADR-138)
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../repos/sharpee/packages/media/src/audio/types.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sharpee/media — Audio and media type definitions for the Sharpee IF platform.
|
|
3
|
+
*
|
|
4
|
+
* Public interface: Re-exports all audio types, event interfaces, registry,
|
|
5
|
+
* and capability/preference types from the audio module.
|
|
6
|
+
*
|
|
7
|
+
* Owner context: Media subsystem (ADR-138). Types-only package with no
|
|
8
|
+
* runtime dependencies beyond @sharpee/core.
|
|
9
|
+
*
|
|
10
|
+
* Importing this module activates TypeScript declaration merging for
|
|
11
|
+
* audio event keys in @sharpee/core's EventDataRegistry.
|
|
12
|
+
*/
|
|
13
|
+
export * from './audio';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
package/index.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../repos/sharpee/packages/media/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,cAAc,SAAS,CAAC"}
|
package/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
/**
|
|
18
|
+
* @sharpee/media — Audio and media type definitions for the Sharpee IF platform.
|
|
19
|
+
*
|
|
20
|
+
* Public interface: Re-exports all audio types, event interfaces, registry,
|
|
21
|
+
* and capability/preference types from the audio module.
|
|
22
|
+
*
|
|
23
|
+
* Owner context: Media subsystem (ADR-138). Types-only package with no
|
|
24
|
+
* runtime dependencies beyond @sharpee/core.
|
|
25
|
+
*
|
|
26
|
+
* Importing this module activates TypeScript declaration merging for
|
|
27
|
+
* audio event keys in @sharpee/core's EventDataRegistry.
|
|
28
|
+
*/
|
|
29
|
+
__exportStar(require("./audio"), exports);
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/media/src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;GAWG;AACH,0CAAwB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sharpee/media",
|
|
3
|
+
"version": "0.9.100",
|
|
4
|
+
"description": "Audio and media type definitions for Sharpee Interactive Fiction Platform",
|
|
5
|
+
"main": "./index.js",
|
|
6
|
+
"types": "./index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./index.d.ts",
|
|
10
|
+
"require": "./index.js",
|
|
11
|
+
"default": "./index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@sharpee/core": "^0.9.100"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"interactive-fiction",
|
|
19
|
+
"if",
|
|
20
|
+
"text-adventure",
|
|
21
|
+
"sharpee",
|
|
22
|
+
"media",
|
|
23
|
+
"audio"
|
|
24
|
+
],
|
|
25
|
+
"author": "Sharpee Team",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/ChicagoDave/sharpee.git",
|
|
30
|
+
"directory": "packages/media"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/ChicagoDave/sharpee#readme",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/ChicagoDave/sharpee/issues"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18.0.0"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
}
|
|
42
|
+
}
|