pepperscore 0.3.0 → 0.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 +30 -0
- package/README.md +32 -3
- package/dist/assets/{import.worker-nfqQ5M0Y.js → import.worker-Rop-z7az.js} +2 -2
- package/dist/assets/verovio.worker-DQm-ikdG.js +7 -0
- package/dist/components/InstrumentChooser.d.ts +17 -0
- package/dist/components/OctaveTool.d.ts +21 -0
- package/dist/components/PepperScore.d.ts +7 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3214 -2198
- package/dist/index.js.map +1 -1
- package/dist/instruments.d.ts +2 -0
- package/dist/instruments.js +2 -0
- package/dist/lib/chrome.d.ts +7 -2
- package/dist/lib/file-state.d.ts +28 -1
- package/dist/lib/instrument-model.d.ts +80 -0
- package/dist/lib/instrument-switch-state.d.ts +169 -0
- package/dist/lib/instrument-view.d.ts +92 -0
- package/dist/lib/notation/document.d.ts +11 -1
- package/dist/lib/notation/mei-spelling.d.ts +9 -1
- package/dist/lib/notation/mei-tab.d.ts +7 -0
- package/dist/lib/prefs.d.ts +17 -0
- package/dist/lib/range-fit-core.d.ts +26 -0
- package/dist/lib/score.d.ts +16 -1
- package/dist/lib/tab/tab-parts.d.ts +8 -2
- package/dist/lib/transpose.d.ts +3 -2
- package/dist/range-fit-core-B1rMWdI4.js +468 -0
- package/dist/range-fit-core-B1rMWdI4.js.map +1 -0
- package/dist/style.css +1 -1
- package/package.json +9 -2
- package/dist/assets/verovio.worker-DGik-H4a.js +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0 - 2026-10-24
|
|
4
|
+
|
|
5
|
+
0.3.0 was never published, so 0.4.0 also contains everything listed under 0.3.0 below (guitar TAB, text sizes, the shared audio engine and the host hooks).
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Instrument switch (docs/specs/instrument-switch.md). `settings.instrument`, `settings.instruments` (per part, keyed by 1-based source part number or `onReady` part id), `settings.rangeLevel` (`'beginner' | 'intermediate' | 'advanced'`, default `'intermediate'`) and `settings.autoRange` (default `true`). A switched part changes sound, clef and written transposition (B♭ and E♭ instruments read at written pitch, also in a concert-pitch score) and each phrase is fitted into the instrument's range. A grand staff switches together. A piano part switched to guitar gets generated TAB, and a TAB staff doubling a switched part is hidden or regenerated.
|
|
10
|
+
- Highlights `ps-transposed` (moved by fitting or the octave tool), `ps-out-of-range` (`--ps-out-of-range`) and `ps-octave-selection`.
|
|
11
|
+
- `controls.instrumentSwitch` and `controls.octaveTool`: both on in `full`, off in `minimal` and `none` unless set. In `minimal` and `none`, `settings.instrument` / `settings.instruments` alone switch the part but show no switcher. The octave tool selects a note (with its tie chain), a passage or a phrase and moves it 8va/8vb relative to the shown pitch; a 0 override pins a note as written; Reset clears.
|
|
12
|
+
- The mixer separates Instrument from Sound (a playback override). Embeds get a popover switcher and, on a phone, a bottom toolbar. Part labels read "→ Instrument".
|
|
13
|
+
- `pepperscore/instruments`: the instrument model and range-fit core (`INSTRUMENTS`, `INSTRUMENT_IDS`, `EMBED_INSTRUMENTS`, levels, ranges, transpositions, clefs, spelling helpers, `writtenKeyFifths`, `joinRuns`, `tieChainOf`, `planShifts`, `applyOverrides`), shared with the editor.
|
|
14
|
+
- `onReady` parts gain `sourcePart` and `switchable`. Types `RangeLevel` and `SwitchInstrumentId` (from both `pepperscore` and `pepperscore/instruments`). The model's instrument type is `InstrumentInfo`, named apart from `pepperscore/audio`'s `Instrument`; `INSTRUMENTS` and `EMBED_INSTRUMENTS` are typed read-only and frozen.
|
|
15
|
+
- Saved per-score records (still version 2) keep each part's switch (`PartState.switch`: instrument, level, autoRange, octaves, sound) and a fingerprint of the host's instrument settings (`hostInstruments`, optional). Records without a switch open as written.
|
|
16
|
+
- Host instrument settings vs saved choices: a saved record's switches win while the host's instrument settings (`instrument`, `instruments`, `rangeLevel`, `autoRange`) are the ones it was saved under, or the host gives none. When they differ (the same score embedded as another instrument, or a block changed to another instrument), the host's apply again over the record; a part whose instrument changes loses its saved octave moves, and the rest of the record is kept.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Space on a focused button inside the reader now presses that button instead of turning the page (affects all embeds).
|
|
21
|
+
|
|
22
|
+
### Compatibility
|
|
23
|
+
|
|
24
|
+
- A reader's "keep as written" octave pin (8vb on an auto-raised phrase) is dropped once a transpose, key flip, level, instrument or fit change means auto-fit no longer moves that note, and it is not restored when transposing back.
|
|
25
|
+
- Saved records can now contain an octave override of 0. An older pepperscore reader sharing the same site storage accepts only +-12 and drops that part's whole saved switch.
|
|
26
|
+
|
|
27
|
+
### Known limitations
|
|
28
|
+
|
|
29
|
+
- A switched part's written transposition and key come from its first measure; a mid-part transposition change is not reflected in the engraving.
|
|
30
|
+
- MEI-file imports do not group grand staves.
|
|
31
|
+
- The octave tool moves a note at most one octave from as written (±12 in total), so a phrase two octaves out of range stays flagged.
|
|
32
|
+
|
|
3
33
|
## 0.3.0 - 2026-10-23
|
|
4
34
|
|
|
5
35
|
### Added
|
package/README.md
CHANGED
|
@@ -195,18 +195,18 @@ export default defineConfig({
|
|
|
195
195
|
| `scoreUrl` | `string` | | A score to download. Relative URLs resolve against the page. Cross-origin URLs need CORS. |
|
|
196
196
|
| `abc` | `string` | | ABC notation. |
|
|
197
197
|
| `chrome` | `'full' \| 'minimal' \| 'none'` | `'full'` | See the chrome table below. |
|
|
198
|
-
| `controls` | `{ transport?, viewToggle?, openFile?, mixer?, drawer?, zoom?, tabToggle? }` (booleans) | from `chrome` | Per-control overrides of the preset, see below. |
|
|
198
|
+
| `controls` | `{ transport?, viewToggle?, openFile?, mixer?, drawer?, zoom?, tabToggle?, instrumentSwitch?, octaveTool? }` (booleans) | from `chrome` | Per-control overrides of the preset, see below. |
|
|
199
199
|
| `view` | `'vertical' \| 'endless'` | saved or `'vertical'` | Vertical scrolls down, Endless scrolls sideways. Changing the prop re-applies it. |
|
|
200
200
|
| `height` | `string` | natural | `"fill"`: the parent's height. Any CSS length (`"420px"`, `"60vh"`, `"100dvh"`) fixes it. Omitted: `full` fills its parent with a 480px floor, and `minimal`/`none` take the height of their score. |
|
|
201
201
|
| `className` | `string` | | Extra classes on the `.pepperscore` root. |
|
|
202
202
|
| `ariaLabel` | `string` | `"Score: <title>"`, or `"Score reader"` | Accessible name of the reader's landmark region. By default it is `Score: ` and the loaded score's title, or `Score reader` while there is no titled score. Give each snippet on a page a distinct name when titles repeat. |
|
|
203
|
-
| `settings` | `PepperScoreSettings` | | **Initial** reader settings: `noteNames`, `chordSymbols`, `inferChords`, `beatCounts`, `subdivisions` (booleans); `musicFont` (`'Bravura' \| 'Petaluma'`); `staveFont` (`'Sans' \| 'Serif' \| 'Mono'`); `barsPerLine` (`'auto' \| 1–8`, Vertical view; without a `zoom`, an explicit count also sets the on-load size: that many bars fill the width, see below); `zoom` (stave scale, `null` = device default; with a `zoom`, `barsPerLine` only sets the line breaks); `semitones` (−12…12); `concert` (concert vs written pitch); `keyFlip` (spell a transposed view in the enharmonic key, for example Gb major for F# major); `bpm` (initial tempo, 30–240; the score's own tempo otherwise); `overlap` (0–3 lines kept on a page turn); `tabView`, `tabTuning`, `capo` (guitar TAB, see [Guitar TAB](#guitar-tab)); `annotationSizes` (text size per add-on, see below). Changing a key in the prop re-applies that key. Drawer edits still work in between. With `persist` on, **a saved per-score record overrides `settings` and `view`** when that score is opened again. The record holds the settings, view, zoom, transposition, part sounds
|
|
203
|
+
| `settings` | `PepperScoreSettings` | | **Initial** reader settings: `noteNames`, `chordSymbols`, `inferChords`, `beatCounts`, `subdivisions` (booleans); `musicFont` (`'Bravura' \| 'Petaluma'`); `staveFont` (`'Sans' \| 'Serif' \| 'Mono'`); `barsPerLine` (`'auto' \| 1–8`, Vertical view; without a `zoom`, an explicit count also sets the on-load size: that many bars fill the width, see below); `zoom` (stave scale, `null` = device default; with a `zoom`, `barsPerLine` only sets the line breaks); `semitones` (−12…12); `concert` (concert vs written pitch); `keyFlip` (spell a transposed view in the enharmonic key, for example Gb major for F# major); `bpm` (initial tempo, 30–240; the score's own tempo otherwise); `overlap` (0–3 lines kept on a page turn); `tabView`, `tabTuning`, `capo` (guitar TAB, see [Guitar TAB](#guitar-tab)); `annotationSizes` (text size per add-on, see below); `instrument`, `instruments`, `rangeLevel`, `autoRange` (the instrument switch, see below). Changing a key in the prop re-applies that key. Drawer edits still work in between. With `persist` on, **a saved per-score record overrides `settings` and `view`** when that score is opened again. The record holds the settings, view, zoom, transposition, part sounds, hidden staves and instrument switches the reader stored for that exact file. The instrument settings are the exception: when they differ from the ones the record was saved under, they apply again (see [Instrument switch](#instrument-switch)). |
|
|
204
204
|
| `persist` | `string \| false` | `'pepperscore'` for `full`, `false` for `minimal`/`none` | Storage namespace, see below. `false` reads and writes nothing. |
|
|
205
205
|
| `assetBaseUrl` | `string` | jsDelivr copy of `pepperscore-sounds-<soundPack>` | Root of a sounds-package layout. Relative values resolve against the page, and a missing trailing slash is added. |
|
|
206
206
|
| `verovioBaseUrl` | `string` | the copy in `dist/verovio/` | A directory with an interface-compatible Verovio build to engrave with, laid out like the `verovio` npm package's `dist/` (`verovio-module.mjs`, `verovio.mjs`), e.g. `https://cdn.jsdelivr.net/npm/verovio@6.3.0/dist/`. Shared by every reader on the page: set it before the first score engraves. See [Verovio](#verovio). |
|
|
207
207
|
| `soundPack` | `'core' \| 'complete'` | `'core'` | Picks the default `assetBaseUrl`. With your own `assetBaseUrl`, the `pack.json` found there decides which FluidR3 sounds exist. |
|
|
208
208
|
| `soundSources` | `SoundSource[]` | `[]` | Your own sounds for specific programs or the drum kit, see below. |
|
|
209
|
-
| `onReady` | `(info: { title, composer?, parts: { id, name }[], measures }) => void` | | Once per loaded score, after it is drawn. |
|
|
209
|
+
| `onReady` | `(info: { title, composer?, parts: { id, name, sourcePart, switchable }[], measures }) => void` | | Once per loaded score, after it is drawn. `parts` lists every staff (a grand staff's staves share one `sourcePart` number); `switchable` says whether the instrument switch applies. |
|
|
210
210
|
| `onPlay` / `onStop` | `() => void` | | Playback starts or stops, including when another instance takes over playback. |
|
|
211
211
|
| `onError` | `(error: Error) => void` | | Each error the reader shows: an unreadable file, a failed download or a renderer failure. |
|
|
212
212
|
| `clock` | `ExternalClock` | | A host clock that drives the playhead, see "Driving the playhead from your own clock". |
|
|
@@ -219,6 +219,8 @@ export default defineConfig({
|
|
|
219
219
|
| `paintTransition` | `'reveal' \| 'none'` | `'reveal'` | How a new `musicXml` or `abc` replaces a score already on screen. `'reveal'` fades it out, shows the loading overlay, scrolls to the top and fades the new score in. `'none'` keeps the current engraving and scroll position until the new one replaces it in place, with no fade or overlay (for a host that edits the score it shows). The first paint, other sources and setting changes always reveal. |
|
|
220
220
|
| `ref` | `Ref<PepperScoreHandle>` | | `{ play(): Promise<void>; stop(): void; transpose(semitones: number): void; seek(seconds: number): void; currentTime(): number; scrollToMeasure(index: number): Promise<void>; seekToMeasure(index: number): void }`. `play` does nothing while playing, before a score has loaded, with `chrome="none"`, or with a `clock`. `stop` does nothing with a `clock`. `transpose` sets the **absolute** transposition (clamped to −12…12), the same as `settings.semitones`. It does not add to the current value. `seek` moves the playhead (and keeps playing from there when playing). With a `clock` it calls `onSeek` instead. `currentTime` returns the playhead seconds, or `clock.now()` with a `clock`. |
|
|
221
221
|
|
|
222
|
+
**The instrument switch.** `settings.instrument` (a `SwitchInstrumentId`: any `InstrumentId` but `'drum-kit'`) shows the first switchable part as that instrument: its clef, written pitch, range and sound. `settings.instruments` sets it per part and wins over `instrument`. A key is either the 1-based source part number as a string (`{ '2': 'trumpet' }`: parts in score order, a grand staff counted once, a drum kit counted too) or an `onReady` part id; a staff id of a grand staff switches the whole part. `onReady`'s `parts[].sourcePart` and `parts[].id` are both valid keys, and parts with `switchable: false` (drum kits, percussion) are ignored. `rangeLevel` (`RangeLevel`: `'beginner' | 'intermediate' | 'advanced'`, default `'intermediate'`) and `autoRange` (default `true`: phrases outside the range move by an octave) set how switched parts fit. They apply to a score without a saved record, and to a saved one when they differ from the host settings it was saved under (see [Instrument switch](#instrument-switch)). In `minimal` and `none` they switch the part without showing a switcher; set `controls.instrumentSwitch` for one.
|
|
223
|
+
|
|
222
224
|
**Text add-on sizes with `annotationSizes`.** Each text add-on has its own size, in six steps: `'xs' | 'sm' | 'md' | 'rg' | 'lg' | 'xl'` (type `AnnotationSize`). `'rg'` (regular) is the default and draws the size earlier versions drew; the steps scale it by 0.7, 0.8, 0.9, 1, 1.2 and 1.45. Keys: `noteNames`, `chordSymbols` (source chord symbols and inferred ones), `beatCounts` (on-beat counts) and `subdivisions` (the e/&/a counts between beats). Give only the add-ons you want to change, for example `settings={{ noteNames: true, annotationSizes: { noteNames: 'lg' } }}`; unknown sizes are ignored. The rows under the staff grow with their labels, and Verovio sizes and spaces source chord symbols itself; the stave size and bar layout do not change. In the full reader each add-on's size is also a segmented control beside its switch in the options drawer (shown while that add-on is on), saved with the other reader settings and in each score's record.
|
|
223
225
|
|
|
224
226
|
**Sizing a snippet with `barsPerLine`.** In Vertical view, `settings={{ barsPerLine: N }}` without a `zoom` picks the stave size at which exactly N bars fill the reader's width, so N is the simplest way to set how large an embed draws: on the same width, `barsPerLine: 2` draws larger staves than `barsPerLine: 4`. The size is bounded (at most stave scale 2.5, at least 0.2; a single bar on a very wide reader is stretched to fill rather than drawn huge), and lines always hold N bars. A score shorter than one line takes its share of the width, centred. `'auto'` keeps the device default (four bars across on desktop). Endless view ignores `barsPerLine`.
|
|
@@ -286,6 +288,8 @@ For hosts that build on the reader (selection, cursors, navigation):
|
|
|
286
288
|
| `mixer` | The track mixer, plus the part icons, instrument picker and stave eyes. |
|
|
287
289
|
| `zoom` | The stave-scale slider, pinch zoom and the page arrows row. |
|
|
288
290
|
| `drawer` | The bottom drawer and its handle. |
|
|
291
|
+
| `instrumentSwitch` | The instrument switcher: the Instrument choice in the mixer and the embed popover, the range-level and auto-range controls, and the phone bottom toolbar of embeds. On in `full`; off in `minimal` and `none` unless you set it. `settings.instrument` / `settings.instruments` alone still switch the part, but show no switcher. |
|
|
292
|
+
| `octaveTool` | The octave tool (select a note, passage or phrase and move it 8va/8vb). On in `full`; off in `minimal` and `none` unless you set it. |
|
|
289
293
|
| `tabToggle` | The Notation / TAB / Both switch, in the header (in the More panel on a phone) and in the drawer. With the drawer on, the header copy is left out between 761 and 1260px, where the full header has no room for it. It shows only for a score with a pitched part. |
|
|
290
294
|
|
|
291
295
|
The header appears when any of `transport`, `viewToggle`, `openFile`, `mixer`, `zoom` or `tabToggle` is on. For example, `<PepperScore chrome="minimal" controls={{ viewToggle: true }} … />` keeps the compact play button and adds a small header with only the view toggle.
|
|
@@ -306,6 +310,29 @@ The header appears when any of `transport`, `viewToggle`, `openFile`, `mixer`, `
|
|
|
306
310
|
- Tied continuations keep their rhythm on the TAB staff but show no fret.
|
|
307
311
|
- **Baked fingerings.** The repository's `npm run tab:bake` (`scripts/tab-bake.mjs`, see the root README) writes the solver's string/fret onto a score's notes ahead of time, and can add a TAB staff. The reader keeps those fingerings as they are.
|
|
308
312
|
|
|
313
|
+
### Instrument switch
|
|
314
|
+
|
|
315
|
+
Full behaviour: `docs/specs/instrument-switch.md`. Choose an instrument for a part and the reader changes its sound, clef and written transposition (B♭ and E♭ instruments read at written pitch, also in a concert-pitch score), then fits each phrase into the instrument's range for the chosen level.
|
|
316
|
+
|
|
317
|
+
| Setting | Type | Default | Meaning |
|
|
318
|
+
| --- | --- | --- | --- |
|
|
319
|
+
| `instrument` | `SwitchInstrumentId` | | Shows the first switchable part as this instrument. |
|
|
320
|
+
| `instruments` | `Record<string, SwitchInstrumentId>` | | Per part: key is the 1-based source part number or an `onReady` part id. Wins over `instrument`. |
|
|
321
|
+
| `rangeLevel` | `RangeLevel` (`'beginner' \| 'intermediate' \| 'advanced'`) | `'intermediate'` | How wide a range the instrument is taken to have. |
|
|
322
|
+
| `autoRange` | `boolean` | `true` | Phrases outside the range move by an octave. `false` leaves them and marks them. |
|
|
323
|
+
|
|
324
|
+
- Notes moved by fitting get `ps-transposed` (`--ps-transposed`), notes still out of range get `ps-out-of-range` (`--ps-out-of-range`), and the octave tool's selection gets `ps-octave-selection`.
|
|
325
|
+
- A grand staff switches as one part. A piano part switched to guitar gets generated TAB, and a TAB staff that doubled the switched part is hidden or regenerated.
|
|
326
|
+
- The mixer lists Instrument (what the part is) and Sound (a playback override that keeps the notation).
|
|
327
|
+
- Embeds show a popover switcher with a short instrument list (`EMBED_INSTRUMENTS`), and on a phone a bottom toolbar.
|
|
328
|
+
- The octave tool (`controls.octaveTool`) selects a note and its tie chain, a passage (Shift-click) or a phrase, then moves it 8va or 8vb relative to its shown pitch. Reset clears the part's moves.
|
|
329
|
+
- The switcher shows in `full`, and in `minimal` or `none` only with `controls.instrumentSwitch: true`. Without it, `settings.instrument` / `settings.instruments` still switch the part.
|
|
330
|
+
- With `persist` on, saved records now hold instrument switches: each part's instrument, level, auto-range, octave moves and sound override, plus a fingerprint of the host's instrument settings (`instrument`, `instruments`, `rangeLevel`, `autoRange`). Records without a switch open as written.
|
|
331
|
+
- **Host settings vs saved choices.** Records are keyed by the score file, so one score embedded as piano in one lesson and as trumpet in another shares a record. When a score opens with a saved record, the reader compares the host's instrument settings with the ones saved in it. If they are the same, or the host gives none, the reader's saved choices win. If they differ (a teacher changed a block's instrument), the host's instrument, level and fit apply again; a part whose instrument changes loses its saved octave moves, and everything else in the record (other settings, zoom, sounds, hidden staves) is kept.
|
|
332
|
+
- `onReady` parts carry `sourcePart` and `switchable`.
|
|
333
|
+
|
|
334
|
+
**`pepperscore/instruments`** is a framework-free entry (no React, no Verovio) with the instrument model (`INSTRUMENTS`, `INSTRUMENT_IDS`, `EMBED_INSTRUMENTS`, levels, ranges, transpositions, clefs, `spellMidi`, `writtenPitch`, `transposePitchSpelled`, `writtenKeyFifths`) and the range-fit core (`joinRuns`, `tieChainOf`, `planShifts`, `applyOverrides`). The editor uses the same module. Its types include `InstrumentInfo` (one model entry; not the audio player's `Instrument` from `pepperscore/audio`), `InstrumentId`, `SwitchInstrumentId` and `RangeLevel`. `INSTRUMENTS` (`Readonly<Record<InstrumentId, Readonly<InstrumentInfo>>>`) and `EMBED_INSTRUMENTS` (`readonly InstrumentId[]`) are frozen.
|
|
335
|
+
|
|
309
336
|
### `persist`
|
|
310
337
|
|
|
311
338
|
Saved state lives under a namespace `<ns>`:
|
|
@@ -453,6 +480,8 @@ Sounds resolve exactly as in the reader (above): your `sources`, then the pack's
|
|
|
453
480
|
- Settings are initial values, not fully controlled props.
|
|
454
481
|
- Many large scores on one page engrave one after another, because they share a single Verovio worker. It is slow, not broken.
|
|
455
482
|
|
|
483
|
+
- **Instrument switch.** A switched part's written transposition and key come from its first measure, so a mid-part transposition change is not reflected in the engraving. MEI-file imports do not group grand staves, so a piano switches one staff at a time. The octave tool moves a note at most one octave from as written (±12 in total), and fitting moves a phrase by one octave, so a phrase two octaves out of range stays flagged `ps-out-of-range`.
|
|
484
|
+
|
|
456
485
|
## Licenses
|
|
457
486
|
|
|
458
487
|
The package licence is `MIT AND LGPL-3.0-or-later`:
|