openaudio-suite 2.4.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/CHANGELOG.md +196 -0
- package/CONTRIBUTING.md +349 -0
- package/LICENSE +674 -0
- package/OpenAudio.js +386 -0
- package/OpenAudio_r.js +863 -0
- package/OpenAudio_s.js +445 -0
- package/README.md +433 -0
- package/docs/COMPARISON.md +449 -0
- package/docs/OPENAUDIO-v1.1.0.md +641 -0
- package/docs/OPENAUDIO_R.md +571 -0
- package/docs/OPENAUDIO_S.md +760 -0
- package/package.json +79 -0
package/README.md
ADDED
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
# OpenAudio Suite
|
|
2
|
+
|
|
3
|
+
A family of **zero-dependency, browser-native audio utilities** for web projects. Choose the library that fits your use case.
|
|
4
|
+
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
[]()
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## đ Three Libraries in This Suite
|
|
11
|
+
|
|
12
|
+
### **OpenAudio_r.js** â Randomized Scheduler
|
|
13
|
+
*For ambient, looped, or randomized audio playback*
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
const engine = new AudioEngine([
|
|
17
|
+
{ src: 'ambient/forest.mp3', label: 'Forest' },
|
|
18
|
+
{ src: 'ambient/rain.mp3', label: 'Rain' },
|
|
19
|
+
{ src: 'ambient/birds.mp3', label: 'Birds' }
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
// Plays clips in random order, every 3â5 seconds
|
|
23
|
+
document.addEventListener('click', () => engine.start(), { once: true });
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Key Features:**
|
|
27
|
+
- đ˛ **Shuffle bag algorithm** â Each clip plays exactly once per cycle
|
|
28
|
+
- đ **Ambient scheduling** â Random inter-clip delays (customizable)
|
|
29
|
+
- đą **Mobile-friendly** â Handles autoplay policies automatically
|
|
30
|
+
- đ **Background tab resilience** â Detects visibility changes, recalculates timing
|
|
31
|
+
- đī¸ **Lifecycle callbacks** â `onPlay`, `onEnd`, `onCycleReset`
|
|
32
|
+
|
|
33
|
+
**Version:** 2.4.0 | **File:** `OpenAudio_r.js` (~9 KB, 3 KB gzipped)
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
### **OpenAudio_s.js** â Sequential Playlist
|
|
38
|
+
*For click-to-advance or auto-play sequential audio*
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
const player = new SequentialAudio([
|
|
42
|
+
{ src: 'intro.mp3', label: 'Introduction' },
|
|
43
|
+
{ src: 'chapter1.mp3', label: 'Chapter 1' },
|
|
44
|
+
{ src: 'chapter2.mp3', label: 'Chapter 2' }
|
|
45
|
+
], {
|
|
46
|
+
autoAdvance: false // Require click to advance
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
document.addEventListener('click', () => player.play(), { once: true });
|
|
50
|
+
document.getElementById('next-btn').addEventListener('click', () => player.next());
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Key Features:**
|
|
54
|
+
- âļī¸ **Sequential playback** â Plays clips in fixed order
|
|
55
|
+
- đąī¸ **Manual or auto-advance** â User controls pacing or auto-play
|
|
56
|
+
- đ **Jump & navigation** â Goto clip by index or label
|
|
57
|
+
- â¸ī¸ **Play/pause/resume** â Full transport controls
|
|
58
|
+
- đ **Progress tracking** â Know your current position in sequence
|
|
59
|
+
|
|
60
|
+
**Version:** 1.0.0 | **File:** `OpenAudio_s.js` (~5 KB, 2 KB gzipped)
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### **OpenAudio.js** â Simple Player
|
|
65
|
+
*For single-clip, one-shot audio playback with background tab awareness*
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
const player = new OpenAudio('audio/chime.mp3', {
|
|
69
|
+
volume: 0.8,
|
|
70
|
+
pauseOnHidden: true, // Pause when tab loses focus
|
|
71
|
+
onPlay: () => console.log('Playing'),
|
|
72
|
+
onEnd: () => console.log('Done'),
|
|
73
|
+
onHidden: () => console.log('Tab hidden'),
|
|
74
|
+
onVisible: () => console.log('Tab visible')
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
document.getElementById('btn').addEventListener('click', () => player.play());
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Key Features:**
|
|
81
|
+
- âļī¸ **One-shot playback** â Plays a single audio file once
|
|
82
|
+
- đ **Replayable** â Call `play()` again to replay from start
|
|
83
|
+
- âšī¸ **Stop control** â Pause and rewind mid-playback
|
|
84
|
+
- đ **Background tab detection** â Detects when tab loses/regains focus
|
|
85
|
+
- â¸ī¸ **Smart pause/resume** â Optional pause on background, resume on return
|
|
86
|
+
- đą **Same autoplay unlock** â Silent MP3 unlock as others
|
|
87
|
+
|
|
88
|
+
**Version:** 1.1.0 | **File:** `OpenAudio.js` (~5 KB, 2 KB gzipped)
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Quick Comparison
|
|
93
|
+
|
|
94
|
+
| Feature | OpenAudio_r.js | OpenAudio_s.js | OpenAudio.js |
|
|
95
|
+
|---------|---|---|---|
|
|
96
|
+
| **Clips** | Multiple | Multiple | Single |
|
|
97
|
+
| **Order** | Random | Sequential | N/A |
|
|
98
|
+
| **Scheduling** | Delays between clips | Manual or auto-advance | On-demand |
|
|
99
|
+
| **Shuffle Bag** | â
Yes | â No | â N/A |
|
|
100
|
+
| **Navigation** | â No | â
Goto/label jump | â N/A |
|
|
101
|
+
| **Volume Control** | â
Runtime | â Constructor | â
Constructor |
|
|
102
|
+
| **Callbacks** | onPlay, onEnd, onCycleReset | onPlay, onEnd, onComplete | onPlay, onEnd, onHidden, onVisible |
|
|
103
|
+
| **Pause/Resume** | â No | â
Yes | â
Yes (pauseOnHidden) |
|
|
104
|
+
| **Background Tab Detection** | â
Yes | â No | â
Yes |
|
|
105
|
+
| **File Size** | ~9 KB | ~5 KB | ~5 KB |
|
|
106
|
+
| **Use Case** | Ambient, randomized | Guided tours, tutorials, stories | UI sounds, notifications, game audio |
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Use Case Decision Tree
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
START
|
|
114
|
+
|
|
115
|
+
Q1: How many audio clips do you need?
|
|
116
|
+
ââ ONE: Use OpenAudio.js (Single-clip player)
|
|
117
|
+
ââ MULTIPLE: Continue to Q2
|
|
118
|
+
|
|
119
|
+
Q2: What order should clips play?
|
|
120
|
+
ââ RANDOM: Use OpenAudio_r.js (Randomized scheduler)
|
|
121
|
+
ââ SEQUENTIAL: Continue to Q3
|
|
122
|
+
ââ ON-DEMAND: Use OpenAudio.js (one instance per sound)
|
|
123
|
+
|
|
124
|
+
Q3: How should users advance through the sequence?
|
|
125
|
+
ââ MANUAL CLICKS: Use OpenAudio_s.js with autoAdvance: false
|
|
126
|
+
ââ AUTO-ADVANCE: Use OpenAudio_s.js with autoAdvance: true
|
|
127
|
+
ââ NO CONTROL: Use OpenAudio_r.js
|
|
128
|
+
|
|
129
|
+
Q4: Do you need frame-perfect scheduling or effects?
|
|
130
|
+
ââ YES: Graduate to Web Audio API
|
|
131
|
+
ââ NO: You're set!
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Installation
|
|
137
|
+
|
|
138
|
+
### Option 1: Direct Script Tags
|
|
139
|
+
```html
|
|
140
|
+
<!-- Use whichever you need -->
|
|
141
|
+
<script src="OpenAudio_r.js"></script> <!-- Randomized scheduler -->
|
|
142
|
+
<script src="OpenAudio_s.js"></script> <!-- Sequential player -->
|
|
143
|
+
<script src="OpenAudio.js"></script> <!-- Single-clip player -->
|
|
144
|
+
|
|
145
|
+
<!-- Or combine as needed -->
|
|
146
|
+
<script src="OpenAudio_s.js"></script>
|
|
147
|
+
<script src="OpenAudio.js"></script>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Option 2: ES6 Modules
|
|
151
|
+
```javascript
|
|
152
|
+
import { AudioEngine } from './OpenAudio_r.js';
|
|
153
|
+
import { SequentialAudio } from './OpenAudio_s.js';
|
|
154
|
+
import { SingleAudio } from './OpenAudio.js';
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Option 3: npm (when published)
|
|
158
|
+
```bash
|
|
159
|
+
npm install openaudio-suite
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
import { AudioEngine, SequentialAudio, SingleAudio } from 'openaudio-suite';
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Examples
|
|
169
|
+
|
|
170
|
+
### Scenario 1: Game with Ambient + UI Sounds
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
// Ambient soundscape
|
|
174
|
+
const ambience = new AudioEngine([
|
|
175
|
+
{ src: 'forest.mp3' },
|
|
176
|
+
{ src: 'rain.mp3' }
|
|
177
|
+
], { lowTime: 5, maxTime: 15, volume: 0.6 });
|
|
178
|
+
|
|
179
|
+
// UI sounds
|
|
180
|
+
const clickSound = new SingleAudio('ui/click.mp3', { volume: 0.8 });
|
|
181
|
+
|
|
182
|
+
// Start
|
|
183
|
+
document.addEventListener('click', () => ambience.start(), { once: true });
|
|
184
|
+
document.querySelectorAll('button').forEach(btn => {
|
|
185
|
+
btn.addEventListener('click', () => clickSound.play());
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### Scenario 2: Narrated Story with Pause/Resume
|
|
192
|
+
|
|
193
|
+
```javascript
|
|
194
|
+
const story = new SequentialAudio([
|
|
195
|
+
{ src: 'chapter1.mp3', label: 'Chapter 1' },
|
|
196
|
+
{ src: 'chapter2.mp3', label: 'Chapter 2' },
|
|
197
|
+
{ src: 'chapter3.mp3', label: 'Chapter 3' }
|
|
198
|
+
], {
|
|
199
|
+
autoAdvance: false, // User controls pacing
|
|
200
|
+
onPlay: (clip) => updateUI(`Reading: ${clip.label}`),
|
|
201
|
+
onComplete: () => showTheEnd()
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
document.addEventListener('click', () => story.play(), { once: true });
|
|
205
|
+
document.getElementById('next-btn').addEventListener('click', () => story.next());
|
|
206
|
+
document.getElementById('pause-btn').addEventListener('click', () => story.pause());
|
|
207
|
+
document.getElementById('resume-btn').addEventListener('click', () => story.resume());
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
### Scenario 3: Tutorial with Auto-Advance
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
const tutorial = new SequentialAudio([
|
|
216
|
+
{ src: 'intro.mp3', label: 'Intro' },
|
|
217
|
+
{ src: 'step1.mp3', label: 'Step 1' },
|
|
218
|
+
{ src: 'step2.mp3', label: 'Step 2' }
|
|
219
|
+
], {
|
|
220
|
+
autoAdvance: true, // Auto-play next step
|
|
221
|
+
onPlay: (clip) => highlightStep(clip.label),
|
|
222
|
+
onComplete: () => showCertificate()
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
document.getElementById('start-tutorial').addEventListener('click', () => {
|
|
226
|
+
tutorial.play();
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
### Scenario 4: Notification System
|
|
233
|
+
|
|
234
|
+
```javascript
|
|
235
|
+
const sounds = {
|
|
236
|
+
email: new SingleAudio('email.mp3'),
|
|
237
|
+
message: new SingleAudio('message.mp3'),
|
|
238
|
+
alert: new SingleAudio('alert.mp3')
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
function notify(type, message) {
|
|
242
|
+
sounds[type].play();
|
|
243
|
+
showNotification(message);
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Browser Compatibility
|
|
250
|
+
|
|
251
|
+
All three libraries require:
|
|
252
|
+
- **HTML5 Audio element support** (universal)
|
|
253
|
+
- **User gesture** for first audio playback (autoplay policy)
|
|
254
|
+
|
|
255
|
+
| Browser | Version | Status |
|
|
256
|
+
|---------|---------|--------|
|
|
257
|
+
| Chrome | 70+ | â
Full support |
|
|
258
|
+
| Firefox | 65+ | â
Full support |
|
|
259
|
+
| Safari | 12+ | â
Full support |
|
|
260
|
+
| Edge | 79+ | â
Full support |
|
|
261
|
+
| iOS Safari | 12+ | â
Full support |
|
|
262
|
+
| Chrome Android | Latest | â
Full support |
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## API Quick Reference
|
|
267
|
+
|
|
268
|
+
### OpenAudio_r.js (AudioEngine)
|
|
269
|
+
```javascript
|
|
270
|
+
engine.start() // Begin playback
|
|
271
|
+
engine.stop() // Pause
|
|
272
|
+
engine.reset() // Stop & reset cycle
|
|
273
|
+
engine.setVolume(0.5) // Set volume
|
|
274
|
+
engine.addClip(clip) // Add clip at runtime
|
|
275
|
+
engine.destroy() // Cleanup
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
See [OPENAUDIO_R.md](./docs/OPENAUDIO_R.md) for full API.
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
### OpenAudio_s.js (SequentialAudio)
|
|
283
|
+
```javascript
|
|
284
|
+
player.play() // Start playback
|
|
285
|
+
player.next() // Advance to next clip
|
|
286
|
+
player.goto(index) // Jump to clip by index
|
|
287
|
+
player.gotoLabel(label) // Jump to clip by label
|
|
288
|
+
player.pause() // Pause
|
|
289
|
+
player.resume() // Resume from pause
|
|
290
|
+
player.stop() // Stop & rewind
|
|
291
|
+
player.reset() // Reset to start
|
|
292
|
+
player.destroy() // Cleanup
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
See [OPENAUDIO_S.md](./docs/OPENAUDIO_S.md) for full API.
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
### OpenAudio.js (SingleAudio)
|
|
300
|
+
```javascript
|
|
301
|
+
player.play() // Play the clip
|
|
302
|
+
player.stop() // Stop & rewind
|
|
303
|
+
player.destroy() // Cleanup
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
See [OPENAUDIO.md](./docs/OPENAUDIO.md) for full API.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Troubleshooting
|
|
311
|
+
|
|
312
|
+
### Audio Won't Play
|
|
313
|
+
**Cause:** Not called inside a user gesture.
|
|
314
|
+
**Fix:** Call `play()` or `start()` inside a click, keydown, or touchstart handler.
|
|
315
|
+
|
|
316
|
+
```javascript
|
|
317
|
+
// â
Correct
|
|
318
|
+
document.addEventListener('click', () => player.play());
|
|
319
|
+
|
|
320
|
+
// â Wrong
|
|
321
|
+
setTimeout(() => player.play(), 1000);
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
### "NotAllowedError" in Console
|
|
327
|
+
**Cause:** Autoplay policy blocked playback.
|
|
328
|
+
**Fix:** Same as above â use a user gesture.
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
### Multiple Libraries in Same Project
|
|
333
|
+
**No problem!** They don't conflict.
|
|
334
|
+
|
|
335
|
+
```javascript
|
|
336
|
+
const ambience = new AudioEngine([...]); // OpenAudio_r.js
|
|
337
|
+
const story = new SequentialAudio([...]); // OpenAudio_s.js
|
|
338
|
+
const click = new SingleAudio('sound.mp3'); // OpenAudio.js
|
|
339
|
+
|
|
340
|
+
// All three can run simultaneously
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Performance & Sizing
|
|
346
|
+
|
|
347
|
+
| Scenario | Size | Memory |
|
|
348
|
+
|----------|------|--------|
|
|
349
|
+
| OpenAudio_r.js only | 9 KB | < 1 MB |
|
|
350
|
+
| OpenAudio_s.js only | 5 KB | < 150 KB |
|
|
351
|
+
| OpenAudio.js only | 4 KB | < 100 KB |
|
|
352
|
+
| All three combined | ~18 KB | < 2 MB |
|
|
353
|
+
| All three gzipped | ~6.5 KB | â |
|
|
354
|
+
|
|
355
|
+
No external dependencies. Pure HTML5 Audio API.
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## Contributing
|
|
360
|
+
|
|
361
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for:
|
|
362
|
+
- Bug reports
|
|
363
|
+
- Feature requests
|
|
364
|
+
- Code style
|
|
365
|
+
- Testing checklist
|
|
366
|
+
- PR guidelines
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## License
|
|
371
|
+
|
|
372
|
+
All libraries are licensed under **GNU General Public License v3.0 or later**.
|
|
373
|
+
|
|
374
|
+
See [LICENSE](./LICENSE) for the full text.
|
|
375
|
+
|
|
376
|
+
**Commercial use permitted** â Include license and copyright notice. Derivative works must also be GPL-3.0-or-later.
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## Changelog
|
|
381
|
+
|
|
382
|
+
See [CHANGELOG.md](./CHANGELOG.md) for version history.
|
|
383
|
+
|
|
384
|
+
**Current Versions:**
|
|
385
|
+
- OpenAudio_r.js: **2.4.0** (March 2025)
|
|
386
|
+
- OpenAudio_s.js: **1.0.0** (March 2025)
|
|
387
|
+
- OpenAudio.js: **1.0.0** (March 2025)
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Documentation
|
|
392
|
+
|
|
393
|
+
- đ [OpenAudio_r.js API](./docs/OPENAUDIO_R.md) â Randomized scheduler
|
|
394
|
+
- đ [OpenAudio_s.js API](./docs/OPENAUDIO_S.md) â Sequential player
|
|
395
|
+
- đ [OpenAudio.js API](./docs/OPENAUDIO.md) â Single-clip player
|
|
396
|
+
- đ [Feature Comparison](./docs/COMPARISON.md) â Detailed comparison
|
|
397
|
+
- đģ [Examples](./examples/) â Working demos
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
Have questions? Open a GitHub Issue or Discussion.
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## FAQ
|
|
406
|
+
|
|
407
|
+
**Q: Can I use all three in the same project?**
|
|
408
|
+
A: Yes! They complement each other and don't conflict.
|
|
409
|
+
|
|
410
|
+
**Q: Do I need a build system?**
|
|
411
|
+
A: No. All work as plain `<script>` tags. No bundler needed.
|
|
412
|
+
|
|
413
|
+
**Q: Can I modify these?**
|
|
414
|
+
A: Yes, under GPL-3.0. Include the license and note your changes.
|
|
415
|
+
|
|
416
|
+
**Q: Commercial use?**
|
|
417
|
+
A: Yes. GPL-3.0 allows commercial use. You must provide source code and include the license.
|
|
418
|
+
|
|
419
|
+
**Q: What about Web Audio API?**
|
|
420
|
+
A: These libraries use HTML5 Audio. Web Audio API is for advanced features (effects, visualization, frame-perfect timing). See [COMPARISON.md](./docs/COMPARISON.md).
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## Resources
|
|
425
|
+
|
|
426
|
+
- đ [HTML5 Audio â MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio)
|
|
427
|
+
- đī¸ [Web Audio API â MDN](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API)
|
|
428
|
+
- đŽ [Browser Autoplay Policy â Chrome Blog](https://developer.chrome.com/blog/autoplay/)
|
|
429
|
+
- đą [Page Visibility API â MDN](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API)
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
*Last updated: March 2025*
|