@sagl/server 0.0.0-stage → 0.1.0-next.51
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/LICENSE +21 -0
- package/README.md +61 -2
- package/dist/actions.d.ts +46 -0
- package/dist/actions.js +80 -0
- package/dist/actions.js.map +1 -0
- package/dist/animations.d.ts +32 -0
- package/dist/animations.js +95 -0
- package/dist/animations.js.map +1 -0
- package/dist/audio.d.ts +180 -0
- package/dist/audio.js +353 -0
- package/dist/audio.js.map +1 -0
- package/dist/audio_effects.d.ts +219 -0
- package/dist/audio_effects.js +84 -0
- package/dist/audio_effects.js.map +1 -0
- package/dist/camera.d.ts +188 -0
- package/dist/camera.js +247 -0
- package/dist/camera.js.map +1 -0
- package/dist/claims.d.ts +27 -0
- package/dist/claims.js +48 -0
- package/dist/claims.js.map +1 -0
- package/dist/commands.d.ts +135 -0
- package/dist/commands.js +373 -0
- package/dist/commands.js.map +1 -0
- package/dist/console.d.ts +21 -0
- package/dist/console.js +100 -0
- package/dist/console.js.map +1 -0
- package/dist/constants.d.ts +654 -0
- package/dist/constants.js +657 -0
- package/dist/constants.js.map +1 -0
- package/dist/cutscene.d.ts +47 -0
- package/dist/cutscene.js +190 -0
- package/dist/cutscene.js.map +1 -0
- package/dist/draw.d.ts +106 -0
- package/dist/draw.js +132 -0
- package/dist/draw.js.map +1 -0
- package/dist/effects.d.ts +91 -0
- package/dist/effects.js +116 -0
- package/dist/effects.js.map +1 -0
- package/dist/gangzones.d.ts +47 -0
- package/dist/gangzones.js +122 -0
- package/dist/gangzones.js.map +1 -0
- package/dist/geo.d.ts +11 -0
- package/dist/geo.js +25 -0
- package/dist/geo.js.map +1 -0
- package/dist/hud.d.ts +159 -0
- package/dist/hud.js +247 -0
- package/dist/hud.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction.d.ts +81 -0
- package/dist/interaction.js +143 -0
- package/dist/interaction.js.map +1 -0
- package/dist/junctions.d.ts +1 -0
- package/dist/junctions.js +330 -0
- package/dist/junctions.js.map +1 -0
- package/dist/map.d.ts +55 -0
- package/dist/map.js +71 -0
- package/dist/map.js.map +1 -0
- package/dist/menu.d.ts +96 -0
- package/dist/menu.js +129 -0
- package/dist/menu.js.map +1 -0
- package/dist/mission.d.ts +482 -0
- package/dist/mission.js +1258 -0
- package/dist/mission.js.map +1 -0
- package/dist/models.d.ts +56 -0
- package/dist/models.js +71 -0
- package/dist/models.js.map +1 -0
- package/dist/modshop.d.ts +229 -0
- package/dist/modshop.js +904 -0
- package/dist/modshop.js.map +1 -0
- package/dist/modshop_data.d.ts +44 -0
- package/dist/modshop_data.js +287 -0
- package/dist/modshop_data.js.map +1 -0
- package/dist/native.d.ts +809 -0
- package/dist/native.js +27 -0
- package/dist/native.js.map +1 -0
- package/dist/objects.d.ts +249 -0
- package/dist/objects.js +455 -0
- package/dist/objects.js.map +1 -0
- package/dist/paint.d.ts +124 -0
- package/dist/paint.js +84 -0
- package/dist/paint.js.map +1 -0
- package/dist/paynspray.d.ts +44 -0
- package/dist/paynspray.js +177 -0
- package/dist/paynspray.js.map +1 -0
- package/dist/ped.d.ts +335 -0
- package/dist/ped.js +536 -0
- package/dist/ped.js.map +1 -0
- package/dist/player.d.ts +685 -0
- package/dist/player.js +1163 -0
- package/dist/player.js.map +1 -0
- package/dist/screeneffects.d.ts +99 -0
- package/dist/screeneffects.js +257 -0
- package/dist/screeneffects.js.map +1 -0
- package/dist/scripts.d.ts +69 -0
- package/dist/scripts.js +125 -0
- package/dist/scripts.js.map +1 -0
- package/dist/server.d.ts +713 -0
- package/dist/server.js +1080 -0
- package/dist/server.js.map +1 -0
- package/dist/shopblips.d.ts +9 -0
- package/dist/shopblips.js +30 -0
- package/dist/shopblips.js.map +1 -0
- package/dist/special.d.ts +33 -0
- package/dist/special.js +26 -0
- package/dist/special.js.map +1 -0
- package/dist/splash.d.ts +42 -0
- package/dist/splash.js +55 -0
- package/dist/splash.js.map +1 -0
- package/dist/text.d.ts +19 -0
- package/dist/text.js +25 -0
- package/dist/text.js.map +1 -0
- package/dist/ui.d.ts +141 -0
- package/dist/ui.js +243 -0
- package/dist/ui.js.map +1 -0
- package/dist/vehicle.d.ts +306 -0
- package/dist/vehicle.js +612 -0
- package/dist/vehicle.js.map +1 -0
- package/dist/vehiclecolors.d.ts +26 -0
- package/dist/vehiclecolors.js +49 -0
- package/dist/vehiclecolors.js.map +1 -0
- package/dist/world.d.ts +222 -0
- package/dist/world.js +227 -0
- package/dist/world.js.map +1 -0
- package/dist/zone.d.ts +89 -0
- package/dist/zone.js +140 -0
- package/dist/zone.js.map +1 -0
- 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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"}
|