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 ADDED
@@ -0,0 +1,196 @@
1
+ # Changelog
2
+
3
+ All notable changes to the OpenAudio suite are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).
6
+
7
+ ---
8
+
9
+ ## OpenAudio.js
10
+
11
+ ### [1.1.0] — 2025-03-15
12
+
13
+ #### Added
14
+ - **Background tab detection** — Listens to Page Visibility API (`document.visibilitychange`)
15
+ - **`pauseOnHidden` option** — Pause audio when tab hides, resume when tab returns
16
+ - **`onHidden` callback** — Fires when tab becomes hidden
17
+ - **`onVisible` callback** — Fires when tab becomes visible
18
+ - **`#boundVisibility` bound listener** — Proper cleanup prevents stale listeners in SPAs
19
+
20
+ #### Fixed
21
+ - Stale visibilitychange listeners in SPA environments (React, Vue, Svelte, etc.)
22
+ - Listener cleanup in `destroy()` now removes the exact function reference
23
+
24
+ #### Changed
25
+ - Class renamed: `SingleAudio` → `OpenAudio` (matches filename)
26
+ - Improved documentation with background tab behavior examples
27
+
28
+ ---
29
+
30
+ ### [1.0.0] — 2025-01-15
31
+
32
+ #### Added
33
+ - Initial release: Single-clip, one-shot player
34
+ - Silent MP3 unlock for autoplay policy compliance
35
+ - `onPlay` and `onEnd` callbacks
36
+ - `destroy()` method for SPA cleanup
37
+ - `canPlay()` static format checking
38
+ - Complete API documentation
39
+
40
+ ---
41
+
42
+ ## OpenAudio_s.js
43
+
44
+ ### [1.0.0] — 2025-01-15
45
+
46
+ #### Added
47
+ - Initial release: Sequential playlist player
48
+ - Click-to-advance playback control
49
+ - Jump to clip by index or label
50
+ - Pause/resume support
51
+ - Progress tracking
52
+ - Complete API documentation with usage patterns
53
+
54
+ ---
55
+
56
+ ## OpenAudio_r.js
57
+
58
+ ### [2.4.0] — 2025-03-15
59
+
60
+ ### Added
61
+ - **`#isUnlocking` flag** — Prevents duplicate unlock attempts when `start()` is called rapidly (spam-clicks). The unlock play() is async; without this flag, a race condition allowed multiple overlapping unlock sequences.
62
+ - **`destroy()` method** — Removes the `visibilitychange` listener. Essential for SPAs (React, Vue, Svelte, etc.) where engine instances are created and destroyed across component lifecycles. Without it, stale listeners accumulate on `document` and defunct engines wake up on every tab-focus event.
63
+ - **`AudioEngine.canPlay(type)` static method** — Wraps `HTMLAudioElement.canPlayType()` with a clean boolean return. Use to check browser support for `.ogg`, `.wav`, or `.flac` before constructing an engine, rather than discovering a silent failure at play() time.
64
+ - **Callback resilience for `onCycleReset`** — Wrapped in try/catch, matching the existing resilience applied to `onPlay` and `onEnd`. A throwing `onCycleReset` can no longer stall the engine loop.
65
+ - **Comprehensive documentation** — Added HTML5 AUDIO vs. WEB AUDIO API comparison, browser autoplay policy deep-dive, background tab throttling mitigation, and callback resilience guarantees.
66
+
67
+ ### Fixed
68
+ - Race condition where spam-clicking `start()` could trigger multiple `#scheduleNext()` calls before the first unlock completed.
69
+ - Potential memory leak: `visibilitychange` listener now properly removed on `destroy()`.
70
+
71
+ ### Changed
72
+ - Better error messages in console (include clip label and context).
73
+
74
+ ### Documentation
75
+ - Added CHANGELOG.md (this file)
76
+ - Expanded README with better examples and API reference
77
+ - Created CONTRIBUTING.md with PR guidelines and testing checklist
78
+
79
+ ---
80
+
81
+ ## [2.3.0] — 2025-02-20
82
+
83
+ ### Added
84
+ - **Clip src validation** — Constructor and `addClip()` now verify that every clip has a non-empty string `src`. Previously a clip with missing or non-string `src` would silently map `undefined` into the engine, producing a confusing audio error rather than a clear failure at the point of entry.
85
+ - **Next-clip prefetch** — `#scheduleNext()` now sets `#audio.src` to the next selected clip immediately after the current clip ends, before the inter-clip delay fires. The browser begins buffering the file during the gap, eliminating the network fetch delay at `#playNext()` time. The clip is still marked played and selected at schedule time, preserving shuffle-bag correctness.
86
+ - **Background tab throttling mitigation** — `#scheduleNext()` records the wall-clock time (`#timerSetAt`) and delay duration (`#timerDelay`). A `visibilitychange` listener fires when the tab returns to foreground. If elapsed time meets or exceeds the intended delay, the pending timer is cancelled and `#playNext()` is called immediately. Otherwise, the remaining time is rescheduled precisely.
87
+
88
+ ### Fixed
89
+ - Network latency no longer visible as gaps between clips (prefetch eliminates fetch delay).
90
+ - Background tab throttling no longer causes clips to bunch together on tab return (recalculation uses wall-clock time, not timer promises).
91
+
92
+ ### Changed
93
+ - Improved console logging for debugging background tab behavior.
94
+
95
+ ---
96
+
97
+ ## [2.2.0] — 2025-01-10
98
+
99
+ ### Added
100
+ - **`reset()` method** — Stops playback, clears all `played` flags, and optionally resets the current clip. Next `start()` begins a completely fresh random cycle.
101
+ - **`setVolume()` method** — Updates volume immediately on live playback and all future clips. Clamps to [0, 1].
102
+
103
+ ### Fixed
104
+ - Volume no longer resets to default on clip transition.
105
+
106
+ ---
107
+
108
+ ## [2.1.0] — 2024-12-05
109
+
110
+ ### Added
111
+ - **`addClip(clip)` method** — Add new clips to the engine at runtime without reconstructing.
112
+ - **Cycle-boundary repeat prevention** — When the unplayed pool is empty (cycle reset), the next clip is selected from all clips *except* the current clip, preventing the same clip from playing twice in a row across a cycle boundary.
113
+
114
+ ### Fixed
115
+ - Shuffle bag now correctly prevents the same clip from playing at the start and end of successive cycles.
116
+
117
+ ---
118
+
119
+ ## [2.0.0] — 2024-10-01
120
+
121
+ ### Added
122
+ - **Public API methods** — `start()`, `stop()`, `start()` for public control.
123
+ - **Lifecycle callbacks** — `onPlay(clip)`, `onEnd(clip)`, `onCycleReset()` for integration with game/app logic.
124
+ - **Options object** — `lowTime`, `maxTime`, `volume`, and callback configuration.
125
+ - **Shuffle bag algorithm** — Guarantees each clip plays exactly once per cycle before repeats.
126
+ - **Browser autoplay policy handling** — Silent base64 MP3 unlock on first `start()` call, subsequent clips scheduled via `setTimeout`.
127
+ - **Background tab throttling mitigation** — Page Visibility API monitoring and wall-clock delay recalculation.
128
+
129
+ ### Documentation
130
+ - Comprehensive JSDoc comments throughout
131
+ - Browser compatibility notes
132
+ - Web Audio API vs. HTML5 Audio comparison
133
+ - Usage examples in code comments
134
+
135
+ ---
136
+
137
+ ## [1.0.0] — 2024-09-01
138
+
139
+ ### Initial Release
140
+ - Self-contained randomized audio scheduling engine
141
+ - No dependencies, no external libraries
142
+ - HTML5 `<audio>` element-based scheduling
143
+ - Basic shuffle bag implementation
144
+ - Mobile-compatible (respects autoplay policies)
145
+
146
+ ---
147
+
148
+ ## Upgrade Guide
149
+
150
+ ### 2.3 → 2.4
151
+ - **No breaking changes.** New features are additive.
152
+ - **Recommended:** Call `engine.destroy()` when tearing down in SPAs to prevent listener accumulation.
153
+ - **New:** Use `AudioEngine.canPlay('audio/ogg')` to check format support before constructing.
154
+
155
+ ### 2.2 → 2.3
156
+ - **No breaking changes.** Prefetch is transparent.
157
+ - **Benefit:** Faster clip transitions due to network prefetch during inter-clip gap.
158
+
159
+ ### 2.0 → 2.1
160
+ - **No breaking changes.** New methods are additive.
161
+ - **New:** Cycle-boundary repeat prevention automatically enabled.
162
+
163
+ ### 1.0 → 2.0
164
+ - **Breaking:** Old version had no public API. Complete rewrite with methods and callbacks.
165
+ - **Migration:** Wrap old code in a new `AudioEngine` constructor.
166
+
167
+ ---
168
+
169
+ ## Future Considerations
170
+
171
+ These features are **out of scope** for OpenAudio_r.js (it would violate the "self-contained, no dependencies" principle):
172
+
173
+ - Crossfading between clips
174
+ - Sub-second precision scheduling
175
+ - Real-time DSP effects (reverb, EQ, compression)
176
+ - Frequency analysis or visualization
177
+
178
+ For these, consider graduating to the **Web Audio API**. See README.md for comparison.
179
+
180
+ ---
181
+
182
+ ## Contributing
183
+
184
+ Have a feature request or bug to report? See [CONTRIBUTING.md](./CONTRIBUTING.md).
185
+
186
+ All contributions will be credited in the changelog.
187
+
188
+ ---
189
+
190
+ ## License
191
+
192
+ OpenAudio_r.js is licensed under the GNU General Public License v3.0 or later. See [LICENSE](./LICENSE) for details.
193
+
194
+ ---
195
+
196
+ *Last updated: March 15, 2025*
@@ -0,0 +1,349 @@
1
+ # Contributing to OpenAudio Suite
2
+
3
+ Thank you for considering a contribution to the OpenAudio Suite! Contributions—whether bug reports, feature suggestions, or code—are how these projects improve.
4
+
5
+ The OpenAudio Suite consists of three libraries:
6
+ - **OpenAudio_r.js** (v2.4.0) — Randomized audio scheduler
7
+ - **OpenAudio_s.js** (v1.0.0) — Sequential playlist player
8
+ - **OpenAudio.js** (v1.1.0) — Single-clip player with background tab detection
9
+
10
+ ## Code of Conduct
11
+
12
+ This project adheres to the [Contributor Covenant](https://www.contributor-covenant.org/). By participating, you are expected to uphold this code of conduct.
13
+
14
+ ---
15
+
16
+ ## Reporting Bugs
17
+
18
+ Before submitting a bug report, please:
19
+
20
+ 1. **Check existing issues** — Your bug may already be reported.
21
+ 2. **Check the browser console** — Paste any errors.
22
+ 3. **Test in a different browser** — Narrow down the scope.
23
+ 4. **Read the troubleshooting section** of README.md.
24
+
25
+ ### Bug Report Template
26
+
27
+ When opening an issue, include:
28
+
29
+ ```markdown
30
+ **Describe the bug:**
31
+ A clear description of what is broken.
32
+
33
+ **Steps to reproduce:**
34
+ 1. I created an engine with clips: [paste code]
35
+ 2. I clicked the play button...
36
+ 3. Expected: audio plays
37
+ 4. Actual: [what actually happens]
38
+
39
+ **Browser & OS:**
40
+ - Browser: Chrome 120 / Firefox 121 / Safari 17
41
+ - OS: Windows 11 / macOS 14 / iOS 17
42
+
43
+ **Console errors:**
44
+ (paste any errors from DevTools Console)
45
+
46
+ **Minimal code example:**
47
+ (paste the smallest code snippet that reproduces the bug)
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Suggesting Features
53
+
54
+ Have an idea? Open an issue with:
55
+
56
+ 1. **Clear title** — What is the feature?
57
+ 2. **Motivation** — Why would this be useful?
58
+ 3. **Proposed API** — How would a user call it?
59
+ 4. **Alternatives** — Other approaches considered?
60
+
61
+ Example:
62
+
63
+ ```markdown
64
+ **Feature Request: Crossfade between clips**
65
+
66
+ Currently, clips change abruptly. It would sound more polished if clips
67
+ faded out/in over 500ms.
68
+
69
+ Proposed API:
70
+ engine = new AudioEngine(clips, {
71
+ fadeInDuration: 500, // ms
72
+ fadeOutDuration: 500 // ms
73
+ });
74
+
75
+ This is a common pattern in game audio engines.
76
+ ```
77
+
78
+ **Note:** Feature requests for crossfading, real-time DSP, or sub-second precision
79
+ are better suited to the Web Audio API. OpenAudio_r.js is intentionally simple.
80
+
81
+ ---
82
+
83
+ ## Submitting Code Changes
84
+
85
+ ### Setup
86
+
87
+ 1. Fork the repository
88
+ 2. Clone your fork
89
+ ```bash
90
+ git clone https://github.com/YOUR-USERNAME/openaudio-r.git
91
+ cd openaudio-r
92
+ ```
93
+ 3. Create a branch
94
+ ```bash
95
+ git checkout -b fix/autoplay-ios
96
+ ```
97
+
98
+ ### Make Changes
99
+
100
+ - **Edit only `OpenAudio_r.js`** (unless updating docs).
101
+ - **Test thoroughly** in multiple browsers and on mobile.
102
+ - **Update JSDoc comments** if you change signatures.
103
+ - **Add/update examples** if adding features.
104
+ - **Update CHANGELOG.md** with your change.
105
+
106
+ ### Code Style
107
+
108
+ - **Naming:** Use camelCase for variables/methods, PascalCase for classes.
109
+ - **Comments:** Comment *why*, not *what*. The code shows what; comments explain why.
110
+ - **JSDoc:** Document all public methods with parameter types and return values.
111
+ - **Error messages:** Be specific (include clip label, current time, etc.).
112
+ - **Callbacks:** Wrap in try/catch (see existing `onPlay`, `onEnd`, `onCycleReset` patterns).
113
+
114
+ ### Testing Checklist
115
+
116
+ Before opening a PR, test:
117
+
118
+ - [ ] **Desktop browsers:** Chrome, Firefox, Safari (all latest versions)
119
+ - [ ] **Mobile:** iOS Safari, Chrome Android
120
+ - [ ] **First play on page load:** Must be inside a user gesture
121
+ - [ ] **Background tab test:** Switch to another tab, wait 10 seconds, switch back—next clip should fire correctly
122
+ - [ ] **Multiple clips:** Add 5+ clips and verify shuffle bag (no repeats in a cycle)
123
+ - [ ] **volume control:** Verify `setVolume()` updates live playback
124
+ - [ ] **destroy():** Ensure listeners are removed (no memory leaks)
125
+ - [ ] **Example code:** Test minimal and advanced examples from README
126
+
127
+ ### Commit Messages
128
+
129
+ Write clear, atomic commits:
130
+
131
+ ```bash
132
+ git commit -m "Fix: prevent double unlock on rapid start() calls
133
+
134
+ - Added #isUnlocking flag to track unlock phase
135
+ - Rapid clicks to start() are now ignored until unlock completes
136
+ - Solves race condition where multiple #scheduleNext() calls overlap"
137
+ ```
138
+
139
+ **Guidelines:**
140
+ - Start with a type: `fix:`, `feat:`, `docs:`, `refactor:`, `test:`
141
+ - Reference any related issue: `Fixes #42`
142
+ - Explain *why*, not just *what*
143
+
144
+ ### Opening a Pull Request
145
+
146
+ 1. **Push to your fork**
147
+ ```bash
148
+ git push origin fix/autoplay-ios
149
+ ```
150
+
151
+ 2. **Open PR on GitHub**
152
+ - Title: `fix: prevent audio unlock race condition`
153
+ - Description: Explain the problem, your solution, and testing steps
154
+ - Link any related issues: `Fixes #42`
155
+ - Check the "allow edits from maintainers" box
156
+
157
+ 3. **PR Template**
158
+
159
+ ```markdown
160
+ ## Description
161
+ Briefly explain the change.
162
+
163
+ ## Type
164
+ - [ ] Bug fix (non-breaking change fixing an issue)
165
+ - [ ] New feature (non-breaking change adding functionality)
166
+ - [ ] Breaking change (fix or feature that changes existing API)
167
+ - [ ] Documentation update
168
+
169
+ ## Related Issue
170
+ Fixes #42
171
+
172
+ ## Testing
173
+ How did you verify this change?
174
+ - [ ] Tested in Chrome 120
175
+ - [ ] Tested in Firefox 121
176
+ - [ ] Tested in Safari 17
177
+ - [ ] Tested on iOS
178
+ - [ ] Tested on Android
179
+
180
+ ## Checklist
181
+ - [ ] Code follows project style (camelCase, JSDoc)
182
+ - [ ] Comments added for new logic
183
+ - [ ] CHANGELOG.md updated
184
+ - [ ] README.md updated (if API change)
185
+ - [ ] No breaking changes introduced
186
+ - [ ] Tests pass in all listed browsers
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Documentation Changes
192
+
193
+ ### Updating README.md
194
+
195
+ - Use clear, concise language
196
+ - Include code examples
197
+ - Test all code snippets (they should work as-is)
198
+ - Update table of contents if adding new sections
199
+
200
+ ### Adding Examples
201
+
202
+ 1. Create `/examples/your-example.html`
203
+ 2. Include a comment block explaining what it demonstrates
204
+ 3. Make it self-contained (no external dependencies)
205
+ 4. Link it from README.md
206
+
207
+ Example structure:
208
+
209
+ ```html
210
+ <!DOCTYPE html>
211
+ <html>
212
+ <head>
213
+ <title>OpenAudio_r.js — [Feature] Example</title>
214
+ </head>
215
+ <body>
216
+ <h1>[Feature] Example</h1>
217
+ <p>This example demonstrates [feature].</p>
218
+
219
+ <button id="play">Play</button>
220
+ <button id="stop">Stop</button>
221
+ <div id="status"></div>
222
+
223
+ <script src="../OpenAudio_r.js"></script>
224
+ <script>
225
+ // Your example code here
226
+ </script>
227
+ </body>
228
+ </html>
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Review Process
234
+
235
+ After you submit a PR:
236
+
237
+ 1. **Automated checks** run (linting, tests if any)
238
+ 2. **Code review** — I'll review the code and suggest changes if needed
239
+ 3. **Discussion** — We'll discuss any questions or concerns
240
+ 4. **Approval & merge** — Once approved, your code is merged
241
+
242
+ Expect 2–7 days for a response (I review contributions in batches).
243
+
244
+ ---
245
+
246
+ ## Project Structure
247
+
248
+ ```
249
+ openaudio-r/
250
+ ├── OpenAudio_r.js # Main source file
251
+ ├── README.md # Project documentation
252
+ ├── CONTRIBUTING.md # This file
253
+ ├── CHANGELOG.md # Version history
254
+ ├── LICENSE # GPL-3.0-or-later
255
+ ├── .gitignore # Git ignore rules
256
+ ├── package.json # npm metadata (if publishing)
257
+ ├── /examples # HTML demo files
258
+ ├── /docs # Extra documentation
259
+ └── /test # Test files (if added)
260
+ ```
261
+
262
+ ---
263
+
264
+ ## Development Tips
265
+
266
+ ### Testing Autoplay Policy
267
+
268
+ Browsers block autoplay unless inside a user gesture. Test this:
269
+
270
+ ```javascript
271
+ // ✅ This will work
272
+ document.addEventListener('click', () => engine.start());
273
+
274
+ // ❌ This will fail
275
+ setTimeout(() => engine.start(), 1000);
276
+ ```
277
+
278
+ ### Debugging Background Tab Throttling
279
+
280
+ 1. Open DevTools
281
+ 2. Go to Console
282
+ 3. Type: `engine.#timerSetAt` (to check timer state)
283
+ 4. Switch tabs and wait
284
+ 5. Return to tab and check if next clip fires on schedule
285
+
286
+ ### Memory Leaks
287
+
288
+ Always call `destroy()` when tearing down:
289
+
290
+ ```javascript
291
+ // React
292
+ useEffect(() => {
293
+ const engine = new AudioEngine(clips);
294
+ return () => engine.destroy();
295
+ }, []);
296
+ ```
297
+
298
+ ---
299
+
300
+ ## Versioning
301
+
302
+ This project uses [Semantic Versioning](https://semver.org/):
303
+
304
+ - **MAJOR** (2.0.0) — Breaking API changes
305
+ - **MINOR** (2.4.0) — New features, backward-compatible
306
+ - **PATCH** (2.4.1) — Bug fixes
307
+
308
+ Version numbers appear in:
309
+ - `OpenAudio_r.js` header (line 4)
310
+ - `CHANGELOG.md`
311
+ - `package.json` (if published to npm)
312
+
313
+ ---
314
+
315
+ ## Deployment & Publishing
316
+
317
+ ### Releases
318
+
319
+ 1. Update version in `OpenAudio_r.js` header
320
+ 2. Update `CHANGELOG.md`
321
+ 3. Create a GitHub Release with tag `v2.4.0`
322
+ 4. Add release notes summarizing changes
323
+
324
+ ### npm Publishing (if applicable)
325
+
326
+ ```bash
327
+ npm login
328
+ npm publish
329
+ ```
330
+
331
+ This will publish the package to https://www.npmjs.com/package/openaudio-r.
332
+
333
+ ---
334
+
335
+ ## Questions?
336
+
337
+ - 💬 Open a GitHub Discussion
338
+ - 📧 Mention me in an issue
339
+ - 🐛 Check existing issues first
340
+
341
+ ---
342
+
343
+ ## Recognition
344
+
345
+ Contributors will be listed in CHANGELOG.md and credited in commit messages. Thank you for helping make OpenAudio_r.js better!
346
+
347
+ ---
348
+
349
+ **Happy coding! 🎵**