@sudobility/music_types 0.13.26 → 0.13.27
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 -3
- package/dist/domain/documents/document-state.d.ts +17 -0
- package/dist/domain/documents/document-state.d.ts.map +1 -0
- package/dist/domain/documents/document-state.js +6 -0
- package/dist/domain/documents/document-state.js.map +1 -0
- package/dist/domain/documents/export-formats.d.ts +74 -0
- package/dist/domain/documents/export-formats.d.ts.map +1 -0
- package/dist/domain/documents/export-formats.js +53 -0
- package/dist/domain/documents/export-formats.js.map +1 -0
- package/dist/domain/documents/formats.d.ts +17 -0
- package/dist/domain/documents/formats.d.ts.map +1 -0
- package/dist/domain/documents/formats.js +61 -0
- package/dist/domain/documents/formats.js.map +1 -0
- package/dist/domain/documents/project-file.d.ts +33 -0
- package/dist/domain/documents/project-file.d.ts.map +1 -0
- package/dist/domain/documents/project-file.js +14 -0
- package/dist/domain/documents/project-file.js.map +1 -0
- package/dist/domain/documents/publish.d.ts +6 -0
- package/dist/domain/documents/publish.d.ts.map +1 -0
- package/dist/domain/documents/publish.js +2 -0
- package/dist/domain/documents/publish.js.map +1 -0
- package/dist/domain/documents/templates.d.ts +21 -0
- package/dist/domain/documents/templates.d.ts.map +1 -0
- package/dist/domain/documents/templates.js +22 -0
- package/dist/domain/documents/templates.js.map +1 -0
- package/dist/domain/editor/app-errors.d.ts +16 -0
- package/dist/domain/editor/app-errors.d.ts.map +1 -0
- package/dist/domain/editor/app-errors.js +8 -0
- package/dist/domain/editor/app-errors.js.map +1 -0
- package/dist/domain/editor/context-menu.d.ts +74 -0
- package/dist/domain/editor/context-menu.d.ts.map +1 -0
- package/dist/domain/editor/context-menu.js +19 -0
- package/dist/domain/editor/context-menu.js.map +1 -0
- package/dist/domain/editor/device-prefs.d.ts +107 -0
- package/dist/domain/editor/device-prefs.d.ts.map +1 -0
- package/dist/domain/editor/device-prefs.js +66 -0
- package/dist/domain/editor/device-prefs.js.map +1 -0
- package/dist/domain/editor/docs.d.ts +56 -0
- package/dist/domain/editor/docs.d.ts.map +1 -0
- package/dist/domain/editor/docs.js +41 -0
- package/dist/domain/editor/docs.js.map +1 -0
- package/dist/domain/editor/edit-mode.d.ts +31 -0
- package/dist/domain/editor/edit-mode.d.ts.map +1 -0
- package/dist/domain/editor/edit-mode.js +40 -0
- package/dist/domain/editor/edit-mode.js.map +1 -0
- package/dist/domain/editor/editing-copy.d.ts +91 -0
- package/dist/domain/editor/editing-copy.d.ts.map +1 -0
- package/dist/domain/editor/editing-copy.js +88 -0
- package/dist/domain/editor/editing-copy.js.map +1 -0
- package/dist/domain/editor/inspector.d.ts +45 -0
- package/dist/domain/editor/inspector.d.ts.map +1 -0
- package/dist/domain/editor/inspector.js +34 -0
- package/dist/domain/editor/inspector.js.map +1 -0
- package/dist/domain/editor/labelled-option.d.ts +6 -0
- package/dist/domain/editor/labelled-option.d.ts.map +1 -0
- package/dist/domain/editor/labelled-option.js +2 -0
- package/dist/domain/editor/labelled-option.js.map +1 -0
- package/dist/domain/editor/library-copy.d.ts +61 -0
- package/dist/domain/editor/library-copy.d.ts.map +1 -0
- package/dist/domain/editor/library-copy.js +2 -0
- package/dist/domain/editor/library-copy.js.map +1 -0
- package/dist/domain/editor/print.d.ts +30 -0
- package/dist/domain/editor/print.d.ts.map +1 -0
- package/dist/domain/editor/print.js +43 -0
- package/dist/domain/editor/print.js.map +1 -0
- package/dist/domain/editor/score-input.d.ts +158 -0
- package/dist/domain/editor/score-input.d.ts.map +1 -0
- package/dist/domain/editor/score-input.js +2 -0
- package/dist/domain/editor/score-input.js.map +1 -0
- package/dist/domain/editor/toast.d.ts +32 -0
- package/dist/domain/editor/toast.d.ts.map +1 -0
- package/dist/domain/editor/toast.js +5 -0
- package/dist/domain/editor/toast.js.map +1 -0
- package/dist/domain/editor/toolbar.d.ts +62 -0
- package/dist/domain/editor/toolbar.d.ts.map +1 -0
- package/dist/domain/editor/toolbar.js +83 -0
- package/dist/domain/editor/toolbar.js.map +1 -0
- package/dist/domain/editor/view-settings.d.ts +22 -0
- package/dist/domain/editor/view-settings.d.ts.map +1 -0
- package/dist/domain/editor/view-settings.js +30 -0
- package/dist/domain/editor/view-settings.js.map +1 -0
- package/dist/domain/generation/replace-drafts.d.ts +78 -0
- package/dist/domain/generation/replace-drafts.d.ts.map +1 -0
- package/dist/domain/generation/replace-drafts.js +40 -0
- package/dist/domain/generation/replace-drafts.js.map +1 -0
- package/dist/domain/generation/request-drafts.d.ts +226 -0
- package/dist/domain/generation/request-drafts.d.ts.map +1 -0
- package/dist/domain/generation/request-drafts.js +52 -0
- package/dist/domain/generation/request-drafts.js.map +1 -0
- package/dist/domain/instruments/gm-catalogue.d.ts +27 -3
- package/dist/domain/instruments/gm-catalogue.d.ts.map +1 -1
- package/dist/domain/instruments/gm-catalogue.js +4 -3
- package/dist/domain/instruments/gm-catalogue.js.map +1 -1
- package/dist/domain/instruments/gm-polyphony.d.ts +25 -2
- package/dist/domain/instruments/gm-polyphony.d.ts.map +1 -1
- package/dist/domain/instruments/gm-polyphony.js +9 -3
- package/dist/domain/instruments/gm-polyphony.js.map +1 -1
- package/dist/domain/instruments/gm-range.d.ts +10 -6
- package/dist/domain/instruments/gm-range.d.ts.map +1 -1
- package/dist/domain/instruments/gm-range.js +18 -3
- package/dist/domain/instruments/gm-range.js.map +1 -1
- package/dist/domain/instruments/out-of-range.d.ts +70 -0
- package/dist/domain/instruments/out-of-range.d.ts.map +1 -0
- package/dist/domain/instruments/out-of-range.js +106 -0
- package/dist/domain/instruments/out-of-range.js.map +1 -0
- package/dist/domain/instruments/track-instrument.d.ts +23 -0
- package/dist/domain/instruments/track-instrument.d.ts.map +1 -1
- package/dist/domain/instruments/track-instrument.js +26 -0
- package/dist/domain/instruments/track-instrument.js.map +1 -1
- package/dist/domain/notation/music-vocabulary.d.ts +17 -0
- package/dist/domain/notation/music-vocabulary.d.ts.map +1 -1
- package/dist/domain/notation/music-vocabulary.js +25 -1
- package/dist/domain/notation/music-vocabulary.js.map +1 -1
- package/dist/domain/notation/picker-options.d.ts +42 -2
- package/dist/domain/notation/picker-options.d.ts.map +1 -1
- package/dist/domain/notation/picker-options.js +41 -2
- package/dist/domain/notation/picker-options.js.map +1 -1
- package/dist/domain/score/transport-settings.d.ts +29 -0
- package/dist/domain/score/transport-settings.d.ts.map +1 -0
- package/dist/domain/score/transport-settings.js +2 -0
- package/dist/domain/score/transport-settings.js.map +1 -0
- package/dist/formats/audio-import.d.ts +15 -0
- package/dist/formats/audio-import.d.ts.map +1 -0
- package/dist/formats/audio-import.js +26 -0
- package/dist/formats/audio-import.js.map +1 -0
- package/dist/formats/index.d.ts +10 -0
- package/dist/formats/index.d.ts.map +1 -1
- package/dist/formats/index.js +10 -0
- package/dist/formats/index.js.map +1 -1
- package/dist/formats/midi-import.d.ts +128 -0
- package/dist/formats/midi-import.d.ts.map +1 -0
- package/dist/formats/midi-import.js +2 -0
- package/dist/formats/midi-import.js.map +1 -0
- package/dist/formats/musicxml.d.ts +44 -0
- package/dist/formats/musicxml.d.ts.map +1 -0
- package/dist/formats/musicxml.js +2 -0
- package/dist/formats/musicxml.js.map +1 -0
- package/dist/formats/tracker-export.d.ts +55 -0
- package/dist/formats/tracker-export.d.ts.map +1 -0
- package/dist/formats/tracker-export.js +18 -0
- package/dist/formats/tracker-export.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -1
- package/dist/platform/index.d.ts +2 -0
- package/dist/platform/index.d.ts.map +1 -1
- package/dist/platform/index.js +2 -0
- package/dist/platform/index.js.map +1 -1
- package/dist/platform/score-files.d.ts +36 -0
- package/dist/platform/score-files.d.ts.map +1 -0
- package/dist/platform/score-files.js +2 -0
- package/dist/platform/score-files.js.map +1 -0
- package/dist/platform/storage.d.ts +19 -0
- package/dist/platform/storage.d.ts.map +1 -0
- package/dist/platform/storage.js +10 -0
- package/dist/platform/storage.js.map +1 -0
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
> explicitly asks in that turn**. Approval for an earlier change does not carry forward, and
|
|
6
6
|
> finishing a task is not permission to commit it.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
The model of the Moosiac music family, and every name the family shares: the score types and their Zod schemas, the pure primitives both the frontend and the backend need (pitch and tick math, factories, commands, instrument knowledge, readout formatting, `outOfRangeNoteIds`), and **every shared type and closed vocabulary** — the codecs' option and result types, the platform contracts, the editor's vocabulary, the generation drafts, the export formats and the formats table. Consumed by music_api, music_codecs, music_player, music_drawing, music_editing, music_client, music_io, music_lib and both apps.
|
|
9
|
+
|
|
10
|
+
**Two rules decide what lives here, and both are the user's.** *All type definitions and vocabulary constants live in music_types* — a shape or a closed list another package names is declared here once, never in the package that happens to use it first. *Pure helper functions used by both the frontend and the backend live in music_types* too. Either kind must still pass the four tests every module here passes: it works on both sides, adds no dependency (the runtime dependencies are `zod` and `immer`, and that is the whole list), contains no hook, and contains no async code. A type whose shape needs zustand, React, a class or a renderer stays with the package that has that dependency.
|
|
9
11
|
|
|
10
12
|
## Tech Stack
|
|
11
13
|
|
|
@@ -35,15 +37,42 @@ Everything exports from a single sectioned `src/index.ts`:
|
|
|
35
37
|
8. Zod schemas for the project API
|
|
36
38
|
9. Response envelope (`ApiResponse<T>`, `successResponse`, `errorResponse`, `API_ERROR_CODES`)
|
|
37
39
|
|
|
40
|
+
Then the shared primitives under `src/domain/` (score, commands, instruments, notation, generation, …) and the shared vocabulary:
|
|
41
|
+
|
|
42
|
+
- `src/formats/` — the codecs' option and result types and the audio-import extensions
|
|
43
|
+
- `src/platform/` — the platform contracts (`ScoreFiles`, `PrefsStorage`/`DocumentFileStorage`, `XmlParser`, `FileExporter`, MIDI input, playback)
|
|
44
|
+
- `src/domain/editor/` — the editor's vocabulary (edit modes, device prefs, toasts, `LAYOUT_MODES`/`LayoutMode`, `PAPER_OPTIONS`/`ORIENTATION_OPTIONS`, docs, inspector, toolbar and context-menu vocabularies, input shapes, copy contracts)
|
|
45
|
+
- `src/domain/documents/` — `export-formats.ts` (`WRITABLE_EXPORT_FORMATS`), `formats.ts` (`IMPORT_FORMATS`/`EXPORT_FORMATS`), `templates.ts`, `document-state.ts`, `publish.ts`, and `project-file.ts` (`DOCUMENT_EXTENSION(S)`, `PROJECT_FILE_VERSION`, `ProjectFile`; the parser and serializer are music_codecs')
|
|
46
|
+
- `src/domain/generation/request-drafts.ts` / `replace-drafts.ts` — the generation forms; `src/domain/score/transport-settings.ts` — `TransportSettings`/`PlayerFailure`
|
|
47
|
+
|
|
38
48
|
`src/test-helpers.ts` is a test-only fixture helper (excluded from the published build); shared score factories live in this package under `domain/score/`.
|
|
39
49
|
|
|
40
50
|
## Gotchas
|
|
41
51
|
|
|
52
|
+
- **Frontend vocabulary lives here too, as types and data only.** Both apps and every frontend library name the same closed lists and shapes, and music_lib re-exports this package *and* music_editing/music_codecs/music_drawing wholesale — so a shape declared in two of them is a TS2308 in music_lib and a "Cannot redefine property" crash in a CommonJS consumer. `domain/editor/` holds the editor's vocabulary (`EDIT_MODES`/`EDIT_MODE_OPTIONS`, `THEME_MODES`/`FONT_SIZES`/`DevicePrefs`/`DevSettings`, `Toast`/`ToastSink`, `LAYOUT_MODES`, `QUANTIZE_GRIDS`, the inspector, toolbar and context-menu vocabularies, `ClipboardData`, `ScoreCanvasHit` and the other input shapes, `EditingCopy`/`LibraryCopy`, the docs and shortcut shapes, the paper options, `AppErrorCode`); `domain/generation/request-drafts.ts` and `replace-drafts.ts` the generation forms (`NewProjectSubmission`, `LOCKABLE`, `ReplaceSubmission`); `domain/documents/` the export formats (`WRITABLE_EXPORT_FORMATS`) and the formats table (`formats.ts`, which came from music_editing), `TEMPLATE_IDS`, `DocumentOrigin`/`SaveState`, `PublishNames`, and the project file's name and version (`DOCUMENT_EXTENSION(S)`, `PROJECT_FILE_VERSION`); `domain/score/transport-settings.ts` `TransportSettings`/`PlayerFailure`; `formats/` the codecs' option and result types (`MidiImportOptions`, `MusicXmlWarnings`, `TrackerFitReport`) and the audio-import extensions; `platform/` the `ScoreFiles`, `PrefsStorage` and `DocumentFileStorage` contracts. The rules over them live with whatever owns the rule — `selectToolbarAvailability` in music_editing; `bindPlayer`, `planExport`, `decideClose`/`decideQuit`, `resolveThemeMode` and the docs content in music_lib; `litKeys` in music_drawing; the parsers and serializers in music_codecs. This package has no moved-names guard because it is where names move *to*; each package they left carries one (`__moved-to-types.test.ts` in music_codecs, music_client, music_io and music_lib, `__moved-out.test.ts` in music_drawing and music_editing).
|
|
53
|
+
- **`outOfRangeNoteIds` is a pure question about the model**, so it lives in `domain/instruments/out-of-range.ts`, beside `trackRangeIsBinding` (`range-fit.ts`), rather than in music_drawing, which only colours the answer. It takes the **stored** score, never `displayScore`'s.
|
|
54
|
+
- **A file named `document.ts` trips `platform-free.test.ts`**: the export path `./documents/document.js` reads as the `document.` global to its pattern. That is why it is `document-state.ts`.
|
|
55
|
+
|
|
56
|
+
|
|
42
57
|
- **One row per General MIDI program, and every row says where its numbers came from** (`gm-catalogue.ts`). Range, polyphony and transposition used to be three tables of family defaults plus a handful of per-program overrides — which looked like deduplication and was not: 90 of the 128 programs inherited a compass nobody had chosen for them, and an inherited value was indistinguishable from a researched one. It hid a real bug (**Muted Trumpet** had no transposition entry, so a B-flat trumpet with a mute in the bell was treated as non-transposing and its part displayed a whole tone wrong), gave the **Clavinet** an 88-key piano compass where it has 60 keys F1-E6, and handed the flute's exact range to five instruments that share none of it. The repetition where eight guitars genuinely share a compass is the point: writing it eight times is a decision somebody made, where inheriting it eight times is a question nobody was asked. **`basis` is the field to read before trusting a number** — `measured` (checked against a source), `synthetic` (an electronic patch has no acoustic compass, so it gets the whole keyboard rather than an invented limit), `unpitched` (a sound effect), and `assumed` (**not verified**, carried over from the old default, left deliberately wide). No row is left `assumed`: the 31 that were have each been settled, most by looking the instrument up and ten by finding that the honest answer is `tunable` — a shamisen is tuned to the singer, a koto to the piece, an mbira to notes that are not on the tempered scale at all, and a pan flute or hammered dulcimer is built in many sizes; refusing a note against those would be refusing against the sampler rather than the instrument. Section patches (`String Ensemble`, `Brass Section`) take the **union of the instruments in them, computed rather than typed**, so a string section cannot end up narrower than the cello inside it. Where General MIDI names a family rather than an instrument the row covers the common members: "Recorder" is soprano and alto together, "Bagpipe" is the Highland chanter's nine notes and the uilleann's two octaves together — the Highland compass alone is fifteen semitones and rejected honest music. The split is now 75 measured, 30 synthetic, 13 unpitched, 10 tunable. `gmRangeIsBinding` answers `true` only for `measured`, and the generation inspector consults it before reporting an out-of-range note: refusing a note against a compass nobody checked rejects music that was fine, and since that finding drives a retry it would spend real money arguing about a limit we invented.
|
|
43
58
|
|
|
59
|
+
- **`Track.midiProgram` means two different things, and
|
|
60
|
+
`domain/instruments/track-instrument.ts` is the only place that knows which.**
|
|
61
|
+
On a percussion-clef track (`isPercussionTrack`) it addresses a General MIDI
|
|
62
|
+
*drum kit* (`gm-kit.ts`); everywhere else it is an instrument (`gm.ts`). The two
|
|
63
|
+
never coincide — Brush is kit 40, and program 40 is Violin — so every
|
|
64
|
+
program-keyed table (`gm-range`, `gm-polyphony`, `gm-transposition`,
|
|
65
|
+
`gm-icon`) gives a confidently wrong answer for a drum track. Take a `Track`
|
|
66
|
+
and call `trackKeyboardRange`/`trackMaxPolyphony`/`trackWrittenTransposition`/
|
|
67
|
+
`trackInstrumentIcon`/`trackInstrumentLabel` instead; the program-keyed
|
|
68
|
+
functions stay exported for callers that genuinely hold only a program.
|
|
69
|
+
`scoreWithResolvedKits` (which music_editing's `setScore` runs inbound) snaps a
|
|
70
|
+
percussion track to a real kit and returns the **identical score** when there
|
|
71
|
+
is nothing to fix, which is what keeps opening a project from marking it dirty.
|
|
72
|
+
|
|
44
73
|
- **A regeneration request says who is playing, and a kit gets told how a kit is written.** A `ScoreFragment` is measures and nothing else — no name, no clef, no program — so "Replace Track" used to hand the model anonymous bars and let it infer the instrument from the notes in front of it. On a drum track there is nothing to infer from: the pitches are drum numbers, not notes. Measured on a real Power Kit regeneration, the result was the kick on every eighth of all 118 bars at a constant velocity 100, the snare on all four beats instead of the backbeat, and five of the 47 drums used — a metronome, not a groove. `RegenerateRegionRequest.tracks` now carries a `GenerateScoreRequestTrack` per fragment track, built by `describeTrackForGeneration` in music_types so whole-score generation and regeneration describe a track the *same* way; the range and polyphony come from `trackKeyboardRange`/`trackMaxPolyphony`, which answer about the **kit** on a percussion track rather than about whatever melodic program shares its number. The roster is matched to the fragment **by position**, so `buildRegeneratePrompt` emits it only when the lengths agree — a roster of a different length is not partial information but wrong information, naming the kit as the cello. And `percussionRules()` — previously generate-only, and previously just the GM map — now travels on both paths and states the two Expression rules that **invert** for percussion: an accent is the rule rather than the exception (velocity variation between accented and ghost notes *is* the groove), and a kit does play continuously even though each individual drum still rests. The map alone is not enough, which is the thing that had to be measured to be believed.
|
|
45
74
|
|
|
46
|
-
- **One fact, one declaration — and `src/__single-source.test.ts` enforces it
|
|
75
|
+
- **One fact, one declaration — and each consuming package's `src/__single-source.test.ts` enforces it** (here, `domain/vocabulary-source.test.ts` pins the array-then-type shape). 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.
|
|
47
76
|
|
|
48
77
|
- **The playhead is the one stateful service in this package, and that is a
|
|
49
78
|
deliberate precedent.** `MusicPosition` and its singleton live in
|
|
@@ -67,7 +96,8 @@ Everything exports from a single sectioned `src/index.ts`:
|
|
|
67
96
|
|
|
68
97
|
- Pure shared domain logic belongs here when both frontend and backend need it:
|
|
69
98
|
tick math, factories, commands, validation, instrument knowledge, generation
|
|
70
|
-
presets and prompt-facing shared data
|
|
99
|
+
presets and prompt-facing shared data — and every type and vocabulary
|
|
100
|
+
constant, whoever uses it (see the two rules at the top). This package must never depend on
|
|
71
101
|
`music_lib`, and `music_api` must never pull in frontend UI/audio code just
|
|
72
102
|
to reach a shared rule.
|
|
73
103
|
- `noteEventSchema`/`restEventSchema` are `.strict()` on purpose (a stray `pitch` key must not pass as a rest); other schemas strip unknown keys for forward compatibility.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A document, as vocabulary: where its bytes live and whether they are
|
|
3
|
+
* written. The per-document store and the saver are music_lib's.
|
|
4
|
+
*/
|
|
5
|
+
/** Where a document's bytes live, and therefore what saving it means. */
|
|
6
|
+
export type DocumentOrigin = {
|
|
7
|
+
kind: "unsaved";
|
|
8
|
+
} | {
|
|
9
|
+
kind: "file";
|
|
10
|
+
uri: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: "project";
|
|
13
|
+
projectId: string;
|
|
14
|
+
};
|
|
15
|
+
/** Whether the document on screen is the one written. */
|
|
16
|
+
export type SaveState = "saved" | "saving" | "unsaved";
|
|
17
|
+
//# sourceMappingURL=document-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-state.d.ts","sourceRoot":"","sources":["../../../src/domain/documents/document-state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,yEAAyE;AACzE,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C,yDAAyD;AACzD,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-state.js","sourceRoot":"","sources":["../../../src/domain/documents/document-state.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What an export can write, as vocabulary: the formats, their extensions and
|
|
3
|
+
* labels, and the shape of a plan to write one.
|
|
4
|
+
*
|
|
5
|
+
* Both apps offer the same menu of formats, and the docs table of export
|
|
6
|
+
* formats (`EXPORT_FORMATS`, beside this) is derived from the same list, so the
|
|
7
|
+
* menu and the documentation cannot come to disagree. Deciding a plan
|
|
8
|
+
* (`planExport`) is music_lib's; naming the file, rendering audio and the write
|
|
9
|
+
* itself belong to the packages that own each.
|
|
10
|
+
*/
|
|
11
|
+
import type { Score } from "../../model/score.js";
|
|
12
|
+
/**
|
|
13
|
+
* How a format reaches disk.
|
|
14
|
+
*
|
|
15
|
+
* `notation` is a single codec call; `tracker` has a fit report to show first;
|
|
16
|
+
* `audio` has to be rendered by a synth before it is encoded; `project` writes
|
|
17
|
+
* the document itself.
|
|
18
|
+
*/
|
|
19
|
+
export type ExportRoute = "notation" | "tracker" | "audio" | "project";
|
|
20
|
+
export declare const WRITABLE_EXPORT_FORMATS: readonly [{
|
|
21
|
+
readonly id: "midi";
|
|
22
|
+
readonly extension: "mid";
|
|
23
|
+
readonly route: "notation";
|
|
24
|
+
readonly labelKey: "editor.midi";
|
|
25
|
+
readonly noteKey: "docs.formats.out.midi";
|
|
26
|
+
}, {
|
|
27
|
+
readonly id: "musicxml";
|
|
28
|
+
readonly extension: "musicxml";
|
|
29
|
+
readonly route: "notation";
|
|
30
|
+
readonly labelKey: "editor.musicXml";
|
|
31
|
+
readonly noteKey: "docs.formats.out.musicxml";
|
|
32
|
+
}, {
|
|
33
|
+
readonly id: "xm";
|
|
34
|
+
readonly extension: "xm";
|
|
35
|
+
readonly route: "tracker";
|
|
36
|
+
readonly labelKey: "editor.xmModule";
|
|
37
|
+
readonly noteKey: "docs.formats.out.tracker";
|
|
38
|
+
}, {
|
|
39
|
+
readonly id: "wav";
|
|
40
|
+
readonly extension: "wav";
|
|
41
|
+
readonly route: "audio";
|
|
42
|
+
readonly labelKey: "editor.audioWav";
|
|
43
|
+
readonly noteKey: "docs.formats.out.wav";
|
|
44
|
+
}, {
|
|
45
|
+
readonly id: "mp3";
|
|
46
|
+
readonly extension: "mp3";
|
|
47
|
+
readonly route: "audio";
|
|
48
|
+
readonly labelKey: "editor.audioMp3";
|
|
49
|
+
readonly noteKey: "docs.formats.out.mp3";
|
|
50
|
+
}, {
|
|
51
|
+
readonly id: "project";
|
|
52
|
+
readonly extension: "moo";
|
|
53
|
+
readonly route: "project";
|
|
54
|
+
readonly labelKey: "editor.projectJson";
|
|
55
|
+
readonly noteKey: "docs.formats.out.project";
|
|
56
|
+
}];
|
|
57
|
+
export type WritableExportFormat = (typeof WRITABLE_EXPORT_FORMATS)[number];
|
|
58
|
+
export type ExportFormatId = WritableExportFormat["id"];
|
|
59
|
+
/** Which tracks an export covers; see `exportScopeNeedsPrompt` for when to ask. */
|
|
60
|
+
export type ExportScope = "all" | "visible";
|
|
61
|
+
export type ExportPlan = {
|
|
62
|
+
format: ExportFormatId;
|
|
63
|
+
extension: string;
|
|
64
|
+
route: ExportRoute;
|
|
65
|
+
/** The score to write — already narrowed to the scope. */
|
|
66
|
+
target: Score;
|
|
67
|
+
/**
|
|
68
|
+
* What the file is named after: the score's own title, not a project or
|
|
69
|
+
* document name. Hand it to `exportFilename`, which keeps it and replaces
|
|
70
|
+
* only the characters a filesystem refuses.
|
|
71
|
+
*/
|
|
72
|
+
title: string;
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=export-formats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-formats.d.ts","sourceRoot":"","sources":["../../../src/domain/documents/export-formats.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAGlD;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAEvE,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwDlC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC5E,MAAM,MAAM,cAAc,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;AAExD,mFAAmF;AACnF,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,CAAC;AAE5C,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,WAAW,CAAC;IACnB,0DAA0D;IAC1D,MAAM,EAAE,KAAK,CAAC;IACd;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;CACf,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { DOCUMENT_EXTENSION } from "./project-file.js";
|
|
2
|
+
export const WRITABLE_EXPORT_FORMATS = [
|
|
3
|
+
{
|
|
4
|
+
id: "midi",
|
|
5
|
+
extension: "mid",
|
|
6
|
+
route: "notation",
|
|
7
|
+
labelKey: "editor.midi",
|
|
8
|
+
noteKey: "docs.formats.out.midi",
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "musicxml",
|
|
12
|
+
extension: "musicxml",
|
|
13
|
+
route: "notation",
|
|
14
|
+
labelKey: "editor.musicXml",
|
|
15
|
+
noteKey: "docs.formats.out.musicxml",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: "xm",
|
|
19
|
+
extension: "xm",
|
|
20
|
+
route: "tracker",
|
|
21
|
+
labelKey: "editor.xmModule",
|
|
22
|
+
noteKey: "docs.formats.out.tracker",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "wav",
|
|
26
|
+
extension: "wav",
|
|
27
|
+
route: "audio",
|
|
28
|
+
labelKey: "editor.audioWav",
|
|
29
|
+
noteKey: "docs.formats.out.wav",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: "mp3",
|
|
33
|
+
extension: "mp3",
|
|
34
|
+
route: "audio",
|
|
35
|
+
labelKey: "editor.audioMp3",
|
|
36
|
+
noteKey: "docs.formats.out.mp3",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "project",
|
|
40
|
+
/*
|
|
41
|
+
The document's own extension. This said `json` — the web's old export —
|
|
42
|
+
long after both apps had moved to `.moo`, so each overrode the plan by
|
|
43
|
+
hand and the docs table went on calling a project file JSON. The file is
|
|
44
|
+
still JSON inside; the name is what the platform uses to hand it back to
|
|
45
|
+
this app.
|
|
46
|
+
*/
|
|
47
|
+
extension: DOCUMENT_EXTENSION,
|
|
48
|
+
route: "project",
|
|
49
|
+
labelKey: "editor.projectJson",
|
|
50
|
+
noteKey: "docs.formats.out.project",
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
//# sourceMappingURL=export-formats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-formats.js","sourceRoot":"","sources":["../../../src/domain/documents/export-formats.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAWvD,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC;QACE,EAAE,EAAE,MAAM;QACV,SAAS,EAAE,KAAK;QAChB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,aAAa;QACvB,OAAO,EAAE,uBAAuB;KACjC;IACD;QACE,EAAE,EAAE,UAAU;QACd,SAAS,EAAE,UAAU;QACrB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,iBAAiB;QAC3B,OAAO,EAAE,2BAA2B;KACrC;IACD;QACE,EAAE,EAAE,IAAI;QACR,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,iBAAiB;QAC3B,OAAO,EAAE,0BAA0B;KACpC;IACD;QACE,EAAE,EAAE,KAAK;QACT,SAAS,EAAE,KAAK;QAChB,KAAK,EAAE,OAAO;QACd,QAAQ,EAAE,iBAAiB;QAC3B,OAAO,EAAE,sBAAsB;KAChC;IACD;QACE,EAAE,EAAE,KAAK;QACT,SAAS,EAAE,KAAK;QAChB,KAAK,EAAE,OAAO;QACd,QAAQ,EAAE,iBAAiB;QAC3B,OAAO,EAAE,sBAAsB;KAChC;IACD;QACE,EAAE,EAAE,SAAS;QACb;;;;;;UAME;QACF,SAAS,EAAE,kBAAkB;QAC7B,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,oBAAoB;QAC9B,OAAO,EAAE,0BAA0B;KACpC;CAOD,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type FormatEntry = {
|
|
2
|
+
id: string;
|
|
3
|
+
/** Extensions as a reader would write them. */
|
|
4
|
+
extensions: string;
|
|
5
|
+
/** i18n key describing what survives the trip. */
|
|
6
|
+
noteKey: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const IMPORT_FORMATS: readonly FormatEntry[];
|
|
9
|
+
/**
|
|
10
|
+
* What the docs export table lists: every format the export menu writes, then
|
|
11
|
+
* printing, which produces a document rather than a file.
|
|
12
|
+
*
|
|
13
|
+
* Derived from `WRITABLE_EXPORT_FORMATS` rather than written out beside it: the
|
|
14
|
+
* table was its own list, and a list about the menu is a copy of the menu.
|
|
15
|
+
*/
|
|
16
|
+
export declare const EXPORT_FORMATS: readonly FormatEntry[];
|
|
17
|
+
//# sourceMappingURL=formats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formats.d.ts","sourceRoot":"","sources":["../../../src/domain/documents/formats.ts"],"names":[],"mappings":"AAiBA,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,SAAS,WAAW,EA4BhD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,WAAW,EAOhD,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every file format the app reads and writes, declared once.
|
|
3
|
+
*
|
|
4
|
+
* The documentation, and anything else that has to list them, reads this —
|
|
5
|
+
* rather than a paragraph of prose naming formats, which is a copy of the list
|
|
6
|
+
* that stops being true the first time a format is added.
|
|
7
|
+
*
|
|
8
|
+
* **Here because both apps document these formats**, and what this product
|
|
9
|
+
* can open is a fact about the product, not about a web page. A table of
|
|
10
|
+
* vocabulary rather than logic, so it sits with the rest of the vocabulary.
|
|
11
|
+
*
|
|
12
|
+
* Every description is an i18n key, so the prose lives in each host's locale
|
|
13
|
+
* files and no library holds strings in any language.
|
|
14
|
+
*/
|
|
15
|
+
import { DOCUMENT_EXTENSIONS } from "./project-file.js";
|
|
16
|
+
import { WRITABLE_EXPORT_FORMATS } from "./export-formats.js";
|
|
17
|
+
export const IMPORT_FORMATS = [
|
|
18
|
+
{ id: "midi", extensions: ".mid, .midi", noteKey: "docs.formats.in.midi" },
|
|
19
|
+
{
|
|
20
|
+
id: "musicxml",
|
|
21
|
+
extensions: ".musicxml, .xml",
|
|
22
|
+
noteKey: "docs.formats.in.musicxml",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "tracker",
|
|
26
|
+
extensions: ".mod, .dsm, .s3m, .xm, .it, .mptm",
|
|
27
|
+
noteKey: "docs.formats.in.tracker",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: "audio",
|
|
31
|
+
extensions: ".wav, .mp3, .mpa",
|
|
32
|
+
noteKey: "docs.formats.in.audio",
|
|
33
|
+
},
|
|
34
|
+
/*
|
|
35
|
+
Every extension a project file opens under — the `.moo` both apps write,
|
|
36
|
+
the `.moosiac` documents were saved as before it was shortened, and the
|
|
37
|
+
web's old `.json` export — read from the list the codec decides by, so the
|
|
38
|
+
table cannot list fewer than the importer accepts.
|
|
39
|
+
*/
|
|
40
|
+
{
|
|
41
|
+
id: "project",
|
|
42
|
+
extensions: DOCUMENT_EXTENSIONS.map((ext) => `.${ext}`).join(", "),
|
|
43
|
+
noteKey: "docs.formats.in.project",
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
/**
|
|
47
|
+
* What the docs export table lists: every format the export menu writes, then
|
|
48
|
+
* printing, which produces a document rather than a file.
|
|
49
|
+
*
|
|
50
|
+
* Derived from `WRITABLE_EXPORT_FORMATS` rather than written out beside it: the
|
|
51
|
+
* table was its own list, and a list about the menu is a copy of the menu.
|
|
52
|
+
*/
|
|
53
|
+
export const EXPORT_FORMATS = [
|
|
54
|
+
...WRITABLE_EXPORT_FORMATS.map((format) => ({
|
|
55
|
+
id: format.id,
|
|
56
|
+
extensions: `.${format.extension}`,
|
|
57
|
+
noteKey: format.noteKey,
|
|
58
|
+
})),
|
|
59
|
+
{ id: "print", extensions: "—", noteKey: "docs.formats.out.print" },
|
|
60
|
+
];
|
|
61
|
+
//# sourceMappingURL=formats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formats.js","sourceRoot":"","sources":["../../../src/domain/documents/formats.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAU9D,MAAM,CAAC,MAAM,cAAc,GAA2B;IACpD,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,OAAO,EAAE,sBAAsB,EAAE;IAC1E;QACE,EAAE,EAAE,UAAU;QACd,UAAU,EAAE,iBAAiB;QAC7B,OAAO,EAAE,0BAA0B;KACpC;IACD;QACE,EAAE,EAAE,SAAS;QACb,UAAU,EAAE,mCAAmC;QAC/C,OAAO,EAAE,yBAAyB;KACnC;IACD;QACE,EAAE,EAAE,OAAO;QACX,UAAU,EAAE,kBAAkB;QAC9B,OAAO,EAAE,uBAAuB;KACjC;IACD;;;;;MAKE;IACF;QACE,EAAE,EAAE,SAAS;QACb,UAAU,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAClE,OAAO,EAAE,yBAAyB;KACnC;CACF,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAA2B;IACpD,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC1C,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,UAAU,EAAE,IAAI,MAAM,CAAC,SAAS,EAAE;QAClC,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAC;IACH,EAAE,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,wBAAwB,EAAE;CACpE,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project file, as vocabulary: what it is called, which version this build
|
|
3
|
+
* writes, and its shape.
|
|
4
|
+
*
|
|
5
|
+
* Declared here rather than beside the parser in music_codecs, because these
|
|
6
|
+
* are facts other packages read without needing to parse anything. The export
|
|
7
|
+
* formats and the docs formats table beside this module name the file, the apps
|
|
8
|
+
* pick files by extension, and a package that only wants the word `moo` must
|
|
9
|
+
* not have to depend on a codec to get it — music_editing briefly did, while it
|
|
10
|
+
* held the export menu and the formats table, which is how a package for
|
|
11
|
+
* editing came to import the file-format layer. The serializer and
|
|
12
|
+
* the parser stay in music_codecs; the words and the types they read and write
|
|
13
|
+
* are the model's.
|
|
14
|
+
*/
|
|
15
|
+
import type { Score } from "../../index.js";
|
|
16
|
+
/** The format version this build writes and the newest it reads. */
|
|
17
|
+
export declare const PROJECT_FILE_VERSION = 1;
|
|
18
|
+
/** What the apps write. */
|
|
19
|
+
export declare const DOCUMENT_EXTENSION = "moo";
|
|
20
|
+
/**
|
|
21
|
+
* What the apps open: their own extension, the longer one documents were
|
|
22
|
+
* saved under before it was shortened, and the web's `.json` project export.
|
|
23
|
+
*/
|
|
24
|
+
export declare const DOCUMENT_EXTENSIONS: readonly ["moo", "moosiac", "json"];
|
|
25
|
+
/** A project file as it is written: the score, plus its title. */
|
|
26
|
+
export type ProjectFile = {
|
|
27
|
+
version: number;
|
|
28
|
+
title: string;
|
|
29
|
+
score: Score;
|
|
30
|
+
};
|
|
31
|
+
/** Why a project file could not be read, for an app to word. */
|
|
32
|
+
export type ProjectFileErrorReason = "invalidJson" | "notAProject" | "newerVersion" | "invalidScore";
|
|
33
|
+
//# sourceMappingURL=project-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-file.d.ts","sourceRoot":"","sources":["../../../src/domain/documents/project-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,oEAAoE;AACpE,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,2BAA2B;AAC3B,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AAExC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,qCAItB,CAAC;AAEX,kEAAkE;AAClE,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF,gEAAgE;AAChE,MAAM,MAAM,sBAAsB,GAC9B,aAAa,GACb,aAAa,GACb,cAAc,GACd,cAAc,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** The format version this build writes and the newest it reads. */
|
|
2
|
+
export const PROJECT_FILE_VERSION = 1;
|
|
3
|
+
/** What the apps write. */
|
|
4
|
+
export const DOCUMENT_EXTENSION = "moo";
|
|
5
|
+
/**
|
|
6
|
+
* What the apps open: their own extension, the longer one documents were
|
|
7
|
+
* saved under before it was shortened, and the web's `.json` project export.
|
|
8
|
+
*/
|
|
9
|
+
export const DOCUMENT_EXTENSIONS = [
|
|
10
|
+
DOCUMENT_EXTENSION,
|
|
11
|
+
"moosiac",
|
|
12
|
+
"json",
|
|
13
|
+
];
|
|
14
|
+
//# sourceMappingURL=project-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-file.js","sourceRoot":"","sources":["../../../src/domain/documents/project-file.ts"],"names":[],"mappings":"AAgBA,oEAAoE;AACpE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAEtC,2BAA2B;AAC3B,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAExC;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,kBAAkB;IAClB,SAAS;IACT,MAAM;CACE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/domain/documents/publish.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,MAAM,MAAM,YAAY,GAAG;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../../src/domain/documents/publish.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which starter scores exist, as vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* The templates themselves — the instruments, clefs and bar counts each builds
|
|
5
|
+
* — are music_lib's. The ids are here because a host keys its copy off them.
|
|
6
|
+
*/
|
|
7
|
+
/** Every template music_lib can build. Stable — it is persisted in nothing, but hosts key their copy off it. */
|
|
8
|
+
export declare const TEMPLATE_IDS: readonly ["lead-sheet", "piano-grand-staff", "string-quartet", "jazz-combo", "rock-band", "satb-choir", "drum-kit", "waltz", "jig", "gentle-piano-melody", "pop-arrangement", "orchestral-passage"];
|
|
9
|
+
export type TemplateId = (typeof TEMPLATE_IDS)[number];
|
|
10
|
+
/**
|
|
11
|
+
* The name and description shown for each template, supplied by the host.
|
|
12
|
+
*
|
|
13
|
+
* music_lib's templates own the *music* — which instruments, clefs, keys and
|
|
14
|
+
* bar counts a starter score has — and nothing else. The words describing them
|
|
15
|
+
* are the host's, because only the host knows what language it is speaking.
|
|
16
|
+
*/
|
|
17
|
+
export type TemplateCopy = Record<TemplateId, {
|
|
18
|
+
name: string;
|
|
19
|
+
description: string;
|
|
20
|
+
}>;
|
|
21
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/domain/documents/templates.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,gHAAgH;AAChH,eAAO,MAAM,YAAY,qMAaf,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAC/B,UAAU,EACV;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CACtC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which starter scores exist, as vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* The templates themselves — the instruments, clefs and bar counts each builds
|
|
5
|
+
* — are music_lib's. The ids are here because a host keys its copy off them.
|
|
6
|
+
*/
|
|
7
|
+
/** Every template music_lib can build. Stable — it is persisted in nothing, but hosts key their copy off it. */
|
|
8
|
+
export const TEMPLATE_IDS = [
|
|
9
|
+
"lead-sheet",
|
|
10
|
+
"piano-grand-staff",
|
|
11
|
+
"string-quartet",
|
|
12
|
+
"jazz-combo",
|
|
13
|
+
"rock-band",
|
|
14
|
+
"satb-choir",
|
|
15
|
+
"drum-kit",
|
|
16
|
+
"waltz",
|
|
17
|
+
"jig",
|
|
18
|
+
"gentle-piano-melody",
|
|
19
|
+
"pop-arrangement",
|
|
20
|
+
"orchestral-passage",
|
|
21
|
+
];
|
|
22
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/domain/documents/templates.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,gHAAgH;AAChH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,YAAY;IACZ,mBAAmB;IACnB,gBAAgB;IAChB,YAAY;IACZ,WAAW;IACX,YAAY;IACZ,UAAU;IACV,OAAO;IACP,KAAK;IACL,qBAAqB;IACrB,iBAAiB;IACjB,oBAAoB;CACZ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The frontend's failure taxonomy (spec §28), as vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* The `AppError` class and `reportError`, which turns any thrown value into a
|
|
5
|
+
* toast, are music_lib's.
|
|
6
|
+
*/
|
|
7
|
+
/** Stable, machine-readable failure categories (spec §28's list). */
|
|
8
|
+
export type AppErrorCode = "midi-import" | "midi-export" | "musicxml-import" | "musicxml-export" | "project-load" | "project-save" | "project-data" | "audio-init" | "generation" | "storage-quota" | "rendering" | "unsupported-feature" | "unknown";
|
|
9
|
+
export type AppErrorOptions = {
|
|
10
|
+
code: AppErrorCode;
|
|
11
|
+
/** Shown to the user, verbatim, in a toast — never a raw stack trace or exception class name. */
|
|
12
|
+
userMessage: string;
|
|
13
|
+
/** Technical detail (the original error, Zod issues, ...), logged via `console.debug` only in development. */
|
|
14
|
+
detail?: unknown;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=app-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-errors.d.ts","sourceRoot":"","sources":["../../../src/domain/editor/app-errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,qEAAqE;AACrE,MAAM,MAAM,YAAY,GACpB,aAAa,GACb,aAAa,GACb,iBAAiB,GACjB,iBAAiB,GACjB,cAAc,GACd,cAAc,GACd,cAAc,GACd,YAAY,GACZ,YAAY,GACZ,eAAe,GACf,WAAW,GACX,qBAAqB,GACrB,SAAS,CAAC;AAEd,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,YAAY,CAAC;IACnB,iGAAiG;IACjG,WAAW,EAAE,MAAM,CAAC;IACpB,8GAA8G;IAC9G,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-errors.js","sourceRoot":"","sources":["../../../src/domain/editor/app-errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The score's context menu, and the two things it acts between: what the
|
|
3
|
+
* selection is *of*, and what the clipboard holds.
|
|
4
|
+
*
|
|
5
|
+
* The model and the rules (`scoreContextMenuModel`, `selectionKind`,
|
|
6
|
+
* `canPasteInto`) are music_editing's. Keys, never words.
|
|
7
|
+
*/
|
|
8
|
+
import type { NoteEvent, Track } from "../../model/score.js";
|
|
9
|
+
import type { MeasureSlice } from "../commands/clipboard-commands.js";
|
|
10
|
+
/**
|
|
11
|
+
* What a selection is *of*. **Notes win, then measures, then tracks** — see
|
|
12
|
+
* `selectionKind` in music_editing.
|
|
13
|
+
*/
|
|
14
|
+
export type SelectionKind = "notes" | "measures" | "track";
|
|
15
|
+
/**
|
|
16
|
+
* What was copied, tagged with what kind of thing it is.
|
|
17
|
+
*
|
|
18
|
+
* A union rather than three fields, because the clipboard holds exactly one
|
|
19
|
+
* thing and Paste is only offered when its kind matches the selection's — see
|
|
20
|
+
* `canPasteInto`. It was a bare `{events, anchorTick}` while notes were the only
|
|
21
|
+
* thing that could be copied at all.
|
|
22
|
+
*
|
|
23
|
+
* A **measures** entry is a vertical slice: the bars at those indices across
|
|
24
|
+
* every track, not one part's. That is what the score model already means by a
|
|
25
|
+
* bar — `deleteMeasureCommand` removes one from every track — and it is what
|
|
26
|
+
* lets insert and replace put a slice back without leaving the parts
|
|
27
|
+
* disagreeing about where bar 40 is.
|
|
28
|
+
*/
|
|
29
|
+
export type ClipboardData = ({
|
|
30
|
+
kind: "notes";
|
|
31
|
+
events: NoteEvent[];
|
|
32
|
+
anchorTick: number;
|
|
33
|
+
} | {
|
|
34
|
+
kind: "measures";
|
|
35
|
+
slice: MeasureSlice;
|
|
36
|
+
count: number;
|
|
37
|
+
} | {
|
|
38
|
+
kind: "track";
|
|
39
|
+
track: Track;
|
|
40
|
+
}) & {
|
|
41
|
+
/**
|
|
42
|
+
* Whether the clipboard was filled by a cut rather than a copy.
|
|
43
|
+
*
|
|
44
|
+
* It matters only when a paste is refused: after a copy the music is still
|
|
45
|
+
* where it was, but after a cut it exists nowhere except the clipboard and
|
|
46
|
+
* the undo history, so the refusal offers Undo. Absent reads as a copy, so a
|
|
47
|
+
* clipboard built by hand elsewhere needs no change.
|
|
48
|
+
*/
|
|
49
|
+
fromCut?: boolean;
|
|
50
|
+
};
|
|
51
|
+
/** Every entry, in the order the menu shows them. */
|
|
52
|
+
export declare const SCORE_CONTEXT_ACTIONS: readonly ["copy", "cut", "clear", "delete", "paste", "selectAll"];
|
|
53
|
+
export type ScoreContextAction = (typeof SCORE_CONTEXT_ACTIONS)[number];
|
|
54
|
+
/** The label each entry is read as. A record, so a new action fails to compile here. */
|
|
55
|
+
export declare const SCORE_CONTEXT_ACTION_LABEL_KEY: Record<ScoreContextAction, string>;
|
|
56
|
+
export type ScoreContextMenuEntry = {
|
|
57
|
+
action: ScoreContextAction;
|
|
58
|
+
labelKey: string;
|
|
59
|
+
enabled: boolean;
|
|
60
|
+
};
|
|
61
|
+
export type ScoreContextMenuModel = {
|
|
62
|
+
/** The menu's accessible name / sheet title. */
|
|
63
|
+
titleKey: string;
|
|
64
|
+
/**
|
|
65
|
+
* What every entry acts on — "Track", "Bars", "Notes" — or null with nothing
|
|
66
|
+
* selected. `count` is for the plural; translate with `{ count }`.
|
|
67
|
+
*/
|
|
68
|
+
subject: {
|
|
69
|
+
key: string;
|
|
70
|
+
count: number;
|
|
71
|
+
} | null;
|
|
72
|
+
entries: readonly ScoreContextMenuEntry[];
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=context-menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-menu.d.ts","sourceRoot":"","sources":["../../../src/domain/editor/context-menu.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEtE;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,aAAa,GAAG,CACxB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,SAAS,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAClC,GAAG;IACF;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,qBAAqB,mEAOxB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE,wFAAwF;AACxF,eAAO,MAAM,8BAA8B,EAAE,MAAM,CACjD,kBAAkB,EAClB,MAAM,CAQP,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/C,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC3C,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Every entry, in the order the menu shows them. */
|
|
2
|
+
export const SCORE_CONTEXT_ACTIONS = [
|
|
3
|
+
"copy",
|
|
4
|
+
"cut",
|
|
5
|
+
"clear",
|
|
6
|
+
"delete",
|
|
7
|
+
"paste",
|
|
8
|
+
"selectAll",
|
|
9
|
+
];
|
|
10
|
+
/** The label each entry is read as. A record, so a new action fails to compile here. */
|
|
11
|
+
export const SCORE_CONTEXT_ACTION_LABEL_KEY = {
|
|
12
|
+
copy: "editor.copy",
|
|
13
|
+
cut: "editor.cut",
|
|
14
|
+
clear: "editor.clear",
|
|
15
|
+
delete: "editor.deleteSelection",
|
|
16
|
+
paste: "editor.paste",
|
|
17
|
+
selectAll: "editor.selectAllNotes",
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=context-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-menu.js","sourceRoot":"","sources":["../../../src/domain/editor/context-menu.ts"],"names":[],"mappings":"AA8CA,qDAAqD;AACrD,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,MAAM;IACN,KAAK;IACL,OAAO;IACP,QAAQ;IACR,OAAO;IACP,WAAW;CACH,CAAC;AAIX,wFAAwF;AACxF,MAAM,CAAC,MAAM,8BAA8B,GAGvC;IACF,IAAI,EAAE,aAAa;IACnB,GAAG,EAAE,YAAY;IACjB,KAAK,EAAE,cAAc;IACrB,MAAM,EAAE,wBAAwB;IAChC,KAAK,EAAE,cAAc;IACrB,SAAS,EAAE,uBAAuB;CACnC,CAAC"}
|