@sudobility/music_player 0.1.27 → 0.1.29
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/CLAUDE.md +33 -29
- package/dist/shared/bus.d.ts +1 -1
- package/dist/shared/bus.d.ts.map +1 -1
- package/dist/shared/bus.js.map +1 -1
- package/dist/web/playback/click.d.ts +20 -7
- package/dist/web/playback/click.d.ts.map +1 -1
- package/dist/web/playback/click.js +0 -19
- package/dist/web/playback/click.js.map +1 -1
- package/package.json +5 -5
package/CLAUDE.md
CHANGED
|
@@ -10,8 +10,10 @@ building, and offline rendering. One of seven repos in the Moosiac family — se
|
|
|
10
10
|
`music_app/docs/architecture.md`.
|
|
11
11
|
|
|
12
12
|
**The rule: this package makes sound. `music_io` moves bytes. `music_codecs`
|
|
13
|
-
reads and writes score formats. `
|
|
14
|
-
|
|
13
|
+
reads and writes score formats. `music_editing` edits, and `music_lib` binds
|
|
14
|
+
the two (`bindPlayer`, typed on this package's `IMusicPlayer`).** It takes a
|
|
15
|
+
`Score` and produces audio; it knows nothing about editing, files or the store —
|
|
16
|
+
and music_editing does not depend on it either.
|
|
15
17
|
|
|
16
18
|
Its own package because playback was previously spread across three: the engines
|
|
17
19
|
in `music_io`, the transport brain in `music_lib` where it read the Zustand
|
|
@@ -40,6 +42,9 @@ installs `js-synthesizer` and a React Native app installs
|
|
|
40
42
|
|
|
41
43
|
## Gotchas
|
|
42
44
|
|
|
45
|
+
- **`ScheduledClick` and `Unsubscribe` are declared once each** — in `playback/synth-backend.ts` and `types.ts`. The web click and the bus import them; each had an identical second declaration, which agrees only until one is edited. `src/__one-declaration.test.ts` counts them. This is a within-package guard against drift, not the moved-names guard the other libraries carry: music_lib imports this package through `/core` by name rather than re-exporting it wholesale, so a duplicate here is not a TS2308 in music_lib — it is two types that silently part.
|
|
46
|
+
|
|
47
|
+
|
|
43
48
|
- **One fact, one declaration — and `src/__single-source.test.ts` enforces it.** A constant restated in a second package agrees with the first right up until one of them is edited, and nothing fails when they part: the build is clean, the types match, and the only symptom is a wrong sound or a picker quietly missing an entry. Measured across the family, 23 UPPER_CASE constants were declared in more than one repo — `CC_VOLUME` three times, `DYNAMICS` four, `C_MAJOR` five, and `DEFAULT_TIME_SIGNATURE` in four places under two names. The guard reads the list of names **from music_types at runtime** rather than restating it, because a check against duplication that duplicates what it checks would drift like everything else; its `ALLOWED` list is empty on purpose, so an exemption is a decision somebody writes down. Two shapes matter beyond the constants themselves. **A closed vocabulary is declared as an array and the type read off it** (`export const DYNAMICS = [...] as const; export type Dynamic = (typeof DYNAMICS)[number];`) — a TypeScript union has no runtime form, so anything that must *validate* a value has to write the list out again, which is exactly how music_api's decoder came to check generated music against its own private copy. **A label or option list keyed by the vocabulary is a `Record<T, ...>`, never a parallel array** — a record fails to compile when a member is added, an array silently goes on offering the old set; that is why the inspector's picker lists are `ACCIDENTAL_OPTIONS`/`ARTICULATION_OPTIONS` built from the vocabulary rather than `ACCIDENTALS`/`ARTICULATIONS` retyped. Test fixtures follow the same rule: the score fixtures live once, in `@sudobility/music_types/test`, and a package that needs a rendering fixture of its own re-exports them and adds to them.
|
|
44
49
|
|
|
45
50
|
- **`IMusicPlayer.load()` takes a `Score`; the engine still takes a plan.** This
|
|
@@ -90,30 +95,28 @@ installs `js-synthesizer` and a React Native app installs
|
|
|
90
95
|
*production build that works fine*; music_app's `vite.config.ts` lists it
|
|
91
96
|
beside music_lib and music_io.
|
|
92
97
|
|
|
93
|
-
- **Platform *engines* are optional peers
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
a shared component calling `pause()` on unmount does not crash the app. The
|
|
116
|
-
historical spikes are in `spikes/tone-on-rn-audio-api.md`.
|
|
98
|
+
- **Platform *engines* are optional peers, and there is no exception.** A React
|
|
99
|
+
Native app must never pull a browser audio library into its graph, which is
|
|
100
|
+
why `js-synthesizer` — libfluidsynth compiled to WASM, for an AudioWorklet —
|
|
101
|
+
and `react-native-audio-api` are both optional peers the app declares itself,
|
|
102
|
+
and `dependencies` is empty (`no-domain-imports.test.ts` pins it). The mp3
|
|
103
|
+
encoder, `@breezystack/lamejs`, is not this package's: encoding a rendered file
|
|
104
|
+
is music_io's, which carries it as its one runtime dependency and records why
|
|
105
|
+
it is not a peer.
|
|
106
|
+
- **React Native audio is a different implementation, not a port.** The web
|
|
107
|
+
engine is libfluidsynth compiled to WASM running in an `AudioWorklet`; React
|
|
108
|
+
Native has no AudioWorklet, so there was nothing to port — an RN engine had to
|
|
109
|
+
be a different implementation of the same `PlaybackEngine` interface. What was
|
|
110
|
+
there first subclassed the Tone engine over `react-native-audio-api` and
|
|
111
|
+
synthesised its own approximations of the instruments, so it could never match
|
|
112
|
+
what the web plays; it was deleted, and for a while RN deliberately had no
|
|
113
|
+
audio at all rather than a wrong sound. That gap is closed two ways, both in
|
|
114
|
+
`src/rn/`: `createMusicPlayer` builds `RNSamplePlaybackEngine`
|
|
115
|
+
(`playback/sample-engine.ts`, the FluidR3 sample engine described next), which
|
|
116
|
+
needs no native module and is the default; and `NativeSynthBackend`
|
|
117
|
+
(`playback/native-backend.ts`) drives a host-supplied native synth through the
|
|
118
|
+
same `SoundfontPlaybackEngine` scheduler the browser uses. The historical
|
|
119
|
+
spikes are in music_io's `spikes/tone-on-rn-audio-api.md`.
|
|
117
120
|
- **The two platforms play the same font by different means, and that is the
|
|
118
121
|
design.** Web runs libfluidsynth (WebAssembly) in an `AudioWorklet`; React
|
|
119
122
|
Native has neither — `react-native-audio-api` exposes no `addModule` and
|
|
@@ -124,7 +127,7 @@ installs `js-synthesizer` and a React Native app installs
|
|
|
124
127
|
What is lost is SF2's live per-zone filters, LFOs and modulator envelopes —
|
|
125
128
|
expressive variation, not the instrument's identity. The engine that was
|
|
126
129
|
deleted synthesised oscillator approximations, which is a different and much
|
|
127
|
-
worse thing. See `spikes/rn-sample-playback.md`.
|
|
130
|
+
worse thing. See music_io's `spikes/rn-sample-playback.md`.
|
|
128
131
|
- **`applyMix(score)` exists because mute and solo had setters and volume and pan did not.** A track's volume was read once at `loadScore` and pan only in `applyScoreToHost`, so once `music_lib`'s edit lock made a mix change stop reloading the score, moving a fader mid-playback moved the fader and not the sound. The web engine pushes CC7 and CC10 from the score and schedules nothing. **The RN engine reaches the same place with a node instead of a control change:** one gain-and-panner strip per track, built on first use, with voices connecting to their track's strip rather than to the master. Per-track rather than per-voice — the offline renderer builds a panner per voice because it schedules once and never changes its mind, where a live fader has to move under notes that are already sounding. That also settles where the headroom trim lives on RN: on the master, as it is on web, not multiplied into every voice's gain. **The metronome click bypasses the master on both platforms** so a score with more parts does not get a quieter click.
|
|
129
132
|
- **The transport is shared; only voicing is per platform.** `shared/playback/`
|
|
130
133
|
holds score flattening, the note cursor, the sounding set, the dispatch window
|
|
@@ -316,7 +319,7 @@ installs `js-synthesizer` and a React Native app installs
|
|
|
316
319
|
schedules against a *live* clock and pumps 200ms at a time, so reusing it for
|
|
317
320
|
export would make a render take as long as the piece. `RenderPlan` arrives
|
|
318
321
|
fully resolved (seconds, not ticks; mute and solo already applied by
|
|
319
|
-
`renderEvents` in
|
|
322
|
+
`renderEvents` in `shared/render-events.ts`), so `rn/audio/offline-render.ts` schedules the
|
|
320
323
|
whole thing up front against an `OfflineAudioContext`. What it *does* share
|
|
321
324
|
with the engine is `PackLibrary` and `planVoice` — the sample choice and the
|
|
322
325
|
gain — which is what keeps the file a recording of what was heard rather than
|
|
@@ -329,7 +332,8 @@ installs `js-synthesizer` and a React Native app installs
|
|
|
329
332
|
- `music_types` — the model, the score domain, the playhead (`@sudobility/music_types`)
|
|
330
333
|
- `music_codecs` — score file formats
|
|
331
334
|
- `music_io` — files, audio encoding, XML, MIDI input
|
|
332
|
-
- `
|
|
335
|
+
- `music_editing` — editing; depends on neither this package nor music_codecs
|
|
336
|
+
- `music_lib` — binds a store to this through `bindPlayer` and its playback adapter
|
|
333
337
|
- `music_app` — the web UI
|
|
334
338
|
|
|
335
339
|
## Git Workflow
|
package/dist/shared/bus.d.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* the caret and the piano keyboard genuinely care about different things.
|
|
20
20
|
*/
|
|
21
21
|
import type { SoundingNote, TransportPlaybackState } from '@sudobility/music_types';
|
|
22
|
-
|
|
22
|
+
import type { Unsubscribe } from '../types.js';
|
|
23
23
|
export declare class PlaybackBus {
|
|
24
24
|
private readonly soundingListeners;
|
|
25
25
|
private readonly transportListeners;
|
package/dist/shared/bus.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../src/shared/bus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EACV,YAAY,EACZ,sBAAsB,EACvB,MAAM,yBAAyB,CAAC;AAEjC,
|
|
1
|
+
{"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../src/shared/bus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EACV,YAAY,EACZ,sBAAsB,EACvB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,qBAAa,WAAW;IAUtB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAE9B;IACJ,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAE/B;IAEJ,yGAAyG;IACzG,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,aAAa,CAAqC;IAE1D,UAAU,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,WAAW;IAIzD,UAAU,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,KAAK,IAAI,GAAG,WAAW;IAK3E,WAAW,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,GAAG,WAAW;IAK3E;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMnC;;;OAGG;IACH,eAAe,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,IAAI;IAKrD,gBAAgB,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI;IAKrD;;;;;;;;;;;;OAYG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,IAAI,QAAQ,IAAI,SAAS,YAAY,EAAE,CAEtC;IAED,IAAI,SAAS,IAAI,sBAAsB,CAEtC;IAED,uEAAuE;IACvE,KAAK,IAAI,IAAI;CAId"}
|
package/dist/shared/bus.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bus.js","sourceRoot":"","sources":["../../src/shared/bus.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bus.js","sourceRoot":"","sources":["../../src/shared/bus.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,MAAM,OAAO,WAAW;IACtB;;;;;;;;MAQE;IACe,iBAAiB,GAAG,IAAI,GAAG,EAEzC,CAAC;IACa,kBAAkB,GAAG,IAAI,GAAG,EAE1C,CAAC;IAEJ,yGAAyG;IACjG,YAAY,GAA4B,EAAE,CAAC;IAC3C,aAAa,GAA2B,SAAS,CAAC;IAE1D,UAAU,CAAC,QAAgC;QACzC,OAAO,sBAAsB,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED,UAAU,CAAC,QAAkD;QAC3D,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACrC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC;IAED,WAAW,CAAC,QAAiD;QAC3D,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACxD,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,IAAY;QAC1B,wEAAwE;QACxE,mCAAmC;QACnC,sBAAsB,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED;;;OAGG;IACH,eAAe,CAAC,KAA8B;QAC5C,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,iBAAiB;YAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACjE,CAAC;IAED,gBAAgB,CAAC,KAA6B;QAC5C,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAC3B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,kBAAkB;YAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,IAAI,YAAY;QACd,OAAO,sBAAsB,EAAE,CAAC,YAAY,CAAC;IAC/C,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,uEAAuE;IACvE,KAAK;QACH,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAC;IAClC,CAAC;CACF"}
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The metronome click, in plain Web Audio.
|
|
3
|
+
*
|
|
4
|
+
* Not routed through the synth, and not through the mixer. A click is a
|
|
5
|
+
* monitoring aid rather than part of the music, so the master headroom trim and
|
|
6
|
+
* the per-track balance have no business changing how loud it is — and it
|
|
7
|
+
* should not consume one of the sixteen MIDI channels a score might need.
|
|
8
|
+
*
|
|
9
|
+
* Unlike notes, clicks are scheduled *ahead* at an exact time: an oscillator
|
|
10
|
+
* started with `start(at)` sounds at that sample whatever the main thread is
|
|
11
|
+
* doing. So the click stays steady even when the pump runs late, which makes it
|
|
12
|
+
* a usable reference rather than a second thing to distrust.
|
|
13
|
+
*
|
|
14
|
+
* Which is also why scheduling one hands back a way to take it back. The
|
|
15
|
+
* engine keeps a whole horizon of them queued, and `allSoundOff` does not
|
|
16
|
+
* reach any of it — that speaks to the synth, and a click deliberately does
|
|
17
|
+
* not go through the synth. So pausing left the room ticking for as long as
|
|
18
|
+
* the horizon was deep.
|
|
19
|
+
*/
|
|
20
|
+
import type { ScheduledClick } from '../../playback/synth-backend.js';
|
|
8
21
|
export declare function scheduleClick(context: BaseAudioContext, destination: AudioNode, atSeconds: number, accent: boolean): ScheduledClick;
|
|
9
22
|
//# sourceMappingURL=click.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"click.d.ts","sourceRoot":"","sources":["../../../src/web/playback/click.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"click.d.ts","sourceRoot":"","sources":["../../../src/web/playback/click.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAQtE,wBAAgB,aAAa,CAC3B,OAAO,EAAE,gBAAgB,EACzB,WAAW,EAAE,SAAS,EACtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,GACd,cAAc,CAqChB"}
|
|
@@ -1,22 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The metronome click, in plain Web Audio.
|
|
3
|
-
*
|
|
4
|
-
* Not routed through the synth, and not through the mixer. A click is a
|
|
5
|
-
* monitoring aid rather than part of the music, so the master headroom trim and
|
|
6
|
-
* the per-track balance have no business changing how loud it is — and it
|
|
7
|
-
* should not consume one of the sixteen MIDI channels a score might need.
|
|
8
|
-
*
|
|
9
|
-
* Unlike notes, clicks are scheduled *ahead* at an exact time: an oscillator
|
|
10
|
-
* started with `start(at)` sounds at that sample whatever the main thread is
|
|
11
|
-
* doing. So the click stays steady even when the pump runs late, which makes it
|
|
12
|
-
* a usable reference rather than a second thing to distrust.
|
|
13
|
-
*
|
|
14
|
-
* Which is also why scheduling one hands back a way to take it back. The
|
|
15
|
-
* engine keeps a whole horizon of them queued, and `allSoundOff` does not
|
|
16
|
-
* reach any of it — that speaks to the synth, and a click deliberately does
|
|
17
|
-
* not go through the synth. So pausing left the room ticking for as long as
|
|
18
|
-
* the horizon was deep.
|
|
19
|
-
*/
|
|
20
1
|
const ACCENT_HZ = 1500;
|
|
21
2
|
const BEAT_HZ = 1000;
|
|
22
3
|
const CLICK_SECONDS = 0.03;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"click.js","sourceRoot":"","sources":["../../../src/web/playback/click.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"click.js","sourceRoot":"","sources":["../../../src/web/playback/click.ts"],"names":[],"mappings":"AAqBA,MAAM,SAAS,GAAG,IAAI,CAAC;AACvB,MAAM,OAAO,GAAG,IAAI,CAAC;AACrB,MAAM,aAAa,GAAG,IAAI,CAAC;AAC3B,wEAAwE;AACxE,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB,MAAM,UAAU,aAAa,CAC3B,OAAyB,EACzB,WAAsB,EACtB,SAAiB,EACjB,MAAe;IAEf,MAAM,UAAU,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAClC,UAAU,CAAC,SAAS,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IAC1D,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAE1B,6EAA6E;IAC7E,2BAA2B;IAC3B,MAAM,GAAG,GAAG,SAAS,GAAG,aAAa,CAAC;IACtC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAChD,IAAI,CAAC,IAAI,CAAC,4BAA4B,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEpD,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC5B,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,UAAU,CAAC,OAAO,GAAG,GAAG,EAAE;QACxB,QAAQ,GAAG,IAAI,CAAC;QAChB,UAAU,CAAC,UAAU,EAAE,CAAC;QACxB,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC,CAAC;IAEF,OAAO;QACL,MAAM,EAAE,GAAG;QACX,MAAM,CAAC,IAAY;YACjB,oEAAoE;YACpE,yEAAyE;YACzE,kEAAkE;YAClE,IAAI,QAAQ,IAAI,IAAI,IAAI,GAAG;gBAAE,OAAO;YACpC,qEAAqE;YACrE,wDAAwD;YACxD,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YAClC,6DAA6D;YAC7D,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sudobility/music_player",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"description": "Playback for ScoreSmith: transport, synth engines and offline rendering, for web and React Native",
|
|
5
5
|
"author": "Sudobility",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -63,17 +63,17 @@
|
|
|
63
63
|
"scripts": {
|
|
64
64
|
"build": "tsc -p tsconfig.esm.json",
|
|
65
65
|
"clean": "rimraf dist",
|
|
66
|
-
"test": "vitest run",
|
|
66
|
+
"test:unit": "vitest run",
|
|
67
67
|
"test:watch": "vitest",
|
|
68
68
|
"lint": "eslint src",
|
|
69
69
|
"format": "prettier --write src/**/*.ts",
|
|
70
70
|
"format:check": "prettier --check src/**/*.ts",
|
|
71
71
|
"typecheck": "tsc --noEmit",
|
|
72
|
-
"verify": "bun run format:check && bun run typecheck && bun run lint && bun run test && bun run build",
|
|
72
|
+
"verify": "bun run format:check && bun run typecheck && bun run lint && bun run test:unit && bun run build",
|
|
73
73
|
"prepublishOnly": "bun run clean && bun run verify"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"@sudobility/music_types": "^0.13.
|
|
76
|
+
"@sudobility/music_types": "^0.13.28",
|
|
77
77
|
"js-synthesizer": "^1.13.0",
|
|
78
78
|
"react-native-audio-api": ">=0.13.0"
|
|
79
79
|
},
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
89
|
"@eslint/js": "^10.0.1",
|
|
90
|
-
"@sudobility/music_types": "^0.13.
|
|
90
|
+
"@sudobility/music_types": "^0.13.28",
|
|
91
91
|
"@types/node": "^26.2.0",
|
|
92
92
|
"@typescript-eslint/eslint-plugin": "^8.65.0",
|
|
93
93
|
"@typescript-eslint/parser": "^8.65.0",
|