audio-mixer-engine 1.1.6 → 1.3.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/README.md +78 -2
- package/dist/audio-mixer-engine.cjs.js +1 -1
- package/dist/audio-mixer-engine.es.js +1887 -671
- package/package.json +2 -1
- package/src/index.js +7 -0
- package/src/lib/metadata-utils.js +140 -0
- package/src/lib/midi-parser.js +6 -113
- package/src/lib/musicxml/metadata-extractor.js +116 -0
- package/src/lib/musicxml/mxl-loader.js +230 -0
- package/src/lib/musicxml/note-extractor.js +291 -0
- package/src/lib/musicxml/structure-analyzer.js +529 -0
- package/src/lib/musicxml/timing-engine.js +250 -0
- package/src/lib/musicxml/xml-helpers.js +112 -0
- package/src/lib/musicxml-converter.js +357 -0
- package/src/lib/playback-manager.js +47 -10
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ A part-centric JavaScript audio library for mixer applications. Provides individ
|
|
|
8
8
|
- **MIDI processing**: Parse files, beat/bar mapping, tempo changes, metadata extraction
|
|
9
9
|
- **Dual audio engines**: SpessaSynth (soundfont, ~10-50MB) or Lightweight (samples, ~574KB bundle)
|
|
10
10
|
- **Playback control**: Metronome, lead-in, seeking, speed changes, bar navigation, real-time events
|
|
11
|
+
- **MusicXML support**: Load MusicXML/MXL files directly — repeats, voltas, jumps, lyrics, dynamics
|
|
11
12
|
- **Mixer-ready**: Designed for solo/mute, routing, and level monitoring workflows
|
|
12
13
|
|
|
13
14
|
## Installation
|
|
@@ -63,6 +64,38 @@ for (const [partName, outputNode] of manager.getPartOutputs()) {
|
|
|
63
64
|
await manager.play({ leadIn: true, metronome: true });
|
|
64
65
|
```
|
|
65
66
|
|
|
67
|
+
### Loading MusicXML Files
|
|
68
|
+
|
|
69
|
+
PlaybackManager auto-detects MusicXML strings and MXL/ZIP ArrayBuffers:
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
import { loadMusicXml } from 'audio-mixer-engine';
|
|
73
|
+
|
|
74
|
+
// MXL file (ArrayBuffer) — auto-detected from ZIP magic bytes
|
|
75
|
+
await manager.load(mxlArrayBuffer);
|
|
76
|
+
|
|
77
|
+
// MusicXML string — auto-detected from <?xml or <score-partwise> prefix
|
|
78
|
+
const xmlString = await loadMusicXml(fileArrayBuffer);
|
|
79
|
+
await manager.load(xmlString);
|
|
80
|
+
|
|
81
|
+
// With metadata overrides (title, composer, per-part instrument mapping)
|
|
82
|
+
await manager.load(xmlString, metadataOverrides);
|
|
83
|
+
|
|
84
|
+
// From here on, playback works exactly the same as MIDI
|
|
85
|
+
await manager.play({ leadIn: true, metronome: true });
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
You can also convert manually for more control:
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
import { MusicXmlConverter, loadMusicXml } from 'audio-mixer-engine';
|
|
92
|
+
|
|
93
|
+
const xmlString = await loadMusicXml(fileArrayBuffer);
|
|
94
|
+
const converter = new MusicXmlConverter();
|
|
95
|
+
const parsedData = converter.convert(xmlString, { defaultTempo: 120 }, metadataOverrides);
|
|
96
|
+
await manager.load(parsedData);
|
|
97
|
+
```
|
|
98
|
+
|
|
66
99
|
## Key Concepts
|
|
67
100
|
|
|
68
101
|
**Part-centric design**: Each musical part gets an independent `ChannelHandle` with its own `AudioNode` output. Your application connects these outputs to gain controls, analyzers, and effects.
|
|
@@ -80,8 +113,12 @@ await manager.play({ leadIn: true, metronome: true });
|
|
|
80
113
|
### PlaybackManager
|
|
81
114
|
|
|
82
115
|
```javascript
|
|
83
|
-
// Lifecycle
|
|
84
|
-
await manager.load(midiArrayBuffer
|
|
116
|
+
// Lifecycle — load() auto-detects input type
|
|
117
|
+
await manager.load(midiArrayBuffer); // MIDI ArrayBuffer
|
|
118
|
+
await manager.load(mxlArrayBuffer); // MXL/ZIP ArrayBuffer (auto-detected)
|
|
119
|
+
await manager.load(musicXmlString); // MusicXML string (auto-detected)
|
|
120
|
+
await manager.load(parsedData); // Pre-parsed data object
|
|
121
|
+
await manager.load(input, metadata, instrumentMap); // With optional overrides
|
|
85
122
|
manager.reset();
|
|
86
123
|
|
|
87
124
|
// Transport
|
|
@@ -198,6 +235,42 @@ audioEngine.allSoundsOff();
|
|
|
198
235
|
audioEngine.destroy();
|
|
199
236
|
```
|
|
200
237
|
|
|
238
|
+
### MusicXML Processing
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
import { MusicXmlConverter, loadMusicXml, loadMusicXmlSync } from 'audio-mixer-engine';
|
|
242
|
+
|
|
243
|
+
// Load from ArrayBuffer (MXL or plain XML)
|
|
244
|
+
const xmlString = await loadMusicXml(fileArrayBuffer);
|
|
245
|
+
|
|
246
|
+
// Or load synchronously when data is already available
|
|
247
|
+
const xmlString2 = loadMusicXmlSync(uint8ArrayData);
|
|
248
|
+
|
|
249
|
+
// Convert to parsedData (same format as MidiParser output)
|
|
250
|
+
const converter = new MusicXmlConverter();
|
|
251
|
+
const parsedData = converter.convert(xmlString, {
|
|
252
|
+
defaultTempo: 120, // Fallback tempo if none in score
|
|
253
|
+
defaultVelocity: 80 // Fallback note velocity
|
|
254
|
+
}, metadataOverrides); // Optional: override title, composer, per-part instruments
|
|
255
|
+
|
|
256
|
+
// parsedData includes parts, barStructure, metadata, and structureMetadata
|
|
257
|
+
// Use with PlaybackManager or MidiPlayer just like MIDI-parsed data
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Metadata Utilities
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
import { resolveInstrument, normalizeLegacyMetadata } from 'audio-mixer-engine';
|
|
264
|
+
|
|
265
|
+
// Map instrument names/numbers to MIDI program numbers
|
|
266
|
+
resolveInstrument('piano'); // 0
|
|
267
|
+
resolveInstrument('choir_aahs'); // 52
|
|
268
|
+
resolveInstrument(40); // 40
|
|
269
|
+
|
|
270
|
+
// Normalize legacy v1 metadata format to v2
|
|
271
|
+
const normalized = normalizeLegacyMetadata(legacyMetadata);
|
|
272
|
+
```
|
|
273
|
+
|
|
201
274
|
## Mixer Example
|
|
202
275
|
|
|
203
276
|
```javascript
|
|
@@ -251,11 +324,13 @@ class AudioMixer {
|
|
|
251
324
|
|
|
252
325
|
## Additional Documentation
|
|
253
326
|
|
|
327
|
+
- **[MUSICXML.md](./MUSICXML.md)** - MusicXML/MXL file loading, supported elements, and API reference
|
|
254
328
|
- **[LIGHTWEIGHT_ENGINE.md](./LIGHTWEIGHT_ENGINE.md)** - Lightweight engine setup and sample file configuration
|
|
255
329
|
- **[METADATA.md](./METADATA.md)** - Score metadata, part configuration, and playback modifiers
|
|
256
330
|
- **[BEATMAPPING.md](./BEATMAPPING.md)** - Beat mapping and non-linear playback structures
|
|
257
331
|
- **[INTERFACE.md](./INTERFACE.md)** - Complete interface contract for UI integration
|
|
258
332
|
- **[INIT_PROGRESS.md](./INIT_PROGRESS.md)** - Initialization progress tracking and best practices
|
|
333
|
+
- **[IOS_AUDIO_RESUMPTION.md](./IOS_AUDIO_RESUMPTION.md)** - Handling iOS screen lock/background audio suspension
|
|
259
334
|
|
|
260
335
|
## Development
|
|
261
336
|
|
|
@@ -281,3 +356,4 @@ MIT License - see LICENSE file for details.
|
|
|
281
356
|
|
|
282
357
|
- **Chromium browsers** (Chrome, Edge, Brave): May experience audio distortion due to Web Audio API bugs
|
|
283
358
|
- **Safari**: Should work with standard Web Audio API support
|
|
359
|
+
- **iOS Safari**: AudioContext is suspended on screen lock/app background. Consuming applications must handle resumption -- see [IOS_AUDIO_RESUMPTION.md](./IOS_AUDIO_RESUMPTION.md)
|