@primitiv/client 0.18.0
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.txt +285 -0
- package/README.md +34 -0
- package/dist/audio.cjs +1 -0
- package/dist/audio.d.ts +1 -0
- package/dist/audio.mjs +1 -0
- package/dist/core.cjs +4 -0
- package/dist/core.d.ts +1 -0
- package/dist/core.mjs +4 -0
- package/dist/index.cjs +204 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +204 -0
- package/dist/input.cjs +1 -0
- package/dist/input.d.ts +1 -0
- package/dist/input.mjs +1 -0
- package/dist/network.cjs +1 -0
- package/dist/network.d.ts +2 -0
- package/dist/network.mjs +1 -0
- package/dist/render.cjs +204 -0
- package/dist/render.d.ts +1 -0
- package/dist/render.mjs +204 -0
- package/dist/types.cjs +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.mjs +1 -0
- package/package.json +86 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
================================================================================
|
|
2
|
+
PRIMITIV ENGINE - END USER LICENSE AGREEMENT (EULA)
|
|
3
|
+
================================================================================
|
|
4
|
+
Version 1.1 - February 2026
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
1. DEFINITIONS
|
|
8
|
+
--------------
|
|
9
|
+
|
|
10
|
+
1.1 "Software" means the Primitiv Engine packages, including all compiled code,
|
|
11
|
+
documentation, and associated materials provided by Licensor.
|
|
12
|
+
|
|
13
|
+
1.2 "Licensor" means Thomas Piquet (THP Software), the copyright holder of the
|
|
14
|
+
Software.
|
|
15
|
+
|
|
16
|
+
1.3 "You" or "Licensee" means the individual or legal entity exercising rights
|
|
17
|
+
under this License.
|
|
18
|
+
|
|
19
|
+
1.4 "End Product" means a software application, game, developer tool,
|
|
20
|
+
framework, or specialized library (such as an NPM package) that
|
|
21
|
+
incorporates the Software as an integrated component and provides
|
|
22
|
+
independent functionality or vertical specialization beyond the
|
|
23
|
+
Software itself.
|
|
24
|
+
|
|
25
|
+
1.5 "Commercial Use" means use of the Software in any manner primarily intended
|
|
26
|
+
for commercial advantage or monetary compensation.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
2. ACCEPTANCE OF TERMS
|
|
30
|
+
----------------------
|
|
31
|
+
|
|
32
|
+
By downloading, installing, copying, or using the Software, You acknowledge that
|
|
33
|
+
You have read, understood, and agree to be bound by all terms of this Agreement.
|
|
34
|
+
If You do not agree, You are not authorized to use the Software.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
3. GRANT OF LICENSE
|
|
38
|
+
-------------------
|
|
39
|
+
|
|
40
|
+
3.1 Subject to compliance with this Agreement, Licensor grants You a worldwide,
|
|
41
|
+
royalty-free, non-exclusive, non-transferable license to:
|
|
42
|
+
|
|
43
|
+
(a) Use the Software to develop End Products;
|
|
44
|
+
(b) Distribute the Software solely as an integrated, functional component
|
|
45
|
+
of Your End Products;
|
|
46
|
+
(c) Use the Software for both personal and Commercial Use without additional
|
|
47
|
+
royalties or fees.
|
|
48
|
+
|
|
49
|
+
3.2 This license does not grant You any rights to patents, trademarks, or other
|
|
50
|
+
intellectual property of Licensor except as expressly stated herein.
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
4. RESTRICTIONS
|
|
54
|
+
---------------
|
|
55
|
+
|
|
56
|
+
4.1 You may NOT:
|
|
57
|
+
|
|
58
|
+
(a) Redistribute as Standalone: Distribute, sublicense, sell, rent, lease,
|
|
59
|
+
or lend the Software as a standalone product, library, or development
|
|
60
|
+
tool where the Software serves as the primary or sole feature.
|
|
61
|
+
|
|
62
|
+
(b) No Core Modifications: Alter, modify, adapt, translate, or create
|
|
63
|
+
derivative works of the distributed compiled files or the core
|
|
64
|
+
logic of the Software itself. You may NOT re-bundle, patch, or
|
|
65
|
+
re-distribute a modified version of the Primitiv Engine.
|
|
66
|
+
|
|
67
|
+
(c) Remove Notices: Remove, obscure, or alter any copyright notices,
|
|
68
|
+
trademarks, or proprietary rights notices contained in or on the
|
|
69
|
+
Software;
|
|
70
|
+
|
|
71
|
+
(d) Misrepresent Origin: Claim authorship of the Software or misrepresent
|
|
72
|
+
the origin of the Software in any way.
|
|
73
|
+
|
|
74
|
+
4.2 Reverse Engineering: Subject to applicable mandatory law, You agree not to
|
|
75
|
+
reverse engineer, decompile, disassemble, or otherwise attempt to derive
|
|
76
|
+
the source code, underlying algorithms, or structure of the Software.
|
|
77
|
+
This restriction does not apply where such activity is expressly permitted
|
|
78
|
+
by applicable law notwithstanding this limitation (such as interoperability
|
|
79
|
+
rights under EU Directive 2009/24/EC).
|
|
80
|
+
|
|
81
|
+
4.3 Permitted External Layers: You ARE permitted to develop and distribute
|
|
82
|
+
external software layers, "sur-moteurs" (wrapper engines), developer
|
|
83
|
+
tools, or specialized frameworks that interface with the Software,
|
|
84
|
+
provided that:
|
|
85
|
+
(i) Your product interacts with the Software's original, unmodified
|
|
86
|
+
compiled files (e.g., as a dependency or via an API);
|
|
87
|
+
(ii) Your product adds independent and distinct functionality or
|
|
88
|
+
specialization beyond the Software itself;
|
|
89
|
+
(iii) You do not modify the core Software files to achieve this.
|
|
90
|
+
|
|
91
|
+
4.4 Any modifications to Your own code that interfaces with the Software are
|
|
92
|
+
permitted and remain Your property.
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
5. OWNERSHIP AND INTELLECTUAL PROPERTY
|
|
96
|
+
--------------------------------------
|
|
97
|
+
|
|
98
|
+
5.1 The Software is licensed, not sold. Licensor retains all right, title, and
|
|
99
|
+
interest in and to the Software, including all intellectual property
|
|
100
|
+
rights therein.
|
|
101
|
+
|
|
102
|
+
5.2 This Agreement does not grant You any ownership rights in the Software.
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
6. OWNERSHIP OF END PRODUCTS
|
|
106
|
+
----------------------------
|
|
107
|
+
|
|
108
|
+
6.1 You retain full and exclusive ownership of Your End Products, including all
|
|
109
|
+
original code, assets, designs, and creative content You create.
|
|
110
|
+
|
|
111
|
+
6.2 Licensor claims no ownership rights over Your End Products.
|
|
112
|
+
|
|
113
|
+
6.3 You may license Your End Products under any terms You choose, including
|
|
114
|
+
open source or proprietary licenses.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
7. ATTRIBUTION
|
|
118
|
+
--------------
|
|
119
|
+
|
|
120
|
+
7.1 While not strictly mandatory, You are encouraged to include the following
|
|
121
|
+
notice in Your End Product's documentation or credits section (digital or
|
|
122
|
+
physical). Such attribution is greatly appreciated and helps support the
|
|
123
|
+
growth and visibility of the Primitiv Engine:
|
|
124
|
+
|
|
125
|
+
"Powered by Primitiv Engine - https://primitivengine.dev"
|
|
126
|
+
|
|
127
|
+
7.2 Naming and Branding: To avoid confusion of origin, You agree not to use
|
|
128
|
+
"Primitiv" as the leading or primary part of Your tool, framework, or
|
|
129
|
+
library's name. Descriptive terms such as "for Primitiv", "built with
|
|
130
|
+
Primitiv", or "powered by Primitiv" are encouraged.
|
|
131
|
+
|
|
132
|
+
(Example: "RTS Toolkit for Primitiv" is acceptable, whereas
|
|
133
|
+
"Primitiv RTS" is reserved for official modules).
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
8. WARRANTY DISCLAIMER
|
|
137
|
+
----------------------
|
|
138
|
+
|
|
139
|
+
8.1 THE SOFTWARE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY
|
|
140
|
+
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
|
141
|
+
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE,
|
|
142
|
+
AND NON-INFRINGEMENT.
|
|
143
|
+
|
|
144
|
+
8.2 LICENSOR MAKES NO WARRANTIES ABOUT:
|
|
145
|
+
|
|
146
|
+
(a) The accuracy, reliability, or completeness of the Software;
|
|
147
|
+
(b) That the Software will meet Your requirements or expectations;
|
|
148
|
+
(c) That the Software will operate uninterrupted, error-free, or secure;
|
|
149
|
+
(d) That defects will be corrected;
|
|
150
|
+
(e) That the Software is free from viruses or harmful components.
|
|
151
|
+
|
|
152
|
+
8.3 THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE REMAINS
|
|
153
|
+
WITH YOU.
|
|
154
|
+
|
|
155
|
+
8.4 Some jurisdictions do not allow the exclusion of implied warranties. In such
|
|
156
|
+
jurisdictions, the above exclusions may not apply to You.
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
9. LIMITATION OF LIABILITY
|
|
160
|
+
--------------------------
|
|
161
|
+
|
|
162
|
+
9.1 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, LICENSOR SHALL NOT BE
|
|
163
|
+
LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES
|
|
164
|
+
FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS
|
|
165
|
+
INFORMATION, LOSS OF DATA, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE
|
|
166
|
+
USE OF OR INABILITY TO USE THE SOFTWARE, EVEN IF LICENSOR HAS BEEN ADVISED
|
|
167
|
+
OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
168
|
+
|
|
169
|
+
9.2 IN JURISDICTIONS THAT DO NOT ALLOW THE COMPLETE EXCLUSION OR LIMITATION OF
|
|
170
|
+
LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, LICENSOR'S LIABILITY IS
|
|
171
|
+
LIMITED TO THE GREATEST EXTENT PERMITTED BY LAW.
|
|
172
|
+
|
|
173
|
+
9.3 NOTWITHSTANDING ANY OTHER PROVISION OF THIS AGREEMENT, AND TO THE EXTENT
|
|
174
|
+
PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL LICENSOR'S TOTAL CUMULATIVE
|
|
175
|
+
LIABILITY UNDER THIS AGREEMENT EXCEED FIFTY EUROS (50 EUR). Given that the
|
|
176
|
+
Software is provided at no charge, You acknowledge that this cap represents
|
|
177
|
+
a reasonable allocation of risk between the parties.
|
|
178
|
+
|
|
179
|
+
9.4 THE LIMITATIONS IN THIS SECTION 9 SHALL APPLY EVEN IF ANY REMEDY FAILS OF
|
|
180
|
+
ITS ESSENTIAL PURPOSE.
|
|
181
|
+
|
|
182
|
+
9.5 Some jurisdictions do not allow the exclusion or limitation of certain
|
|
183
|
+
warranties or liabilities. In such cases, Licensor's liability shall be
|
|
184
|
+
limited to the maximum extent permitted by law.
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
10. TERMINATION
|
|
188
|
+
---------------
|
|
189
|
+
|
|
190
|
+
10.1 This License is effective until terminated.
|
|
191
|
+
|
|
192
|
+
10.2 Your rights under this License will terminate automatically without notice
|
|
193
|
+
if You fail to comply with any term of this Agreement.
|
|
194
|
+
|
|
195
|
+
10.3 Licensor may terminate this License immediately upon written notice if You
|
|
196
|
+
breach any material term and fail to cure such breach within thirty (30)
|
|
197
|
+
days of receiving notice.
|
|
198
|
+
|
|
199
|
+
10.4 Upon termination for breach of contract, You must:
|
|
200
|
+
|
|
201
|
+
(a) Cease all use of the Software;
|
|
202
|
+
(b) Destroy or remove all copies of the Software in Your possession or
|
|
203
|
+
control.
|
|
204
|
+
|
|
205
|
+
10.5 Safe Harbor for Ongoing Projects:
|
|
206
|
+
(a) In the event of general discontinuance of the Software by the
|
|
207
|
+
Licensor or cancellation of this License for reasons other than
|
|
208
|
+
Your breach of contract, any End Products that are already completed
|
|
209
|
+
or actively in development at the time may continue to include and
|
|
210
|
+
use the Software. However, You may not start development of NEW
|
|
211
|
+
End Products using the Software after the date of discontinuance.
|
|
212
|
+
(b) This Safe Harbor does NOT apply if Your License is terminated due
|
|
213
|
+
to Your breach of any material term of this Agreement (Section 10.4).
|
|
214
|
+
In such cases, all rights to use the Software cease immediately.
|
|
215
|
+
|
|
216
|
+
10.6 Sections 5, 6, 8, 9, 11, and 12 shall survive termination.
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
11. UPDATES AND SUPPORT
|
|
220
|
+
-----------------------
|
|
221
|
+
|
|
222
|
+
11.1 Licensor is under no obligation to provide updates, upgrades, support,
|
|
223
|
+
maintenance, or bug fixes for the Software.
|
|
224
|
+
|
|
225
|
+
11.2 Any updates provided shall be considered part of the Software and subject
|
|
226
|
+
to this Agreement unless accompanied by a separate license.
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
12. GENERAL PROVISIONS
|
|
230
|
+
----------------------
|
|
231
|
+
|
|
232
|
+
12.1 Governing Law: This Agreement shall be governed by and construed in
|
|
233
|
+
accordance with the laws of France, without regard to its conflict of
|
|
234
|
+
law provisions.
|
|
235
|
+
|
|
236
|
+
12.2 Jurisdiction: Any disputes arising from this Agreement shall be subject
|
|
237
|
+
to the exclusive jurisdiction of the courts located in France.
|
|
238
|
+
|
|
239
|
+
12.3 Severability: If any provision of this Agreement is held to be invalid or
|
|
240
|
+
unenforceable, the remaining provisions shall continue in full force and
|
|
241
|
+
effect, and the invalid or unenforceable provision shall be deemed
|
|
242
|
+
modified to the minimum extent necessary to make it valid and enforceable.
|
|
243
|
+
|
|
244
|
+
12.4 Entire Agreement: This Agreement constitutes the entire agreement between
|
|
245
|
+
You and Licensor concerning the Software and supersedes all prior
|
|
246
|
+
agreements and understandings, whether written or oral.
|
|
247
|
+
|
|
248
|
+
12.5 Waiver: No waiver of any provision of this Agreement shall be deemed or
|
|
249
|
+
shall constitute a waiver of any other provision, nor shall any waiver
|
|
250
|
+
constitute a continuing waiver unless expressly provided in writing.
|
|
251
|
+
|
|
252
|
+
12.6 Assignment: You may not assign or transfer this License or any rights
|
|
253
|
+
granted hereunder without prior written consent of Licensor. Any attempted
|
|
254
|
+
assignment in violation of this provision is void. Licensor may assign
|
|
255
|
+
this Agreement without restriction.
|
|
256
|
+
|
|
257
|
+
12.7 Export Compliance: You agree to comply with all applicable export and
|
|
258
|
+
import laws and regulations in Your use of the Software.
|
|
259
|
+
|
|
260
|
+
12.8 Amendments: Licensor reserves the right to modify this Agreement for
|
|
261
|
+
future versions of the Software. Continued use of updated versions
|
|
262
|
+
constitutes acceptance of the revised terms. Your use of any specific
|
|
263
|
+
version is governed by the Agreement in effect at the time of download.
|
|
264
|
+
|
|
265
|
+
12.9 Force Majeure: Licensor shall not be liable for any failure or delay in
|
|
266
|
+
performance under this Agreement due to causes beyond its reasonable
|
|
267
|
+
control.
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
13. CONTACT INFORMATION
|
|
271
|
+
-----------------------
|
|
272
|
+
|
|
273
|
+
For questions regarding this License, please contact:
|
|
274
|
+
|
|
275
|
+
THP Software
|
|
276
|
+
Author: Thomas Piquet
|
|
277
|
+
Website: https://primitivengine.dev
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
BY USING THE SOFTWARE, YOU ACKNOWLEDGE THAT YOU HAVE READ THIS AGREEMENT,
|
|
281
|
+
UNDERSTAND IT, AND AGREE TO BE BOUND BY ITS TERMS AND CONDITIONS.
|
|
282
|
+
|
|
283
|
+
--------------------------------------------------------------------------------
|
|
284
|
+
(c) 2026 Thomas Piquet (THP Software). All rights reserved.
|
|
285
|
+
================================================================================
|
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# @primitiv/client
|
|
2
|
+
|
|
3
|
+
> **Status: Prototype** — API is unstable and may change between minor versions.
|
|
4
|
+
|
|
5
|
+
Browser-side runtime for the Primitiv engine. Provides rendering (Canvas 2D & WebGL), audio, input handling and networking for multiplayer games.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @primitiv/client
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @primitiv/client
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { ClientRuntime } from '@primitiv/client';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Subpath exports
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { Engine, Display, User } from '@primitiv/client/core';
|
|
25
|
+
import { Vector2, ScalingMode } from '@primitiv/client/types';
|
|
26
|
+
import { NetworkClient } from '@primitiv/client/network';
|
|
27
|
+
import { AudioEngine, SoundBank } from '@primitiv/client/audio';
|
|
28
|
+
import { Inputs, KeyboardInputs } from '@primitiv/client/input';
|
|
29
|
+
import { Terminal2D, TerminalGL } from '@primitiv/client/render';
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## License
|
|
33
|
+
|
|
34
|
+
See [LICENSE.txt](./LICENSE.txt).
|
package/dist/audio.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var y=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var P=(e,t)=>{for(var i in t)y(e,i,{get:t[i],enumerable:!0})},q=(e,t,i,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of L(t))!F.call(e,n)&&n!==i&&y(e,n,{get:()=>t[n],enumerable:!(s=E(t,n))||s.enumerable});return e};var H=e=>q(y({},"__esModule",{value:!0}),e);var ie={};P(ie,{AudioEngine:()=>te,ManagedSource:()=>D,RetroTones:()=>R,SoundBank:()=>M,SpatialProcessor:()=>G});module.exports=H(ie);var v={trace:0,debug:1,info:2,warn:3,error:4,silent:5},u=[],T="info",w=new Map,d=new Map,O=typeof performance<"u"&&typeof performance.now=="function"?()=>performance.now():()=>Date.now(),x=null;function A(e){let t=null,i=-1;for(let[s,n]of w)if(z(s,e)){let a=s.length;a>i&&(i=a,t=n)}return t??T}function z(e,t){if(e==="*")return!0;if(e.endsWith(":*")){let i=e.slice(0,-1);return t===e.slice(0,-2)||t.startsWith(i)}return e===t}function N(){for(let[e,t]of d)t.c(A(e))}var m=class p{namespace;r;i;s;constructor(t,i,s){this.namespace=t,this.i=i,this.s=s,this.r=v[A(t)]}static create(t){let i=d.get(t);return i||(i=new p(t),d.set(t,i)),i}child(t){return p.create(`${this.namespace}:${t}`)}forClient(t,i){let s=`${this.namespace}:client:${t}`,n=d.get(s);return n?(n.i=t,n.s=i):(n=new p(s,t,i),d.set(s,n)),n}static dispose(t){d.delete(t)}trace(t,i){this.n("trace",t,i)}debug(t,i){this.n("debug",t,i)}info(t,i){this.n("info",t,i)}warn(t,i){this.n("warn",t,i)}error(t,i){this.n("error",t,i)}isEnabled(t){return v[t]>=this.r}c(t){this.r=v[t]}n(t,i,s){if(v[t]<this.r||u.length===0)return;let n=typeof i=="function"?i():i,a={timestamp:O(),level:t,namespace:this.namespace,message:n};x!==null&&(a.tick=x()),s!==void 0&&(a.data=s),this.i!==void 0&&(a.clientId=this.i),this.s!==void 0&&(a.username=this.s);for(let r=0;r<u.length;r++)u[r](a)}static setLevel(t,i){i===void 0?T=t:w.set(t,i),N()}static clearLevelOverrides(){w.clear(),N()}static enable(t){p.setLevel(t,"trace")}static disable(t){p.setLevel(t,"silent")}static addHandler(t){return u.push(t),()=>{let i=u.indexOf(t);i!==-1&&u.splice(i,1)}}static clearHandlers(){u.length=0}static get handlerCount(){return u.length}static setTickProvider(t){x=t}static reset(){u.length=0,w.clear(),d.clear(),T="info",x=null}},f="\x1B[0m",U={trace:"\x1B[90m",debug:"\x1B[36m",info:"\x1B[32m",warn:"\x1B[33m",error:"\x1B[31m"},j="\x1B[35m",$="\x1B[2m",X="\x1B[93m",Y={trace:"color:#888",debug:"color:#0cc",info:"color:#0a0",warn:"color:#cc0",error:"color:#c00;font-weight:bold"},W="color:#c0c;font-weight:bold",S="color:#888",J="color:#c90;font-weight:bold",I={trace:"debug",debug:"debug",info:"info",warn:"warn",error:"error"},K=typeof globalThis<"u"&&typeof globalThis.process=="object"&&typeof globalThis.process?.versions=="object";function b(e,t){return String(e).padStart(t,"0")}function C(e){let t=Math.floor(e/1e3)%60,i=Math.floor(e/6e4)%60,s=Math.floor(e%1e3);return`${b(i,2)}:${b(t,2)}.${b(s,3)}`}function V(e){return e.toUpperCase().padEnd(5)}function B(e){if(e.clientId===void 0)return"";let t=e.username?`/${e.username}`:"";return` [client:${e.clientId}${t}]`}function Q(e){let t=`${$}${C(e.timestamp)}${f}`,i=e.tick!==void 0?` ${X}#${e.tick}${f}`:"",s=`${U[e.level]}${V(e.level)}${f}`,n=`${j}${e.namespace}${f}`,a=e.clientId!==void 0?`${$}${B(e)}${f}`:"",r=I[e.level],o=`${t}${i} ${s} ${n}${a}`;e.data!==void 0?console[r](o,e.message,e.data):console[r](o,e.message)}function Z(e){let t=I[e.level],i=B(e),s=e.tick!==void 0?` %c#${e.tick}`:"",n=e.tick!==void 0?[J]:[],a=`%c${C(e.timestamp)}${s} %c${V(e.level)} %c${e.namespace}%c${i} %c${e.message}`,r=[S,...n,Y[e.level],W,S,""];e.data!==void 0?console[t](a,...r,e.data):console[t](a,...r)}var _=K?Q:Z;m.handlerCount===0&&m.addHandler(_);var k=m.create("audio:soundbank"),M=class{sounds=new Map;nameToId=new Map;audioContext;constructor(e){this.audioContext=e}async loadFromData(e,t,i){try{let s=await this.audioContext.decodeAudioData(i.buffer);this.store(e,t,s)}catch(s){throw k.error(`Failed to decode sound "${t}" (${e})`,s),s}}async loadFromUrl(e,t,i){try{let s=await(await fetch(i)).arrayBuffer(),n=await this.audioContext.decodeAudioData(s);this.store(e,t,n)}catch(s){throw k.error(`Failed to load sound "${t}" from URL ${i}`,s),s}}store(e,t,i){this.sounds.set(e,i),this.nameToId.set(t,e)}get(e){if(typeof e=="number")return this.sounds.get(e);let t=this.nameToId.get(e);return t!==void 0?this.sounds.get(t):void 0}has(e){return this.get(e)!==void 0}clear(){this.sounds.clear(),this.nameToId.clear()}getAll(){let e=[],t=new Map;for(let[i,s]of this.nameToId)t.set(s,i);for(let[i,s]of this.sounds)e.push({soundId:i,name:t.get(i)??`Sound ${i}`,duration:s.duration});return e}},D=class{instanceId;soundId;name;source;gainNode;pannerNode;lowpassNode;highpassNode;reverbSend;audioContext;destination;t=!1;i=!1;e=1;n=1;position;onEnded;constructor(e,t,i,s,n,a={}){this.audioContext=e,this.instanceId=t,this.soundId=i,this.name=a.name??"",this.destination=n,this.e=a.volume??1,this.position=a.position,this.source=e.createBufferSource(),this.source.buffer=s,this.source.loop=a.loop??!1,this.source.playbackRate.value=a.pitch??1,this.gainNode=e.createGain();let r=a.fadeIn??0;r>0?(this.gainNode.gain.setValueAtTime(0,e.currentTime),this.gainNode.gain.linearRampToValueAtTime(this.e,e.currentTime+r)):this.gainNode.gain.value=this.e,a.position&&(this.pannerNode=e.createStereoPanner()),this.source.connect(this.gainNode),this.pannerNode?(this.gainNode.connect(this.pannerNode),this.pannerNode.connect(this.destination)):this.gainNode.connect(this.destination),a.reverbNode&&(this.reverbSend=e.createGain(),this.reverbSend.gain.value=a.reverb??0,this.gainNode.connect(this.reverbSend),this.reverbSend.connect(a.reverbNode)),a.lowpass&&this.setLowpass(a.lowpass),a.highpass&&this.setHighpass(a.highpass),this.source.onended=()=>{this.i||(this.t=!0,this.onEnded?.())}}start(e=0){this.source.start(0,e)}stop(e=0){this.t||(e>0?(this.gainNode.gain.linearRampToValueAtTime(0,this.audioContext.currentTime+e),setTimeout(()=>this.internalStop(),e*1e3)):this.internalStop())}internalStop(){try{this.source.stop()}catch{}this.t=!0,this.onEnded?.()}setVolume(e,t=0){this.e=e,this.updateTotalVolume(t)}setSpatialVolume(e){this.n=e,this.updateTotalVolume()}updateTotalVolume(e=0){let t=this.e*this.n;e>0?this.gainNode.gain.linearRampToValueAtTime(t,this.audioContext.currentTime+e):this.gainNode.gain.setValueAtTime(t,this.audioContext.currentTime)}setPan(e){this.pannerNode&&this.pannerNode.pan.setValueAtTime(e,this.audioContext.currentTime)}setPitch(e){this.source.playbackRate.setValueAtTime(e,this.audioContext.currentTime)}setLowpass(e){e<=0?this.lowpassNode=void 0:(this.lowpassNode||(this.lowpassNode=this.audioContext.createBiquadFilter(),this.lowpassNode.type="lowpass"),this.lowpassNode.frequency.setValueAtTime(e,this.audioContext.currentTime)),this.updateChain()}setHighpass(e){e<=0?this.highpassNode=void 0:(this.highpassNode||(this.highpassNode=this.audioContext.createBiquadFilter(),this.highpassNode.type="highpass"),this.highpassNode.frequency.setValueAtTime(e,this.audioContext.currentTime)),this.updateChain()}updateChain(){this.source.disconnect(),this.lowpassNode&&this.lowpassNode.disconnect(),this.highpassNode&&this.highpassNode.disconnect();let e=this.source;this.lowpassNode&&(e.connect(this.lowpassNode),e=this.lowpassNode),this.highpassNode&&(e.connect(this.highpassNode),e=this.highpassNode),e.connect(this.gainNode),this.reverbSend&&this.gainNode.connect(this.reverbSend)}setReverb(e){this.reverbSend&&this.reverbSend.gain.setTargetAtTime(e,this.audioContext.currentTime,.1)}isPlaying(){return!this.t&&!this.i}},G=class{config={listenerX:0,listenerY:0,maxDistance:200,referenceDistance:20,rolloffFactor:1,panSpread:1};configure(e){e.maxDistance!==void 0&&(this.config.maxDistance=e.maxDistance),e.referenceDistance!==void 0&&(this.config.referenceDistance=e.referenceDistance),e.rolloffFactor!==void 0&&(this.config.rolloffFactor=e.rolloffFactor),e.panSpread!==void 0&&(this.config.panSpread=e.panSpread)}setListenerPosition(e,t){this.config.listenerX=e,this.config.listenerY=t}getConfig(){return this.config}calculate2D(e,t){let{listenerX:i,listenerY:s,maxDistance:n,referenceDistance:a,panSpread:r}=this.config,o=e-i,c=t-s,l=Math.sqrt(o*o+c*c),h;l<=a?h=1:l>=n?h=0:h=1-(l-a)/(n-a);let g=0;return n>0&&r>0&&(g=o/n*r,g=Math.max(-1,Math.min(1,g))),{pan:g,distanceVolume:h}}},R=class{static playStartSound(e,t){let i=e.currentTime,s=[261.63,329.63,392,523.25],n=.06,a=.07;s.forEach((r,o)=>{let c=i+o*a,l=e.createOscillator(),h=e.createGain();l.type="square",l.frequency.setValueAtTime(r,c),h.gain.setValueAtTime(0,c),h.gain.linearRampToValueAtTime(.2,c+.005),h.gain.setValueAtTime(.2,c+n-.01),h.gain.linearRampToValueAtTime(0,c+n),l.connect(h),h.connect(t),l.start(c),l.stop(c+n)})}static noteToFrequency(e){let t=/^([A-G])([#b]?)(\d)$/i,i=e.match(t);if(!i)return null;let[,s,n,a]=i,r=parseInt(a,10),o={C:0,D:2,E:4,F:5,G:7,A:9,B:11}[s.toUpperCase()];n==="#"?o+=1:n==="b"&&(o-=1);let c=o+(r+1)*12;return 440*Math.pow(2,(c-49)/12)}},ee=m.create("audio:engine"),te=class{ctx=null;masterGain=null;reverbBus=null;soundBank=null;spatial=new G;instances=new Map;nextInstanceId=1;onAudioEvent=null;initialize(){if(this.ctx)return!0;try{return this.ctx=new(window.AudioContext||window.webkitAudioContext),this.masterGain=this.ctx.createGain(),this.masterGain.connect(this.ctx.destination),this.ctx.state==="suspended"&&this.ctx.resume(),this.reverbBus=this.ctx.createConvolver(),this.reverbBus.buffer=this.createImpulseResponse(2,2),this.reverbBus.connect(this.masterGain),this.soundBank=new M(this.ctx),!0}catch(e){return ee.error("Failed to initialize",e),!1}}createImpulseResponse(e,t){if(!this.ctx)throw new Error("Context not initialized");let i=this.ctx.sampleRate,s=i*e,n=this.ctx.createBuffer(2,s,i);for(let a=0;a<2;a++){let r=n.getChannelData(a);for(let o=0;o<s;o++){let c=Math.pow(1-o/s,t);r[o]=(Math.random()*2-1)*c}}return n}getLoader(){return this.soundBank}setMasterVolume(e){this.masterGain&&(this.masterGain.gain.value=Math.max(0,Math.min(1,e)))}getMasterVolume(){return this.masterGain?.gain.value??1}play(e,t={}){if(!this.ctx||!this.masterGain||!this.soundBank)return null;let i=this.soundBank.get(e);if(!i)return null;let s=t.instanceId??this.nextInstanceId++,n=typeof e=="number"?e:-1,a=new D(this.ctx,s,n,i,this.masterGain,{...t,name:t.name??(typeof e=="string"?e:""),reverbNode:this.reverbBus||void 0});if(t.position){let{pan:r,distanceVolume:o}=this.spatial.calculate2D(t.position.x,t.position.y);a.setSpatialVolume(o),a.setPan(r)}return a.onEnded=()=>{this.onAudioEvent?.({type:"playback-ended",instanceId:s,soundId:n}),this.instances.delete(s)},this.instances.set(s,a),a.start(),this.onAudioEvent?.({type:"playback-started",instanceId:s,soundId:n}),{instanceId:s}}stop(e){if(typeof e=="number"){let t=this.instances.get(e);if(t)return t.stop(),1}else{let t=0;for(let i of this.instances.values())(e==="all"||i.name===e)&&(i.stop(),t++);return t}return 0}stopAll(){let e=this.instances.size;return this.instances.forEach(t=>t.stop()),this.instances.clear(),e}fadeOut(e,t){if(e==="all"){let i=this.instances.size;return this.instances.forEach(s=>s.stop(t)),i}if(typeof e=="number"){let i=this.instances.get(e);if(i)return i.stop(t),1}return 0}pause(e){return 0}resume(e){return 0}setListenerPosition(e,t){this.spatial.setListenerPosition(e,t);for(let i of this.instances.values())if(i.position){let{pan:s,distanceVolume:n}=this.spatial.calculate2D(i.position.x,i.position.y);i.setPan(s),i.setSpatialVolume(n)}}configureSpatial(e){this.spatial.configure(e)}setEffects(e,t){let i=this.instances.get(e);i&&(t.lowpass!==void 0&&i.setLowpass(t.lowpass),t.highpass!==void 0&&i.setHighpass(t.highpass),t.reverb!==void 0&&i.setReverb(t.reverb),t.pitch!==void 0&&i.setPitch(t.pitch),t.volume!==void 0&&i.setVolume(t.volume))}stopBySoundId(e){let t=0;for(let i of this.instances.values())i.soundId===e&&(i.stop(),t++);return t}fadeOutBySoundId(e,t){let i=0;for(let s of this.instances.values())s.soundId===e&&(s.stop(t),i++);return i}pauseBySoundId(e){return 0}resumeBySoundId(e){return 0}playTone(e,t,i={}){if(!this.ctx||!this.masterGain)return;let{type:s="sine",volume:n=.3,attack:a=.01,release:r=.1}=i,o=this.ctx.currentTime,c=this.ctx.createOscillator();c.type=s,c.frequency.setValueAtTime(e,o);let l=this.ctx.createGain();l.gain.setValueAtTime(0,o),l.gain.linearRampToValueAtTime(n,o+a),l.gain.setValueAtTime(n,o+t-r),l.gain.linearRampToValueAtTime(0,o+t),c.connect(l),l.connect(this.masterGain),c.start(o),c.stop(o+t)}playStartSound(){this.ctx&&this.masterGain&&R.playStartSound(this.ctx,this.masterGain)}};
|
package/dist/audio.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@primitiv/audio';
|
package/dist/audio.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var v={trace:0,debug:1,info:2,warn:3,error:4,silent:5},u=[],b="info",w=new Map,d=new Map,k=typeof performance<"u"&&typeof performance.now=="function"?()=>performance.now():()=>Date.now(),x=null;function S(e){let t=null,i=-1;for(let[s,a]of w)if(M(s,e)){let n=s.length;n>i&&(i=n,t=a)}return t??b}function M(e,t){if(e==="*")return!0;if(e.endsWith(":*")){let i=e.slice(0,-1);return t===e.slice(0,-2)||t.startsWith(i)}return e===t}function T(){for(let[e,t]of d)t.c(S(e))}var m=class p{namespace;r;i;s;constructor(t,i,s){this.namespace=t,this.i=i,this.s=s,this.r=v[S(t)]}static create(t){let i=d.get(t);return i||(i=new p(t),d.set(t,i)),i}child(t){return p.create(`${this.namespace}:${t}`)}forClient(t,i){let s=`${this.namespace}:client:${t}`,a=d.get(s);return a?(a.i=t,a.s=i):(a=new p(s,t,i),d.set(s,a)),a}static dispose(t){d.delete(t)}trace(t,i){this.n("trace",t,i)}debug(t,i){this.n("debug",t,i)}info(t,i){this.n("info",t,i)}warn(t,i){this.n("warn",t,i)}error(t,i){this.n("error",t,i)}isEnabled(t){return v[t]>=this.r}c(t){this.r=v[t]}n(t,i,s){if(v[t]<this.r||u.length===0)return;let a=typeof i=="function"?i():i,n={timestamp:k(),level:t,namespace:this.namespace,message:a};x!==null&&(n.tick=x()),s!==void 0&&(n.data=s),this.i!==void 0&&(n.clientId=this.i),this.s!==void 0&&(n.username=this.s);for(let r=0;r<u.length;r++)u[r](n)}static setLevel(t,i){i===void 0?b=t:w.set(t,i),T()}static clearLevelOverrides(){w.clear(),T()}static enable(t){p.setLevel(t,"trace")}static disable(t){p.setLevel(t,"silent")}static addHandler(t){return u.push(t),()=>{let i=u.indexOf(t);i!==-1&&u.splice(i,1)}}static clearHandlers(){u.length=0}static get handlerCount(){return u.length}static setTickProvider(t){x=t}static reset(){u.length=0,w.clear(),d.clear(),b="info",x=null}},f="\x1B[0m",D={trace:"\x1B[90m",debug:"\x1B[36m",info:"\x1B[32m",warn:"\x1B[33m",error:"\x1B[31m"},G="\x1B[35m",N="\x1B[2m",R="\x1B[93m",E={trace:"color:#888",debug:"color:#0cc",info:"color:#0a0",warn:"color:#cc0",error:"color:#c00;font-weight:bold"},L="color:#c0c;font-weight:bold",$="color:#888",F="color:#c90;font-weight:bold",A={trace:"debug",debug:"debug",info:"info",warn:"warn",error:"error"},P=typeof globalThis<"u"&&typeof globalThis.process=="object"&&typeof globalThis.process?.versions=="object";function y(e,t){return String(e).padStart(t,"0")}function I(e){let t=Math.floor(e/1e3)%60,i=Math.floor(e/6e4)%60,s=Math.floor(e%1e3);return`${y(i,2)}:${y(t,2)}.${y(s,3)}`}function C(e){return e.toUpperCase().padEnd(5)}function V(e){if(e.clientId===void 0)return"";let t=e.username?`/${e.username}`:"";return` [client:${e.clientId}${t}]`}function q(e){let t=`${N}${I(e.timestamp)}${f}`,i=e.tick!==void 0?` ${R}#${e.tick}${f}`:"",s=`${D[e.level]}${C(e.level)}${f}`,a=`${G}${e.namespace}${f}`,n=e.clientId!==void 0?`${N}${V(e)}${f}`:"",r=A[e.level],o=`${t}${i} ${s} ${a}${n}`;e.data!==void 0?console[r](o,e.message,e.data):console[r](o,e.message)}function H(e){let t=A[e.level],i=V(e),s=e.tick!==void 0?` %c#${e.tick}`:"",a=e.tick!==void 0?[F]:[],n=`%c${I(e.timestamp)}${s} %c${C(e.level)} %c${e.namespace}%c${i} %c${e.message}`,r=[$,...a,E[e.level],L,$,""];e.data!==void 0?console[t](n,...r,e.data):console[t](n,...r)}var O=P?q:H;m.handlerCount===0&&m.addHandler(O);var B=m.create("audio:soundbank"),z=class{sounds=new Map;nameToId=new Map;audioContext;constructor(e){this.audioContext=e}async loadFromData(e,t,i){try{let s=await this.audioContext.decodeAudioData(i.buffer);this.store(e,t,s)}catch(s){throw B.error(`Failed to decode sound "${t}" (${e})`,s),s}}async loadFromUrl(e,t,i){try{let s=await(await fetch(i)).arrayBuffer(),a=await this.audioContext.decodeAudioData(s);this.store(e,t,a)}catch(s){throw B.error(`Failed to load sound "${t}" from URL ${i}`,s),s}}store(e,t,i){this.sounds.set(e,i),this.nameToId.set(t,e)}get(e){if(typeof e=="number")return this.sounds.get(e);let t=this.nameToId.get(e);return t!==void 0?this.sounds.get(t):void 0}has(e){return this.get(e)!==void 0}clear(){this.sounds.clear(),this.nameToId.clear()}getAll(){let e=[],t=new Map;for(let[i,s]of this.nameToId)t.set(s,i);for(let[i,s]of this.sounds)e.push({soundId:i,name:t.get(i)??`Sound ${i}`,duration:s.duration});return e}},U=class{instanceId;soundId;name;source;gainNode;pannerNode;lowpassNode;highpassNode;reverbSend;audioContext;destination;t=!1;i=!1;e=1;n=1;position;onEnded;constructor(e,t,i,s,a,n={}){this.audioContext=e,this.instanceId=t,this.soundId=i,this.name=n.name??"",this.destination=a,this.e=n.volume??1,this.position=n.position,this.source=e.createBufferSource(),this.source.buffer=s,this.source.loop=n.loop??!1,this.source.playbackRate.value=n.pitch??1,this.gainNode=e.createGain();let r=n.fadeIn??0;r>0?(this.gainNode.gain.setValueAtTime(0,e.currentTime),this.gainNode.gain.linearRampToValueAtTime(this.e,e.currentTime+r)):this.gainNode.gain.value=this.e,n.position&&(this.pannerNode=e.createStereoPanner()),this.source.connect(this.gainNode),this.pannerNode?(this.gainNode.connect(this.pannerNode),this.pannerNode.connect(this.destination)):this.gainNode.connect(this.destination),n.reverbNode&&(this.reverbSend=e.createGain(),this.reverbSend.gain.value=n.reverb??0,this.gainNode.connect(this.reverbSend),this.reverbSend.connect(n.reverbNode)),n.lowpass&&this.setLowpass(n.lowpass),n.highpass&&this.setHighpass(n.highpass),this.source.onended=()=>{this.i||(this.t=!0,this.onEnded?.())}}start(e=0){this.source.start(0,e)}stop(e=0){this.t||(e>0?(this.gainNode.gain.linearRampToValueAtTime(0,this.audioContext.currentTime+e),setTimeout(()=>this.internalStop(),e*1e3)):this.internalStop())}internalStop(){try{this.source.stop()}catch{}this.t=!0,this.onEnded?.()}setVolume(e,t=0){this.e=e,this.updateTotalVolume(t)}setSpatialVolume(e){this.n=e,this.updateTotalVolume()}updateTotalVolume(e=0){let t=this.e*this.n;e>0?this.gainNode.gain.linearRampToValueAtTime(t,this.audioContext.currentTime+e):this.gainNode.gain.setValueAtTime(t,this.audioContext.currentTime)}setPan(e){this.pannerNode&&this.pannerNode.pan.setValueAtTime(e,this.audioContext.currentTime)}setPitch(e){this.source.playbackRate.setValueAtTime(e,this.audioContext.currentTime)}setLowpass(e){e<=0?this.lowpassNode=void 0:(this.lowpassNode||(this.lowpassNode=this.audioContext.createBiquadFilter(),this.lowpassNode.type="lowpass"),this.lowpassNode.frequency.setValueAtTime(e,this.audioContext.currentTime)),this.updateChain()}setHighpass(e){e<=0?this.highpassNode=void 0:(this.highpassNode||(this.highpassNode=this.audioContext.createBiquadFilter(),this.highpassNode.type="highpass"),this.highpassNode.frequency.setValueAtTime(e,this.audioContext.currentTime)),this.updateChain()}updateChain(){this.source.disconnect(),this.lowpassNode&&this.lowpassNode.disconnect(),this.highpassNode&&this.highpassNode.disconnect();let e=this.source;this.lowpassNode&&(e.connect(this.lowpassNode),e=this.lowpassNode),this.highpassNode&&(e.connect(this.highpassNode),e=this.highpassNode),e.connect(this.gainNode),this.reverbSend&&this.gainNode.connect(this.reverbSend)}setReverb(e){this.reverbSend&&this.reverbSend.gain.setTargetAtTime(e,this.audioContext.currentTime,.1)}isPlaying(){return!this.t&&!this.i}},j=class{config={listenerX:0,listenerY:0,maxDistance:200,referenceDistance:20,rolloffFactor:1,panSpread:1};configure(e){e.maxDistance!==void 0&&(this.config.maxDistance=e.maxDistance),e.referenceDistance!==void 0&&(this.config.referenceDistance=e.referenceDistance),e.rolloffFactor!==void 0&&(this.config.rolloffFactor=e.rolloffFactor),e.panSpread!==void 0&&(this.config.panSpread=e.panSpread)}setListenerPosition(e,t){this.config.listenerX=e,this.config.listenerY=t}getConfig(){return this.config}calculate2D(e,t){let{listenerX:i,listenerY:s,maxDistance:a,referenceDistance:n,panSpread:r}=this.config,o=e-i,c=t-s,l=Math.sqrt(o*o+c*c),h;l<=n?h=1:l>=a?h=0:h=1-(l-n)/(a-n);let g=0;return a>0&&r>0&&(g=o/a*r,g=Math.max(-1,Math.min(1,g))),{pan:g,distanceVolume:h}}},X=class{static playStartSound(e,t){let i=e.currentTime,s=[261.63,329.63,392,523.25],a=.06,n=.07;s.forEach((r,o)=>{let c=i+o*n,l=e.createOscillator(),h=e.createGain();l.type="square",l.frequency.setValueAtTime(r,c),h.gain.setValueAtTime(0,c),h.gain.linearRampToValueAtTime(.2,c+.005),h.gain.setValueAtTime(.2,c+a-.01),h.gain.linearRampToValueAtTime(0,c+a),l.connect(h),h.connect(t),l.start(c),l.stop(c+a)})}static noteToFrequency(e){let t=/^([A-G])([#b]?)(\d)$/i,i=e.match(t);if(!i)return null;let[,s,a,n]=i,r=parseInt(n,10),o={C:0,D:2,E:4,F:5,G:7,A:9,B:11}[s.toUpperCase()];a==="#"?o+=1:a==="b"&&(o-=1);let c=o+(r+1)*12;return 440*Math.pow(2,(c-49)/12)}},Y=m.create("audio:engine"),Q=class{ctx=null;masterGain=null;reverbBus=null;soundBank=null;spatial=new j;instances=new Map;nextInstanceId=1;onAudioEvent=null;initialize(){if(this.ctx)return!0;try{return this.ctx=new(window.AudioContext||window.webkitAudioContext),this.masterGain=this.ctx.createGain(),this.masterGain.connect(this.ctx.destination),this.ctx.state==="suspended"&&this.ctx.resume(),this.reverbBus=this.ctx.createConvolver(),this.reverbBus.buffer=this.createImpulseResponse(2,2),this.reverbBus.connect(this.masterGain),this.soundBank=new z(this.ctx),!0}catch(e){return Y.error("Failed to initialize",e),!1}}createImpulseResponse(e,t){if(!this.ctx)throw new Error("Context not initialized");let i=this.ctx.sampleRate,s=i*e,a=this.ctx.createBuffer(2,s,i);for(let n=0;n<2;n++){let r=a.getChannelData(n);for(let o=0;o<s;o++){let c=Math.pow(1-o/s,t);r[o]=(Math.random()*2-1)*c}}return a}getLoader(){return this.soundBank}setMasterVolume(e){this.masterGain&&(this.masterGain.gain.value=Math.max(0,Math.min(1,e)))}getMasterVolume(){return this.masterGain?.gain.value??1}play(e,t={}){if(!this.ctx||!this.masterGain||!this.soundBank)return null;let i=this.soundBank.get(e);if(!i)return null;let s=t.instanceId??this.nextInstanceId++,a=typeof e=="number"?e:-1,n=new U(this.ctx,s,a,i,this.masterGain,{...t,name:t.name??(typeof e=="string"?e:""),reverbNode:this.reverbBus||void 0});if(t.position){let{pan:r,distanceVolume:o}=this.spatial.calculate2D(t.position.x,t.position.y);n.setSpatialVolume(o),n.setPan(r)}return n.onEnded=()=>{this.onAudioEvent?.({type:"playback-ended",instanceId:s,soundId:a}),this.instances.delete(s)},this.instances.set(s,n),n.start(),this.onAudioEvent?.({type:"playback-started",instanceId:s,soundId:a}),{instanceId:s}}stop(e){if(typeof e=="number"){let t=this.instances.get(e);if(t)return t.stop(),1}else{let t=0;for(let i of this.instances.values())(e==="all"||i.name===e)&&(i.stop(),t++);return t}return 0}stopAll(){let e=this.instances.size;return this.instances.forEach(t=>t.stop()),this.instances.clear(),e}fadeOut(e,t){if(e==="all"){let i=this.instances.size;return this.instances.forEach(s=>s.stop(t)),i}if(typeof e=="number"){let i=this.instances.get(e);if(i)return i.stop(t),1}return 0}pause(e){return 0}resume(e){return 0}setListenerPosition(e,t){this.spatial.setListenerPosition(e,t);for(let i of this.instances.values())if(i.position){let{pan:s,distanceVolume:a}=this.spatial.calculate2D(i.position.x,i.position.y);i.setPan(s),i.setSpatialVolume(a)}}configureSpatial(e){this.spatial.configure(e)}setEffects(e,t){let i=this.instances.get(e);i&&(t.lowpass!==void 0&&i.setLowpass(t.lowpass),t.highpass!==void 0&&i.setHighpass(t.highpass),t.reverb!==void 0&&i.setReverb(t.reverb),t.pitch!==void 0&&i.setPitch(t.pitch),t.volume!==void 0&&i.setVolume(t.volume))}stopBySoundId(e){let t=0;for(let i of this.instances.values())i.soundId===e&&(i.stop(),t++);return t}fadeOutBySoundId(e,t){let i=0;for(let s of this.instances.values())s.soundId===e&&(s.stop(t),i++);return i}pauseBySoundId(e){return 0}resumeBySoundId(e){return 0}playTone(e,t,i={}){if(!this.ctx||!this.masterGain)return;let{type:s="sine",volume:a=.3,attack:n=.01,release:r=.1}=i,o=this.ctx.currentTime,c=this.ctx.createOscillator();c.type=s,c.frequency.setValueAtTime(e,o);let l=this.ctx.createGain();l.gain.setValueAtTime(0,o),l.gain.linearRampToValueAtTime(a,o+n),l.gain.setValueAtTime(a,o+t-r),l.gain.linearRampToValueAtTime(0,o+t),c.connect(l),l.connect(this.masterGain),c.start(o),c.stop(o+t)}playStartSound(){this.ctx&&this.masterGain&&X.playStartSound(this.ctx,this.masterGain)}};export{Q as AudioEngine,U as ManagedSource,X as RetroTones,z as SoundBank,j as SpatialProcessor};
|