@sagl/server 0.0.0-stage → 0.1.0-next.49

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.
Files changed (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -2
  3. package/dist/actions.d.ts +46 -0
  4. package/dist/actions.js +80 -0
  5. package/dist/actions.js.map +1 -0
  6. package/dist/animations.d.ts +32 -0
  7. package/dist/animations.js +95 -0
  8. package/dist/animations.js.map +1 -0
  9. package/dist/audio.d.ts +180 -0
  10. package/dist/audio.js +353 -0
  11. package/dist/audio.js.map +1 -0
  12. package/dist/audio_effects.d.ts +219 -0
  13. package/dist/audio_effects.js +84 -0
  14. package/dist/audio_effects.js.map +1 -0
  15. package/dist/camera.d.ts +188 -0
  16. package/dist/camera.js +247 -0
  17. package/dist/camera.js.map +1 -0
  18. package/dist/claims.d.ts +27 -0
  19. package/dist/claims.js +48 -0
  20. package/dist/claims.js.map +1 -0
  21. package/dist/commands.d.ts +135 -0
  22. package/dist/commands.js +373 -0
  23. package/dist/commands.js.map +1 -0
  24. package/dist/console.d.ts +21 -0
  25. package/dist/console.js +100 -0
  26. package/dist/console.js.map +1 -0
  27. package/dist/constants.d.ts +654 -0
  28. package/dist/constants.js +657 -0
  29. package/dist/constants.js.map +1 -0
  30. package/dist/cutscene.d.ts +47 -0
  31. package/dist/cutscene.js +190 -0
  32. package/dist/cutscene.js.map +1 -0
  33. package/dist/draw.d.ts +106 -0
  34. package/dist/draw.js +132 -0
  35. package/dist/draw.js.map +1 -0
  36. package/dist/effects.d.ts +91 -0
  37. package/dist/effects.js +116 -0
  38. package/dist/effects.js.map +1 -0
  39. package/dist/gangzones.d.ts +47 -0
  40. package/dist/gangzones.js +122 -0
  41. package/dist/gangzones.js.map +1 -0
  42. package/dist/geo.d.ts +11 -0
  43. package/dist/geo.js +25 -0
  44. package/dist/geo.js.map +1 -0
  45. package/dist/hud.d.ts +159 -0
  46. package/dist/hud.js +247 -0
  47. package/dist/hud.js.map +1 -0
  48. package/dist/index.d.ts +40 -0
  49. package/dist/index.js +43 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/interaction.d.ts +81 -0
  52. package/dist/interaction.js +143 -0
  53. package/dist/interaction.js.map +1 -0
  54. package/dist/junctions.d.ts +1 -0
  55. package/dist/junctions.js +330 -0
  56. package/dist/junctions.js.map +1 -0
  57. package/dist/map.d.ts +55 -0
  58. package/dist/map.js +71 -0
  59. package/dist/map.js.map +1 -0
  60. package/dist/menu.d.ts +96 -0
  61. package/dist/menu.js +129 -0
  62. package/dist/menu.js.map +1 -0
  63. package/dist/mission.d.ts +482 -0
  64. package/dist/mission.js +1258 -0
  65. package/dist/mission.js.map +1 -0
  66. package/dist/models.d.ts +56 -0
  67. package/dist/models.js +71 -0
  68. package/dist/models.js.map +1 -0
  69. package/dist/modshop.d.ts +229 -0
  70. package/dist/modshop.js +904 -0
  71. package/dist/modshop.js.map +1 -0
  72. package/dist/modshop_data.d.ts +44 -0
  73. package/dist/modshop_data.js +287 -0
  74. package/dist/modshop_data.js.map +1 -0
  75. package/dist/native.d.ts +809 -0
  76. package/dist/native.js +27 -0
  77. package/dist/native.js.map +1 -0
  78. package/dist/objects.d.ts +249 -0
  79. package/dist/objects.js +455 -0
  80. package/dist/objects.js.map +1 -0
  81. package/dist/paint.d.ts +124 -0
  82. package/dist/paint.js +84 -0
  83. package/dist/paint.js.map +1 -0
  84. package/dist/paynspray.d.ts +44 -0
  85. package/dist/paynspray.js +177 -0
  86. package/dist/paynspray.js.map +1 -0
  87. package/dist/ped.d.ts +335 -0
  88. package/dist/ped.js +536 -0
  89. package/dist/ped.js.map +1 -0
  90. package/dist/player.d.ts +685 -0
  91. package/dist/player.js +1163 -0
  92. package/dist/player.js.map +1 -0
  93. package/dist/screeneffects.d.ts +99 -0
  94. package/dist/screeneffects.js +257 -0
  95. package/dist/screeneffects.js.map +1 -0
  96. package/dist/scripts.d.ts +69 -0
  97. package/dist/scripts.js +125 -0
  98. package/dist/scripts.js.map +1 -0
  99. package/dist/server.d.ts +713 -0
  100. package/dist/server.js +1080 -0
  101. package/dist/server.js.map +1 -0
  102. package/dist/shopblips.d.ts +9 -0
  103. package/dist/shopblips.js +30 -0
  104. package/dist/shopblips.js.map +1 -0
  105. package/dist/special.d.ts +33 -0
  106. package/dist/special.js +26 -0
  107. package/dist/special.js.map +1 -0
  108. package/dist/splash.d.ts +42 -0
  109. package/dist/splash.js +55 -0
  110. package/dist/splash.js.map +1 -0
  111. package/dist/text.d.ts +19 -0
  112. package/dist/text.js +25 -0
  113. package/dist/text.js.map +1 -0
  114. package/dist/ui.d.ts +141 -0
  115. package/dist/ui.js +243 -0
  116. package/dist/ui.js.map +1 -0
  117. package/dist/vehicle.d.ts +306 -0
  118. package/dist/vehicle.js +612 -0
  119. package/dist/vehicle.js.map +1 -0
  120. package/dist/vehiclecolors.d.ts +26 -0
  121. package/dist/vehiclecolors.js +49 -0
  122. package/dist/vehiclecolors.js.map +1 -0
  123. package/dist/world.d.ts +222 -0
  124. package/dist/world.js +227 -0
  125. package/dist/world.js.map +1 -0
  126. package/dist/zone.d.ts +89 -0
  127. package/dist/zone.js +140 -0
  128. package/dist/zone.js.map +1 -0
  129. package/package.json +33 -4
package/dist/audio.js ADDED
@@ -0,0 +1,353 @@
1
+ import { statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { Player } from "./player.js";
4
+ import { Vehicle } from "./vehicle.js";
5
+ import { encodeEffects } from "./audio_effects.js";
6
+ /** A sound playing (`server.audio.play()`). */
7
+ export class Sound {
8
+ id;
9
+ file;
10
+ /** How long the file plays (ms), read from the server's copy; undefined if it can't be read. */
11
+ duration;
12
+ /**
13
+ * Resolves when it's over: when it has played through (by its duration,
14
+ * from when the server sent it), or is stopped. A looping one, when
15
+ * stopped.
16
+ *
17
+ * ```ts
18
+ * await server.audio.play("audio/caller.mp3", { to: [player] }).done;
19
+ * ```
20
+ */
21
+ done;
22
+ #stop;
23
+ #playing = true;
24
+ #ended;
25
+ #timer = null;
26
+ /** @internal */
27
+ constructor(id, file, duration, loop, stop) {
28
+ this.id = id;
29
+ this.file = file;
30
+ this.duration = duration;
31
+ this.#stop = stop;
32
+ this.done = new Promise((resolve) => (this.#ended = resolve));
33
+ if (!loop && duration !== undefined) {
34
+ this.#timer = setTimeout(() => {
35
+ this.#playing = false;
36
+ this.#ended();
37
+ }, duration);
38
+ }
39
+ else if (!loop) {
40
+ // Unknown length: over as far as the server knows.
41
+ this.#playing = false;
42
+ this.#ended();
43
+ }
44
+ }
45
+ /** False once it has played through or been stopped. */
46
+ get playing() {
47
+ return this.#playing;
48
+ }
49
+ stop() {
50
+ if (!this.#playing)
51
+ return;
52
+ this.#playing = false;
53
+ if (this.#timer)
54
+ clearTimeout(this.#timer);
55
+ this.#stop(this);
56
+ this.#ended();
57
+ }
58
+ }
59
+ /**
60
+ * A line as subtitles: its sentences, short ones together, up to about
61
+ * `max` characters each (default 70).
62
+ */
63
+ export function splitSubtitles(text, max = 70) {
64
+ const out = [];
65
+ for (const s of text.split(/(?<=[.!?…])\s+/)) {
66
+ if (!s)
67
+ continue;
68
+ if (out.length && out[out.length - 1].length + s.length < max)
69
+ out[out.length - 1] += " " + s;
70
+ else
71
+ out.push(s);
72
+ }
73
+ return out;
74
+ }
75
+ /**
76
+ * Sounds from client files (MP3, WAV, FLAC) on players' games:
77
+ * `server.audio`. Positioned ones are heard from where they are, fading
78
+ * with distance, as the game's own sounds.
79
+ */
80
+ export class ServerAudio {
81
+ #native;
82
+ #players;
83
+ #next = 1;
84
+ /**
85
+ * The default for positioned sounds' `realism` (highs fading with
86
+ * distance, muffled behind buildings). Default false.
87
+ */
88
+ realism = false;
89
+ // Looping sounds for everyone, for players joining later.
90
+ #loops = new Map();
91
+ #heard = new Map();
92
+ #files;
93
+ #durations = new Map();
94
+ /** @internal */
95
+ constructor(native, players, clientFiles) {
96
+ this.#native = native;
97
+ this.#players = players;
98
+ this.#files = clientFiles;
99
+ }
100
+ /**
101
+ * How long a client file plays (ms), from the server's copy (the
102
+ * `clientFiles` directory); undefined if it isn't there or isn't a sound.
103
+ */
104
+ duration(file) {
105
+ if (!this.#files || file.includes(".."))
106
+ return undefined;
107
+ const path = join(this.#files, file);
108
+ let mtime;
109
+ try {
110
+ mtime = statSync(path).mtimeMs;
111
+ }
112
+ catch {
113
+ return undefined;
114
+ }
115
+ const known = this.#durations.get(file);
116
+ if (known && known.mtime === mtime)
117
+ return known.ms;
118
+ const ms = this.#native.audioDuration(path);
119
+ const result = ms >= 0 ? Math.round(ms) : undefined;
120
+ this.#durations.set(file, { mtime, ms: result });
121
+ return result;
122
+ }
123
+ /**
124
+ * Plays a recorded line with its subtitles timed to it, as speech (the
125
+ * radio ducks under it). `at` a ped or vehicle: from them (`muffled`:
126
+ * from inside the vehicle, through the glass).
127
+ *
128
+ * ```ts
129
+ * await server.audio.speak("audio/benny-my-car.mp3", { at: benny, subtitle: "My car! That's my car!" }).done;
130
+ * await server.audio.speak("audio/caller.mp3", { to: [player], effects: "phone", subtitle: lines, prefix: "~y~" }).done;
131
+ * ```
132
+ */
133
+ speak(file, options = {}) {
134
+ const { subtitle, subtitleTo, prefix = "", muffled, ...sound } = options;
135
+ const effects = muffled
136
+ ? [...(Array.isArray(sound.effects) ? sound.effects : sound.effects ? [sound.effects] : []),
137
+ { type: "lowpass", cutoff: 1400 }, { type: "gain", volume: 1.8 }]
138
+ : sound.effects;
139
+ const played = this.play(file, { ...sound, effects, speech: true, range: sound.range ?? (sound.at ? 45 : undefined) });
140
+ const ms = played.duration ?? 4000;
141
+ const lines = subtitle === undefined ? [] : typeof subtitle === "string" ? splitSubtitles(subtitle) : [...subtitle];
142
+ const total = lines.reduce((n, l) => n + l.length, 0) || 1;
143
+ const viewers = () => {
144
+ if (subtitleTo)
145
+ return subtitleTo.filter((p) => p.connected);
146
+ if (sound.to)
147
+ return sound.to.filter((p) => p.connected);
148
+ const at = sound.at;
149
+ if (!at)
150
+ return this.#players();
151
+ const pos = "position" in at ? at.position : at;
152
+ const range = sound.range ?? 45;
153
+ return this.#players().filter((p) => Math.hypot(p.position.x - pos.x, p.position.y - pos.y) <= range);
154
+ };
155
+ const timers = [];
156
+ let start = 0;
157
+ for (const line of lines) {
158
+ const share = Math.round((line.length / total) * ms);
159
+ timers.push(setTimeout(() => {
160
+ for (const p of viewers())
161
+ p.subtitle(prefix + line, share + 200);
162
+ }, start));
163
+ start += share;
164
+ }
165
+ let finish;
166
+ const done = new Promise((resolve) => (finish = resolve));
167
+ const end = setTimeout(() => finish(), ms + 200);
168
+ return {
169
+ sound: played,
170
+ done,
171
+ stop: () => {
172
+ for (const t of timers)
173
+ clearTimeout(t);
174
+ clearTimeout(end);
175
+ played.stop();
176
+ finish();
177
+ },
178
+ };
179
+ }
180
+ /**
181
+ * Plays a client file. `at` places it (a spot, or a ped, player or
182
+ * vehicle it follows); `to` picks who hears it.
183
+ *
184
+ * ```ts
185
+ * const ring = server.audio.play("audio/payphone-ring.mp3", { at: phone, loop: true, range: 25 });
186
+ * ring.stop();
187
+ * ```
188
+ */
189
+ play(file, options = {}) {
190
+ const id = this.#next++;
191
+ const spec = {
192
+ id, file, loop: options.loop ?? false, volume: options.volume ?? 1, effects: encodeEffects(options.effects),
193
+ realism: options.realism ?? this.realism, speech: options.speech ?? false,
194
+ };
195
+ const at = options.at;
196
+ if (at) {
197
+ spec.range = options.range ?? 30;
198
+ if (at instanceof Player)
199
+ Object.assign(spec, { on: 2, target: at.id });
200
+ else if (at instanceof Vehicle)
201
+ Object.assign(spec, { on: 3, target: at.id });
202
+ else if ("model" in at && "id" in at)
203
+ Object.assign(spec, { on: 1, target: at.id });
204
+ else
205
+ Object.assign(spec, { x: at.x, y: at.y, z: at.z });
206
+ }
207
+ const to = options.to ? options.to.filter((p) => p.connected).map((p) => p.id) : null;
208
+ for (const p of this.#players()) {
209
+ if (!to || to.includes(p.id))
210
+ this.#native.sound(p.id, spec);
211
+ }
212
+ this.#heard.set(id, to);
213
+ if (spec.loop && !to)
214
+ this.#loops.set(id, spec);
215
+ return new Sound(id, file, this.duration(file), spec.loop ?? false, (s) => {
216
+ this.#loops.delete(s.id);
217
+ const who = this.#heard.get(s.id);
218
+ this.#heard.delete(s.id);
219
+ for (const p of this.#players()) {
220
+ if (!who || who.includes(p.id))
221
+ this.#native.sound(p.id, { id: s.id, stop: true });
222
+ }
223
+ });
224
+ }
225
+ /**
226
+ * Plays one of the game's own sounds (see `GameSound`): a frontend one
227
+ * (the HUD's: pickups, the Pay 'n' Spray jingle), or, with `at`, one of
228
+ * the mission script's sounds at a spot. `to` picks who hears it
229
+ * (default everyone).
230
+ *
231
+ * ```ts
232
+ * server.audio.playGame(GameSound.CarRespray, { to: [player] });
233
+ * ```
234
+ */
235
+ playGame(sound, options = {}) {
236
+ if (!Number.isInteger(sound) || sound < 0)
237
+ throw new RangeError(`not a game sound: ${sound}`);
238
+ const at = options.at;
239
+ const spec = at ? { sound, atSpot: true, x: at.x, y: at.y, z: at.z } : { sound };
240
+ for (const p of options.to ?? this.#players()) {
241
+ if (p.connected)
242
+ this.#native.gameSound(p.id, spec);
243
+ }
244
+ }
245
+ /**
246
+ * Plays one of the game's mission audio, by its audio id: the recordings
247
+ * and effects its missions and machines load (a vending machine's clunk:
248
+ * 42600). From a player, ped or vehicle (following them), a spot, or
249
+ * (no `at`) as is. `to` picks who hears it (default everyone). Each
250
+ * game reads it from its own copy and plays it as the server's sounds,
251
+ * so `effects` work on it.
252
+ *
253
+ * ```ts
254
+ * server.audio.playMission(42600, { at: player });
255
+ * ```
256
+ */
257
+ playMission(id, options = {}) {
258
+ if (!Number.isInteger(id) || id < 0)
259
+ throw new RangeError(`not a mission audio id: ${id}`);
260
+ const at = options.at;
261
+ const spec = {
262
+ sound: id, mission: true, range: options.range ?? 30, effects: encodeEffects(options.effects),
263
+ realism: options.realism ?? this.realism,
264
+ };
265
+ if (at instanceof Player)
266
+ Object.assign(spec, { on: 2, target: at.id });
267
+ else if (at instanceof Vehicle)
268
+ Object.assign(spec, { on: 3, target: at.id });
269
+ else if (at && "model" in at && "id" in at)
270
+ Object.assign(spec, { on: 1, target: at.id });
271
+ else if (at)
272
+ Object.assign(spec, { atSpot: true, x: at.x, y: at.y, z: at.z });
273
+ for (const p of options.to ?? this.#players()) {
274
+ if (p.connected)
275
+ this.#native.gameSound(p.id, spec);
276
+ }
277
+ }
278
+ /**
279
+ * The effects every sound of the server's and its scripts' passes through
280
+ * for this player now: where they are (a hall's reverb, a tunnel's echo).
281
+ * `null`: none. The game's own world sounds aren't affected.
282
+ *
283
+ * ```ts
284
+ * server.audio.setEnvironment(player, "tunnel");
285
+ * ```
286
+ */
287
+ setEnvironment(player, effects) {
288
+ this.#chosen.set(player, effects ? encodeEffects(effects) : []);
289
+ this.#apply(player);
290
+ }
291
+ /**
292
+ * An environment for everyone inside a zone, while they're in it (the
293
+ * most recently entered, where zones overlap; one set with
294
+ * `setEnvironment` wins over all).
295
+ *
296
+ * ```ts
297
+ * server.audio.setZoneEnvironment(server.createZone({ ... }), "hall");
298
+ * ```
299
+ */
300
+ setZoneEnvironment(zone, effects) {
301
+ if (effects)
302
+ this.#zoneEnv.set(zone, encodeEffects(effects));
303
+ else
304
+ this.#zoneEnv.delete(zone);
305
+ for (const [player, zones] of this.#inZones)
306
+ if (zones.includes(zone))
307
+ this.#apply(player);
308
+ }
309
+ #chosen = new Map();
310
+ #zoneEnv = new Map();
311
+ #inZones = new Map();
312
+ #sent = new Map();
313
+ #apply(player) {
314
+ let effects = this.#chosen.get(player);
315
+ if (!effects || !effects.length) {
316
+ const zones = this.#inZones.get(player) ?? [];
317
+ effects = [];
318
+ for (let i = zones.length - 1; i >= 0; --i) {
319
+ const e = this.#zoneEnv.get(zones[i]);
320
+ if (e) {
321
+ effects = e;
322
+ break;
323
+ }
324
+ }
325
+ }
326
+ const key = JSON.stringify(effects);
327
+ if (this.#sent.get(player) === key || !player.connected)
328
+ return;
329
+ this.#sent.set(player, key);
330
+ this.#native.audioEnvironment(player.id, effects);
331
+ }
332
+ /** @internal */
333
+ zoneEvent(player, zone, entered) {
334
+ const zones = (this.#inZones.get(player) ?? []).filter((z) => z !== zone);
335
+ if (entered)
336
+ zones.push(zone);
337
+ this.#inZones.set(player, zones);
338
+ if (this.#zoneEnv.has(zone))
339
+ this.#apply(player);
340
+ }
341
+ /** @internal */
342
+ forget(player) {
343
+ this.#chosen.delete(player);
344
+ this.#inZones.delete(player);
345
+ this.#sent.delete(player);
346
+ }
347
+ /** @internal A player joined: the loops playing for everyone. */
348
+ replay(player) {
349
+ for (const spec of this.#loops.values())
350
+ this.#native.sound(player.id, spec);
351
+ }
352
+ }
353
+ //# sourceMappingURL=audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.js","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,219 @@
1
+ /**
2
+ * One stage of a sound's effects. Stages are layered in order, and each is
3
+ * mixed with what it was given by `mix` (0: none of it, 1: all of it), so
4
+ * any effect can be applied lightly or fully.
5
+ */
6
+ export type AudioEffect =
7
+ /** Cuts the highs above `cutoff` (Hz): muffled, through a wall. */
8
+ {
9
+ type: "lowpass";
10
+ cutoff: number;
11
+ mix?: number;
12
+ }
13
+ /** Cuts the lows below `cutoff` (Hz): thin, tinny. */
14
+ | {
15
+ type: "highpass";
16
+ cutoff: number;
17
+ mix?: number;
18
+ }
19
+ /** Keeps only `low`-`high` (Hz): a phone line, a radio. */
20
+ | {
21
+ type: "bandpass";
22
+ low: number;
23
+ high: number;
24
+ mix?: number;
25
+ }
26
+ /** Clipping, harsher with `drive` (0-1): a cheap speaker, a megaphone. */
27
+ | {
28
+ type: "distortion";
29
+ drive: number;
30
+ mix?: number;
31
+ }
32
+ /** Repeats after `delay` (s), each `decay` (0-1) as loud. Default mix 0.4, decay 0.4. */
33
+ | {
34
+ type: "echo";
35
+ delay: number;
36
+ decay?: number;
37
+ mix?: number;
38
+ }
39
+ /** A room's reverb: `size` (0-1) small room to cathedral, `damping` (0-1) bright to dull. Default mix 0.35. */
40
+ | {
41
+ type: "reverb";
42
+ size?: number;
43
+ damping?: number;
44
+ mix?: number;
45
+ }
46
+ /** Louder or quieter (1: as is, up to 4). */
47
+ | {
48
+ type: "gain";
49
+ volume: number;
50
+ };
51
+ /** The ready-made effects: name -> stages. */
52
+ export declare const AudioPresets: {
53
+ /** A phone line: thin, a little crackly. */
54
+ phone: ({
55
+ type: "bandpass";
56
+ low: number;
57
+ high: number;
58
+ drive?: undefined;
59
+ mix?: undefined;
60
+ volume?: undefined;
61
+ } | {
62
+ type: "distortion";
63
+ drive: number;
64
+ mix: number;
65
+ low?: undefined;
66
+ high?: undefined;
67
+ volume?: undefined;
68
+ } | {
69
+ type: "gain";
70
+ volume: number;
71
+ low?: undefined;
72
+ high?: undefined;
73
+ drive?: undefined;
74
+ mix?: undefined;
75
+ })[];
76
+ /** A two-way radio, a police scanner. */
77
+ radio: ({
78
+ type: "bandpass";
79
+ low: number;
80
+ high: number;
81
+ drive?: undefined;
82
+ mix?: undefined;
83
+ volume?: undefined;
84
+ } | {
85
+ type: "distortion";
86
+ drive: number;
87
+ mix: number;
88
+ low?: undefined;
89
+ high?: undefined;
90
+ volume?: undefined;
91
+ } | {
92
+ type: "gain";
93
+ volume: number;
94
+ low?: undefined;
95
+ high?: undefined;
96
+ drive?: undefined;
97
+ mix?: undefined;
98
+ })[];
99
+ /** A megaphone, a PA. */
100
+ megaphone: ({
101
+ type: "bandpass";
102
+ low: number;
103
+ high: number;
104
+ drive?: undefined;
105
+ mix?: undefined;
106
+ volume?: undefined;
107
+ } | {
108
+ type: "distortion";
109
+ drive: number;
110
+ mix: number;
111
+ low?: undefined;
112
+ high?: undefined;
113
+ volume?: undefined;
114
+ } | {
115
+ type: "gain";
116
+ volume: number;
117
+ low?: undefined;
118
+ high?: undefined;
119
+ drive?: undefined;
120
+ mix?: undefined;
121
+ })[];
122
+ /** Through a wall or a closed door. */
123
+ muffled: {
124
+ type: "lowpass";
125
+ cutoff: number;
126
+ }[];
127
+ /** Underwater. */
128
+ underwater: ({
129
+ type: "lowpass";
130
+ cutoff: number;
131
+ size?: undefined;
132
+ damping?: undefined;
133
+ mix?: undefined;
134
+ } | {
135
+ type: "reverb";
136
+ size: number;
137
+ damping: number;
138
+ mix: number;
139
+ cutoff?: undefined;
140
+ })[];
141
+ /** A small room. */
142
+ room: {
143
+ type: "reverb";
144
+ size: number;
145
+ damping: number;
146
+ mix: number;
147
+ }[];
148
+ /** A large hall, a warehouse. */
149
+ hall: {
150
+ type: "reverb";
151
+ size: number;
152
+ damping: number;
153
+ mix: number;
154
+ }[];
155
+ /** A cave. */
156
+ cave: ({
157
+ type: "reverb";
158
+ size: number;
159
+ damping: number;
160
+ mix: number;
161
+ delay?: undefined;
162
+ decay?: undefined;
163
+ } | {
164
+ type: "echo";
165
+ delay: number;
166
+ decay: number;
167
+ mix: number;
168
+ size?: undefined;
169
+ damping?: undefined;
170
+ })[];
171
+ /** A tunnel, a car park. */
172
+ tunnel: ({
173
+ type: "echo";
174
+ delay: number;
175
+ decay: number;
176
+ mix: number;
177
+ size?: undefined;
178
+ damping?: undefined;
179
+ } | {
180
+ type: "reverb";
181
+ size: number;
182
+ damping: number;
183
+ mix: number;
184
+ delay?: undefined;
185
+ decay?: undefined;
186
+ })[];
187
+ /** A canyon: a long, clear echo. */
188
+ canyon: {
189
+ type: "echo";
190
+ delay: number;
191
+ decay: number;
192
+ mix: number;
193
+ }[];
194
+ };
195
+ export type AudioPreset = keyof typeof AudioPresets;
196
+ /**
197
+ * A sound's effects: a preset, or a list of presets and stages layered in
198
+ * order. `{ preset, strength }` is a preset at a strength (0-1: each of its
199
+ * stages' mix scaled).
200
+ *
201
+ * ```ts
202
+ * "phone"
203
+ * ["phone", { type: "echo", delay: 0.3, mix: 0.2 }]
204
+ * [{ preset: "hall", strength: 0.5 }, { type: "lowpass", cutoff: 2000, mix: 0.5 }]
205
+ * ```
206
+ */
207
+ export type AudioEffects = AudioPreset | (AudioPreset | {
208
+ preset: AudioPreset;
209
+ strength?: number;
210
+ } | AudioEffect)[];
211
+ /** @internal As the client takes them: {kind, a, b, mix}, at most 8. */
212
+ export interface EncodedEffect {
213
+ kind: number;
214
+ a: number;
215
+ b: number;
216
+ mix: number;
217
+ }
218
+ /** @internal */
219
+ export declare function encodeEffects(effects: AudioEffects | undefined): EncodedEffect[] | undefined;
@@ -0,0 +1,84 @@
1
+ /** The ready-made effects: name -> stages. */
2
+ export const AudioPresets = {
3
+ /** A phone line: thin, a little crackly. */
4
+ phone: [
5
+ { type: "bandpass", low: 400, high: 3000 },
6
+ { type: "distortion", drive: 0.15, mix: 0.4 },
7
+ { type: "gain", volume: 1.4 },
8
+ ],
9
+ /** A two-way radio, a police scanner. */
10
+ radio: [
11
+ { type: "bandpass", low: 500, high: 4500 },
12
+ { type: "distortion", drive: 0.3, mix: 0.5 },
13
+ { type: "gain", volume: 1.3 },
14
+ ],
15
+ /** A megaphone, a PA. */
16
+ megaphone: [
17
+ { type: "bandpass", low: 800, high: 3500 },
18
+ { type: "distortion", drive: 0.6, mix: 0.8 },
19
+ { type: "gain", volume: 1.2 },
20
+ ],
21
+ /** Through a wall or a closed door. */
22
+ muffled: [{ type: "lowpass", cutoff: 500 }],
23
+ /** Underwater. */
24
+ underwater: [
25
+ { type: "lowpass", cutoff: 300 },
26
+ { type: "reverb", size: 0.5, damping: 0.9, mix: 0.3 },
27
+ ],
28
+ /** A small room. */
29
+ room: [{ type: "reverb", size: 0.3, damping: 0.5, mix: 0.2 }],
30
+ /** A large hall, a warehouse. */
31
+ hall: [{ type: "reverb", size: 0.8, damping: 0.3, mix: 0.4 }],
32
+ /** A cave. */
33
+ cave: [
34
+ { type: "reverb", size: 0.95, damping: 0.2, mix: 0.45 },
35
+ { type: "echo", delay: 0.25, decay: 0.3, mix: 0.25 },
36
+ ],
37
+ /** A tunnel, a car park. */
38
+ tunnel: [
39
+ { type: "echo", delay: 0.12, decay: 0.5, mix: 0.35 },
40
+ { type: "reverb", size: 0.6, damping: 0.4, mix: 0.25 },
41
+ ],
42
+ /** A canyon: a long, clear echo. */
43
+ canyon: [{ type: "echo", delay: 0.5, decay: 0.45, mix: 0.4 }],
44
+ };
45
+ const KINDS = { lowpass: 0, highpass: 1, bandpass: 2, distortion: 3, echo: 4, reverb: 5, gain: 6 };
46
+ const MAX_STAGES = 8;
47
+ function encodeOne(e, strength) {
48
+ const mix = (m, d) => Math.max(0, Math.min(1, (m ?? d) * strength));
49
+ switch (e.type) {
50
+ case "lowpass": return { kind: KINDS.lowpass, a: e.cutoff, b: 0, mix: mix(e.mix, 1) };
51
+ case "highpass": return { kind: KINDS.highpass, a: e.cutoff, b: 0, mix: mix(e.mix, 1) };
52
+ case "bandpass": return { kind: KINDS.bandpass, a: e.low, b: e.high, mix: mix(e.mix, 1) };
53
+ case "distortion": return { kind: KINDS.distortion, a: e.drive, b: 0, mix: mix(e.mix, 1) };
54
+ case "echo": return { kind: KINDS.echo, a: e.delay, b: e.decay ?? 0.4, mix: mix(e.mix, 0.4) };
55
+ case "reverb": return { kind: KINDS.reverb, a: e.size ?? 0.5, b: e.damping ?? 0.5, mix: mix(e.mix, 0.35) };
56
+ case "gain": return { kind: KINDS.gain, a: 1 + (e.volume - 1) * strength, b: 0, mix: 1 };
57
+ default: throw new TypeError(`not an audio effect: ${JSON.stringify(e)}`);
58
+ }
59
+ }
60
+ /** @internal */
61
+ export function encodeEffects(effects) {
62
+ if (effects === undefined)
63
+ return undefined;
64
+ const out = [];
65
+ const preset = (name, strength) => {
66
+ const stages = AudioPresets[name];
67
+ if (!stages)
68
+ throw new RangeError(`not an audio preset: "${name}" (${Object.keys(AudioPresets).join(", ")})`);
69
+ for (const s of stages)
70
+ out.push(encodeOne(s, strength));
71
+ };
72
+ for (const item of typeof effects === "string" ? [effects] : effects) {
73
+ if (typeof item === "string")
74
+ preset(item, 1);
75
+ else if ("preset" in item)
76
+ preset(item.preset, Math.max(0, Math.min(1, item.strength ?? 1)));
77
+ else
78
+ out.push(encodeOne(item, 1));
79
+ }
80
+ if (out.length > MAX_STAGES)
81
+ throw new RangeError(`at most ${MAX_STAGES} effect stages (presets count theirs)`);
82
+ return out;
83
+ }
84
+ //# sourceMappingURL=audio_effects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio_effects.js","sourceRoot":"","sources":["../src/audio_effects.ts"],"names":[],"mappings":"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"}