openaudio-suite 2.5.5 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +163 -109
- package/CONTRIBUTING.md +39 -324
- package/OpenAudio.js +314 -159
- package/OpenAudio_r.js +211 -164
- package/OpenAudio_s.js +420 -204
- package/README.md +142 -122
- package/docs/OPENAUDIO_R.md +135 -143
- package/docs/OPENAUDIO_S.md +162 -377
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,16 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
A family of **zero-dependency, browser-native audio utilities** for web projects. Choose the library that fits your use case.
|
|
4
4
|
|
|
5
|
-
[]()
|
|
5
|
+
[](https://github.com/Rexore/OpenAudio/blob/main/LICENSE)
|
|
6
|
+
[](https://github.com/Rexore/OpenAudio/blob/main)
|
|
7
|
+
[](https://www.npmjs.com/package/openaudio-suite)
|
|
8
|
+
[](https://www.npmjs.com/package/openaudio-suite)
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
```
|
|
11
|
+
npm i openaudio-suite
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
> ⚠️ **Alpha Software**
|
|
15
|
+
> The entire OpenAudio suite is currently in public alpha. APIs may change, bugs are expected, and production use is not recommended. `OpenAudio_r.js` is the most tested library; `OpenAudio_s.js` and `OpenAudio.js` have received limited testing. Use at your own risk and please report issues.
|
|
9
16
|
|
|
10
17
|
---
|
|
11
18
|
|
|
12
19
|
## Three Libraries in This Suite
|
|
13
20
|
|
|
14
21
|
### **OpenAudio_r.js** — Randomized Scheduler
|
|
22
|
+
|
|
15
23
|
*For ambient, looped, or randomized audio playback*
|
|
16
24
|
|
|
17
25
|
```javascript
|
|
@@ -26,24 +34,26 @@ document.addEventListener('click', () => engine.start(), { once: true });
|
|
|
26
34
|
```
|
|
27
35
|
|
|
28
36
|
**Key Features:**
|
|
29
|
-
- 🎲 **Shuffle bag algorithm** — Each clip plays exactly once per cycle
|
|
30
|
-
- 🔄 **Ambient scheduling** — Random inter-clip delays (customizable)
|
|
31
|
-
- 📱 **Mobile-friendly** — Handles autoplay policies automatically
|
|
32
|
-
- 🌙 **Background tab resilience** — Detects visibility changes, recalculates timing
|
|
33
|
-
- 🎛️ **Lifecycle callbacks** — `onPlay`, `onEnd`, `onCycleReset`
|
|
34
37
|
|
|
35
|
-
**
|
|
38
|
+
* 🎲 **Shuffle bag algorithm** — Each clip plays exactly once per cycle
|
|
39
|
+
* 🔄 **Ambient scheduling** — Random inter-clip delays (customizable)
|
|
40
|
+
* 📱 **Mobile-friendly** — Handles autoplay policies automatically
|
|
41
|
+
* 🌙 **Background tab resilience** — Detects visibility changes, recalculates timing
|
|
42
|
+
* 🎛️ **Lifecycle callbacks** — `onPlay`, `onEnd`, `onCycleReset`
|
|
43
|
+
|
|
44
|
+
**Version:** 2.6.0 | **File:** `OpenAudio_r.js` (~9 KB, 3 KB gzipped)
|
|
36
45
|
|
|
37
46
|
---
|
|
38
47
|
|
|
39
48
|
### **OpenAudio_s.js** — Sequential Playlist
|
|
49
|
+
|
|
40
50
|
*For click-to-advance or auto-play sequential audio*
|
|
41
51
|
|
|
42
52
|
```javascript
|
|
43
53
|
const player = new SequentialAudio([
|
|
44
|
-
{ src: 'intro.mp3',
|
|
45
|
-
{ src: 'chapter1.mp3', label: 'Chapter 1'
|
|
46
|
-
{ src: 'chapter2.mp3', label: 'Chapter 2'
|
|
54
|
+
{ src: 'intro.mp3', label: 'Introduction' },
|
|
55
|
+
{ src: 'chapter1.mp3', label: 'Chapter 1' },
|
|
56
|
+
{ src: 'chapter2.mp3', label: 'Chapter 2' }
|
|
47
57
|
], {
|
|
48
58
|
autoAdvance: false // Require click to advance
|
|
49
59
|
});
|
|
@@ -53,57 +63,61 @@ document.getElementById('next-btn').addEventListener('click', () => player.next(
|
|
|
53
63
|
```
|
|
54
64
|
|
|
55
65
|
**Key Features:**
|
|
56
|
-
- ▶️ **Sequential playback** — Plays clips in fixed order
|
|
57
|
-
- 🖱️ **Manual or auto-advance** — User controls pacing or auto-play
|
|
58
|
-
- 🔀 **Jump & navigation** — Goto clip by index or label
|
|
59
|
-
- ⏸️ **Play/pause/resume** — Full transport controls
|
|
60
|
-
- 📊 **Progress tracking** — Know your current position in sequence
|
|
61
66
|
|
|
62
|
-
|
|
67
|
+
* ▶️ **Sequential playback** — Plays clips in fixed order
|
|
68
|
+
* 🖱️ **Manual or auto-advance** — User controls pacing or auto-play
|
|
69
|
+
* 🔀 **Jump & navigation** — Goto clip by index or label
|
|
70
|
+
* ⏸️ **Play/pause/resume** — Full transport controls
|
|
71
|
+
* 📊 **Progress tracking** — Know your current position in sequence
|
|
72
|
+
|
|
73
|
+
**Version:** 1.3.0 | **File:** `OpenAudio_s.js` (~5 KB, 2 KB gzipped)
|
|
63
74
|
|
|
64
75
|
---
|
|
65
76
|
|
|
66
77
|
### **OpenAudio.js** — Simple Player
|
|
78
|
+
|
|
67
79
|
*For single-clip, one-shot audio playback with background tab awareness*
|
|
68
80
|
|
|
69
81
|
```javascript
|
|
70
82
|
const player = new OpenAudio('audio/chime.mp3', {
|
|
71
|
-
volume:
|
|
72
|
-
pauseOnHidden: true,
|
|
73
|
-
onPlay:
|
|
74
|
-
onEnd:
|
|
75
|
-
onHidden:
|
|
76
|
-
onVisible:
|
|
83
|
+
volume: 0.8,
|
|
84
|
+
pauseOnHidden: true,
|
|
85
|
+
onPlay: () => console.log('Playing'),
|
|
86
|
+
onEnd: () => console.log('Done'),
|
|
87
|
+
onHidden: () => console.log('Tab hidden'),
|
|
88
|
+
onVisible: () => console.log('Tab visible')
|
|
77
89
|
});
|
|
78
90
|
|
|
79
91
|
document.getElementById('btn').addEventListener('click', () => player.play());
|
|
80
92
|
```
|
|
81
93
|
|
|
82
94
|
**Key Features:**
|
|
83
|
-
- ▶️ **One-shot playback** — Plays a single audio file once
|
|
84
|
-
- 🔁 **Replayable** — Call `play()` again to replay from start
|
|
85
|
-
- ⏹️ **Stop control** — Pause and rewind mid-playback
|
|
86
|
-
- 🔍 **Background tab detection** — Detects when tab loses/regains focus
|
|
87
|
-
- ⏸️ **Smart pause/resume** — Optional pause on background, resume on return
|
|
88
|
-
- 📱 **Same autoplay unlock** — Silent MP3 unlock as others
|
|
89
95
|
|
|
90
|
-
|
|
96
|
+
* ▶️ **One-shot playback** — Plays a single audio file once
|
|
97
|
+
* 🔁 **Replayable** — Call `play()` again to replay from start; preloaded data preserved on replay
|
|
98
|
+
* ⏹️ **Stop control** — Pause and rewind mid-playback
|
|
99
|
+
* 🔍 **Background tab detection** — Detects when tab loses/regains focus
|
|
100
|
+
* ⏸️ **Smart pause/resume** — Optional pause on background, resume on return
|
|
101
|
+
* 📱 **Same autoplay unlock** — Silent MP3 unlock, performed only once per instance
|
|
102
|
+
|
|
103
|
+
**Version:** 1.3.0 | **File:** `OpenAudio.js` (~5 KB, 2 KB gzipped)
|
|
91
104
|
|
|
92
105
|
---
|
|
93
106
|
|
|
94
107
|
## Quick Comparison
|
|
95
108
|
|
|
96
109
|
| Feature | OpenAudio_r.js | OpenAudio_s.js | OpenAudio.js |
|
|
97
|
-
|
|
110
|
+
| --- | --- | --- | --- |
|
|
98
111
|
| **Clips** | Multiple | Multiple | Single |
|
|
99
112
|
| **Order** | Random | Sequential | N/A |
|
|
100
113
|
| **Scheduling** | Delays between clips | Manual or auto-advance | On-demand |
|
|
101
114
|
| **Shuffle Bag** | ✅ Yes | ❌ No | ❌ N/A |
|
|
102
115
|
| **Navigation** | ❌ No | ✅ Goto/label jump | ❌ N/A |
|
|
103
|
-
| **Volume Control** | ✅ Runtime |
|
|
116
|
+
| **Volume Control** | ✅ Runtime | ✅ Constructor | ✅ Constructor |
|
|
104
117
|
| **Callbacks** | onPlay, onEnd, onCycleReset | onPlay, onEnd, onComplete | onPlay, onEnd, onHidden, onVisible |
|
|
105
118
|
| **Pause/Resume** | ❌ No | ✅ Yes | ✅ Yes (pauseOnHidden) |
|
|
106
119
|
| **Background Tab Detection** | ✅ Yes | ❌ No | ✅ Yes |
|
|
120
|
+
| **isPlaying / isStarted** | ✅ Read-only | ✅ Read-only | ✅ Read-only |
|
|
107
121
|
| **File Size** | ~9 KB | ~5 KB | ~5 KB |
|
|
108
122
|
| **Use Case** | Ambient, randomized | Guided tours, tutorials, stories | UI sounds, notifications, game audio |
|
|
109
123
|
|
|
@@ -138,6 +152,7 @@ Q4: Do you need frame-perfect scheduling or effects?
|
|
|
138
152
|
## Installation
|
|
139
153
|
|
|
140
154
|
### Option 1: Direct Script Tags
|
|
155
|
+
|
|
141
156
|
```html
|
|
142
157
|
<!-- Use whichever you need -->
|
|
143
158
|
<script src="OpenAudio_r.js"></script> <!-- Randomized scheduler -->
|
|
@@ -150,19 +165,21 @@ Q4: Do you need frame-perfect scheduling or effects?
|
|
|
150
165
|
```
|
|
151
166
|
|
|
152
167
|
### Option 2: ES6 Modules
|
|
168
|
+
|
|
153
169
|
```javascript
|
|
154
|
-
import { AudioEngine }
|
|
170
|
+
import { AudioEngine } from './OpenAudio_r.js';
|
|
155
171
|
import { SequentialAudio } from './OpenAudio_s.js';
|
|
156
|
-
import {
|
|
172
|
+
import { OpenAudio } from './OpenAudio.js';
|
|
157
173
|
```
|
|
158
174
|
|
|
159
|
-
### Option 3: npm
|
|
160
|
-
|
|
161
|
-
|
|
175
|
+
### Option 3: npm
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
npm i openaudio-suite
|
|
162
179
|
```
|
|
163
180
|
|
|
164
181
|
```javascript
|
|
165
|
-
import { AudioEngine, SequentialAudio,
|
|
182
|
+
import { AudioEngine, SequentialAudio, OpenAudio } from 'openaudio-suite';
|
|
166
183
|
```
|
|
167
184
|
|
|
168
185
|
---
|
|
@@ -175,11 +192,11 @@ import { AudioEngine, SequentialAudio, SingleAudio } from 'openaudio-suite';
|
|
|
175
192
|
// Ambient soundscape
|
|
176
193
|
const ambience = new AudioEngine([
|
|
177
194
|
{ src: 'forest.mp3' },
|
|
178
|
-
{ src: 'rain.mp3'
|
|
195
|
+
{ src: 'rain.mp3' }
|
|
179
196
|
], { lowTime: 5, maxTime: 15, volume: 0.6 });
|
|
180
197
|
|
|
181
198
|
// UI sounds
|
|
182
|
-
const clickSound = new
|
|
199
|
+
const clickSound = new OpenAudio('ui/click.mp3', { volume: 0.8 });
|
|
183
200
|
|
|
184
201
|
// Start
|
|
185
202
|
document.addEventListener('click', () => ambience.start(), { once: true });
|
|
@@ -188,8 +205,6 @@ document.querySelectorAll('button').forEach(btn => {
|
|
|
188
205
|
});
|
|
189
206
|
```
|
|
190
207
|
|
|
191
|
-
---
|
|
192
|
-
|
|
193
208
|
### Scenario 2: Narrated Story with Pause/Resume
|
|
194
209
|
|
|
195
210
|
```javascript
|
|
@@ -198,46 +213,40 @@ const story = new SequentialAudio([
|
|
|
198
213
|
{ src: 'chapter2.mp3', label: 'Chapter 2' },
|
|
199
214
|
{ src: 'chapter3.mp3', label: 'Chapter 3' }
|
|
200
215
|
], {
|
|
201
|
-
autoAdvance: false,
|
|
202
|
-
onPlay:
|
|
203
|
-
onComplete:
|
|
216
|
+
autoAdvance: false,
|
|
217
|
+
onPlay: (clip) => updateUI(`Reading: ${clip.label}`),
|
|
218
|
+
onComplete: () => showTheEnd()
|
|
204
219
|
});
|
|
205
220
|
|
|
206
221
|
document.addEventListener('click', () => story.play(), { once: true });
|
|
207
|
-
document.getElementById('next-btn').addEventListener('click',
|
|
208
|
-
document.getElementById('pause-btn').addEventListener('click',
|
|
222
|
+
document.getElementById('next-btn').addEventListener('click', () => story.next());
|
|
223
|
+
document.getElementById('pause-btn').addEventListener('click', () => story.pause());
|
|
209
224
|
document.getElementById('resume-btn').addEventListener('click', () => story.resume());
|
|
210
225
|
```
|
|
211
226
|
|
|
212
|
-
---
|
|
213
|
-
|
|
214
227
|
### Scenario 3: Tutorial with Auto-Advance
|
|
215
228
|
|
|
216
229
|
```javascript
|
|
217
230
|
const tutorial = new SequentialAudio([
|
|
218
|
-
{ src: 'intro.mp3', label: 'Intro'
|
|
231
|
+
{ src: 'intro.mp3', label: 'Intro' },
|
|
219
232
|
{ src: 'step1.mp3', label: 'Step 1' },
|
|
220
233
|
{ src: 'step2.mp3', label: 'Step 2' }
|
|
221
234
|
], {
|
|
222
|
-
autoAdvance: true,
|
|
223
|
-
onPlay:
|
|
224
|
-
onComplete:
|
|
235
|
+
autoAdvance: true,
|
|
236
|
+
onPlay: (clip) => highlightStep(clip.label),
|
|
237
|
+
onComplete: () => showCertificate()
|
|
225
238
|
});
|
|
226
239
|
|
|
227
|
-
document.getElementById('start-tutorial').addEventListener('click', () =>
|
|
228
|
-
tutorial.play();
|
|
229
|
-
});
|
|
240
|
+
document.getElementById('start-tutorial').addEventListener('click', () => tutorial.play());
|
|
230
241
|
```
|
|
231
242
|
|
|
232
|
-
---
|
|
233
|
-
|
|
234
243
|
### Scenario 4: Notification System
|
|
235
244
|
|
|
236
245
|
```javascript
|
|
237
246
|
const sounds = {
|
|
238
|
-
email:
|
|
239
|
-
message: new
|
|
240
|
-
alert:
|
|
247
|
+
email: new OpenAudio('email.mp3'),
|
|
248
|
+
message: new OpenAudio('message.mp3'),
|
|
249
|
+
alert: new OpenAudio('alert.mp3')
|
|
241
250
|
};
|
|
242
251
|
|
|
243
252
|
function notify(type, message) {
|
|
@@ -251,11 +260,12 @@ function notify(type, message) {
|
|
|
251
260
|
## Browser Compatibility
|
|
252
261
|
|
|
253
262
|
All three libraries require:
|
|
254
|
-
|
|
255
|
-
|
|
263
|
+
|
|
264
|
+
* **HTML5 Audio element support** (universal)
|
|
265
|
+
* **User gesture** for first audio playback (autoplay policy)
|
|
256
266
|
|
|
257
267
|
| Browser | Version | Status |
|
|
258
|
-
|
|
268
|
+
| --- | --- | --- |
|
|
259
269
|
| Chrome | 70+ | ✅ Full support |
|
|
260
270
|
| Firefox | 65+ | ✅ Full support |
|
|
261
271
|
| Safari | 12+ | ✅ Full support |
|
|
@@ -268,20 +278,25 @@ All three libraries require:
|
|
|
268
278
|
## API Quick Reference
|
|
269
279
|
|
|
270
280
|
### OpenAudio_r.js (AudioEngine)
|
|
281
|
+
|
|
271
282
|
```javascript
|
|
272
|
-
engine.start() // Begin playback
|
|
273
|
-
engine.stop() // Pause
|
|
274
|
-
engine.reset() // Stop & reset cycle
|
|
275
|
-
engine.setVolume(0.5) // Set volume
|
|
276
|
-
engine.addClip(clip) // Add clip at runtime
|
|
277
|
-
engine.destroy() // Cleanup
|
|
283
|
+
engine.start() // Begin playback (no-op after destroy)
|
|
284
|
+
engine.stop() // Pause (no-op after destroy)
|
|
285
|
+
engine.reset() // Stop & reset cycle (no-op after destroy)
|
|
286
|
+
engine.setVolume(0.5) // Set volume (no-op after destroy)
|
|
287
|
+
engine.addClip(clip) // Add clip at runtime (no-op after destroy)
|
|
288
|
+
engine.destroy() // Cleanup — all subsequent calls are safe no-ops
|
|
289
|
+
|
|
290
|
+
engine.isStarted // boolean, read-only
|
|
291
|
+
engine.isPlaying // boolean, read-only
|
|
278
292
|
```
|
|
279
293
|
|
|
280
|
-
See [OPENAUDIO_R.md](
|
|
294
|
+
See [OPENAUDIO_R.md](https://github.com/Rexore/OpenAudio/blob/main/docs/OPENAUDIO_R.md) for full API.
|
|
281
295
|
|
|
282
296
|
---
|
|
283
297
|
|
|
284
298
|
### OpenAudio_s.js (SequentialAudio)
|
|
299
|
+
|
|
285
300
|
```javascript
|
|
286
301
|
player.play() // Start playback
|
|
287
302
|
player.next() // Advance to next clip
|
|
@@ -289,29 +304,36 @@ player.goto(index) // Jump to clip by index
|
|
|
289
304
|
player.gotoLabel(label) // Jump to clip by label
|
|
290
305
|
player.pause() // Pause
|
|
291
306
|
player.resume() // Resume from pause
|
|
292
|
-
player.stop() // Stop
|
|
307
|
+
player.stop() // Stop, rewind, cancel pending auto-advance
|
|
293
308
|
player.reset() // Reset to start
|
|
294
|
-
player.destroy() // Cleanup
|
|
309
|
+
player.destroy() // Cleanup — all subsequent calls are safe no-ops
|
|
310
|
+
|
|
311
|
+
player.isPlaying // boolean, read-only
|
|
312
|
+
player.isStarted // boolean, read-only
|
|
295
313
|
```
|
|
296
314
|
|
|
297
|
-
See [OPENAUDIO_S.md](
|
|
315
|
+
See [OPENAUDIO_S.md](https://github.com/Rexore/OpenAudio/blob/main/docs/OPENAUDIO_S.md) for full API.
|
|
298
316
|
|
|
299
317
|
---
|
|
300
318
|
|
|
301
|
-
### OpenAudio.js (
|
|
319
|
+
### OpenAudio.js (OpenAudio)
|
|
320
|
+
|
|
302
321
|
```javascript
|
|
303
|
-
player.play() // Play the clip
|
|
304
|
-
player.stop() // Stop
|
|
305
|
-
player.destroy() // Cleanup
|
|
322
|
+
player.play() // Play the clip (unlock once, direct play on replay)
|
|
323
|
+
player.stop() // Stop, rewind, cancel in-flight unlock
|
|
324
|
+
player.destroy() // Cleanup — all subsequent calls are safe no-ops
|
|
325
|
+
|
|
326
|
+
player.isPlaying // boolean, read-only
|
|
306
327
|
```
|
|
307
328
|
|
|
308
|
-
See [OPENAUDIO.md](
|
|
329
|
+
See [OPENAUDIO.md](https://github.com/Rexore/OpenAudio/blob/main/docs/OPENAUDIO.md) for full API.
|
|
309
330
|
|
|
310
331
|
---
|
|
311
332
|
|
|
312
333
|
## Troubleshooting
|
|
313
334
|
|
|
314
335
|
### Audio Won't Play
|
|
336
|
+
|
|
315
337
|
**Cause:** Not called inside a user gesture.
|
|
316
338
|
**Fix:** Call `play()` or `start()` inside a click, keydown, or touchstart handler.
|
|
317
339
|
|
|
@@ -323,21 +345,19 @@ document.addEventListener('click', () => player.play());
|
|
|
323
345
|
setTimeout(() => player.play(), 1000);
|
|
324
346
|
```
|
|
325
347
|
|
|
326
|
-
---
|
|
327
|
-
|
|
328
348
|
### "NotAllowedError" in Console
|
|
349
|
+
|
|
329
350
|
**Cause:** Autoplay policy blocked playback.
|
|
330
351
|
**Fix:** Same as above — use a user gesture.
|
|
331
352
|
|
|
332
|
-
---
|
|
333
|
-
|
|
334
353
|
### Multiple Libraries in Same Project
|
|
335
|
-
|
|
354
|
+
|
|
355
|
+
No problem! They don't conflict.
|
|
336
356
|
|
|
337
357
|
```javascript
|
|
338
|
-
const ambience = new AudioEngine([...]);
|
|
339
|
-
const story
|
|
340
|
-
const click
|
|
358
|
+
const ambience = new AudioEngine([...]); // OpenAudio_r.js
|
|
359
|
+
const story = new SequentialAudio([...]); // OpenAudio_s.js
|
|
360
|
+
const click = new OpenAudio('sound.mp3'); // OpenAudio.js
|
|
341
361
|
|
|
342
362
|
// All three can run simultaneously
|
|
343
363
|
```
|
|
@@ -347,7 +367,7 @@ const click = new SingleAudio('sound.mp3'); // OpenAudio.js
|
|
|
347
367
|
## Performance & Sizing
|
|
348
368
|
|
|
349
369
|
| Scenario | Size | Memory |
|
|
350
|
-
|
|
370
|
+
| --- | --- | --- |
|
|
351
371
|
| OpenAudio_r.js only | 9 KB | < 1 MB |
|
|
352
372
|
| OpenAudio_s.js only | 5 KB | < 150 KB |
|
|
353
373
|
| OpenAudio.js only | 4 KB | < 100 KB |
|
|
@@ -360,45 +380,45 @@ No external dependencies. Pure HTML5 Audio API.
|
|
|
360
380
|
|
|
361
381
|
## Contributing
|
|
362
382
|
|
|
363
|
-
See [CONTRIBUTING.md](
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
383
|
+
See [CONTRIBUTING.md](https://github.com/Rexore/OpenAudio/blob/main/CONTRIBUTING.md) for:
|
|
384
|
+
|
|
385
|
+
* Bug reports
|
|
386
|
+
* Feature requests
|
|
387
|
+
* Code style
|
|
388
|
+
* Testing checklist
|
|
389
|
+
* PR guidelines
|
|
369
390
|
|
|
370
391
|
---
|
|
371
392
|
|
|
372
393
|
## License
|
|
373
394
|
|
|
374
|
-
All libraries are licensed under **
|
|
395
|
+
All libraries are licensed under **Apache-2.0**.
|
|
375
396
|
|
|
376
|
-
See [LICENSE](
|
|
397
|
+
See [LICENSE](https://github.com/Rexore/OpenAudio/blob/main/LICENSE) for the full text.
|
|
377
398
|
|
|
378
|
-
**Commercial use permitted** — Include
|
|
399
|
+
**Commercial use permitted** — Include the licence and copyright notice. Note any changes made to the original.
|
|
379
400
|
|
|
380
401
|
---
|
|
381
402
|
|
|
382
403
|
## Changelog
|
|
383
404
|
|
|
384
|
-
See [CHANGELOG.md](
|
|
405
|
+
See [CHANGELOG.md](https://github.com/Rexore/OpenAudio/blob/main/CHANGELOG.md) for version history.
|
|
385
406
|
|
|
386
407
|
**Current Versions:**
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
408
|
+
|
|
409
|
+
* OpenAudio_r.js: **2.6.0** (March 2026)
|
|
410
|
+
* OpenAudio_s.js: **1.3.0** (March 2026)
|
|
411
|
+
* OpenAudio.js: **1.3.0** (March 2026)
|
|
390
412
|
|
|
391
413
|
---
|
|
392
414
|
|
|
393
415
|
## Documentation
|
|
394
416
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
---
|
|
417
|
+
* 📖 [OpenAudio_r.js API](https://github.com/Rexore/OpenAudio/blob/main/docs/OPENAUDIO_R.md) — Randomized scheduler
|
|
418
|
+
* 📖 [OpenAudio_s.js API](https://github.com/Rexore/OpenAudio/blob/main/docs/OPENAUDIO_S.md) — Sequential player
|
|
419
|
+
* 📖 [OpenAudio.js API](https://github.com/Rexore/OpenAudio/blob/main/docs/OPENAUDIO.md) — Single-clip player
|
|
420
|
+
* 📊 [Feature Comparison](https://github.com/Rexore/OpenAudio/blob/main/docs/COMPARISON.md) — Detailed comparison
|
|
421
|
+
* 💻 [Examples](https://github.com/Rexore/OpenAudio/blob/main/examples) — Working demos
|
|
402
422
|
|
|
403
423
|
Have questions? Open a GitHub Issue or Discussion.
|
|
404
424
|
|
|
@@ -406,30 +426,30 @@ Have questions? Open a GitHub Issue or Discussion.
|
|
|
406
426
|
|
|
407
427
|
## FAQ
|
|
408
428
|
|
|
409
|
-
**Q: Can I use all three in the same project?**
|
|
429
|
+
**Q: Can I use all three in the same project?**
|
|
410
430
|
A: Yes! They complement each other and don't conflict.
|
|
411
431
|
|
|
412
|
-
**Q: Do I need a build system?**
|
|
432
|
+
**Q: Do I need a build system?**
|
|
413
433
|
A: No. All work as plain `<script>` tags. No bundler needed.
|
|
414
434
|
|
|
415
|
-
**Q: Can I modify these?**
|
|
416
|
-
A: Yes, under
|
|
435
|
+
**Q: Can I modify these?**
|
|
436
|
+
A: Yes, under Apache 2.0. Include the licence and note your changes.
|
|
417
437
|
|
|
418
|
-
**Q: Commercial use?**
|
|
419
|
-
A: Yes.
|
|
438
|
+
**Q: Commercial use?**
|
|
439
|
+
A: Yes. Apache 2.0 allows commercial use. You must include the licence and notice of changes.
|
|
420
440
|
|
|
421
|
-
**Q: What about Web Audio API?**
|
|
422
|
-
A: These libraries use HTML5 Audio. Web Audio API is for advanced features (effects,
|
|
441
|
+
**Q: What about Web Audio API?**
|
|
442
|
+
A: These libraries use HTML5 Audio. Web Audio API is for advanced features (effects, visualisation, frame-perfect timing). See [COMPARISON.md](https://github.com/Rexore/OpenAudio/blob/main/docs/COMPARISON.md).
|
|
423
443
|
|
|
424
444
|
---
|
|
425
445
|
|
|
426
446
|
## Resources
|
|
427
447
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
448
|
+
* 📖 [HTML5 Audio — MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio)
|
|
449
|
+
* 🎛️ [Web Audio API — MDN](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API)
|
|
450
|
+
* 🎮 [Browser Autoplay Policy — Chrome Blog](https://developer.chrome.com/blog/autoplay/)
|
|
451
|
+
* 📱 [Page Visibility API — MDN](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API)
|
|
432
452
|
|
|
433
453
|
---
|
|
434
454
|
|
|
435
|
-
*Last updated: March
|
|
455
|
+
*Last updated: March 2026*
|