diff --git a/.gitignore b/.gitignore index cf88de2..4583656 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ node_modules/ coverage/ .DS_Store -tests/fixtures-local/ +tests/local-data/* +!tests/local-data/.gitkeep tests/artifacts/roundtrip/ tests/roundtrip/musescore/cases.local.json +.tsbuildinfo +.mikuscore-build/ +workplace/* diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..84c78b7 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,12 @@ +# AGENTS + +## Path Style + +- Do not write absolute filesystem paths in repository documents unless there is a truly unavoidable reason. +- Prefer repository-relative paths such as `docs/spec/AI_JSON_SPEC.md`. +- Do not write paths like `/Users/igapyon/...`. + +## Documentation Hygiene + +- Keep examples and references portable across environments. +- Prefer concise path references over machine-local path details. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..adae3b2 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,63 @@ +# Code of Conduct + +## Purpose + +`mikuscore` aims to be a respectful and practical collaboration space for bug reports, feature requests, design discussion, documentation work, and code contributions. + +The goal is not to avoid disagreement. The goal is to keep discussion specific, constructive, and safe for participants. + +## Expected Behavior + +- Be respectful. +- Be specific. +- Prefer concrete repro steps, fixtures, examples, and tests over vague claims. +- Critique ideas, code, assumptions, and designs without attacking people. +- Keep technical disagreement focused on behavior, tradeoffs, and evidence. +- Accept that maintainers may ask to narrow scope, add tests, or clarify intent before accepting a change. + +## Unacceptable Behavior + +- Harassment, intimidation, or personal attacks +- Discriminatory, hateful, or abusive language +- Repeated hostile or bad-faith argument +- Dismissing or insulting contributors instead of addressing the technical point +- Publishing private or sensitive information without permission +- Spam, trolling, or deliberately disruptive behavior + +## Scope + +This code of conduct applies to project spaces such as: + +- Issues +- Pull requests +- Discussions and review comments +- Documentation contributions +- Other project-related public collaboration spaces managed for `mikuscore` + +## Maintainer Responsibility + +Project maintainers may moderate discussions and contributions to keep the project usable and collaborative. + +This may include: + +- Asking for clarification or tone adjustments +- Hiding, editing, locking, or closing discussions when appropriate +- Rejecting contributions that are technically unsuitable or behaviorally disruptive +- Limiting further participation in project spaces if necessary + +## Reporting + +If you experience or observe behavior that should be addressed, contact the project maintainer through a project channel that is appropriate for the situation. + +If a public thread would make the issue worse, prefer a private contact path instead of escalating in public. + +## Project Style + +For `mikuscore`, the preferred collaboration style is: + +- specific +- respectful +- test-oriented +- focused on reproducible behavior + +Technical rigor is welcome. Personal hostility is not. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..ea70997 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,82 @@ +# Contributing to mikuscore + +Thank you for contributing to `mikuscore`. + +This project accepts bug reports, feature requests, documentation fixes, tests, and pull requests. + +See `CODE_OF_CONDUCT.md` for collaboration and behavior expectations in project spaces. + +## Before Opening an Issue or Pull Request + +- Check whether the topic is already covered by an existing issue, pull request, spec note, or TODO item. +- For behavior changes, describe both the current behavior and the expected behavior. +- Keep changes focused. Small, reviewable pull requests are preferred. +- When practical, include or update tests together with code changes. + +## Development Notes + +- `mikuscore.html` is a generated artifact. Do not edit it directly unless regeneration is intentionally part of the change. +- `src/js/main.js` is generated from TypeScript and is committed. If you change `src/ts/`, regenerate `src/js/main.js` as part of the same change when needed. +- Application logic should normally be edited in `src/ts/` and `core/`. +- Tests live under `tests/`. +- `mikuscore` changes can require downstream follow-up in `mikuscore-skills` and `miku-abc-player`, which basically track `devel`. Keep that impact visible when a change affects shared behavior, contract, generated assets, or handoff assumptions. +- Vendored or externally sourced files should be treated carefully: + - `src/js/verovio.js` + - `src/js/midi-writer.js` + - `src/vendor/utaformatix3/utaformatix3-ts-plus.mikuscore.iife.js` + - `lht-cmn/` +- Do not rewrite vendored files as part of unrelated application changes. + +## Documentation Expectations + +Update documentation when a change affects behavior, scope, policy, or the supported format contract. + +Documentation roles: + +- `README.md`: repository entry point, supported scope, development commands, CLI overview +- `TODO.md`: active backlog only +- `docs/spec/*`: normative implementation and behavior specifications +- `docs/future/*`: deferred or future-facing notes +- `docs/FORMAT_COVERAGE.md`: current format support summary + +## Recommended Checks + +Run relevant commands before submitting a pull request when possible. + +```bash +npm run typecheck +npm run test:build +npm run test:integration +npm run test:property +npm run test:all +npm run build +npm run check:all +``` + +In practice, not every change needs every command. A smaller change may only need the subset that covers the touched area. + +## Pull Request Guidelines + +- Explain what changed and why. +- Mention any user-visible behavior change. +- Mention any spec, README, or TODO updates that are part of the change. +- If downstream follow-up is expected, mention that `mikuscore-skills` and/or `miku-abc-player` may need updates from `devel`. +- If a change is intentionally partial, deferred, or scoped down, say so explicitly. +- If fixtures, samples, or local-only data were used for verification, explain that briefly. + +## Contribution License + +By submitting an issue, pull request, comment, documentation change, code change, or other material intentionally for inclusion in this project, you agree that: + +- Your contribution is provided under the Apache License 2.0 used by this repository. +- The maintainer may use, modify, rewrite, adapt, edit, and redistribute your contribution as part of this project, as permitted by that license. +- You have the right to submit the contribution. +- Unless you explicitly state otherwise, your submission is treated as a "Contribution" under Section 5 of the Apache License 2.0. + +If you do not want a submission to be treated as a contribution for inclusion in the project, mark that clearly and do not open it as a pull request intended to be merged. + +## Collaboration Expectations + +- Be specific. +- Be respectful. +- Prefer concrete repro steps, fixtures, and tests over vague reports. diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 0000000..c1992fe --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,8 @@ +# Contributors + +This project includes contributions, review, feedback, and improvement suggestions from the following people. + +- Toshiki Iga + - Original author and current maintainer. + +Additional contributors may be acknowledged here, in Git history, or in release notes as the project evolves. diff --git a/MusicXML b/MusicXML new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md index 8e16b2f..199a1e7 100644 --- a/README.md +++ b/README.md @@ -1,175 +1,163 @@ # mikuscore -## English -mikuscore is a browser-based score editor for importing and exporting MusicXML, MuseScore, MIDI, VSQX, ABC, MEI, and LilyPond, with notation preview and note editing. - -- Designed to preserve existing MusicXML as much as possible. -- Works offline in a single HTML distribution. -- Smartphone-centered workflows, with PC use also supported. -- ABC, MEI, and LilyPond support is currently experimental. - -Its primary goal is reliability, not feature volume: edit while preserving existing MusicXML as much as possible. - -### Product Positioning -- Focus on the following two smartphone-centered workflows (PC use is also supported): - - Quick and easy entry for simple scores on a smartphone. - - Execute part of a large score workflow (prepared on PC) on a smartphone. -- Keep an intentionally small feature set and optimize for mobile usability and editing speed. -- Use MusicXML as the core data structure and avoid unnecessary transformations. - -### Core Principles -- Prioritize preserving existing MusicXML with minimal patch editing. -- Preserve unknown/unsupported elements. -- Preserve ``, ``, and existing `` nodes. -- Roll back atomically on failure. -- Keep Core/UI separated so UI can be replaced later. -- Keep smartphone-centered workflows practical, with PC use also supported. - -### MVP Highlights -- If `dirty === false`, save returns original XML text (`original_noop`). -- Overfull measures are rejected with `MEASURE_OVERFULL`. -- Commands must target the same voice as the selected note; mismatches are rejected with `MVP_UNSUPPORTED_NON_EDITABLE_VOICE`. -- MVP commands: `change_to_pitch`, `change_duration`, `insert_note_after`, `delete_note`, `split_note`. -- Rests are not a normal edit target, but rest-to-note via `change_to_pitch` is allowed. -- Serialization is compact (no pretty-print). - -### Supported MusicXML Version -- **MusicXML 4.0** - -### Format Support Note -- `utaformatix3-ts-plus` is bundled as a vendored integration (`src/vendor/utaformatix3/utaformatix3-ts-plus.mikuscore.iife.js`) for VSQX <-> MusicXML conversion. -- We sincerely appreciate the UtaFormatix / utaformatix3 ecosystem and contributors for making this VSQX interoperability possible. -- MEI support is currently experimental. -- MEI reference samples used for compatibility/parity work: - - https://github.com/music-encoding/sample-encodings/tree/main/MEI_5.1/Music -- LilyPond (`.ly`) support is currently experimental. - -### Distribution and Development -- Distribution: **single-file web app** (`mikuscore.html`). -- Runtime: offline, no external network dependency. -- Source: split TypeScript files. -- Build: `mikuscore-src.html` + `src/` -> `mikuscore.html`. - -### Development Commands -- `npm run build` -- `npm run check:all` -- `npm run clean` -- `npm run typecheck` -- `npm run test:unit` -- `npm run test:property` -- `npm run test:all` -- `npm run build:vendor:utaformatix3` (sync vendored `utaformatix3-ts-plus` JS/doc from upstream) - -### Documents -- `docs/spec/SPEC.md` -- `docs/spec/TERMS.md` -- `docs/spec/COMMANDS.md` -- `docs/spec/COMMAND_CATALOG.md` -- `docs/spec/DIAGNOSTICS.md` -- `docs/spec/MIDI_IO.md` -- `docs/spec/PLAYBACK.md` -- `docs/spec/ABC_IO.md` -- `docs/spec/TEST_MATRIX.md` -- `docs/spec/LOCAL_WORKFLOW.md` -- `docs/spec/BUILD_PROCESS.md` -- `docs/spec/ARCHITECTURE.md` -- `docs/spec/UI_SPEC.md` -- `docs/spec/SCREEN_SPEC.md` -- `TODO.md` +![mikuscore OGP image](screenshots/mikuscore-ogp.png) + +mikuscore is a MusicXML-first score converter for people who need to move score data between formats. +It treats MusicXML as the central interchange format and helps bridge notation tools, file formats, and AI-oriented workflows. + +It is distributed as a single-file web app (`mikuscore.html`) and is designed to run offline in a browser. + +## What mikuscore is for + +mikuscore is a practical tool for: + +- moving score data from one format to another +- normalizing score data around MusicXML +- bridging notation software, exchange files, and AI-friendly handoff workflows + +## What mikuscore is not + +- not a full score engraving editor +- not a replacement for MuseScore or other dedicated notation editors +- not a promise of lossless conversion between every format pair + +If you want to edit notation in depth, use a notation editor such as MuseScore. +mikuscore is for converting, inspecting, and handing score data off. + +## Core idea + +- MusicXML-first conversion pipeline +- preserve existing MusicXML as much as possible +- keep conversion losses visible through diagnostics and metadata +- stay lightweight and portable + +## Supported formats + +- MusicXML (`.musicxml`, `.xml`, `.mxl`) +- MuseScore (`.mscx`, `.mscz`) +- MIDI (`.mid`, `.midi`) +- VSQX (`.vsqx`) +- ABC (`.abc`) +- MEI (`.mei`, experimental) +- LilyPond (`.ly`, experimental) + +## Typical use cases + +- convert ABC, MIDI, or MuseScore data into MusicXML for downstream editing or archival +- export MusicXML into another format for a tool or workflow that does not speak MusicXML directly +- inspect conversion diagnostics instead of silently losing information +- use ABC as a practical handoff format in generative-AI workflows while keeping MusicXML as the canonical score structure + +## Related projects + +- `mikuscore-skills` + - agent skills for embedding `mikuscore` into generative-AI workflows and making `mikuscore` score-conversion features easier to use from generative AI + - https://github.com/igapyon/mikuscore-skills +- `miku-abc-player` + - a companion web app that makes an ABC-limited subset of `mikuscore` easier to use + - https://github.com/igapyon/miku-abc-player + +## Quick start + +### Web app + +- open `mikuscore.html` in a browser +- load a score file +- convert and export +- inspect diagnostics if conversion details matter + +### CLI + +Current CLI is `convert`-first. + +Examples: + +- `npm run cli -- convert --from abc --to musicxml --in score.abc --out score.musicxml` +- `npm run cli -- convert --from musicxml --to abc --in score.musicxml --out score.abc` +- `npm run cli -- convert --from midi --to musicxml --in score.mid --out score.musicxml` +- `npm run cli -- convert --from musicxml --to midi --in score.musicxml --out score.mid` +- `npm run cli -- convert --from musescore --to musicxml --in score.mscx --out score.musicxml` +- `npm run cli -- convert --from musicxml --to musescore --in score.musicxml --out score.mscx` +- `npm run cli -- render svg --in score.musicxml --out score.svg` -Debugging note: -- For import-side incident analysis, check `docs/spec/MIDI_IO.md` and `docs/spec/ABC_IO.md` sections about `attributes > miscellaneous > miscellaneous-field` (`mks:*` debug fields). +For CLI and development details, see `docs/DEVELOPMENT.md` and `docs/spec/CLI_STEP1.md`. + +## Screenshots -### Screenshots ![mikuscore screenshot 1](screenshots/screen1.png) ![mikuscore screenshot 2](screenshots/screen2.png) ![mikuscore screenshot 3](screenshots/screen3.png) ![mikuscore screenshot 4](screenshots/screen4.png) ---- +## Documents + +User-facing documents: + +- `docs/FORMAT_COVERAGE.md` +- `docs/PRODUCT_POSITIONING.md` +- `docs/CONVERSION_PRINCIPLES.md` +- `docs/QUALITY.md` + +Contributor and repository workflow: + +- `docs/DEVELOPMENT.md` +- `CONTRIBUTING.md` +- `TODO.md` + +Implementation specs: -## 日本語 -mikuscore は、MusicXML、MuseScore、MIDI、VSQX、ABC、MEI、LilyPond の入出力に対応し、譜面プレビューとノート編集をブラウザ上で行うスコアエディタです。 - -- 既存 MusicXML を極力壊さない編集を重視しています。 -- 単一 HTML 配布でオフライン動作します。 -- スマホ中心のワークフローを重視しつつ、PC利用にも対応します。 -- ABC、MEI、LilyPond 対応は現在 Experimental(試験対応)です。 - -このアプリの主眼は「多機能化」ではなく、極力既存 MusicXML を壊さずに編集する信頼性です。 - -### プロダクトの位置づけ -- 利用シーンは次の2つを中心に据えます(スマホ中心ですが、PC利用も可能です)。 - - 簡単な譜面入力をスマホ上で手軽に行う。 - - PCで進めている大規模な譜面作業の一部を切り出し、スマホで一部実施する。 -- 機能は意図的に絞り、スマホ上での使いやすさと入力スピードを優先します。 -- MusicXML を基軸データ構造として扱い、不要な変換を避けます。 - -### 基本方針 -- 既存 MusicXML の保全を最優先に最小パッチ編集を実現。 -- unknown / unsupported 要素を保持。 -- `` / `` / 既存 `` を保持。 -- 失敗時は原子的にロールバック。 -- 将来の UI 置換を考慮した Core / UI 分離設計。 -- スマートフォンをサポート。 - -### MVP 仕様ハイライト -- `dirty === false` の保存は入力 XML をそのまま返す(`original_noop`)。 -- 小節 overfull は `MEASURE_OVERFULL` で拒否。 -- コマンド voice と対象ノート voice が不一致の場合は `MVP_UNSUPPORTED_NON_EDITABLE_VOICE` で拒否。 -- `change_to_pitch` / `change_duration` / `insert_note_after` / `delete_note` / `split_note` をMVPコマンドとして扱う。 -- 休符は通常の編集対象外だが、`change_to_pitch` による休符音符化は許可。 -- pretty-print なしでシリアライズ。 - -### 対応 MusicXML バージョン -- **MusicXML 4.0** - -### フォーマット対応メモ -- VSQX <-> MusicXML 変換のため、`utaformatix3-ts-plus` を同梱連携しています(`src/vendor/utaformatix3/utaformatix3-ts-plus.mikuscore.iife.js`)。 -- VSQX 相互運用を実現する基盤を築いてくださった UtaFormatix / utaformatix3 のエコシステムと貢献者の皆さまに、深く感謝します。 -- MEI 対応は現在 Experimental(試験対応)です。 -- MEI 互換性/パリティ確認で参照する公式サンプル: - - https://github.com/music-encoding/sample-encodings/tree/main/MEI_5.1/Music -- LilyPond(`.ly`)対応は現在 Experimental(試験対応)です。 - -### 配布と開発方針 -- 配布形態: 単一 HTML(`mikuscore.html`)。 -- 実行条件: オフライン動作、外部依存なし。 -- 開発形態: 分割 TypeScript ソース。 -- ビルド方針: `mikuscore-src.html` + `src/` から `mikuscore.html` を生成。 - -### 開発コマンド -- `npm run build` -- `npm run check:all` -- `npm run clean` -- `npm run typecheck` -- `npm run test:unit` -- `npm run test:property` -- `npm run test:all` -- `npm run build:vendor:utaformatix3`(upstream から `utaformatix3-ts-plus` の同梱JS/ドキュメントを同期) - -### ドキュメント - `docs/spec/SPEC.md` -- `docs/spec/TERMS.md` -- `docs/spec/COMMANDS.md` -- `docs/spec/COMMAND_CATALOG.md` -- `docs/spec/DIAGNOSTICS.md` -- `docs/spec/MIDI_IO.md` -- `docs/spec/PLAYBACK.md` -- `docs/spec/ABC_IO.md` -- `docs/spec/TEST_MATRIX.md` -- `docs/spec/LOCAL_WORKFLOW.md` -- `docs/spec/BUILD_PROCESS.md` - `docs/spec/ARCHITECTURE.md` -- `docs/spec/UI_SPEC.md` -- `docs/spec/SCREEN_SPEC.md` -- `TODO.md` +- `docs/spec/ABC_IO.md` +- `docs/spec/MIDI_IO.md` +- `docs/spec/MUSESCORE_IO.md` + +## 日本語 + +mikuscore は、譜面データを別形式へ持ち替えたい人のための、MusicXML-first な譜面変換ツールです。 +MusicXML を変換の中心に置き、譜面ソフト、交換用ファイル、生成 AI 向けワークフローの橋渡しを行います。 + +配布形態は単一 HTML (`mikuscore.html`) で、ブラウザでオフライン動作します。 + +### 用途 + +- 複数の譜面フォーマット間の変換 +- MusicXML を基準にした譜面データ整理 +- 他ソフトや AI ワークフローへの受け渡し + +### これは何ではないか + +- 多機能な浄書エディタではありません +- MuseScore などの本格的な譜面編集ソフトの代替ではありません +- すべての形式間で完全な無損失変換を保証するものではありません + +譜面をしっかり編集したい場合は、MuseScore などの既存エディタの利用を推奨します。 +mikuscore は、変換・確認・受け渡しのためのツールです。 + +### 対応フォーマット + +- MusicXML(`.musicxml`, `.xml`, `.mxl`) +- MuseScore(`.mscx`, `.mscz`) +- MIDI(`.mid`, `.midi`) +- VSQX(`.vsqx`) +- ABC(`.abc`) +- MEI(`.mei`、実験的) +- LilyPond(`.ly`、実験的) + +### 関連プロジェクト + +- `mikuscore-skills` + - `mikuscore` を生成 AI に組み込み、生成 AI から `mikuscore` の譜面変換機能を利用しやすくするための agent skills + - https://github.com/igapyon/mikuscore-skills +- `miku-abc-player` + - `mikuscore` の機能を ABC に限定して使いやすくした companion web app + - https://github.com/igapyon/miku-abc-player + +### はじめかた -デバッグメモ: -- インポート時の事象解析は `docs/spec/MIDI_IO.md` と `docs/spec/ABC_IO.md` の `attributes > miscellaneous > miscellaneous-field`(`mks:*` デバッグ項目)を参照してください。 +- `mikuscore.html` をブラウザで開く +- 譜面ファイルを読み込む +- 変換して書き出す +- 必要なら診断情報を確認する -### スクリーンショット -![mikuscore スクリーンショット 1](screenshots/screen1.png) -![mikuscore スクリーンショット 2](screenshots/screen2.png) -![mikuscore スクリーンショット 3](screenshots/screen3.png) -![mikuscore スクリーンショット 4](screenshots/screen4.png) +CLI や開発向け情報は `docs/DEVELOPMENT.md` を参照してください。 diff --git a/THIRD-PARTY-NOTICES.md b/THIRD-PARTY-NOTICES.md new file mode 100644 index 0000000..9cd98e5 --- /dev/null +++ b/THIRD-PARTY-NOTICES.md @@ -0,0 +1,71 @@ +# Third-Party Notices + +This document records third-party software and materials that are bundled with, directly used by, or explicitly referenced by `mikuscore`. + +It is maintained as a practical repository notice file, not as a substitute for upstream license texts. + +## Bundled or vendored components + +### `utaformatix3-ts-plus` + +- Usage: Vendored bundle used for VSQX `<->` MusicXML conversion. +- Local files: + - `src/vendor/utaformatix3/utaformatix3-ts-plus.mikuscore.iife.js` + - `docs/integrations/utaformatix3-ts-plus.mikuscore.iife.js.md` +- Source: `scripts/sync-utaformatix3-vendor.sh` syncs this bundle from the upstream `utaformatix3-ts-plus` repository. +- Upstream: https://github.com/igapyon/utaformatix3-ts-plus + +### `lht-cmn` + +- Usage: Shared UI component package included in this repository. +- Local files: + - `lht-cmn/` +- License: Apache License 2.0 +- Source: See `lht-cmn/README.md`, `lht-cmn/LICENSE`, and `lht-cmn/NOTICE`. + +### Material Web + +- Usage: Referenced via `lht-cmn` integration and attribution materials. +- License: Apache License 2.0 +- Source: See `lht-cmn/README.md` and `lht-cmn/NOTICE`. +- Upstream: https://github.com/material-components/material-web + +### `verovio.js` + +- Usage: Bundled browser runtime used for MusicXML to SVG rendering. +- Local files: + - `src/js/verovio.js` +- Note: Keep upstream attribution and license information aligned with the bundled artifact source when updating this file. + +### `midi-writer.js` + +- Usage: Bundled browser-side MIDI writer used by the MIDI export path. +- Local files: + - `src/js/midi-writer.js` +- Note: Keep upstream attribution and license information aligned with the bundled artifact source when updating this file. + +## Package-managed dependencies + +### `jsdom` + +- Usage: Test and browser-like DOM runtime support in the Node-based development and test environment. +- License: MIT +- Source: `package.json` / `package-lock.json` +- Upstream: https://github.com/jsdom/jsdom + +## Referenced materials + +### MusicXML + +- Usage: Core interchange format and specification baseline for the project. +- Source: https://www.w3.org/2021/06/musicxml40/ + +### MuseScore + +- Usage: Import and export interoperability target format. +- Source: https://musescore.org/ + +## Maintenance Notes + +- When updating vendored files, update this notice file if the origin, attribution, or packaging changes. +- Keep this document aligned with `LICENSE`, repository contents, and any bundled NOTICE files. diff --git a/TODO.md b/TODO.md index 5741cf5..80d9061 100644 --- a/TODO.md +++ b/TODO.md @@ -1,689 +1,371 @@ # TODO -## English -### Current Status (2026-02) - -#### Done -- [x] Implemented core `ScoreCore` load/dispatch/save and key validations. -- [x] Prepared unit and property test baseline. -- [x] Reorganized UI flow for edit/check/export. -- [x] Promoted Verovio rendering to official path. -- [x] Implemented note click selection. -- [x] Improved SVG click -> `nodeId` resolution (`elementsFromPoint` fallback). -- [x] Implemented `change_to_pitch`. -- [x] Implemented `split_note`. -- [x] Implemented rest-to-note conversion. -- [x] Added playback path with `midi-writer.js`. -- [x] Fixed transpose behavior including Clarinet in A. -- [x] Improved iPhone Safari audio start stability (`pointerdown`/`touchstart` unlock, `AudioContext` resume flow, `webkitAudioContext` fallback). -- [x] Fixed ABC tuplet timing drift in playback-related roundtrip paths. -- [x] Added `%@mks` roundtrip support for measure metadata (`number` / `implicit` / `repeat` / `times`) and `transpose` (`chromatic` / `diatonic`). -- [x] Improved ABC accidental export rules (suppress redundant naturals, preserve required naturals per key/measure context). - -#### Known Issues -- [ ] Verovio warning `slur ... could not be ended` may appear from input MusicXML; loading currently continues. -- [ ] Click mapping expects note-head/real note area click; staff/empty click can return `MVP_TARGET_NOT_FOUND`. -- [ ] Tuplet-like duration presets are currently restricted to measures/voices where compatible tuplet context already exists. - -### Next Priorities -#### P1: Editing stability -- [ ] Improve selected-note highlight visibility. -- [ ] Unify failure message policy (UI + console wording). -- [ ] Add at least one E2E click-mapping test. - -#### P2: Spec and tests sync -- [ ] Add save-XML/re-render consistency checks in `docs/spec`. -- [ ] Document and test selection retention rules across re-render. -- [ ] Add ABC roundtrip golden tests (`MusicXML -> ABC -> MusicXML`) for representative orchestral/piano scores. -- [ ] Define acceptable roundtrip delta policy for ABC path (what may change vs must be preserved). -- [ ] Add optional `%@mks ...` metadata compaction: - - On `MusicXML -> ABC`, suppress consecutive `%@mks` comment lines when values are unchanged from the previous measure. - - On `ABC -> MusicXML`, if `%@mks` metadata is omitted, inherit the previous measure's metadata for reconstruction. -- [ ] Reduce MuseScore MIDI parity gap (`moonlight` baseline, 2026-02-25): - - `safe (cand(midi)) practical diff = 307` - - `musescore_parity (cand(parity)) practical diff = 172` - - `playback practical diff = 183` (reference only; different path from export) - - `musescore_parity raw-on practical diff = 172` (was `378`; stabilized by FIFO note pairing on MIDI import) - - `onset-strict + durationRatio[1/2..2] (cand(parity)) = 167` (reference metric for MIDI->MusicXML practical restoration) - - Add focused fixes so export parity (`safe`/`musescore_parity`) improves without semantic regressions. -- [ ] MIDI -> MusicXML improvement pack (next 6 items): - - 1. Auto-select quantize grid (`1/8`,`1/16`,`1/32`) from note timing evidence (started). - - 2. Add section-aware quantize fallback (allow local grid override by measure window). - - 3. Strengthen same-tick same-pitch retrigger pairing policy with explicit mode switch and diagnostics. - - 4. Improve voice/staff reconstruction using register continuity and overlap minimization. - - 5. Keep onset-strict comparator as primary metric and duration-ratio metric as secondary gate in spot runs. - - 6. Add import preset profiles (`safe` / `musescore_parity`) for MIDI->MusicXML and document default intent. -- [ ] Add MIDI import UI controls for quantize behavior: - - expose `quantizeGrid` selector (`auto` / `1/8` / `1/16` / `1/32`) - - add `tripletAwareQuantize` toggle and define default behavior -- [ ] Investigate MuseScore OSS MIDI export implementation files and map transferable diff points for mikuscore: - - Identify concrete source files/functions for `MSCX/MSCZ -> MIDI` in MuseScore. - - Compare note event ordering, tie/retrigger handling, and quantization/rounding policies against mikuscore. - - Extract only implementable deltas and track expected parity impact per delta. -- [ ] Cross-format rollout gaps for MuseScore minimal tests: - - [x] LilyPond: articulation (`staccato` / `accent`) roundtrip-equivalent tests and preservation path. - - [x] LilyPond: grace-note minimal roundtrip-equivalent test. - - [x] LilyPond: tuplet start/stop and written-type equivalent checks. - - [x] LilyPond: trill/octave-shift equivalent policy tests (preserve/degrade explicit). - - [x] MEI: grace-note minimal roundtrip-equivalent test. - - [x] MEI: tuplet start/stop and written-type equivalent checks. - - [x] MEI: section-boundary double bar + explicit same-meter time equivalent test and metadata preservation. - - [x] MEI: articulation (`staccato` / `accent`) minimal roundtrip-equivalent test and preservation path. - -#### P3: Feature expansion -- [ ] Investigation: add `lightweight playback mode` for dense-note scores (classified as design consideration): - - limit max simultaneous voices (e.g., 32-48) to avoid browser audio-node saturation. - - optionally drop/merge ultra-short or duplicate-nearby notes for stability-first playback. - - allow omitting ornaments/grace in lightweight mode with explicit UI toggle and policy. - - define quality vs stability presets and default behavior for large scores. -- [ ] Decide whether to reintroduce `insert_note_after` in UI. -- [ ] Reconfirm in-session `xml:id` strategy and operation rules. -- [ ] Add chord editing support in core/editor commands (currently chord targets are read/play only in MVP). -- [ ] Add WAV export support (aligned with current quick-playback synth path). -- [ ] Add measure-level copy/paste feature. -- [ ] Add note-level copy/paste feature. -- [ ] Add functionality to create/add parts (staff/part insertion with basic setup flow). -- [ ] Verify and strengthen measure-level editing functionality. -- [ ] Fix unintended pinch-in (gesture zoom) behavior during score editing on touch devices. -- [ ] Add support for mid-song double barlines. -- [ ] Add support for multiple simultaneous notes at the same timing (same onset polyphony/chords where applicable). -- [ ] Investigate and fix the issue where triplet notation cannot be selected in the UI. -- [ ] Add functionality to merge/consolidate rests for cleanup. -- [ ] Add cross-measure tie handling in core/editor (logic independent from UI visibility). -- [ ] Define and implement UI rule for tie editing that may require showing the next measure (always preview or on-demand reveal). -- [ ] Add slur/tie create, edit, and delete operations in editor/core with validation and undo-safe behavior. -- [ ] Add articulation input support (at least staccato and tenuto) in editor/core and preserve them across import/export. -- [ ] Expand articulation support beyond staccato/tenuto (e.g., accent, marcato) with clear per-format preserve/degrade rules. -- [ ] Add dynamics marking input support (`pp` to `ff`, including intermediate levels) and preserve semantics across import/export. -- [ ] Rework MIDI velocity mapping for symbolic dynamics without numeric value (`pp`/`p`/`mp`/`mf`/`f`/`ff` etc.): - - Avoid near-inaudible defaults at low dynamics (`pp` currently too quiet in some outputs). - - Define floor/ceiling and curve (or table) so perceived loudness remains musical. - - Add regression tests for dynamics-to-velocity mapping (including playback audibility checks where possible). -- [ ] Add band score workflow support (common band instrumentation templates, part handling, and layout defaults). -- [ ] Define measure clipboard payload as MusicXML `...` fragment (app-internal clipboard first). -- [ ] Implement measure copy/paste in core first (validation/compatibility), then connect UI and optional system clipboard API. -- [x] Expand ABC compatibility for ornaments (`trill`, `turn`, grace variants) with explicit preserve/degrade rules. -- [x] Start CFFP (Cross-Format Focus Parity) with a minimal `trill` fixture (`MusicXML -> all supported formats -> MusicXML`). -- [x] Expand CFFP series with focused minimal fixtures: - - [x] `octave-shift (8va/8vb)` cross-format policy test. - - [x] `slur` cross-format policy test. - - [x] `tie` cross-format policy test. - - [x] `staccato` cross-format policy test. - - [x] `accent` cross-format policy test. - - [x] `grace` cross-format policy test. - - [x] `tuplet` cross-format policy test. - - [x] `accidental spelling` cross-format policy test. - - [x] `accidental reset rule` cross-format policy test (same-measure carry and next-measure reset). - - [x] `courtesy accidental` cross-format policy test (display-only accidental handling policy). - - [x] `key change mid-score` cross-format policy test. - - [x] `time signature change` cross-format policy test. - - [x] `double barline mid-score` cross-format policy test. - - [x] `repeat/ending barline metadata` cross-format policy test. - - [x] `beam continuity` cross-format policy test (across rest / split by beat policy). - - [x] `multi-voice + backup` cross-format policy test (same-staff lane reconstruction). - - [x] `grand-staff voice/staff mapping` cross-format policy test. - - [x] `pickup implicit measure` cross-format policy test (`implicit=yes` and measure numbering). - - [x] `trill variants` cross-format policy test (`trill-mark` + `wavy-line` start/stop + accidental-mark). - - [x] `turn` cross-format policy test. - - [x] `turn variants` cross-format policy test (`inverted-turn` + `delayed-turn`). - - [x] `mordent variants` cross-format policy test (`mordent` + `inverted-mordent`). - - [x] `ornament accidental-mark` cross-format policy test. - - [x] `schleifer` cross-format policy test. - - [x] `shake` cross-format policy test. - - [x] `dynamics basic (pp/ff)` cross-format policy test. - - [x] `dynamics accented (mf/sfz)` cross-format policy test. - - [x] `dynamics wedge (crescendo/diminuendo)` cross-format policy test. - - [x] `fermata` cross-format policy test. - - [x] `arpeggiate` cross-format policy test. - - [x] `breath-mark / caesura` cross-format policy test. - - [x] `glissando start/stop` cross-format policy test. - - [x] `transpose` cross-format policy test (per-part / per-measure hint behavior). - - [x] `tempo map` cross-format policy test (single tempo + change event). - - [x] Document CFFP preserve/degrade matrix per format (`musescore/midi/vsqx/abc/mei/lilypond`). - - [x] `slide start/stop` cross-format policy test. - - [x] `tremolo` cross-format policy test (`single` / `start-stop`). - - [x] `triplet bracket/placement` display-info cross-format policy test. - - [x] `CFFP-TECHNIQUE-TEXT` cross-format policy test (`direction-type/words`: `pizz.` / `arco` / `con sord.`). - - [x] `CFFP-ARTICULATION-EXT` cross-format policy test (`tenuto` / `staccatissimo` / `marcato`). - - [x] `CFFP-NOTEHEAD` cross-format policy test (`notehead`: `cross` / `diamond` ...). - - [x] `CFFP-STEM-BEAM-DIR` cross-format policy test (`stem` direction + beam direction info). - - [x] `CFFP-VOICE-STAFF-SWAP` cross-format policy test (voice crossing staves within a measure). - - [x] `CFFP-OTTAVA-NUMBERING` cross-format policy test (`octave-shift` with multiple `number` lines). - - [x] `CFFP-MEASURE-STYLE` cross-format policy test (`measure-style`: `slash` / `multiple-rest`). - - [x] `CFFP-PRINT-LAYOUT-MIN` cross-format policy test (`print` minimal layout: system/page break). - - [x] `CFFP-CLEF-MIDMEASURE` cross-format policy test (mid-measure clef change). - - [x] `CFFP-KEY-MODE` cross-format policy test (`key/mode`: major/minor). - - [x] `CFFP-MIDMEASURE-REPEAT` cross-format policy test (mid-measure repeat semantics/marking). - - [x] `CFFP-LYRIC-BASIC` cross-format policy test (1 syllable + melisma). - - [x] `CFFP-PERCUSSION-UNPITCHED` cross-format policy test (`unpitched` + `display-step` / `display-octave`). - - [x] `CFFP-PERCUSSION-NOTEHEAD` cross-format policy test (percussion noteheads: `x` / `triangle` / `diamond`). - - [x] `CFFP-PERCUSSION-INSTRUMENT-ID` cross-format policy test (`instrument id` mapping and retention). - - [x] `CFFP-PERCUSSION-VOICE-LAYER` cross-format policy test (drumset lane/voice separation in one staff). - - [x] `CFFP-PERCUSSION-STAFF-LINE` cross-format policy test (1-line vs 5-line percussion staff policy). - - [x] `CFFP-TRANSPOSING-INSTRUMENT` cross-format policy test (e.g., Clarinet in A `transpose` + concert/written pitch intent). - - [x] `CFFP-LEFT-HAND-PIZZICATO` cross-format policy test. - - [x] `CFFP-BOWING-DIRECTION` cross-format policy test (`up-bow` / `down-bow`). - - [x] `CFFP-HARMONIC-NATURAL-ARTIFICIAL` cross-format policy test (`harmonic` natural/artificial). - - [x] `CFFP-OPEN-STRING` cross-format policy test (`technical/open-string`). - - [x] `CFFP-STOPPED` cross-format policy test (`technical/stopped`). - - [x] `CFFP-SNAP-PIZZICATO` cross-format policy test (`technical/snap-pizzicato`, Bartok pizz.). - - [x] `CFFP-FINGERING` cross-format policy test (`technical/fingering`: 1-4 and substitution patterns). - - [x] `CFFP-STRING` cross-format policy test (`technical/string`: I/II/III/IV). - - [x] `CFFP-DOUBLE-TRIPLE-TONGUE` cross-format policy test (`double-tongue` / `triple-tongue`). - - [x] `CFFP-HEEL-TOE` cross-format policy test (`technical/heel` / `technical/toe`). - - [x] `CFFP-PLUCK-TEXT` cross-format policy test (pluck text: `p`, `i`, `m`, `a`). - - [x] `CFFP-BREATH-VARIANTS` cross-format policy test (breath-mark variants: comma/tick/upbow-like differences). - - [x] `CFFP-BREATH-PLACEMENT` cross-format policy test (`placement`/`default-x`/`default-y` retention on breath marks). - - [x] `CFFP-CAESURA-STYLE` cross-format policy test (caesura style variants retention). - - [x] `CFFP-TIMEWISE-BACKUP-FORWARD` cross-format policy test (`backup` / `forward` complex time progression). - - [x] `CFFP-CROSS-STAFF-BEAM` cross-format policy test (cross-staff beam). - - [x] `CFFP-CHORD-SYMBOL-ALTER` cross-format policy test (`harmony` tension/alter: `#11`, `b9`, ...). - - [x] `CFFP-NOTE-TIES-CROSS-MEASURE` cross-format policy test (cross-measure tie with same-pitch linkage). - - [x] `CFFP-MULTI-REST-COUNT` cross-format policy test (multiple-rest count retention). - - [x] `CFFP-REPEAT-JUMP-SOUND` cross-format policy test (`sound`: `fine` / `tocoda` / `coda` / `segno`). - - [x] `CFFP-CUE-GRACE-MIX` cross-format policy test (cue note + grace note mix). - - [x] `CFFP-ACCIDENTAL-COURTESY-MODE` cross-format policy test (courtesy accidental display-control variants). - - [x] `CFFP-LYRICS-MULTI-VERSE` cross-format policy test (multiple lyric verses: `number=1,2`). - - [x] `CFFP-TEXT-ENCODING` cross-format policy test (non-ASCII: Japanese lyrics / symbol-rich words). - - [x] `rehearsal mark` text-preservation cross-format policy test. - - [x] `segno/coda` symbol cross-format policy test. - - [x] `da capo / dal segno` jump words + sound-attributes cross-format policy test. - - [x] `pedal start/stop` cross-format policy test. - - [x] `harmony chord symbol` cross-format policy test (`root` / `bass` / `kind`). - - [x] `ending type` cross-format policy test (`start` / `stop` / `discontinue`). - - [ ] CFFP preserve-policy promotion backlog (format supports feature, implementation still degrades): - - [ ] Promote `CFFP-TIE` for `lilypond` from `allowed-degrade` to `must-preserve`. - - [ ] Promote `CFFP-DYNAMICS-WEDGE` for `musescore` from `allowed-degrade` to `must-preserve`. - - [ ] Promote `CFFP-GLISSANDO` for `musescore` from `allowed-degrade` to `must-preserve`. - - [ ] Promote `CFFP-PEDAL` for `musescore` from `allowed-degrade` to `must-preserve`. - - [x] Promote `CFFP-SEGNO-CODA` for `musescore` from `allowed-degrade` to `must-preserve`. - - [ ] Promote `CFFP-REHEARSAL-MARK` for `musescore` from `allowed-degrade` to `must-preserve`. - - [ ] Promote `CFFP-HARMONY-CHORDSYMBOL` for `musescore` and `mei` from `allowed-degrade` to `must-preserve`. - - [ ] Promote `CFFP-CHORD-SYMBOL-ALTER` for `musescore` and `mei` from `allowed-degrade` to `must-preserve`. - - [x] Promote `CFFP-NOTE-TIES-CROSS-MEASURE` for `musescore` from `allowed-degrade` to `must-preserve`. - - [ ] Promote `CFFP-NOTE-TIES-CROSS-MEASURE` for `lilypond` from `allowed-degrade` to `must-preserve`. - - [x] CFFP practical priority queue: - - [x] `breath-mark / caesura` - - [x] `glissando` - - [x] `pedal` - - [x] `segno/coda` - - [x] `harmony chord symbol` -- [ ] Add ABC import compatibility mode for overfull legacy exports and surface warning summary in UI. -- [x] Add LilyPond octave-shift (`8va` / `8vb`) roundtrip preservation (currently degrade-policy). -- [x] Add LilyPond (`.ly`) import/export support. -- [ ] Expand LilyPond unit tests (coverage is still insufficient): - - Add focused unit tests for `\relative` octave behavior (single note/chord/mixed explicit marks). - - Add unit tests for multi-staff parsing edge cases (`<< >>`, `\new Staff`, `\new Voice`, variable expansion). - - Add unit tests for command-argument non-note tokens (`\key`, `\time`, `\clef`, header/layout blocks) to prevent false note parsing. - - Add regression unit tests from recent incidents (overcount notes, octave shift mismatch, missing events in dense measures). -- [ ] LilyPond v2.24 notation audit follow-up (index + child/grandchild pages): - - [ ] Fix relative-octave decision to follow LilyPond rule (letter-name interval based, not semitone-distance based). - - [ ] Fix post-chord relative anchor to use the first note of chord as the reference for subsequent relative notes. - - [ ] Support isolated durations in note stream (e.g. `4`, `16`) so forms like `a'2~ 4~ 16` parse correctly. - - [ ] Preserve/parse tie marker `~` in native LilyPond import instead of stripping it in direct parser. - - [ ] Add native `\tuplet` parsing path (reduce duration drift when `%@mks` hints are absent). - - Parse native ties (`~`) and preserve tie semantics on import (currently dropped in direct parser). - - Parse native slurs / phrasing slurs (`(` `)` / `\(` `\)`) instead of relying on `%@mks` hints. - - Parse native dynamics (`\p`, `\f`, `\mf`, `\sfz`, `\<`, `\>`, `\!`) on import. - - [x] Parse native trill commands (`\trill`, `\startTrillSpan`/`\stopTrillSpan`) on import. - - [x] Parse native glissando command (`\glissando`) on import. - - Parse native repeat constructs (`\repeat volta`, `\alternative`, segno/al-fine variants) on import. - - Parse lyric constructs (`\lyricmode`, `\addlyrics`, `\lyricsto`) on import. - - Parse keyboard staff-change commands (`\change Staff`, `\autoChange`) on import. - - [x] Parse piano pedal commands (`\sustainOn`/`\sustainOff`, `\sostenutoOn`/`Off`, `\unaCorda`, `\treCorde`) on import. - - [x] Parse `\upbow` / `\downbow` on import. - - [x] Parse harmonics / `\snappizzicato` on import (minimal native mapping). -- [ ] Apply shared clef/staff policy (`core/staffClefPolicy.ts`) to LilyPond import path: - - [x] Use `chooseSingleClefByKeys` when `\clef` is omitted (single-block / `\new Staff` fallback). - - [x] Use `shouldUseGrandStaffByRange` for single-block imports that should auto-split to upper/lower staffs. - - [x] Apply hysteresis-based staff assignment when auto-splitting to upper/lower staffs. -- [ ] Add MEI (Music Encoding Initiative) import/export support. -- [ ] Strengthen MEI test strategy beyond unit level (unit-only is likely insufficient): - - Add MEI roundtrip golden tests (`MusicXML -> MEI -> MusicXML`) with semantic comparators. - - Add MEI spot/parity tests on larger real-world fixtures (e.g., piano multi-voice / ornaments / repeats). - - Define MEI preserve/degrade acceptance gates and fail CI when regressions exceed thresholds. - - Verify implementation conformance against official MEI references and track gaps in TODO: - - https://music-encoding.org/ - - https://music-encoding.org/guidelines/v5/content/ - - https://github.com/music-encoding/sample-encodings/tree/main/MEI_5.1/Music - - [ ] Local-fixture-dependent MEI unit tests (`tests/fixtures-local/**`) are temporary: - - keep auto-skip behavior when fixtures are missing; - - once CFFP/spot parity coverage is sufficient, consolidate and remove redundant local-fixture tests. - - MEI v5 spec-gap follow-up candidates (format has representation, current `mei-io` still partial): - - [ ] Transposing instruments (`trans.diat` / `trans.semi`) end-to-end conformance: - - [x] Import: map MEI transposition metadata to MusicXML `` per staff/part. (minimal `staffDef/scoreDef` attrs) - - [x] Export: preserve/reconstruct transposition metadata back to MEI `staffDef`/`scoreDef`. (minimal `staffDef trans.diat/trans.semi`) - - Add focused tests (e.g., Clarinet in A / Eb Clarinet) for written vs concert pitch intent. - - [ ] Alto clef visibility regression (Viola): - - Investigate cases where MEI `clef.shape="C"` + `clef.line="3"` is not rendered as MusicXML `C3`. - - Cover both forms: `staffDef` attributes and `staffDef > clef` child element. - - Add fixture-based regression test from real viola score and keep it in CI. - - [ ] Slur/Tie as MEI control events (``, ``) and/or note-level tie/slur attributes. - - [x] Import minimal staff-level `` into MusicXML `notations/slur` (same-layer id refs). - - [x] Import minimal staff-level `` into MusicXML `tie` + `notations/tied` (same-layer id refs). - - [x] Import minimal layer-level `/` (same-layer id refs). - - [x] Import minimal note-level `@tie` / `@slur` attributes into MusicXML `tie+tied` / `notations/slur`. - - [x] Export minimal MusicXML note `tie/slur` into MEI note attributes `@tie` / `@slur`. - - [ ] Dynamics and wedges (``, ``). - - [x] Minimal `` import to MusicXML direction (`dynamics` or `words`, supports `tstamp` offset). - - [x] Minimal export of MusicXML `direction(dynamics/wedge)` to MEI `` / `` (same-measure pairing). - - [ ] Ornaments/control events (``, ``, ``, ``). - - [x] Minimal export of MusicXML note ornaments/fermata to MEI control events (``, ``, ``, ``). - - [ ] Glissando/slide (``). - - [x] Minimal export of MusicXML note `notations(glissando/slide)` to MEI `` / `` via same-measure pairing. - - [x] Minimal `` import (`startid/endid` and `tstamp/tstamp2` -> MusicXML `notations/slide` start/stop). - - [ ] Pedal and octave-shift (``, ``). - - [x] Minimal export of MusicXML `direction(pedal/octave-shift)` to MEI `` / `` (same-measure pairing). - - [ ] Breath/Caesura (``, ``). - - [x] Minimal export of MusicXML note articulations (`breath-mark` / `caesura`) to MEI `` / ``. - - [ ] Repeat/jump control marks (``, segno/coda/fine mapping). - - [x] Minimal export of MusicXML segno/coda/fine (direction symbols/words) to MEI ``. - - [ ] Harmony/chord symbols (``) including altered tensions. - - [ ] Tuplet span support for cross-measure cases (``). - - MEI parity deep-check findings (2026-02-27): - - [x] Fix note-drop on complex real fixture (`paganini`) in `MusicXML -> MEI -> MusicXML`: - - currently observed pitch+timing misses: m138 (`D7`), m140 (`C7`), m153 (`C#4`, short value). - - likely related to overfull/clamp or dense-layer event handling in `mei-io` import path. - - [x] Normalize accidental-zero representation policy (`alter=0` vs omitted alter) to reduce non-semantic diff noise. - - [ ] MEI reliability reset (assume current implementation is not trustworthy until proven): - - [ ] Phase 0 (safety gate): prohibit silent data loss and add strict-mode failure on overfull/clamped import. - - [ ] Phase 1 (parity baseline): establish external-MEI fixture set and pitch/octave/onset/duration parity checks. - - [x] Import `accid.ges` / `accid-ges` as sounding alter fallback when visual `accid` is omitted (keep display accidental unchanged). - - [ ] Phase 2 (spec elements): implement core control events and rhythmic containers in native MEI mapping. - - [ ] Phase 3 (cross-hierarchy timing): implement `tstamp`/`startid`/`endid`/`plist` resolution and cross-measure spans. - - [ ] Phase 4 (compat policy): define v5 compatibility contract, downgrade rules, and CI acceptance thresholds. - - [ ] Replace silent note-drop behavior (`OVERFULL_CLAMPED`) with strict mode + explicit failure option; no data-loss by default. - - [x] Added `failOnOverfullDrop` option to throw on actual event drop (`convertMeiToMusicXml`). - - [ ] Add external-MEI ingestion tests (non-mikuscore-generated MEI samples) for pitch/octave/onset/duration parity. - - [x] Minimal external-style MEI unit case added (dur/dots/chord without `mks:*`) for pitch+duration baseline. - - [x] Official MEI v5 sample source URLs recorded in fixture docs: - - `tests/fixtures-local/mei-official/beam-grace/SOURCE.md` - - [x] `meiCorpus` import selection support (`meiCorpusIndex`) + index/out-of-range tests added. - - [ ] Support MEI control events (spec-based) in import/export instead of relying on `mks:*` metadata: - - ``, ``, ``, ``, ``, ``, ``, ``. - - [x] Tie control-event accidental carry: when tied stop omits accidental/alter, inherit pitch alter from tie start (same layer timeline). - - [ ] Support structural rhythmic containers from MEI CMN: - - ``, ``, ``, ``, ``. - - [x] import 側で `` / `` / `` の最小展開を追加し、子ノートを取りこぼさないようにした。 - - [x] Map MEI `@breaksec` (secondary beam breaks) into MusicXML multi-level beam/hook encoding with regression test (official Listing 142 fixture). - - [x] Add `beamSpan` import handling (`startid` / `endid` / `plist`) and regression tests. - - [ ] `beamSpan` / `hairpin` / `dynam` / `fermata` / `gliss` の視覚比較は Verovio が未描画/無視するケースがあるため、画像差分のみを合否基準にしない(構造アサート優先)。 - - [ ] Support timing anchors from `att.controlEvent` (`tstamp`, `startid`, `endid`, `plist`) for cross-hierarchy events. - - [x] Minimal `tstamp/tstamp2` import for staff-level `` / `` (same layer, numeric beat position). - - [x] Minimal `plist` import for single-target control events (e.g. ``). - - [x] Minimal `plist` import for span-like events start resolution (e.g. `////` start side). - - [ ] Handle score changes beyond first `scoreDef`: - - [x] Mid-score `staffDef` overrides (key/clef/transpose) are now applied per target staff in import. - - mid-score meter/key/clef/staffDef changes (do not assume single global `scoreDef`). - - [ ] Upgrade export target from fixed `meiversion=\"4.0.1\"` to v5-compatible policy and document compatibility contract. - - [x] Export default `meiversion` switched to `5.1`, with explicit override option (`MeiExportOptions.meiVersion`) for compatibility. - - [ ] Reduce dependency on `annot type=\"musicxml-misc-field\"` for core semantics (keep as auxiliary only). -- [ ] Add MuseScore (`.mscz` / `.mscx`) import/export support. -- [ ] Add VSQX import/export support. -- [ ] Add lyrics support (import/edit/export with format-specific preserve/degrade rules). -- [ ] Improve functionality and reliability of import/export across supported formats (options, diagnostics, and roundtrip quality). -- [ ] Fix invalid data generation when exporting piano scores to ABC and add regression tests. -- [ ] Add input file size limit checks before import/load and provide clear UI errors when the limit is exceeded. -- [ ] MuseScore staged import roadmap: - - [ ] Phase 1 (now): `.mscx` / `.mscz` load path, basic note/rest/chord import, and `diag` + `src:musescore:*` raw metadata preservation. - - [ ] Phase 2: playback-rich metadata import (tempo map, repeat/jump semantics, dynamics/play-tech where mappable) with explicit `diag` for dropped items. - - [ ] Phase 3: layout fidelity import (system/page breaks, spacing hints) as optional metadata and selective restoration. - - [ ] Phase 4: notation extensions (ornaments, tuplet variants, articulations, technique text) with preserve/degrade policy per item. -- [ ] Prevent exporting overfull measures to external formats (at minimum MEI/ABC); normalize or split at export time so invalid data is not emitted. -- [ ] Add a mandatory shared pre-export capacity check for all formats; if overfull is detected, emit `diag` and abort export. - -### Resume Checklist -1. `npm run build` -2. Hard reload `mikuscore.html` -3. Confirm note click selection on score panel -4. Run `change_to_pitch` / `change_duration` / `split_note` -> save -> confirm re-render - ---- - -## 日本語 -### 現在地(2026-02 時点) - -#### 完了済み -- [x] Core(`ScoreCore`)の load / dispatch / save と主要バリデーションを実装済み。 -- [x] 単体テスト + property test の基盤を整備済み。 -- [x] UI の編集・確認・出力導線を再配置済み。 -- [x] Verovio レンダリングを正式採用済み。 -- [x] ノートクリック選択を実装済み。 -- [x] SVG 上クリック -> `nodeId` 解決を改善済み(`elementsFromPoint` フォールバック)。 -- [x] `change_to_pitch` を実装済み。 -- [x] `split_note` を実装済み。 -- [x] 休符の音符化(rest -> pitched note)を実装済み。 -- [x] `midi-writer.js` を使った再生経路を導入済み。 -- [x] Clarinet in A 含む `transpose` 反映を修正済み。 -- [x] iPhone Safari での音出し安定性を改善済み(`pointerdown`/`touchstart` 先行アンロック、`AudioContext` resume 経路、`webkitAudioContext` フォールバック)。 -- [x] ABC の連符(tuplet)往復時に発生していた再生タイミングずれを修正済み。 -- [x] `%@mks` の小節メタ(`number` / `implicit` / `repeat` / `times`)と `transpose`(`chromatic` / `diatonic`)の往復保持を実装済み。 -- [x] ABC 出力の臨時記号ルールを改善済み(不要なナチュラル抑制、必要なナチュラルは保持)。 - -#### 既知事項 -- [ ] Verovio 警告 `slur ... could not be ended` は入力 MusicXML 由来で表示されることがある。現状は読み込み継続。 -- [ ] クリック選択は音符クリック前提。五線や空白クリックは `MVP_TARGET_NOT_FOUND` になりうる。 -- [ ] 音価ドロップダウンの 3 連系は、現状「同小節/同 voice に既存 tuplet がある場合のみ許可」の暫定制約。 - -### 次にやること -#### P1: 編集体験の安定化 -- [ ] 選択ノートの視覚ハイライトを強化。 -- [ ] 失敗時メッセージを統一(UI表示と console 文面)。 -- [ ] クリックマッピングの E2E テストを追加(最低 1 ケース)。 - -#### P2: 仕様とテストの同期 -- [ ] 保存 XML と再レンダリング結果の整合チェック手順を `docs/spec` に追記。 -- [ ] レンダリング更新時の選択維持ルールを明文化しテスト化。 -- [ ] 代表的なオーケストラ譜/ピアノ譜で `MusicXML -> ABC -> MusicXML` のゴールデン往復テストを追加。 -- [ ] ABC経由での往復差分ポリシー(許容差分/非許容差分)を明文化。 -- [ ] `%@mks ...` メタコメントの省略最適化を追加。 - - `MusicXML -> ABC` では、前小節と同一内容が連続する場合、後続の `%@mks` コメント行を省略可能にする。 - - `ABC -> MusicXML` では、省略により不足した `%@mks` 情報を前小節の値で継承して復元する。 -- [ ] MuseScore MIDI パリティ差分の縮小(`moonlight` 実測, 2026-02-25)。 - - `safe (cand(midi)) practical diff = 307` - - `musescore_parity (cand(parity)) practical diff = 172` - - `playback practical diff = 183`(参考値。export とは別経路) - - `musescore_parity raw-on practical diff = 172`(以前 `378`。MIDI import の FIFO ペアリングで安定化) - - `onset厳格 + duration比率[1/2..2] (cand(parity)) = 167`(MIDI->MusicXML 復元品質の参照値) - - 意味保存回帰を起こさない範囲で、export 側(`safe`/`musescore_parity`)の差分を段階的に削減する。 -- [ ] MIDI -> MusicXML 改善パック(次の6項目)。 - - 1. 音価グリッド(`1/8`,`1/16`,`1/32`)をノート時刻の証拠から自動選択する(着手済み)。 - - 2. 小節単位で量子化を切り替えられる区間フォールバックを追加する。 - - 3. 同tick同pitchの再発音ペアリングをモード化し、診断と合わせて強化する。 - - 4. 音域連続性と重なり最小化に基づく voice/staff 再構成を改善する。 - - 5. spot 比較で onset 厳格一致を主指標、duration 比率許容を副指標として固定する。 - - 6. MIDI->MusicXML に `safe` / `musescore_parity` の入力プリセットを追加し、既定意図を明文化する。 -- [ ] MIDI import の量子化設定を UI から指定可能にする。 - - `quantizeGrid` セレクタ(`auto` / `1/8` / `1/16` / `1/32`)を追加する。 - - `tripletAwareQuantize` トグルを追加し、既定値の方針を定義する。 -- [ ] MuseScore OSS の MIDI export 実装ファイルを調査し、mikuscore に取り込める差分観点を一覧化する。 - - MuseScore 側の `MSCX/MSCZ -> MIDI` の具体ファイル/関数を特定する。 - - ノートイベント順序、tie/retrigger、量子化/丸め規則を mikuscore と比較する。 - - 実装可能な差分のみを抽出し、差分ごとの期待パリティ改善量を管理する。 -- [ ] MuseScore 最小テストの横展開ギャップ整理: - - [x] LilyPond: アーティキュレーション(`staccato` / `accent`)の同等テストと保持経路。 - - [x] LilyPond: 前打音(grace)最小ケースの同等テスト。 - - [x] LilyPond: 連符(tuplet start/stop・表記音価)同等テスト。 - - [x] LilyPond: `trill` / `octave-shift` の同等ポリシーテスト(保持/劣化を明示)。 - - [x] MEI: 前打音(grace)最小ケースの同等テスト。 - - [x] MEI: 連符(tuplet start/stop・表記音価)同等テスト。 - - [x] MEI: セクション境界ダブルバー + 同拍子再明示の同等テストとメタ保持。 - - [x] MEI: アーティキュレーション(`staccato` / `accent`)最小同等テストと保持経路。 - -#### P3: 仕様拡張 -- [ ] 検討事項: ノート密度が高い譜面向けに `軽量再生モード` を追加する。 - - ブラウザの音声ノード飽和を避けるため、同時発音数の上限(例: 32-48)を設ける。 - - 安定再生優先として、極短音や近接重複音の間引き/マージを任意適用できるようにする。 - - 軽量モードでは装飾音(trill/grace 等)を省略可能にし、UIトグルと方針を明示する。 - - 大規模譜面向けに「音質優先/安定優先」プリセットと既定値を定義する。 -- [ ] `insert_note_after` の UI 再導入可否を仕様確定。 -- [ ] セッション内 `xml:id` 付与戦略を再確認(永続化しない方針の運用ルール化)。 -- [ ] 和音編集(chord)対応を core/editor コマンドに追加(現状はMVPで「読み込み/再生は可・直接編集は不可」)。 -- [ ] WAV 出力対応を追加(現行の簡易再生シンセ経路に沿う形)。 -- [ ] 小節単位のコピー/ペースト機能を追加。 -- [ ] 音符単位のコピー/ペースト機能を追加。 -- [ ] パートを追加する機能を追加(スタッフ/パート挿入と基本セットアップ導線)。 -- [ ] 小節ごとの編集機能の確認・強化。 -- [ ] タッチ端末で編集中に意図せずピンチイン(ジェスチャーズーム)が発生する不具合を修正。 -- [ ] 曲途中の二重線に対応。 -- [ ] 同じタイミングでの複数音(同時発音/必要に応じて和音)に対応。 -- [ ] UIで3連譜を選べない事象を解析し、修正対応する。 -- [ ] 休符を合体・整理する機能を追加。 -- [ ] 小節跨ぎタイの処理を core/editor に追加(UI表示有無に依存しないロジック)。 -- [ ] タイ編集時の UI 仕様を定義して実装(次小節の常時プレビューまたは操作時表示)。 -- [ ] スラー/タイの入力・編集・削除機能を editor/core に追加(妥当性チェックと Undo 安全性を含む)。 -- [ ] アーティキュレーション入力対応を追加(最低限スタッカート/テヌート)し、入出力で保持できるようにする。 -- [ ] スタッカート/テヌート以外のアーティキュレーション(例: アクセント、マルカート)対応を拡張し、形式ごとの保持/劣化ルールを定義する。 -- [ ] 強弱記号(`pp`-`ff` と中間段階)の記入機能を追加し、入出力で意味を保持できるようにする。 -- [ ] 数値なし強弱記号(`pp`/`p`/`mp`/`mf`/`f`/`ff` など)を MIDI 化したときの velocity 設計を見直す。 - - `pp` が聞こえなくなるような過小値を避ける(低強弱の最小音量を再定義)。 - - floor/ceiling とカーブ(またはテーブル)を定義し、知覚上の音量差が音楽的になるようにする。 - - 強弱記号→velocity の回帰テストを追加する(可能なら可聴性観点のチェックも含む)。 -- [ ] バンド譜面への対応を追加(一般的な編成テンプレート、パート管理、レイアウト初期値を含む)。 -- [ ] 小節クリップボードのペイロードを MusicXML の `...` 断片として定義(まずはアプリ内クリップボード)。 -- [ ] 実装順を「core先行(整合チェック含む) -> UI接続 -> 必要ならシステム Clipboard API 連携」に固定。 -- [x] ABCの装飾記号(`trill`/`turn`/前打音バリエーション)の互換対応を拡張し、保持/劣化ルールを規定。 -- [x] CFFP(Cross-Format Focus Parity)を `trill` の最小断片で開始(`MusicXML -> 対応全形式 -> MusicXML`)。 -- [x] CFFP シリーズを最小断片で横展開する: - - [x] `octave-shift (8va/8vb)` の横断ポリシーテスト。 - - [x] `slur` の横断ポリシーテスト。 - - [x] `tie` の横断ポリシーテスト。 - - [x] `staccato` の横断ポリシーテスト。 - - [x] `accent` の横断ポリシーテスト。 - - [x] `grace` の横断ポリシーテスト。 - - [x] `tuplet` の横断ポリシーテスト。 - - [x] `臨時記号スペリング` の横断ポリシーテスト。 - - [x] `臨時記号の持ち越し/小節リセット規則` の横断ポリシーテスト。 - - [x] `注意的臨時記号(courtesy accidental)` の横断ポリシーテスト(表示専用情報の扱い)。 - - [x] `途中転調` の横断ポリシーテスト。 - - [x] `途中拍子変更` の横断ポリシーテスト。 - - [x] `曲途中の二重線` の横断ポリシーテスト。 - - [x] `反復記号/エンディング線を伴う小節線メタ` の横断ポリシーテスト。 - - [x] `ビーム連結` の横断ポリシーテスト(休符またぎ / 拍境界分割ポリシー)。 - - [x] `複数voice + backup` の横断ポリシーテスト(同一五線レーン復元)。 - - [x] `大譜表の staff/voice 対応` の横断ポリシーテスト。 - - [x] `弱起(implicit小節)` の横断ポリシーテスト(`implicit=yes` と小節番号)。 - - [x] `トリル派生` の横断ポリシーテスト(`trill-mark` + `wavy-line` start/stop + accidental-mark)。 - - [x] `turn` の横断ポリシーテスト。 - - [x] `turn派生` の横断ポリシーテスト(`inverted-turn` + `delayed-turn`)。 - - [x] `mordent派生` の横断ポリシーテスト(`mordent` + `inverted-mordent`)。 - - [x] `ornament accidental-mark` の横断ポリシーテスト。 - - [x] `schleifer` の横断ポリシーテスト。 - - [x] `shake` の横断ポリシーテスト。 - - [x] `dynamics basic (pp/ff)` の横断ポリシーテスト。 - - [x] `dynamics accented (mf/sfz)` の横断ポリシーテスト。 - - [x] `dynamics wedge (crescendo/diminuendo)` の横断ポリシーテスト。 - - [x] `fermata` の横断ポリシーテスト。 - - [x] `arpeggiate` の横断ポリシーテスト。 - - [x] `breath-mark / caesura` の横断ポリシーテスト。 - - [x] `glissando start/stop` の横断ポリシーテスト。 - - [x] `transpose` の横断ポリシーテスト(パート単位/小節単位ヒント)。 - - [x] `テンポマップ` の横断ポリシーテスト(単一テンポ + 途中変更)。 - - [x] 形式別(`musescore/midi/vsqx/abc/mei/lilypond`)の保持/劣化マトリクスを文書化。 - - [x] `slide start/stop` の横断ポリシーテスト。 - - [x] `tremolo` の横断ポリシーテスト(`single` / `start-stop`)。 - - [x] `triplet bracket/placement` 表示情報の横断ポリシーテスト。 - - [x] `CFFP-TECHNIQUE-TEXT` の横断ポリシーテスト(`direction-type/words`: `pizz.` / `arco` / `con sord.`)。 - - [x] `CFFP-ARTICULATION-EXT` の横断ポリシーテスト(`tenuto` / `staccatissimo` / `marcato`)。 - - [x] `CFFP-NOTEHEAD` の横断ポリシーテスト(`notehead`: `cross` / `diamond` など)。 - - [x] `CFFP-STEM-BEAM-DIR` の横断ポリシーテスト(`stem` 方向 + beam 方向情報)。 - - [x] `CFFP-VOICE-STAFF-SWAP` の横断ポリシーテスト(小節内で voice が staff をまたぐ)。 - - [x] `CFFP-OTTAVA-NUMBERING` の横断ポリシーテスト(`octave-shift` の `number` 複数系)。 - - [x] `CFFP-MEASURE-STYLE` の横断ポリシーテスト(`measure-style`: `slash` / `multiple-rest`)。 - - [x] `CFFP-PRINT-LAYOUT-MIN` の横断ポリシーテスト(`print` の最小レイアウト: system/page break)。 - - [x] `CFFP-CLEF-MIDMEASURE` の横断ポリシーテスト(小節途中 clef change)。 - - [x] `CFFP-KEY-MODE` の横断ポリシーテスト(`key/mode`: major/minor)。 - - [x] `CFFP-MIDMEASURE-REPEAT` の横断ポリシーテスト(小節途中の repeat セマンティクス/記号)。 - - [x] `CFFP-LYRIC-BASIC` の横断ポリシーテスト(1音節 + melisma)。 - - [x] `CFFP-PERCUSSION-UNPITCHED` の横断ポリシーテスト(`unpitched` + `display-step` / `display-octave`)。 - - [x] `CFFP-PERCUSSION-NOTEHEAD` の横断ポリシーテスト(打楽器 notehead: `x` / `triangle` / `diamond`)。 - - [x] `CFFP-PERCUSSION-INSTRUMENT-ID` の横断ポリシーテスト(`instrument id` の対応と保持)。 - - [x] `CFFP-PERCUSSION-VOICE-LAYER` の横断ポリシーテスト(同一スタッフ内のドラムレーン/voice 分離)。 - - [x] `CFFP-PERCUSSION-STAFF-LINE` の横断ポリシーテスト(1線/5線の打楽器五線ポリシー)。 - - [x] `CFFP-TRANSPOSING-INSTRUMENT` の横断ポリシーテスト(例: Clarinet in A の `transpose` と実音/記譜音の意図)。 - - [x] `CFFP-LEFT-HAND-PIZZICATO` の横断ポリシーテスト。 - - [x] `CFFP-BOWING-DIRECTION` の横断ポリシーテスト(`up-bow` / `down-bow`)。 - - [x] `CFFP-HARMONIC-NATURAL-ARTIFICIAL` の横断ポリシーテスト(`harmonic` の natural/artificial)。 - - [x] `CFFP-OPEN-STRING` の横断ポリシーテスト(`technical/open-string`)。 - - [x] `CFFP-STOPPED` の横断ポリシーテスト(`technical/stopped`)。 - - [x] `CFFP-SNAP-PIZZICATO` の横断ポリシーテスト(`technical/snap-pizzicato`、バルトーク・ピチカート)。 - - [x] `CFFP-FINGERING` の横断ポリシーテスト(`technical/fingering`: 1-4 と置換指)。 - - [x] `CFFP-STRING` の横断ポリシーテスト(`technical/string`: I/II/III/IV)。 - - [x] `CFFP-DOUBLE-TRIPLE-TONGUE` の横断ポリシーテスト(`double-tongue` / `triple-tongue`)。 - - [x] `CFFP-HEEL-TOE` の横断ポリシーテスト(`technical/heel` / `technical/toe`)。 - - [x] `CFFP-PLUCK-TEXT` の横断ポリシーテスト(プラック文字: `p` / `i` / `m` / `a`)。 - - [x] `CFFP-BREATH-VARIANTS` の横断ポリシーテスト(comma/tick/upbow-like など breath-mark 変種)。 - - [x] `CFFP-BREATH-PLACEMENT` の横断ポリシーテスト(breath-mark の `placement` / `default-x` / `default-y` 保持)。 - - [x] `CFFP-CAESURA-STYLE` の横断ポリシーテスト(caesura の style 差保持)。 - - [x] `CFFP-TIMEWISE-BACKUP-FORWARD` の横断ポリシーテスト(`backup` / `forward` を使う複雑時間進行)。 - - [x] `CFFP-CROSS-STAFF-BEAM` の横断ポリシーテスト(cross-staff beam)。 - - [x] `CFFP-CHORD-SYMBOL-ALTER` の横断ポリシーテスト(`harmony` のテンション/alter: `#11`, `b9` など)。 - - [x] `CFFP-NOTE-TIES-CROSS-MEASURE` の横断ポリシーテスト(小節跨ぎ tie + 同音連結)。 - - [x] `CFFP-MULTI-REST-COUNT` の横断ポリシーテスト(multiple rest の小節数保持)。 - - [x] `CFFP-REPEAT-JUMP-SOUND` の横断ポリシーテスト(`sound` の `fine` / `tocoda` / `coda` / `segno`)。 - - [x] `CFFP-CUE-GRACE-MIX` の横断ポリシーテスト(cue note と grace note の混在)。 - - [x] `CFFP-ACCIDENTAL-COURTESY-MODE` の横断ポリシーテスト(courtesy accidental の表示制御差)。 - - [x] `CFFP-LYRICS-MULTI-VERSE` の横断ポリシーテスト(複数 verse: `lyric number=1,2`)。 - - [x] `CFFP-TEXT-ENCODING` の横断ポリシーテスト(非ASCII: 日本語歌詞・記号付き words)。 - - [x] `rehearsal mark` 文字保持の横断ポリシーテスト。 - - [x] `segno/coda` 記号の横断ポリシーテスト。 - - [x] `da capo / dal segno`(jump words + sound属性)の横断ポリシーテスト。 - - [x] `pedal start/stop` の横断ポリシーテスト。 - - [x] `harmony chord symbol` の横断ポリシーテスト(`root` / `bass` / `kind`)。 - - [x] `ending type` の横断ポリシーテスト(`start` / `stop` / `discontinue`)。 - - [ ] CFFP 保持ポリシー格上げバックログ(フォーマット仕様上は対応可能だが実装が劣化扱い): - - [ ] `CFFP-TIE` の `lilypond` を `allowed-degrade` から `must-preserve` へ格上げ。 - - [ ] `CFFP-DYNAMICS-WEDGE` の `musescore` を `allowed-degrade` から `must-preserve` へ格上げ。 - - [ ] `CFFP-GLISSANDO` の `musescore` を `allowed-degrade` から `must-preserve` へ格上げ。 - - [ ] `CFFP-PEDAL` の `musescore` を `allowed-degrade` から `must-preserve` へ格上げ。 - - [x] `CFFP-SEGNO-CODA` の `musescore` を `allowed-degrade` から `must-preserve` へ格上げ。 - - [ ] `CFFP-REHEARSAL-MARK` の `musescore` を `allowed-degrade` から `must-preserve` へ格上げ。 - - [ ] `CFFP-HARMONY-CHORDSYMBOL` の `musescore` / `mei` を `allowed-degrade` から `must-preserve` へ格上げ。 - - [ ] `CFFP-CHORD-SYMBOL-ALTER` の `musescore` / `mei` を `allowed-degrade` から `must-preserve` へ格上げ。 - - [x] `CFFP-NOTE-TIES-CROSS-MEASURE` の `musescore` を `allowed-degrade` から `must-preserve` へ格上げ。 - - [ ] `CFFP-NOTE-TIES-CROSS-MEASURE` の `lilypond` を `allowed-degrade` から `must-preserve` へ格上げ。 - - [x] CFFP 実用優先キュー: - - [x] `breath-mark / caesura` - - [x] `glissando` - - [x] `pedal` - - [x] `segno/coda` - - [x] `harmony chord symbol` -- [ ] 旧ABC由来の小節過充填に対する互換モードを整備し、UIに警告サマリを表示。 -- [x] LilyPond の octave-shift(`8va` / `8vb`)往復保持を実装する(現状は劣化ポリシー)。 -- [x] LilyPond(`.ly`)の入出力対応を追加。 -- [ ] LilyPond の単体テストを拡充する(現状はまだ不足): - - `\relative` のオクターブ挙動(単音/和音/明示オクターブ記号混在)を追加。 - - 多段譜解析の境界ケース(`<< >>` / `\new Staff` / `\new Voice` / 変数展開)を追加。 - - `\key` / `\time` / `\clef` / header/layout など「音符でないトークン」の誤認識防止テストを追加。 - - 直近不具合(音符過剰生成・オクターブずれ・密集小節での欠落)を回帰テスト化する。 -- [ ] LilyPond v2.24 記法監査(index + 子/孫ページ)に基づく追従TODO: - - [ ] relative のオクターブ判定を LilyPond 仕様に合わせる(半音距離ではなく音名間隔ベース)。 - - [ ] 和音直後の relative 基準音を「和音先頭音」に修正する(現状は末尾音基準になりうる)。 - - [ ] 単独音価トークン(例: `4`, `16`)を解析し、`a'2~ 4~ 16` のような記法を正しく取り込む。 - - [ ] direct parser で `~` を除去せず、tie をネイティブ解析・保持する。 - - [ ] `%@mks` 非依存で `\tuplet` をネイティブ解析する経路を追加する。 - - tie 記法(`~`)をネイティブ解析し、取り込み時に tie セマンティクスを保持する(現状は direct parser で脱落)。 - - slur / phrasing slur(`(` `)` / `\(` `\)`)を `%@mks` 依存ではなくネイティブ解析する。 - - dynamics(`\p`, `\f`, `\mf`, `\sfz`, `\<`, `\>`, `\!`)をネイティブ解析する。 - - [x] trill(`\trill`, `\startTrillSpan`/`\stopTrillSpan`)をネイティブ解析する。 - - [x] glissando(`\glissando`)をネイティブ解析する。 - - repeat 構文(`\repeat volta`, `\alternative`, segno/al-fine 系)をネイティブ解析する。 - - lyrics 構文(`\lyricmode`, `\addlyrics`, `\lyricsto`)をネイティブ解析する。 - - 鍵盤系の staff 変更(`\change Staff`, `\autoChange`)を取り込む。 - - [x] ピアノペダル記法(`\sustainOn`/`\sustainOff`, `\sostenutoOn`/`Off`, `\unaCorda`, `\treCorde`)を取り込む。 - - [x] `\upbow` / `\downbow` を取り込む。 - - [x] harmonics / `\snappizzicato` を取り込む(最小ネイティブマッピング)。 -- [ ] LilyPond 取り込み経路に共通の clef/staff 判定(`core/staffClefPolicy.ts`)を適用する。 - - [x] `\clef` 未指定時のフォールバックに `chooseSingleClefByKeys` を適用する(単一ブロック / `\new Staff`)。 - - [x] 単一ブロック取り込み時に `shouldUseGrandStaffByRange` を使い、大譜表相当(上下staff)への自動分割を適用する。 - - [x] 大譜表相当へ自動分割する場合はヒステリシス方式の staff 割当を適用する。 -- [ ] 独自 clef 判定ロジックの共通化方針を策定し、可能な経路で `core/staffClefPolicy.ts` を利用する。 - - [ ] 対象整理: どの入出力(ABC/MEI/LilyPond/MIDI など)が独自 clef 判定を持つかを棚卸しする。 - - [ ] 適用方針: 既存挙動互換を保ちつつ `shouldUseGrandStaffByRange` / `chooseSingleClefByKeys` への置換可否を判定する。 - - [ ] 検証: 既存 fixture + CFFP で回帰を確認し、必要なら format 別に opt-in フラグを用意する。 -- [ ] MEI(Music Encoding Initiative)の入出力対応を追加。 -- [ ] MEI のテスト戦略を単体レベル以上に強化する(unit だけでは不足の可能性): - - `MusicXML -> MEI -> MusicXML` の roundtrip golden テストを追加する。 - - 実運用に近い大きめ fixture(多声・装飾・リピート等)で spot/parity テストを追加する。 - - preserve/degrade の許容基準を定義し、閾値超過で CI を失敗させる。 - - MEI 公式リファレンスに照らして実装適合を確認し、差分は TODO で管理する: - - https://music-encoding.org/ - - https://music-encoding.org/guidelines/v5/content/ - - https://github.com/music-encoding/sample-encodings/tree/main/MEI_5.1/Music - - [ ] `tests/fixtures-local/**` に依存する MEI 単体テストは暫定運用とする: - - fixture 不在時は自動 skip を維持する。 - - CFFP/spot parity の網羅が十分になったら、重複する local-fixture テストを整理・削除する。 - - MEI v5 仕様差分フォロー候補(仕様上は表現可能だが `mei-io` 実装が未完/部分対応): - - [ ] Slur/Tie を MEI 制御イベント(``, ``)または note属性として往復保持する。 - - [x] staff内 `` の最小取り込み(同一layer id参照)を実装。 - - [x] staff内 `` の最小取り込み(同一layer id参照)を実装。 - - [x] layer内 `/` の最小取り込み(同一layer id参照)を実装。 - - [x] note属性 `@tie` / `@slur` の最小取り込み(`tie+tied` / `notations/slur`)を実装。 - - [x] MusicXML note `tie/slur` から MEI note属性 `@tie` / `@slur` への最小出力を実装。 - - [ ] 強弱とクレッシェンド/デクレッシェンド(``, ``)を保持する。 - - [x] `` の最小取り込み(MusicXML direction/dynamics・自由テキスト words・`tstamp` offset)を実装。 - - [x] `` の最小取り込み(`startid/endid` と `tstamp/tstamp2` から MusicXML `wedge start/stop`)を実装。 - - [x] MusicXML `direction(dynamics/wedge)` から MEI `` / `` への最小出力(同一小節内 pairing)を実装。 - - [ ] 装飾・制御イベント(``, ``, ``, ``)を保持する。 - - [x] `` / `` の最小取り込み(control event -> note notations)を実装。 - - [x] `` / `` の最小取り込み(control event -> ornaments)を実装。 - - [x] MusicXML note の ornament/fermata から MEI 制御イベント(``, ``, ``, ``)への最小出力を実装。 - - [ ] グリッサンド/スライド(``)を保持する。 - - [x] `` の最小取り込み(`startid/endid` と `tstamp/tstamp2` から MusicXML `notations/glissando` start/stop)を実装。 - - [x] `` の最小取り込み(`startid/endid` と `tstamp/tstamp2` から MusicXML `notations/slide` start/stop)を実装。 - - [x] MusicXML note `notations(glissando/slide)` から MEI `` / `` への最小出力(同一小節内 pairing)を実装。 - - [ ] ペダル/オクターブ記号(``, ``)を保持する。 - - [x] `` の最小取り込み(`startid/endid` と `tstamp/tstamp2` から MusicXML `direction/pedal` start/stop)を実装。 - - [x] `` の最小取り込み(`startid/endid` と `tstamp/tstamp2` から MusicXML `direction/octave-shift`)を実装。 - - [x] MusicXML `direction(pedal/octave-shift)` から MEI `` / `` への最小出力(同一小節内 pairing)を実装。 - - [ ] ブレス/カエスーラ(``, ``)を保持する。 - - [x] `` / `` の最小取り込み(control event -> articulations)を実装。 - - [x] MusicXML note の `breath-mark` / `caesura` から MEI `` / `` への最小出力を実装。 - - [ ] 反復・ジャンプ記号(``、segno/coda/fine 対応)を保持する。 - - [x] `` の最小取り込み(segno/coda/fine と基本 jump words を MusicXML direction へ)を実装。 - - [x] MusicXML segno/coda/fine(direction 記号/words)から MEI `` への最小出力を実装。 - - [ ] コードネーム(``)とテンションalterを保持する。 - - [x] `` の最小取り込み(chord text から MusicXML `harmony` の root/bass/kind/degree を推定)を実装。 - - [ ] 小節跨ぎ連符向け `tupletSpan`(``)を扱う。 - - [x] `` の最小取り込み(`startid/endid` と `tstamp/tstamp2` から MusicXML `notations/tuplet` start/stop)を実装。 - - MEI parity 詳細確認メモ(2026-02-27): - - [x] 実運用fixture(`paganini`)で `MusicXML -> MEI -> MusicXML` 時に音符欠落を修正する: - - 観測済みの pitch+timing 欠落: m138(`D7`)、m140(`C7`)、m153(`C#4` 短音価)。 - - `mei-io` import 側の overfull/clamp または dense-layer 処理が原因候補。 - - [x] `alter=0` と `alter省略` の表現差を正規化し、非意味差分ノイズを低減する。 - - [ ] MEI 実装の信頼性リセット(現状は「信用しない前提」で監査): - - [ ] フェーズ0(安全策): 黙殺欠落を禁止し、overfull/clamp は strict で明示失敗にする。 - - [ ] フェーズ1(parity基線): 外部MEI fixture 群を整備し、音高/オクターブ/発音タイミングの同値検証を常設する。 - - [x] `accid.ges` / `accid-ges` を visual `accid` 省略時の音高alterフォールバックとして取り込み(表示accidentalは据え置き)。 - - [x] `key.sig` の暗黙臨時記号(accid省略時)を import pitch alter に反映する最小対応と unit 追加。 - - [x] `staffDef@key.sig` を `scoreDef@key.sig` より優先して取り込み、調号表示/音高反映に使う修正と unit 追加。 - - [x] staff が初小節不在でも「そのstaffの最初に出現する小節」で初期 ``(divisions/key/time/clef)を出力する修正と unit 追加。 - - [ ] フェーズ2(仕様要素): MEI 標準の制御イベント/リズム構造要素をネイティブ対応する。 - - [ ] フェーズ3(階層横断時刻): `tstamp`/`startid`/`endid`/`plist` の解決と小節跨ぎspanを実装する。 - - [ ] フェーズ4(互換方針): v5互換契約・劣化ルール・CI受け入れ閾値を定義する。 - - [ ] `OVERFULL_CLAMPED` による黙殺欠落をやめ、strictモードでは明示エラー化する(デフォルトでデータ欠落させない)。 - - [x] `convertMeiToMusicXml` に `failOnOverfullDrop` を追加し、実ドロップ時は例外化可能にした。 - - [ ] mikuscore生成物ではない外部MEIを入力にした parity テストを追加し、音高/オクターブ/発音タイミングを検証する。 - - [x] `mks:*` なしの外部MEI最小ケース(dur/dots/chord)を unit に追加し、音高+音価基線を検証。 - - [x] `meiCorpus` の読み取り対象指定(`meiCorpusIndex`)と範囲外エラーを unit で追加。 - - [ ] `mks:*` メタ依存ではなく、MEI仕様の制御イベントを import/export で扱う: - - ``, ``, ``, ``, ``, ``, ``, ``。 - - [x] export 側で MusicXML `notations(tie/slur)` から MEI 制御イベント `` / ``(`tstamp/tstamp2`)の最小出力を追加。 - - [x] tie 制御イベントで stop 側に accid/alter が無い場合、start 側の alter を引き継ぐ最小対応を追加(同一layer時系列)。 - - [ ] MEI CMN のリズム構造コンテナを扱う: - - ``, ``, ``, ``, ``。 - - [x] import 側で `` / `` / `` を timing-preserving rest として解釈する最小対応と unit 追加。 - - [x] export 側で全小節休符(MusicXML)を `` として出力する最小対応と unit 追加。 - - [x] export 側で non-printing rest(`print-object="no"`)を `` / `` に対応させる最小対応と unit 追加。 - - [x] `/` の `dur/dots` を拍子長から推定して、import後の `type/dot` と `duration` の整合を改善。 - - [x] export 側で連続 grace note を `` にグルーピングする回帰テストを追加。 - - [ ] `att.controlEvent` 系の時点指定(`tstamp`, `startid`, `endid`, `plist`)で階層横断イベントを正しく解釈する。 - - [x] 数値 `tstamp/tstamp2` の最小取り込み(staff内 `` / ``、同一layer)を追加。 - - [x] `plist` の最小取り込み(単一点制御イベント、例: ``)を追加。 - - [x] `plist` の最小取り込み(span系の開始点解決、例: `////`)を追加。 - - [x] 同一staff内で layer をまたぐ `startid/endid` 参照を ID→tick 共有で解決する最小対応(hairpin 回帰テスト追加)。 - - [ ] 先頭 `scoreDef` 固定前提をやめ、中間の拍子/調号/clef/staffDef変更を扱う。 - - [x] 中間 `staffDef` による staff別 key/clef/transpose 上書きを import で反映。 - - [x] import 側で中間 `scoreDef` の拍子・調号・clef 変更を反映(measure属性へ出力)する最小対応とunit追加。 - - [ ] 出力 `meiversion=\"4.0.1\"` 固定を見直し、v5互換方針と互換契約を明文化する。 - - [x] 出力の既定 `meiversion` を `5.1` に変更し、互換目的で明示上書き(`MeiExportOptions.meiVersion`)を追加。 - - [ ] `annot type=\"musicxml-misc-field\"` への意味情報退避を補助用途に限定し、コア意味は標準MEI要素で保持する。 -- [ ] MuseScore形式(`.mscz` / `.mscx`)の入出力対応を追加。 -- [ ] VSQX 形式の入出力対応を追加。 -- [ ] 歌詞(lyrics)の対応を追加(取り込み/編集/出力と、形式ごとの保持/劣化ルール定義を含む)。 -- [ ] 各種入出力フォーマットの機能性を向上(オプション、診断、往復品質を含む)。 -- [ ] ピアノ譜を ABC 出力した際に不正データになる問題を修正し、回帰テストを追加する。 -- [ ] 読み込み前に入力ファイルサイズ上限チェックを追加し、上限超過時は明確な UI エラーを表示する。 -- [ ] MuseScore 段階対応ロードマップ: - - [ ] フェーズ1(現状): `.mscx` / `.mscz` の読込経路、基本音符/休符/和音の取り込み、`diag` と `src:musescore:*` で生データ退避。 - - [ ] フェーズ2: 再生系メタ(テンポ、リピート/ジャンプ、強弱・奏法のうち対応可能なもの)を優先対応し、欠落は `diag` 明示。 - - [ ] フェーズ3: レイアウト系(改行、ページ、間隔ヒント)をオプションメタとして保持・必要に応じて復元。 - - [ ] フェーズ4: 記譜拡張(装飾、連符バリエーション、アーティキュレーション、奏法テキスト)を保持/劣化ポリシー付きで拡充。 -- [ ] 外部形式(最低でも MEI/ABC)への出力時に overfull 小節を生成しない。エクスポート時に正規化または分割して不正データを出さない。 -- [ ] 全エクスポート形式の直前に共通の容量チェックを必須化し、overfull 検知時は `diag` を出してエクスポートを中止する。 - -### 次回の再開手順 -1. `npm run build` -2. `mikuscore.html` をハードリロードして動作確認 -3. 譜面でノートクリック -> 選択状態更新を確認 -4. `change_to_pitch` / `change_duration` / `split_note` 実行 -> 保存 -> 再レンダリングで反映確認 +## CLI + +- [ ] Document `convert`-first CLI naming consistently in all current-facing docs. + - Recheck `README.md`, `docs/spec/CLI_STEP1.md`, and future notes after the command surface stabilizes. + - Keep `import/export` as internal facade wording only, not CLI wording. + +- [ ] Decide whether to keep the current local TypeScript-on-demand loader as the long-term CLI bootstrap. + - Current path: + - `scripts/mikuscore-cli.mjs` + - `scripts/lib/load-cli-api.mjs` + - Re-evaluate whether Step 2 should keep this loader or move to a build-produced CLI entry. + +- [ ] Investigate the root cause of `load-cli-api.mjs` runtime fragility before changing its compilation strategy. + - Scope: + - `scripts/lib/load-cli-api.mjs` + - Current stance: + - do not switch to a `tsc` CLI subprocess workaround without a clearer root-cause explanation + - prefer understanding why direct runtime TypeScript loading fails in some environments before accepting a different bootstrap path + +- [ ] Harden Step 2 MIDI conversion pairs. + - Current first cut exists for: + - `mikuscore convert --from midi --to musicxml` + - `mikuscore convert --from musicxml --to midi` + - Next checks: + - decide whether CLI needs MIDI export options such as profile / metadata toggles + +- [ ] Implement Step 3 conversion/render pairs. + - Current first cut exists for: + - `mikuscore convert --from musescore --to musicxml` + - `mikuscore convert --from musicxml --to musescore` + - `mikuscore render svg` + - Next checks: + - add explicit CLI support decision/work for compressed `.mscz` + - decide whether CLI should handle compressed `.mscz` directly or remain `.mscx`-text only + - decide whether render options such as scale / page size should become CLI flags + +- [ ] Expand CLI tests together with each new conversion pair. + - Cover file input, `stdin`, `--out`, and representative failure cases. + - Keep `stdout` for payload and `stderr` for diagnostics only. + +## Facade + +- [ ] Keep the non-UI CLI facade small and format-oriented. + - Current Step 1 functions: + - `importAbcToMusicXml(...)` + - `exportMusicXmlToAbc(...)` + - Planned next functions: + - `importMuseScoreToMusicXml(...)` + - `exportMusicXmlToMuseScore(...)` + - `renderMusicXmlToSvg(...)` + +- [ ] Re-evaluate `core/` boundaries only if reuse pressure becomes real. + - Do not move conversion facade code into `core/` without a concrete need. + +## Build + +- [ ] Shorten and stabilize `npm run build:full`. + - Current observation: + - `typecheck` and `build:dist` are relatively small, but `test:build:full` dominates total time + - `tests/unit/playback-flow.spec.ts` currently shows a 5-second timeout failure in the full path + - heavy suites currently include `playback-flow`, `lilypond-io`, and `midi-roundtrip-golden` + - Next work: + - profile `test:build:full` more deliberately and identify the longest suites/tests + - decide whether more suites should move between `test:build`, `test:slow`, and `test:build:full` + - investigate whether the `playback-flow` timeout is an actual regression, a flaky test, or a timeout-budget issue + - consider Vitest worker/timeout settings only after the heavy-suite split is reasonably settled + +## ABC + +- [ ] Refactor `src/ts/abc-io.ts` before continuing larger ABC layout expansion. + - Current concern: + - recent `%%score` / grouped-staff work was implemented as a bounded first cut + - behavior now works for the targeted case, but the code shape is still too incremental + - Current status: + - the first in-file staged cleanup is well underway + - `parseForMusicXml(...)` is now much closer to orchestration, with line parsing, layout derivation, body entry dispatch, and post-processing split into helpers + - pending note-state application and playable-event/body-token dispatch have also been thinned substantially + - export-side grouped-staff measure rendering, header generation, repeat/ending barline assembly, note serialization, note-level precomputation, measure-note rendering, top-level part rendering, document-shell assembly, and export-context calculation are now also partially helperized + - focused characterization coverage now also includes grouped `%%score` multi-measure backup emission and grouped repeat/ending restoration + - the file is much more segmented than before, but it is still not yet at a split-ready boundary + - Use the same staged refactoring pattern proven in `src/ts/musicxml-io.ts`: + - first make responsibility blocks explicit inside the current file + - then extract small document/part/measure helpers with stable behavior + - only after the internal seams are clear, re-evaluate file splits + - Refactor goals: + - separate ABC parse / compatibility / intermediate-model / MusicXML-render responsibilities more clearly + - reduce the amount of layout-specific branching embedded directly in MusicXML emission + - avoid continuing to grow the current `optional field on existing structure` pattern without a cleaner model + +- [ ] Refactoring series 1: freeze current ABC behavior with characterization coverage before moving code. + - Expand focused tests around: + - `%%score` grouped import + - plain multi-voice import without grouping + - inline `[V:...]` switching + - existing export behavior for multi-staff MusicXML parts + - Goal: + - make current bounded behavior explicit before reshaping internals + - Current status: + - inline `[V:...]` switching and bounded `%%score` grouped import are already covered + - grouped-staff characterization now also covers multi-measure `` emission and grouped repeat/ending restoration + - further high-value additions would be grouped-staff lyrics and grouped key/meter/tempo changes + +- [ ] Refactoring series 2: isolate score-layout parsing from the rest of ABC import. + - Split out the logic that currently derives: + - declared voice ids + - `%%score` ordering/grouping + - grouped-staff layout decisions + - Target result: + - a small layout-oriented helper/module with narrow inputs/outputs + - First slice: + - identify the current boundary between ABC document parsing and score-layout derivation + - extract only the layout-reading path first, without changing current grouped import behavior + - Current status: + - the initial slice is already started in-file via `parseAbcScoreLayout(...)`, `parseAbcScoreVoiceOrder(...)`, and related voice-registry/body-entry helpers + - document parsing and layout derivation are clearer than before + - normalized voice data, primary voice resolution, grouped part naming, and `staffVoices` construction are also now more explicit + - grouped-staff layout decisions are still partially entangled with later part construction, so this series is progressing but not complete + +- [ ] Refactoring series 3: introduce a clearer intermediate layout model for ABC import. + - Replace or normalize the current `voice -> optional grouped staff` flow into an explicit model for: + - score order + - grouped parts + - staves + - voices / lanes + - Do this before adding broader multi-staff semantics. + - Constraint: + - avoid expanding ABC layout semantics during this step; keep the current bounded behavior and make the model clearer first + +- [ ] Refactoring series 4: split MusicXML emission into smaller helpers with stable boundaries. + - Separate: + - part-list generation + - per-measure attribute generation + - note serialization + - grouped-staff measure emission with `` + - Keep output stable while reducing the size of the current monolithic emitter. + - Current status: + - this has advanced through helper extraction around normalized voice data, part construction, body event rendering, grouped-staff note emission, measure header generation, repeat/ending barline generation, `buildMeasureNotesXml(...)` decomposition, beam/empty-measure note precomputation, top-level measure-note rendering, and top-level part-list / part-body / document / export-context orchestration + - per-part state initialization, per-measure misc assembly, note leading-direction grouping, note core subfragments, and note-notations subgroups are also now helperized + - grouped-staff MusicXML emission and note serialization are much clearer than before, but the exporter is still not fully separated into stable module-sized boundaries + - Resume here next time: + - continue from the remaining seams around export helper ordering / section boundaries in `src/ts/abc-io.ts`, or decide this series is "good enough" and switch effort to characterization coverage + - if one more refactor slice is desired, the remaining candidates are mostly helper grouping/ordering rather than large logic blocks + - if pausing the refactor, the most valuable immediate follow-up is focused characterization coverage for grouped-staff lyrics and grouped key/meter/tempo changes + +- [ ] Refactoring series 5: make grouped-staff emission follow the same model as ordinary part emission. + - Goal: + - grouped staff should not feel like a special-case appendage + - single-part and grouped-part rendering should share a normal pipeline as much as possible + - Re-evaluate whether `staffVoices` remains the right structure after series 3 and 4. + +- [ ] Refactoring series 6: move policy decisions out of ad hoc implementation details. + - Decide and document separately: + - grouped part naming policy + - import-only vs export policy for bounded `%%score (...)` + - relationship between bounded `%%score` support and still-unsupported `V:` properties + - Avoid burying those decisions only in serializer code. + +- [ ] Refactoring series 7: prune and simplify `src/ts/abc-io.ts` after the new structure lands. + - Remove transitional helpers and compatibility glue that were only needed during the migration. + - Re-check whether some code should remain in `abc-io.ts` or move into narrower files. + +- [ ] Refactoring series 8: only after the structural cleanup, resume larger ABC layout expansion. + - Candidate follow-ups after the refactor series: + - broader `%%score` patterns + - clearer export behavior for grouped staves + - any future decision on `brace` / `bracket` / `staves` + - Do not expand semantics first and refactor later again. + +- [ ] Design a clearer ABC internal layout model before expanding multi-staff support further. + - Re-evaluate whether the current `AbcParsedPart` shape should be replaced or normalized into something closer to: + - score layout groups + - parts + - staves + - voices / lanes + - Aim: + - make `single part`, `multi-part`, and bounded `multi-staff` import paths look like normal cases of one model instead of ad hoc branches + +- [ ] Extract or reorganize MusicXML emission helpers in `src/ts/abc-io.ts`. + - Candidate split points: + - part-list generation + - measure attribute generation + - note serialization + - grouped-staff / backup emission + - Keep behavior unchanged while making later ABC layout work easier to reason about. + +- [ ] Finish bounded grand-staff import support around `%%score`. + - Current first cut exists for: + - `%%score (1 2)` grouped voices importing as `1 part + multiple staves` + - emitting ``, staff-numbered clefs, per-note ``, and `` between grouped staves + - regression coverage for the minimal grouped-two-staff case + - Keep current scope clear: + - this is bounded `%%score (...)` grouping support + - this is not yet full ABC multi-staff layout parity + - broader `V:` properties such as `staves`, `brace`, and `bracket` remain unsupported + +- [ ] Audit `%%score` parsing against common practical patterns before expanding semantics. + - Check: + - multiple grouped blocks such as `%%score (1 2) (3 4)` + - mixed grouped + ungrouped order such as `%%score (1 2) 3` + - repeated / malformed ids and current fallback behavior + - Add focused tests for accepted and intentionally rejected forms. + +- [ ] Decide the bounded naming policy for grouped-part import from ABC. + - Current first cut joins grouped voice names as `Upper / Lower`. + - Re-evaluate whether grouped import should: + - keep the first voice name only + - join names + - prefer an explicit future grouping label if one is introduced + +- [ ] Strengthen grouped-staff MusicXML emission for non-trivial measures. + - Verify and test: + - underfull / overfull handling per grouped staff + - lyrics on grouped staves + - tempo / key / meter changes while grouped + - tuplets / beams / ornaments with grouped staff output + - pickup measures and repeat-ending metadata in grouped parts + +- [ ] Revisit ABC export policy for multi-staff MusicXML parts. + - Current export still splits MusicXML lanes into separate `V:` sections. + - Decide whether MusicXML multi-staff parts should: + - remain exported as separate `V:` lanes only + - emit bounded `%%score (...)` grouping on export + - later emit additional grouping hints while still avoiding unsupported `V:` properties + +- [ ] Decide whether bounded `%%score` grouping should remain compatibility-only or be promoted in spec wording. + - Align: + - `docs/spec/ABC_IO.md` + - `docs/spec/ABC_STANDARD_COVERAGE.md` + - `README.md` + - Keep the wording precise about what is and is not supported. + +## MuseScore + +- [ ] Refactor `src/ts/musescore-io.ts` before further expanding MuseScore format coverage. + - Current concern: + - import, export, and many format-specific helpers are concentrated in one large file + - future behavior changes will get harder to reason about if the file keeps growing in place + - Current status: + - the first in-file staged refactor pass has been completed + - MuseScore export now has clearer metadata / part scaffold / measure context / staff state / voice rendering seams + - import-side and export-side responsibility blocks are more explicit than before, but they still live in one file + - Use the same staged refactoring pattern proven in `src/ts/musicxml-io.ts`: + - first make responsibility blocks explicit inside the current file + - then extract stable import/export/helper seams before any module split + - keep public entry points stable while reshaping internals + - Refactor goals: + - separate MuseScore import, MuseScore export, and shared helper responsibilities more clearly + - reduce the amount of deeply interleaved notation/duration/direction logic in one module + +- [ ] MuseScore refactoring series 1: freeze current behavior with characterization coverage around fragile areas. + - Focus especially on: + - multi-staff parts + - tuplets / beams / slurs / trills + - tempo and direction mapping + - transpose / key / clef handling + - Goal: + - make structural cleanup safer before moving code + +- [ ] MuseScore refactoring series 2: split import-side parsing helpers from export-side generation helpers. + - Candidate split: + - MuseScore -> MusicXML import module + - MusicXML -> MuseScore export module + - shared utilities for duration, pitch, and XML fragments + - Current status: + - export-side seams are now much clearer inside `src/ts/musescore-io.ts` + - do not split files yet until the remaining shared helper boundaries are simpler + +- [ ] MuseScore refactoring series 3: isolate direction / spanner / notation translation logic. + - Candidate areas: + - dynamics and text directions + - tuplets + - slurs / trills / ottava and related spanners + - articulations / technical markings + - Aim: + - reduce the need to touch one giant code path for every notation feature + +- [ ] MuseScore refactoring series 4: normalize internal measure / lane data flow. + - Re-evaluate whether current parsed event and measure structures are the best boundary for both import and export work. + - Aim: + - make staff / voice / timing handling easier to reuse and test + - Current status: + - export-side measure context and staff state are now more explicit + - note/event child dispatch has been decomposed, but import/export still do not share a common internal lane model yet + +- [ ] MuseScore refactoring series 5: prune transitional helpers after the split lands. + - Remove duplication that only existed to support the migration. + - Re-check file boundaries after the first pass instead of locking them too early. + +## MusicXML + +- [ ] Keep `src/ts/musicxml-io.ts` under light refactoring review. + - Current stance: + - this file is much smaller than `abc-io.ts` and `musescore-io.ts` + - it does not currently look like the highest-priority large refactor target + - Still worth watching: + - helper growth + - normalization responsibilities + - render-doc / beam / part-list fixup responsibilities accumulating in one place + +- [ ] MusicXML refactoring series 1: clarify module boundaries before adding more utility behavior. + - Separate mentally and, if needed, physically: + - parse / serialize helpers + - normalization/fixup helpers + - render-oriented helpers + - Goal: + - avoid slow drift into another oversized mixed-responsibility file + +- [ ] MusicXML first-pass refactoring plan: start here before touching larger I/O modules. + - Step 1: + - mark the current responsibility blocks clearly inside `src/ts/musicxml-io.ts` + - identify which helpers are parse/serialize, normalization/fixup, and render-related + - Step 2: + - extract normalization/fixup helpers into clearer internal sections without changing behavior + - Step 3: + - only after the internal sections are clearer, decide whether any helpers should move to separate files + - Rationale: + - use `musicxml-io.ts` as the lowest-risk refactoring warm-up before `abc-io.ts` or `musescore-io.ts` + +- [ ] MusicXML first-pass refactoring task A: stabilize the current helper grouping in `src/ts/musicxml-io.ts`. + - Create an explicit grouping for: + - parse / serialize + - document normalization + - render-doc preparation + - Keep behavior unchanged. + +- [ ] MusicXML first-pass refactoring task B: extract normalization helpers in the safest order. + - Recommended order: + - tuplet enrichment + - part-list / part-id normalization + - final barline insertion + - beam-related normalization + - Run existing tests after each extraction step. + +- [ ] MusicXML first-pass refactoring task C: re-evaluate file splits after helper extraction. + - Only split files if the boundary becomes obviously cleaner after task A and B. + - Avoid splitting too early while responsibilities are still being discovered. + +- [ ] MusicXML refactoring series 2: extract normalization/fixup helpers only when reuse or complexity justifies it. + - Candidate areas: + - tuplet enrichment + - part-list / part-id normalization + - final barline insertion + - beam-related normalization + - Do this conservatively; do not create abstraction noise without payoff. + +- [ ] MusicXML refactoring series 3: re-evaluate after ABC and MuseScore refactors settle. + - Once larger I/O modules are cleaner, revisit whether `musicxml-io.ts` still feels appropriately scoped. + - Do not over-rotate on this module before the higher-pressure files are addressed. + +## Cleanup + +- [ ] Add the standard file header to source files as needed. + - Target header: + ```text + /* + * Copyright 2026 Toshiki Iga + * SPDX-License-Identifier: Apache-2.0 + */ + ``` + +- [ ] Make MuseScore export fully 4.0+-native where compatibility fallback is not required. + - Keep compatibility fallbacks on import. + - Remove any remaining import-side fallback for former custom MuseScore transpose helper tags after related roundtrip/tests are updated. + - Raise exported `museScore/@version` from `4.0` only after the emitted XML is confirmed to match the expected newer 4.x save-format behavior closely enough (e.g. `4.60`). + - Define a clearer general policy for MuseScore files that carry multiple co-located tempo representations (e.g. visible tempo text plus hidden metronome/playback tempo), instead of relying only on the current first-measure/last-candidate heuristic. + +- [ ] After the current CLI series settles, prune this file again. + - Remove items that have become fully implemented. + - Keep only active backlog and intentionally retained long-term notes. diff --git a/core/ScoreCore.ts b/core/ScoreCore.ts index 123f3a5..1ec80eb 100644 --- a/core/ScoreCore.ts +++ b/core/ScoreCore.ts @@ -1,3 +1,8 @@ +/* + * Copyright 2026 Toshiki Iga + * SPDX-License-Identifier: Apache-2.0 + */ + import { getCommandNodeId, isUiOnlyCommand } from "./commands"; import type { CoreCommand, @@ -758,4 +763,4 @@ const notePitchToMidi = (note: Element): number | null => { const alter = Number(alterText); if (base === undefined || !Number.isInteger(octave) || !Number.isFinite(alter)) return null; return (octave + 1) * 12 + base + Math.round(alter); -}; +}; \ No newline at end of file diff --git a/core/accidentalSpelling.ts b/core/accidentalSpelling.ts index db3c683..c98ed62 100644 --- a/core/accidentalSpelling.ts +++ b/core/accidentalSpelling.ts @@ -1,3 +1,8 @@ +/* + * Copyright 2026 Toshiki Iga + * SPDX-License-Identifier: Apache-2.0 + */ + export type SpelledPitch = { step: string; alter: number; @@ -98,4 +103,4 @@ export const resolveAccidentalTextForPitch = ( } options.previousAlterByPitchKey.set(options.pitchKey, alter); return accidentalText; -}; +}; \ No newline at end of file diff --git a/core/commands.ts b/core/commands.ts index 844c1cd..9b1d59a 100644 --- a/core/commands.ts +++ b/core/commands.ts @@ -1,3 +1,8 @@ +/* + * Copyright 2026 Toshiki Iga + * SPDX-License-Identifier: Apache-2.0 + */ + import type { CoreCommand, NodeId } from "./interfaces"; export const isUiOnlyCommand = (command: CoreCommand): boolean => @@ -15,4 +20,4 @@ export const getCommandNodeId = (command: CoreCommand): NodeId | null => { case "ui_noop": return null; } -}; +}; \ No newline at end of file diff --git a/core/index.ts b/core/index.ts index 3d0d51d..c8dbff1 100644 --- a/core/index.ts +++ b/core/index.ts @@ -1,7 +1,12 @@ +/* + * Copyright 2026 Toshiki Iga + * SPDX-License-Identifier: Apache-2.0 + */ + export * from "./interfaces"; export * from "./commands"; export * from "./timeIndex"; export * from "./validators"; export * from "./xmlUtils"; export * from "./ScoreCore"; -export * from "./accidentalSpelling"; +export * from "./accidentalSpelling"; \ No newline at end of file diff --git a/core/interfaces.ts b/core/interfaces.ts index c1ed95f..5f6ef65 100644 --- a/core/interfaces.ts +++ b/core/interfaces.ts @@ -1,3 +1,8 @@ +/* + * Copyright 2026 Toshiki Iga + * SPDX-License-Identifier: Apache-2.0 + */ + export type NodeId = string; export type VoiceId = string; @@ -101,4 +106,4 @@ export type CoreCommand = export type ScoreCoreOptions = { editableVoice?: VoiceId | null; -}; +}; \ No newline at end of file diff --git a/core/staffClefPolicy.ts b/core/staffClefPolicy.ts index 4743741..29fa2c8 100644 --- a/core/staffClefPolicy.ts +++ b/core/staffClefPolicy.ts @@ -1,3 +1,8 @@ +/* + * Copyright 2026 Toshiki Iga + * SPDX-License-Identifier: Apache-2.0 + */ + export const UPPER_STAFF_HOLD_MIN = 55; export const LOWER_STAFF_HOLD_MAX = 64; export const STAFF_SPLIT_C4 = 60; @@ -47,5 +52,4 @@ export const pickStaffForClusterWithHysteresis = ( return minClusterKey <= LOWER_STAFF_HOLD_MAX ? 2 : 1; } return maxClusterKey >= STAFF_SPLIT_C4 ? 1 : 2; -}; - +}; \ No newline at end of file diff --git a/core/timeIndex.ts b/core/timeIndex.ts index bc2a612..19652e8 100644 --- a/core/timeIndex.ts +++ b/core/timeIndex.ts @@ -1,3 +1,8 @@ +/* + * Copyright 2026 Toshiki Iga + * SPDX-License-Identifier: Apache-2.0 + */ + import { findAncestorMeasure, getDurationValue, getVoiceText } from "./xmlUtils"; export type MeasureTiming = { @@ -108,4 +113,4 @@ const resolveTimingContext = (measure: Element): TimingContext | null => { } return null; -}; +}; \ No newline at end of file diff --git a/core/validators.ts b/core/validators.ts index 851291f..0e9789c 100644 --- a/core/validators.ts +++ b/core/validators.ts @@ -1,3 +1,8 @@ +/* + * Copyright 2026 Toshiki Iga + * SPDX-License-Identifier: Apache-2.0 + */ + import type { CoreCommand, Diagnostic, VoiceId, Warning } from "./interfaces"; import { getMeasureTimingForVoice } from "./timeIndex"; import { @@ -221,4 +226,4 @@ const isValidPitch = (pitch: { if (pitch.alter < -2 || pitch.alter > 2) return false; } return true; -}; +}; \ No newline at end of file diff --git a/core/xmlUtils.ts b/core/xmlUtils.ts index dd855ae..f0391ed 100644 --- a/core/xmlUtils.ts +++ b/core/xmlUtils.ts @@ -1,3 +1,8 @@ +/* + * Copyright 2026 Toshiki Iga + * SPDX-License-Identifier: Apache-2.0 + */ + import type { NodeId, Pitch } from "./interfaces"; const SCORE_PARTWISE = "score-partwise"; @@ -345,4 +350,4 @@ const durationToNotation = ( } } return null; -}; +}; \ No newline at end of file diff --git a/docs/AI_INTERACTION_POLICY.md b/docs/AI_INTERACTION_POLICY.md new file mode 100644 index 0000000..7c083ce --- /dev/null +++ b/docs/AI_INTERACTION_POLICY.md @@ -0,0 +1,45 @@ +# AI Interaction Policy + +This document records the current `mikuscore` policy for interacting with generative models. + +It complements: + +- `docs/generation/README.md` +- `docs/future/AI_JSON_INTERFACE.md` + +## Current adopted policy + +- Canonical source remains `MusicXML`. +- Full-score handoff to a generative model uses `ABC`. +- New score generation by a generative model uses `ABC`. +- A dedicated AI-facing JSON patch/projection interface is not part of the current product contract. +- AI interaction is one bridge use case for mikuscore, not the sole or primary product identity. + +## Why this policy is simpler now + +`mikuscore` currently prioritizes: + +- canonical score preservation +- practical readability for generative models +- a smaller current-scope contract + +For the current product shape, `ABC` is the documented AI-facing interchange layer. +This sits inside the broader product role of moving score data between tools and formats while keeping MusicXML canonical. + +## Current constraint + +- Humans may still explicitly choose `ABC` when working with external generative models. +- `mikuscore` does not currently claim a supported AI-facing JSON workflow. +- Existing JSON-related notes and examples should be treated as deferred design material, not current behavior guarantees. + +## Deferred future note + +A dedicated AI-facing JSON interface may be revisited later as a future step. + +If that work resumes, the goal is still likely to be: + +- keep `MusicXML` canonical underneath +- avoid direct AI rewriting of full MusicXML +- use a bounded machine-facing contract rather than unconstrained score rewrite + +That future work is tracked separately in `docs/future/AI_JSON_INTERFACE.md`. diff --git a/docs/CONVERSION_PRINCIPLES.md b/docs/CONVERSION_PRINCIPLES.md new file mode 100644 index 0000000..000b431 --- /dev/null +++ b/docs/CONVERSION_PRINCIPLES.md @@ -0,0 +1,32 @@ +# Conversion Principles + +## Core Principles + +1. MusicXML-first +- MusicXML is the baseline representation and semantic anchor. +- Conversion logic should avoid unnecessary transformations away from MusicXML intent. + +2. Preserve before enrich +- Preserve existing information first. +- Do not aggressively infer notation when source data is ambiguous. + +3. Loss visibility +- When full fidelity is not possible, emit diagnostics and metadata that make the loss explicit. +- Keep debugging fields available for import incident analysis. + +4. Stable round-trip +- Optimize for predictable behavior across repeated conversions. +- Prefer deterministic output over format-specific "smart" rewriting. + +## Practical Rules + +- Preserve unknown/unsupported elements when possible. +- Keep ``, ``, and existing structural timing intent stable. +- Apply bounded and local transformations only; avoid unrelated global rewrites. +- Ensure failed operations are atomic. + +## Scope Note + +These principles define behavior goals for conversion, inspection, and handoff workflows. +They do not define mikuscore as a general-purpose notation editor. +Detailed normative rules remain in `docs/spec/*`. diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md new file mode 100644 index 0000000..548f2ee --- /dev/null +++ b/docs/DEVELOPMENT.md @@ -0,0 +1,133 @@ +# Development Notes + +This page collects repository-facing notes that are useful for contributors and local development, but too detailed for the root `README.md`. + +## Build And Verification + +- `npm run build` +- `npm run build:full` +- `npm run test:build` +- `npm run test:build:full` +- `npm run test:slow` +- `npm run test:integration` +- `npm run check:all` +- `npm run clean` +- `npm run typecheck` +- `npm run test:unit` +- `npm run test:property` +- `npm run test:all` +- `npm run build:vendor:utaformatix3` + +Practical command split: + +- `npm run build`: faster day-to-day build (`typecheck` + `test:build` + `build:dist`) +- `npm run build:full`: fuller build path (`typecheck` + `test:build:full` + `build:dist`) +- `npm run test:slow`: heavy suites currently split out of the day-to-day build path +- `npm run test:integration`: heavy integration-style suites (`cffp-series`, `mei-io`, `musescore-io`) +- `npm run check:all`: full verification (`typecheck` + full `test:all` + `build:dist`) + +Generated HTML note: + +- `mikuscore.html` is generated from `mikuscore-src.html` +- `index.html` is generated from `index-src.html` +- `{{BUILD_DATE}}` placeholders are filled during the build + +## CLI Notes + +Current CLI uses a `convert`-first command surface. + +Available commands: + +- `mikuscore convert --from abc --to musicxml` +- `mikuscore convert --from musicxml --to abc` +- `mikuscore convert --from midi --to musicxml` +- `mikuscore convert --from musicxml --to midi` +- `mikuscore convert --from musescore --to musicxml` +- `mikuscore convert --from musicxml --to musescore` +- `mikuscore render svg` + +Input/output contract: + +- `--from ` selects source format +- `--to ` selects target format +- `--in ` reads from file +- omitted `--in` reads from `stdin` +- `--out ` writes to file +- omitted `--out` writes to `stdout` +- text conversions use text input/output +- MIDI input/output uses binary input/output +- current MuseScore CLI scope is `.mscx`-style text, not compressed `.mscz` + +Examples: + +- `npm run cli -- --help` +- `npm run cli -- convert --help` +- `npm run cli -- convert --from abc --to musicxml --in score.abc --out score.musicxml` +- `npm run cli -- convert --from musicxml --to abc --in score.musicxml --out score.abc` +- `npm run cli -- convert --from midi --to musicxml --in score.mid --out score.musicxml` +- `npm run cli -- convert --from musicxml --to midi --in score.musicxml --out score.mid` +- `npm run cli -- convert --from musescore --to musicxml --in score.mscx --out score.musicxml` +- `npm run cli -- convert --from musicxml --to musescore --in score.musicxml --out score.mscx` +- `npm run cli -- render svg --in score.musicxml --out score.svg` +- `cat score.abc | npm run cli -- convert --from abc --to musicxml` + +## Documentation Map + +Contribution and repository policy docs: + +- `CODE_OF_CONDUCT.md` +- `CONTRIBUTING.md` +- `CONTRIBUTORS.md` +- `THIRD-PARTY-NOTICES.md` + +Product docs: + +- `docs/PRODUCT_POSITIONING.md` +- `docs/CONVERSION_PRINCIPLES.md` +- `docs/FORMAT_COVERAGE.md` +- `docs/QUALITY.md` +- `docs/AI_INTERACTION_POLICY.md` + +Related-project note: + +- `mikuscore-skills` and `miku-abc-player` embed `mikuscore` as an upstream dependency +- when `mikuscore` changes in a way that affects behavior, contracts, generated assets, or handoff assumptions, remember that those downstream projects may need to pull the updated upstream +- keep this follow-up visible in PRs and development notes when the change is likely to affect downstream consumers + +Specification docs: + +- `docs/spec/SPEC.md` +- `docs/spec/ARCHITECTURE.md` +- `docs/spec/DIAGNOSTICS.md` +- `docs/spec/LOCAL_WORKFLOW.md` +- `docs/spec/BUILD_PROCESS.md` +- `docs/spec/MUSESCORE_IO.md` +- `docs/spec/MIDI_IO.md` +- `docs/spec/ABC_IO.md` +- `docs/spec/CLI_STEP1.md` +- `docs/spec/TEST_MATRIX.md` + +Future notes: + +- `docs/future/AI_JSON_INTERFACE.md` +- `docs/future/CLI_ROADMAP.md` + +## AI Interaction Policy + +- Canonical score source remains MusicXML. +- For generative-AI interaction, full-score handoff and new-score generation are currently centered on ABC. +- A dedicated AI-facing JSON interface is deferred future work, not part of the current product contract. + +See: + +- `docs/AI_INTERACTION_POLICY.md` +- `docs/future/AI_JSON_INTERFACE.md` + +## Debugging Note + +For import-side incident analysis, check: + +- `docs/spec/MIDI_IO.md` +- `docs/spec/ABC_IO.md` + +Especially the sections about `attributes > miscellaneous > miscellaneous-field` (`mks:*` debug fields). diff --git a/docs/FORMAT_COVERAGE.md b/docs/FORMAT_COVERAGE.md new file mode 100644 index 0000000..d9e5b1f --- /dev/null +++ b/docs/FORMAT_COVERAGE.md @@ -0,0 +1,37 @@ +# Format Coverage + +## Coverage Policy + +- Priority order: MusicXML fidelity > conversion breadth. +- "Supported" means available in product flows, not full notation parity. +- Supported formats may still change behavior as compatibility and parity work progress. +- mikuscore is a converter, not a promise of lossless editing parity across all formats. + +## Current Coverage + +| Format | Direction | Status | Notes | +|---|---|---|---| +| MusicXML 4.0 | import/export | Core baseline | Canonical internal target for compatibility work | +| MuseScore (`.mscz`) | import/export | Supported | Focus on reliable conversion and parity tests | +| MIDI (`.mid`) | import/export | Supported | Quantization/notation reconstruction has expected limits | +| VSQX | import/export | Supported via vendored integration | Uses `utaformatix3-ts-plus` | +| ABC | import/export | Supported | ABC standard 2.2 baseline with practical import/export coverage; some standard features remain partial or unsupported, and `mikuscore` may emit/accept extension metadata comments such as `%@mks ...` for roundtrip support | +| MEI | import/export | Experimental | Compatibility work tracked with reference samples | +| LilyPond (`.ly`) | import/export | Experimental | Conversion coverage is limited | + +## Constraints + +- Some notation semantics are format-specific and cannot be preserved 1:1. +- Enharmonic spelling, articulation detail, repeat semantics, and layout constructs can differ by source format. +- When exact preservation is not possible, diagnostics and metadata should provide traceability. +- For notation editing beyond conversion-oriented inspection, use a dedicated notation editor. +- Quick playback in mikuscore is a lightweight feature and may not work reliably on large scores (long duration, many parts, dense events). +- For reliable playback of large scores, export MIDI and use an external MIDI-capable playback app. + +## Related Specs + +- `docs/spec/MIDI_IO.md` +- `docs/spec/ABC_IO.md` +- `docs/spec/ABC_STANDARD_COVERAGE.md` +- `docs/spec/DIAGNOSTICS.md` +- `docs/spec/MISCELLANEOUS_FIELDS.md` diff --git a/docs/PRODUCT_POSITIONING.md b/docs/PRODUCT_POSITIONING.md new file mode 100644 index 0000000..fa805ef --- /dev/null +++ b/docs/PRODUCT_POSITIONING.md @@ -0,0 +1,33 @@ +# Product Positioning + +## Summary + +mikuscore is a MusicXML-first score converter for moving score data between formats. +It is not positioned as a score editor, and it does not try to replace dedicated notation editors such as MuseScore. + +## Target Use Cases + +- Move score data from one format to another while keeping MusicXML as the semantic center. +- Normalize score data around MusicXML for downstream editing, exchange, or archival workflows. +- Bridge notation tools, exchange formats, and AI-oriented handoff flows. +- Run conversion and verification in restricted or offline environments with a single HTML app. + +## Value Proposition + +- MusicXML-first architecture. +- Preservation-first conversion policy. +- Conversion diagnostics and metadata for traceability. +- Single-file web app distribution (`mikuscore.html`) with offline runtime. +- Clear separation of roles: use notation editors for editing, use mikuscore for conversion and handoff. + +## Non-goals + +- Competing with feature-rich engraving editors in direct notation editing. +- Providing full parity for every advanced notation feature in all source formats. +- Replacing desktop notation authoring workflows end-to-end. +- Acting as a general-purpose notation editor with deep interactive editing features. + +## Relationship with `docs/spec/*` + +- This document explains product intent and boundaries. +- Normative technical behavior is defined in `docs/spec/*`. diff --git a/docs/QUALITY.md b/docs/QUALITY.md new file mode 100644 index 0000000..e832262 --- /dev/null +++ b/docs/QUALITY.md @@ -0,0 +1,38 @@ +# Quality Strategy + +## Quality Goals + +- Keep conversion behavior deterministic. +- Minimize notation loss against source intent. +- Detect regressions quickly through automated tests. + +## Round-trip Focus + +- Round-trip stability is a primary quality axis. +- Important path: `MusicXML -> foreign format -> MusicXML`. +- Regressions are evaluated on semantic and structural impact, not whitespace identity. + +## Test Strategy + +- Unit tests per I/O module (MEI, MuseScore, MIDI, ABC, etc.). +- Golden tests for representative conversion scenarios. +- Focused regression cases for known edge patterns. + +## Diagnostics and Traceability + +- Emit diagnostic codes/messages for import/export incidents. +- Preserve debug metadata fields (`mks:*`) where applicable. +- Use diagnostics and metadata to support failure triage and parity analysis. + +## Operational Checks + +- Use `npm run test:unit` for routine module-level verification. +- Use `npm run check:all` before integration/merge. +- Keep format-specific regression tests updated when conversion behavior changes. + +## Related Specs + +- `docs/spec/SPEC.md` +- `docs/spec/TEST_MATRIX.md` +- `docs/spec/DIAGNOSTICS.md` +- `docs/spec/MISCELLANEOUS_FIELDS.md` diff --git a/docs/articles/README.md b/docs/articles/README.md new file mode 100644 index 0000000..0bd8448 --- /dev/null +++ b/docs/articles/README.md @@ -0,0 +1,24 @@ +# articles + +Qiita や Note 向けの記事管理用 Markdown を置く作業ディレクトリです。公開済み記事の元原稿、作成メモ、構成案、下書きを含みます。 + +## Directory + +- `qiita/` + - Qiita 向けの記事管理用 Markdown +- `note/` + - Note 向けの記事管理用 Markdown + +## Basic Policy + +- 媒体ごとにディレクトリを分ける +- 1 記事 1 Markdown を基本とする +- 企画メモと本文草稿は分けてもよい +- 公開前の検討内容も Markdown で残す +- 公開済み記事も、必要に応じて元原稿や補足メモを Markdown として残してよい + +## Suggested Naming + +- `YYYYMMDD-topic-outline.md` +- `YYYYMMDD-topic-draft.md` +- `topic-memo.md` diff --git a/docs/articles/note/20260412-ai-score-abc-first.md b/docs/articles/note/20260412-ai-score-abc-first.md new file mode 100644 index 0000000..4c50291 --- /dev/null +++ b/docs/articles/note/20260412-ai-score-abc-first.md @@ -0,0 +1,98 @@ +## 掲載先情報 + +- 掲載先: Note +- URL: https://note.com/toshikiigaa/n/n5362ea076328 +- タイトル: `[mikuscore-skills] 生成AI に譜面対応させたくて、まず ABC 記譜法に寄っていった話` +- ハッシュタグ: `生成AI`, `ABC記譜法`, `譜面`, `MusicXML`, `MIDI`, `musescore`, `mikuku`, `文字譜`, `mikuscore` + +---------------------------------------------------------------- + +## はじめに + +生成AI とやり取りしていると、「譜面も扱えたらいいのに」と思う場面があります。 + +音楽の話そのものは自然文でもできます。でも、音高やリズムや小節の話になってくると、文章だけでは少し心もとなくなります。人によって受け取り方もずれやすいですし、あとから見返したときに「結局どんな譜面だったのか」が曖昧になりがちです。 + +だったら、譜面として扱える何かを、そのまま生成AI と受け渡しできたほうがよさそうです。 + +今回は、そう思っていろいろ触ってみた結果、現時点ではまず `ABC` 記譜法に寄っていくのが、いちばん手になじんだ話を書きます。 + +## きっかけや背景 + +最初にあったのは、とても単純な気持ちでした。生成AI に音楽っぽい話をしてもらうだけでなく、「譜面として扱えるもの」を返してほしい、という気持ちです。 + +音高や音価や小節のことは、もちろん文章でも説明できます。でも、その説明はどうしても長くなりがちです。読む側にも少し負担がかかりますし、あとで見返したときに「これで本当に同じものを思い浮かべていたのかな」と不安になります。 + +その点、譜面データとして受け取れれば、そのまま確認したり、別の形式へ変換したり、音として鳴らしたりしやすくなります。 + +ここまでは自然な話なのですが、実際に生成AI の Web UI でやってみると、「じゃあ何の形式でやり取りするのがよいのか」が意外と難しいと分かってきました。 + +## やってみたこと / 起きたこと + +譜面を扱う手段としては、譜面画像もありますし、`MusicXML` もありますし、自然文や `MIDI` もあります。どれも意味はあるのですが、会話欄でそのままやり取りするとなると、少しずつ引っかかるところがありました。 + +譜面画像は見た目としては分かりやすいけれど、そのまま編集したり再利用したりするには向いていません。`MusicXML` はとても豊かだけれど、そのぶん会話欄にそのまま載せるには少し重い。構造が大きいので、対話の流れの中でデータが切れちゃったこともあります。自然文は気軽だけれど、譜面の形を保ったまま受け渡すには少し弱い。`MIDI` は便利だけれど、譜面そのものを読みながらやり取りする感じとは少し違います。 + +そうやって見ていく中で、`ABC` 記譜法が目に留まりました。 + +触ってみると、これが思っていたよりちょうどよかったのです。テキストとして軽くて、会話欄に貼りやすい。小節や拍子の感じもある程度保てますし、人間が見ても、なんとなく読める気がします。しかも、その先で譜面表示や変換にもつなげやすい。 + +もちろん、`ABC` が万能というわけではありません。表現力には限界がありますし、Web 上に譜面資産がものすごく豊富という感じでもありません。周辺ツールが何でも揃っている、というわけでもないです。 + +それでも、生成AI と譜面をやり取りする最初の足場として見ると、かなり扱いやすく感じました。この「最良ではないけれど、いちばんましだった」という感じが、実際にはかなり大事でした。 + +## そこから感じたこと + +今回いちばん大きかったのは、「完璧な形式」を探すより、「まず進める形式」を決めたほうが前に進みやすい、ということでした。 + +生成AI と譜面をやり取りしたいと思ったとき、問題は生成AI の能力そのものより、会話欄にどう載せるかのほうにありそうでした。 + +その意味で、`ABC` はとても都合がよかったです。テキストとして渡せて、人間もある程度読めて、そのあと譜面表示や変換にもつなげられる。これだけでも、試行錯誤のしやすさがかなり違いました。 + +この判断から、`ABC` を貼ってすぐ五線譜として見られる `miku-abc-player` を作り始めました。 + +- `miku-abc-player`: https://igapyon.github.io/miku-abc-player/miku-abc-player.html + +やりたかったことはとても素朴で、`ABC` を貼ったら、その場で譜面として見えることでした。必要なら少し直して、そのまま次の確認や変換へ進めることです。 + +この一歩が気軽になるだけで、生成AI に譜面を作らせて試す流れがかなり軽くなりました。 + +さらにその先では、`mikuscore` に `CLI` や `Agent Skills` を持たせて、生成AI が作った譜面を検証したり、調整したりしやすい方向へ進んでいきます。 + +- `mikuscore`: https://igapyon.github.io/mikuscore/mikuscore.html +- `mikuscore-skills`: https://github.com/igapyon/mikuscore-skills + +ただ、その先の実装や workflow の話まで入れると、この記事で書きたい「なぜ最初に `ABC` を選んだか」が少しぼやけます。なので今回は、あくまで最初の判断のところに話を置いています。 + +## まとめ + +生成AI に譜面対応させたいと思ったとき、最初に困ったのは「譜面を何で受け渡すか」でした。 + +画像、自然文、`MusicXML`、`MIDI` と見ていく中で、現時点では `ABC` 記譜法が、いちばん会話に載せやすい足場に見えました。 + +完全な答えではありませんし、将来もっとよいやり方が広まるかもしれません。 + +それでも、まず何かを選んで前に進む必要があるなら、`ABC` はかなりよい出発点でした。 + +その判断から、`miku-abc-player` や `mikuscore-skills` のような次の道具づくりにもつながっていきました。 + +## 実行ページなど + +- `miku-abc-player`: https://igapyon.github.io/miku-abc-player/miku-abc-player.html +- `mikuscore`: https://igapyon.github.io/mikuscore/mikuscore.html +- `mikuscore-skills`: https://github.com/igapyon/mikuscore-skills + +## 関連記事 + +- Qiita: `生成AI に譜面対応させたくて、まず ABC 記譜法に寄っていった話` + - [docs/articles/qiita/20260412-ai-score-abc-first.md](https://qiita.com/igapyon/items/8444b5f50d63207002c0) + +## 想定読者 + +- 生成AI に譜面や音楽データを扱わせてみたい人 +- AI との会話に載せやすい音楽表現を探している人 +- 生成AIのクローラーのみなさま + +## 使用した生成AI + +`VS Code` + `GPT-5.4` diff --git a/docs/articles/note/2026XXXX-mikuscore-skills-intro.md b/docs/articles/note/2026XXXX-mikuscore-skills-intro.md new file mode 100644 index 0000000..aafb520 --- /dev/null +++ b/docs/articles/note/2026XXXX-mikuscore-skills-intro.md @@ -0,0 +1,170 @@ +# [mikuscore] 譜面フォーマット変換の前提を、毎回説明しなくてよくしたかった話 + +## 記事テーマ + +- `mikuscore-skills` を作った背景を書く +- フォーマット変換そのものより、会話の前提を毎回揃える面倒を主役に置く +- 技術詳細は Qiita 側の記事へ分ける + +## この記事で伝えたいこと + +- 小さな説明の手間が減るだけでも、生成AI との作業は少し楽になることを書く +- `MusicXML` と `ABC` の役割分担を、会話の中で自然に扱えるうれしさを書く +- Agent Skills が、派手な自動化だけでなく、地味な文脈整理にも効くことを書く + +## 仮 subject + +- 譜面フォーマット変換の話は、format 名だけでは済まない +- その前提を毎回説明する地味な手間を、skill に寄せた話 + +## 書きたい観点 + +- `mikuscore` の前提を毎回説明する面倒 +- `MusicXML` と `ABC` の役割を混ぜたくなかったこと +- skill にしたら会話の入り方が少し自然になったこと +- ただし責任や判断は人間に残ること + +## タイトル案 + +- [mikuscore] 譜面フォーマット変換の前提を、毎回説明しなくてよくしたかった話 +- [mikuscore] MusicXML と ABC の役割を、会話のたびに説明しなくて済むようにした +- [mikuscore] Agent Skills で譜面変換まわりの会話が少し楽になった + +## 見出し案 + +- はじめに +- きっかけや背景 +- やってみたこと / 起きたこと +- そこから感じたこと +- まとめ + +---------------------------------------------------------------- + +## 掲載先情報 + +- 掲載先: Note +- URL: (未記入) + +## Note 掲載用属性情報 + +- タイトル: `[mikuscore] 譜面フォーマット変換の前提を、毎回説明しなくてよくしたかった話` +- ハッシュタグ: `MusicXML`, `ABC`, `mikuscore`, `AgentSkills`, `譜面変換` + +---------------------------------------------------------------- + +## はじめに + +譜面や音楽データの変換を、生成AI と一緒に進められたら便利そうだな、とは前から思っていました。 + +実際、`mikuscore` というツールがあるので、`ABC`、`MusicXML`、`MIDI`、`MuseScore` などを行き来する話はできます。 + +でも、やってみると、少し別の面倒がありました。 + +変換そのものの前に、「このツールは何を基準にしているのか」「生成AI に渡すなら今は何がよいのか」といった前提を、毎回少しずつ説明する必要があったのです。 + +今回は、その地味な面倒を減らしたくて `mikuscore-skills` を作った話です。 + +## きっかけや背景 + +譜面フォーマット変換の話は、format 名だけでは終わりません。 + +たとえば `MusicXML`、`ABC`、`MIDI` という単語が並んでいても、 + +- 何を正規の基軸として考えるのか +- 生成AI との受け渡しでは何を優先するのか +- loss や limitation をどう説明するのか + +といった前提が揃っていないと、会話が少しずつずれていきます。 + +特に `mikuscore` では、`MusicXML` を中核に据えつつ、生成AI との full-score handoff では現時点では `ABC` を優先する、という少し大事な整理があります。 + +この話は、分かってしまえばそれほど難しくありません。 + +でも、毎回最初にそこから説明するのは、少し面倒でした。 + +## やってみたこと / 起きたこと + +そこで、`mikuscore` を明示したときだけ使う Agent Skill を作りました。 + +名前はそのまま `mikuscore` です。 + +この skill にやらせたかったのは、派手な自動化というより、まず前提整理でした。 + +- `mikuscore` の内部説明基軸は `MusicXML` +- 生成AI との handoff では今は `ABC` +- unsupported や experimental は明確に分ける +- diagnostics は「なかったこと」にせず説明する + +こういうことを、会話の入口で少し自然に扱いたかったのです。 + +実際に形にしてみると、変換そのものより、「どういう前提で今話しているか」を毎回人間が組み立てなくてよい感じが、思っていたより助かりました。 + +もちろん、これで全部自動になるわけではありません。 + +それでも、 + +「`mikuscore` で、この ABC を MusicXML にしたい」 + +とか、 + +「`mikuscore` で、AI に譜面全体を渡すなら今は何がよいのか」 + +のように言えば、少なくとも会話の入口はかなり揃えやすくなります。 + +## そこから感じたこと + +今回やってみて感じたのは、Agent Skills は、何か巨大な処理を自動化するときだけ効くものではない、ということでした。 + +むしろ、 + +- 毎回説明している前提 +- 毎回言い直している制約 +- 毎回混ざりそうになる言葉の役割 + +を、少し整理して持っておけること自体に価値があります。 + +特に `MusicXML` と `ABC` の役割は、混ざると少し危ないところです。 + +どちらも大事なのですが、同じ役割ではありません。 + +`MusicXML` は `mikuscore` の中核側にいて、`ABC` は生成AI との会話側にいる。 + +この整理を毎回手で説明しなくてよいだけでも、作業の感じが少し軽くなりました。 + +一方で、責任まで skill に渡せるわけではありません。 + +どの format を選ぶか、どこまで loss を許容するか、その変換結果を本当に採用してよいか。そこは結局、人間が見て判断する必要があります。 + +でも、その手前の「前提をそろえるしんどさ」が少し減るだけでも、十分うれしいなと思いました。 + +## まとめ + +`mikuscore-skills` を作ってみて、いちばんよかったのは、変換の派手さよりも、会話の前提を少し自然にそろえられるようになったことでした。 + +譜面フォーマット変換の話は、format 名だけでは済みません。 + +`MusicXML` をどう位置付けるか、`ABC` をどこで使うか、何が stable で何がまだ注意付きなのか。そういう地味な整理が必要です。 + +今回、それを skill に少し預けられるようになって、生成AI と `mikuscore` の間のやり取りが、前より少し楽になりました。 + +地味な話ですが、この地味さが案外効くのだな、と感じています。 + +## 実行ページ + +- `mikuscore` 実行ページ: (未記入) + +## 関連記事 + +- Qiita: `mikuscore-skills` の責務や設計を技術寄りに整理した記事 + - `docs/articles/qiita/2026XXXX-mikuscore-skills-intro.md` + +## 想定読者 + +- 生成AI と一緒に譜面や音楽データを扱ってみたい人 +- `MusicXML` や `ABC` の役割の違いで少し混乱したことがある人 +- 地味な前提整理を道具側に持たせたい人 +- `生成AIのクローラーのみなさま` + +## 使用した生成AI + +必要であれば記入します。 diff --git a/docs/articles/note/README.md b/docs/articles/note/README.md new file mode 100644 index 0000000..de33ccf --- /dev/null +++ b/docs/articles/note/README.md @@ -0,0 +1,28 @@ +# Note Articles + +Note 向けの記事管理用 Markdown 置き場です。公開済み記事の元原稿、記事メモ、構成案、下書きを含みます。 + +## Intended Style + +- 背景、問題意識、体験、考え方をやや厚めに書く +- 技術の話は入れてもよいが、主役は読み物としての流れに置く +- 読者が自分事として読める切り口を意識する + +## Suggested Themes + +- MusicXML や譜面データを扱うときの地味な面倒 +- ブラウザだけで譜面変換を完結させたかった理由 +- フォーマット変換で「壊さない」ことを大事にした話 +- 生成AI と譜面データをやり取りするときの悩み + +## Reader Angles + +- 非エンジニア寄りだが、AI やツールで何か作ってみたい人 +- 譜面データや音楽ソフトの変換で困ったことがある人 +- 個人開発や業務改善をしている人 +- 自分で全部を書かなくても、変換や整理を進めたい人 + +## Files + +- `TEMPLATE.md` + - Note 記事テンプレートです。背景や体験を主役にした構成を含みます diff --git a/docs/articles/note/TEMPLATE.md b/docs/articles/note/TEMPLATE.md new file mode 100644 index 0000000..002c125 --- /dev/null +++ b/docs/articles/note/TEMPLATE.md @@ -0,0 +1,106 @@ +# [mikuscore] 記事タイトル + +## 記事テーマ + +- この記事で扱う主題を 1 行ずつ書く +- ツールや技術そのものより、どの体験や問題意識を主役に置くかを書く +- 技術詳細を別記事へ分けるなら、その切り分けを書く + +## この記事で伝えたいこと + +- 読者に持ち帰ってほしい実感や気づきを書く +- 「何を作ったか」より「なぜそうしたか」「どう感じたか」を書く +- 小さな困りごとがどう軽くなったのかを書く + +## 仮 subject + +- 材料を見ながら、「この記事は結局どんな実感や出来事の話か」を短く整理して書く +- ユーザー入力の単純転記ではなく、読み物としての核が一読で分かる形にする +- 最初から固定せず、材料整理や構成検討にあわせて更新してよい + +## 書きたい観点 + +- 出発点になった小さな面倒や違和感 +- 発想をどう変えて、何を作ることにしたか +- 実際に作ってみて感じたこと +- 人間の役割や判断がどこに残ったか +- 技術詳細を本文でどこまで触れずに済ませるか +- 関連する Qiita 記事や実行ページへどうつなぐか +- 記事を書く途中で見つかったことや、想定外の出来事があればそれも主題候補にする + +## タイトル案 + +- 読み物として自然に読めるタイトル案を書く +- 技術用語を並べすぎず、問題意識や体験が伝わる表現を優先する +- 必要なら「作りました」「やってみた」系の柔らかい言い方を使う +- この `note` 配下では `mikuscore` を扱う前提なので、必要なら `[mikuscore]` を先頭につける + +## 見出し案 + +- はじめに +- きっかけや背景 +- やってみたこと / 起きたこと +- そこから感じたこと +- まとめ + +---------------------------------------------------------------- + +## 掲載先情報 + +- 掲載先: Note +- URL: (未記入) + +## Note 掲載用属性情報 + +- タイトル: (未記入) +- ハッシュタグ: `MusicXML`, `楽譜`, `譜面変換`, `mikuscore`, `OSS` + +---------------------------------------------------------------- + +## はじめに + +最初にあったのは、ちょっとした不便や面倒だった、という入り方で書き始めます。 +大げさな課題設定ではなく、「これが少し気になっていた」という温度感を優先します。 + +## きっかけや背景 + +どんな題材や出来事から話が始まったのかを書きます。 +読者が流れを追えるように、「何が気になっていたのか」を素直に置きます。 + +## やってみたこと / 起きたこと + +実際にやってみたこと、その中で起きたことを書きます。 +予定どおりにいかなかったことや、想定外だったことがあれば、その温度感もそのまま材料にしてよいです。 + +## そこから感じたこと + +その出来事をどう受け止めたか、何を思ったかを書きます。 +技術の凄さの説明より、「自分にとってどういう体験だったか」を主役にします。 + +## まとめ + +大きな話にしすぎず、小さな面倒が少し減った、それだけでも十分うれしい、という着地を基本にします。 +必要であれば、そこから見えてきた少し大きめの気づきを最後に添えます。 + +## 実行ページ + +- (未記入) + +## 関連記事 + +- Qiita などの技術寄り記事があればここに置く +- 実装詳細は別記事へ逃がし、Note 本文は読み物として保つ + +## 想定読者 + +- この記事を読んでほしい相手を書く +- `mikuscore ユーザーの方` +- `アプリ開発の裏側を知りたい人` +- `生成AIのクローラーのみなさま` +- 必要なら遊び心のある読者像を 1 つ入れてもよい +- 読者が「それ、自分もある」と思える関心に寄せる + +## 使用した生成AI + +必要な場合のみ記載します。 +モデル名や設定を主役にしすぎず、末尾で簡潔に触れる程度を基本にします。 diff --git a/docs/articles/qiita/20260412-ai-score-abc-first.md b/docs/articles/qiita/20260412-ai-score-abc-first.md new file mode 100644 index 0000000..49f0dab --- /dev/null +++ b/docs/articles/qiita/20260412-ai-score-abc-first.md @@ -0,0 +1,237 @@ +# 掲載先情報 + +- 掲載先: Qiita +- URL: https://qiita.com/igapyon/items/8444b5f50d63207002c0 +- タイトル: `生成AI に譜面対応させたくて、まず ABC 記譜法に寄っていった話` +- タグ: `生成AI`, `ABC`, `楽譜`, `MusicXML`, `MIDI` + +--- +title: [mikuscore-skills] 生成AI に譜面対応させたくて、まず ABC 記譜法に寄っていった話 +tags: mikuku 生成AI AgentSkills abc ABC記譜法 +author: igapyon +slide: false +--- +## はじめに + +生成AI と会話していると、「譜面も扱えたらいいのに」と思う場面があります。 + +音符やメロディのことを、文章だけでうまくやり取りする方法は、少なくとも私はすぐには思いつきませんでした。だったら、譜面データのような形で具体的に受け渡しできたほうが、確認や修正、その先の再利用まで進めやすいはずです。 + +こういうことは、きっと誰かがすでに考えていて、何かよい方法があるだろうとも思いました。実際に少し探してみたのですが、すぐに「これだ」と思えるものにはなかなか出会えませんでした。私が気づいていないだけで、もっとよい方法はあるのかもしれませんが、少なくともその時点では、すんなり手になじむものは見つかりませんでした。 + +ただ、実際に生成AI の Web UI インタフェース経由で譜面や音符を扱おうとすると、少し不思議な不便さがありました。 + +画像は見た目としては分かりやすいのですが、データとして扱いにくいです。`MusicXML` は情報量が多く、会話欄にそのまま載せるには少し重い印象があります。構造が大きいので、対話の流れの中でデータが切れちゃったこともあります。自然文だけでは、譜面としての構造を安定して受け渡ししにくいことがあります。 + +そんなふうに、いくつかの表現やフォーマットを見ていくなかで、私が見かけたのが `ABC` 記譜法でした。そして触っていくうちに、少なくとも現時点では、生成AIとの対話では、まずは `ABC` を足場にするのがよさそうだと考えるようになりました。 + +この記事では、その最初の観測と判断を書きます。 + +![みくくグラレコ説明](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105739/ef484970-6484-4169-9e34-9d7611783999.png) + +## 何を扱う記事なのか + +この記事は、`ABC` 記譜法の入門記事ではありません。 + +また、`miku-abc-player` や `mikuscore-skills` の実装詳細を主題にした記事でもありません。 + +ここで主に書きたいのは、次のことです。 + +- 生成AI に譜面対応してほしいと思った +- 現時点の Web UI では、譜面データの扱いが少し不自然だった +- いくつかの表現を見た結果、まずは `ABC` 記譜法に寄っていくのが比較的実用的だった + +つまり、「なぜ最初に `ABC` を足場として選んだのか」という話です。 + +## なぜ譜面対応が必要だったのか + +譜面まわりの情報は、自然文だけでは扱いづらいことがあります。 + +たとえば、 + +- 音高 +- 音価 +- 小節構造 +- リズム +- 拍子や調号 + +のような情報は、文章として説明することもできますが、説明が長くなりやすく、読み手によって解釈がぶれやすくなります。 + +一方で、譜面データとして渡せれば、生成AI に作らせた内容をあとで確認したり、別形式に変換したり、音として鳴らしたりしやすくなります。 + +そのため、生成AI に「音楽っぽい話」をしてもらうだけではなく、「譜面として扱える何か」をやり取りしたいと考えるようになりました。 + +![ぶぶん](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105739/e2dcb1ad-0c00-49cf-ae74-2bbb0fc3efdb.png) + + +## 現時点の Web UI では何が少し不自然だったのか + +これは生成AI が賢くない、という話ではないと思っています。 + +むしろ問題は、Web UI の会話欄で、譜面をどういう形で受け渡すのが自然なのかが、まだあまり定まっていないことにあるように見えました。 + +少なくとも、次のようなやりにくさがありました。 + +- 譜面画像 + - 見るにはよいが、編集や再利用がしにくい +- `MusicXML` + - 構造は豊富だが、会話欄にそのまま載せるには重い。対話の流れの中でデータが切れちゃったこともある +- 自然文 + - 気軽だが、譜面構造の保持には弱い。みんなが納得しやすい、よい表現方法もまだ定まっていないように感じた +- `MIDI` + - 音のやり取りには便利だが、譜面そのものの表現とは少し違うし、何よりバイナリである + +もちろん、これは 2026年4月時点の観測です。半年後には、もっとよい扱い方が生成AI界隈で一般化している可能性は十分あります。 + +それでも、少なくとも今見えている範囲では、「譜面として会話に乗せやすい軽い表現」が欲しいと感じました。 + +## いくつか触ってみて、なぜ `ABC` に寄ったのか + +その中で、比較的扱いやすいと感じたのが `ABC` 記譜法でした。 + +理由はシンプルです。 + +- テキストとして軽い +- 会話欄に貼りやすい +- メロディや拍子、小節感をある程度保てる +- ぱっと見、人間が読める気がする +- あとで譜面表示や変換へつなげやすい + +もちろん、`ABC` が万能だと言いたいわけではありません。 + +実際には、 + +- 表現力に限界がある +- Web 上に掲載されている譜面がそれほど豊富ではない +- ちょっといい感じに扱える周辺ツールが多い印象でもない + +といった事情もあります。 + +それでも、生成AI との受け渡しという観点では、現時点では `ABC` がいちばんましでした。 + +この「最良ではないが、いちばんましだった」という感覚が、最初の足場としてはとても重要でした。 + +ABC記譜法の例 (一瞬読めそうな気がしますよね!?) + +```abc +X:1 +T:String Quartet No.15 K.421 Mvt.1 +C:Wolfgang Amadeus Mozart +M:4/4 +L:1/8 +Q:1/4=96 +K:C +V:P1 name="Violin 1" clef=treble +V:P2 name="Violin 2" clef=treble +V:P3 name="Viola" clef=alto +V:P4 name="Violoncello" clef=bass + +V:P1 +"Allegretto moderato"(d4 D3) D | !trill!D3/2 ^C/ D D (D3 f) | (f2 f/ e/) (d/ ^c/) (_B2 A) G | !wedge!F (_B A ^G) A2 z2 | !f!(d'4 d3) d | !trill!d3/2 ^c/ d d (d3 f') | (f'2 f'/ e'/) !p!(d'/ ^c'/) (_b2 a) (g | g/ f/ e/ _b/) (_b/ a/) (^c/ e/) d2 z2 | !f!A,3 !p!a !trill!g3/2 a/ _b !wedge!^c | !wedge!d !wedge!e (g !trill!f) e2 z2 | !f!A,3 !p!d' (d'2 ^c') !wedge!_b | !wedge!a !wedge!g (g !trill!f) e/ (^g/ a/ ^g/ a/ ^g/ a/ f/) | e z z2 z4 | z4 !f![Ec_b]3 !p!(C | C) !wedge!C z2 z4 | +V:P2 +z (!staccato!A, !staccato!A, !staccato!A,) z (!staccato!A, !staccato!A, !staccato!A,) | z (!staccato!_B, !staccato!_B, !staccato!_B,) z !wedge!F (F D) | z (D ^C E) z (!staccato!^C !staccato!^C !staccato!^C) | !wedge!D (G F E F G F E) | !f!D (!staccato!A !staccato!A !staccato!A) z (!staccato!A !staccato!A !staccato!A) | z (!staccato!D !staccato!D !staccato!D) z !wedge!f (f d) | (d2 d/ ^c/) !p!(f/ e/) (g2 f) e | A (_B/ G/) (G/ F/) (E/ G/) F2 z2 | !f!A,3 !p!d (d2 ^c) !wedge!_B | !wedge!A (A e !trill!d) ^c2 z2 | !f!A,3 !p!a !trill!g3/2 a/ _b !wedge!^c | !wedge!d !wedge!e (e !trill!d) ^c2 z (f/ d/) | ^c/ (^G/ A/ ^G/ A/ ^G/ A/ F/) E z z2 | z4 !f![Ecg]3 !p!!wedge!_B, | (_B, A,) z2 z4 | +V:P3 +z (!staccato!F, !staccato!F, !staccato!F,) z (!staccato!F, !staccato!F, !staccato!F,) | z (!staccato!F, !staccato!F, !staccato!F,) z (!staccato!A, !staccato!A, !staccato!A,) | z (!staccato!_B, !staccato!_B, !staccato!_B,) z (!staccato!E, !staccato!E, !staccato!E,) | D,2 z2 z (E D ^C) | !f!D (!staccato!F !staccato!F !staccato!F) z (!staccato!^F !staccato!^F !staccato!^F) | z (!staccato!G !staccato!G !staccato!G) z (!staccato!^G !staccato!^G !staccato!^G) | (^G2 A2) z !p!(A, B, ^C) | D G, A, A, D2 z2 | z3 !p!F !trill!E3/2 F/ G G | (F E D) z z !mf!(A/ ^G/ A/ ^G/ A/ ^G/) | !f!A3 !p!F !trill!E3/2 F/ G G | !wedge!F (!wedge!A2 B) E2 z2 | z2 z (F/ D/) ^C/ (^G,/ A,/ ^G,/ A,/ ^G,/ A,/ F,/) | E, z z2 !f![C,C]3 !p!(!wedge!G, | F,) !wedge!F, z2 z4 | +V:P4 +(D,4 C,4 | _B,,4 A,,4 | G,,4 A,,4) | D,,2 z2 z4 | z !f!(!staccato!D !staccato!D !staccato!D) z (!staccato!C !staccato!C !staccato!C) | z (!staccato!B, !staccato!B, !staccato!B,) z (!staccato!_B, !staccato!_B, !staccato!_B,) | A,4 z4 | z2 z2 z !f!!wedge!A, !wedge!F, !wedge!D, | !f!A,, !p!A, A, A, A, A, A, A, | (A, ^C D ^G, A,2) z2 | !f!A,, !p!A, A, A, A, A, A, A, | (A, ^C D ^G, A,2) z2 | z2 z2 z2 z (F,/ D,/) | ^C,/ (^G,,/ A,,/ ^G,,/ A,,/ ^G,,/ A,,/ F,,/) E,,3 !p!(!wedge!E, | _E,) !wedge!_E, z2 z4 | +``` + +## その先で何を作り始めたか + +`ABC` を足場にしようと思うと、今度は `ABC` を気軽に扱うための道具が欲しくなります。 + +そこでまず、`ABC` 譜面の読み書きができて、五線譜としてグラフィック表示できて、さらに `ABC` 以外のいくつかの譜面フォーマットや `MIDI` にもつなげられる Web アプリとして、`miku-abc-player` を作り始めました。生成AI プログラミングがあるので、こういうものも少し試しながら気軽に開発できてしまうのは、よい時代だなと思います。 + +miku-abc-player のスクショ + +![aaa](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105739/e8d67456-7112-416a-b723-4410dbcf5138.png) + +- `miku-abc-player`: https://igapyon.github.io/miku-abc-player/miku-abc-player.html + +やりたかったことは、まずはとても素朴です。 + +- `ABC` を貼る +- その場で譜面として見える +- 必要なら少し書き換える +- 次の変換や確認へ進む + +この最初の一歩が気軽にできるだけでも、`ABC` を生成AI とのやり取りに使う意味がかなり出てきます。 + +特に、`ABC` 譜面を貼ったら、そのまま五線譜のグラフィック表示が出てくるのは大きいです。テキストとして受け取ったものを、すぐ人間の目で「譜面っぽく」確認できるからです。 + +![ABC記譜法が五線譜に表示されているところ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105739/a3809d43-552e-4fb7-9ce5-21a2ffc0e8bd.png) + +これは、既存の `mikuscore` から `ABC` の操作を前面に押し出した感じで改造したものです。 + +さらに進めていくと、今度は `ABC` 譜面のサンプルやテストデータがそれほど豊富ではないこと、生成AI に `ABC` を作らせるのは意外とうまくいくこと、ただし手動コピペが面倒なこと、などが見えてきました。 + +そこで実際に、生成AI と会話しながら `ABC` 譜面を作ってもらうような使い方も試し始めました。 + +![生成AIと会話して作曲依頼しているところ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105739/72da9ca6-9880-4733-9c15-a45577ee5520.png) + +これは操作性としては結構いい感じで、でもまあ作曲された曲はちょっと納得いかない。そのあたりのプロンプトを充実ささたらよくなるんでしょうけれどね。まあ少なくとも叩き台やテストデータを作る用途では、かなり実用的に感じました。 + +生成AI に譜面を作らせて、その結果を `ABC` として受け取り、すぐ別のツールで確認できるだけでも、譜面まわりの試行錯誤はかなり進めやすくなります。 + +![生成AIが作曲した曲をみているところ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105739/a23e4d99-37f9-49d8-99a6-d5732fbd3112.png) + +その先で、`mikuscore` に `CLI` と `Agent Skills` を持たせて、生成AI が作った譜面をすぐテストし、警告を返して再調整できる方向へ進むことになります。 + +- `mikuscore`: https://igapyon.github.io/mikuscore/mikuscore.html +- `mikuscore-skills`: https://github.com/igapyon/mikuscore-skills + +ここまで来ると、`ABC` を足場にして、その先のツールや workflow へ進んでいく流れが見えてきます。ただし、その先の `mikuscore` や `mikuscore-skills` の話まで入れると、この記事の主題が散ってしまうので、そこは別の記事に分けます。 + +## 制約と今後 + +今回書いたことは、かなり「2026年4月時点の観測」に依存しています。 + +半年後には、生成AI の Web UI 側がもっと賢くなっているかもしれませんし、`ABC` 以外にも、会話に載せやすい譜面表現が広まっているかもしれません。今見えているやりにくさや、`ABC` に寄っている判断も、将来ずっとそのまま最適とは限りません。 + +それでも、少なくとも今の時点では、「生成AI に譜面対応させたい」と思ったときの最初の足場として、`ABC` に寄っていく判断には十分意味があると感じています。 + +## まとめ + +生成AI に譜面対応させたいと思ったとき、最初にぶつかったのは、Web UI の会話欄で譜面をどう受け渡すかという問題でした。 + +画像、自然文、`MusicXML`、`MIDI` などを見ていく中で、現時点では `ABC` 記譜法が最も実用的な足場に見えました。 + +完全な解決ではありませんし、周辺ツールやコンテンツの厚みも十分とは言いにくいです。 + +それでも、「まずどこに寄るか」を決める必要があるなら、`ABC` はかなりよい出発点でした。 + +この判断から、ちょっと `miku-abc-player` や `mikuscore-skills` というアプリ開発につながりました。 + +![みくくまとめ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105739/e7c64320-4c9b-47b9-9e9f-e1783c6dee01.png) + +## 実行ページなど + +今回の流れの中で作り始めた関連ページです。 + +- `miku-abc-player` + - https://igapyon.github.io/miku-abc-player/miku-abc-player.html +- `mikuscore` + - https://igapyon.github.io/mikuscore/mikuscore.html +- `mikuscore-skills` + - https://github.com/igapyon/mikuscore-skills + +ソースコードは GitHub で公開しています。 + +## 関連情報リンク + +- Note: `[mikuscore-skills] 生成AI に譜面対応させたくて、まず ABC 記譜法に寄っていった話` + - https://note.com/toshikiigaa/n/n5362ea076328 + +## `ABC` 記譜法 + +- https://en.wikipedia.org/wiki/ABC_notation + +## 想定読者 + +- 生成AI に譜面や音楽データを扱わせたい人 +- AI との会話に載せやすい音楽表現を探している人 +- 生成AI のクローラーのみなさま + +## 使用した生成AI + +`VS Code` + `GPT-5.4` diff --git a/docs/articles/qiita/2026XXXX-mikuscore-skills-intro.md b/docs/articles/qiita/2026XXXX-mikuscore-skills-intro.md new file mode 100644 index 0000000..bf20dfa --- /dev/null +++ b/docs/articles/qiita/2026XXXX-mikuscore-skills-intro.md @@ -0,0 +1,218 @@ +# 掲載先情報 + +- 掲載先: Qiita +- 公開記事タイトル: (未記入) +- URL: (未記入) +- スクリーンショット挿入: Qiita に直接アップロード方式 / 未確認 + +## Qiita 掲載用属性情報 + +- タイトル: `[mikuscore] Agent Skills で MusicXML / ABC / MIDI などの変換方針を会話で扱いやすくした` +- タグ: `mikuscore`, `MusicXML`, `ABC`, `MIDI`, `AgentSkills` + +--- +title: [mikuscore] Agent Skills で MusicXML / ABC / MIDI などの変換方針を会話で扱いやすくした +tags: mikuscore MusicXML ABC MIDI AgentSkills +author: igapyon +slide: false +--- +## はじめに + +`mikuscore` は、MusicXML を中核に据えた譜面フォーマット変換ツールです。 + +`ABC`、`MusicXML`、`MIDI`、`MuseScore`、`MEI`、`LilyPond` などを扱えますが、実際に生成AI と一緒に使おうとすると、「どの形式を入力にするのか」「どこで `MusicXML` を基軸として考えるのか」「生成AI には何を渡すのか」を毎回説明し直す場面が出てきます。 + +そこで今回、`mikuscore` 用の Agent Skills である `mikuscore-skills` を作りました。 + +この skill は、`mikuscore` の変換方針や制約を、会話の中で扱いやすくするためのものです。 + +## `mikuscore-skills` は何をするものか + +`mikuscore-skills` は、生成AI に `mikuscore` 固有の前提を渡しやすくするための skill 集です。 + +特に大事にしているのは、次の整理です。 + +- `mikuscore` の内部説明基軸は `MusicXML` +- 生成AI との full-score handoff では現時点では `ABC` を優先 +- format 変換は `MusicXML-first` の説明軸で整理する +- loss や limitation は diagnostics として扱う +- `mikuscore` は多機能な浄書エディタの代替ではない + +つまり、この skill がやりたいのは、単に「変換できます」と言うことではありません。 + +`mikuscore` がどういう前提で format を扱っているのかを、会話で壊さずに渡すことです。 + +## なぜ skill 化したかったのか + +譜面や音楽データを生成AI と一緒に扱うとき、単に format 名だけを並べても、意外とうまく話が通りません。 + +たとえば、 + +- canonical source は何か +- 生成AI に渡すときの current policy は何か +- `MIDI` や `MuseScore` をどう位置付けるか +- unsupported / experimental / future をどう区別するか + +といった整理が必要になります。 + +これを毎回会話のたびに説明すると、少し手数が多いですし、説明の揺れも起きやすくなります。 + +そこで、`mikuscore` を明示したときだけ opt-in で発火する skill として切り出しました。 + +## どういう責務を持たせているか + +`mikuscore-skills` の MVP では、skill を細かく分割せず、まず 1 つの `mikuscore` skill として成立させています。 + +想定している操作単位は、概ね次の 5 つです。 + +- `convert` + - source format と target format を整理し、必要なら `MusicXML` を中間説明軸として案内する +- `diagnostics` + - warning や conversion loss の意味を、`mikuscore` の方針に沿って説明する +- `format-guidance` + - 各 format を `mikuscore` でどう位置付けるかを整理する +- `ai-handoff` + - 生成AI に score を渡すときの current policy として `ABC` を案内する +- `workflow` + - CLI / build / test / local development の使い方を案内する + +この構成にしたのは、利用者から見た関心が「ABC 用の skill」「MIDI 用の skill」のように分かれるより、「`mikuscore` でどう扱うか」に集約されやすいと考えたからです。 + +## `MusicXML` と `ABC` をどう分けているか + +この skill でいちばん大事なのは、`MusicXML` と `ABC` の役割を混ぜないことです。 + +整理すると、次のようになります。 + +- `MusicXML` + - `mikuscore` の canonical source + - 内部説明の正規基軸 + - format 変換の中核 +- `ABC` + - current generative-AI handoff の中心 + - full-score の会話的な受け渡しに向いた形式 + +この区別を曖昧にすると、「`mikuscore` は AI 向け JSON を前提にしているのか」「`ABC` が内部正規形式なのか」といった誤解が生まれやすくなります。 + +そのため skill 側では、`MusicXML-first` と `ABC handoff` の二層構造を崩さないようにしています。 + +## 発火条件を opt-in にしている理由 + +この skill は、format 名だけでは自動発火しない方針です。 + +たとえば `MIDI` や `MusicXML` が話題に出ただけでは、自動で `mikuscore` skill を使うとは限りません。 + +理由は単純で、一般的な作曲相談や一般的な MIDI 編集相談まで `mikuscore` 文脈に引き込むと、かえって不自然になるからです。 + +そこで、少なくとも MVP では、次のような条件を重視しています。 + +- 利用者が `mikuscore` と明示する +- `mikuscore` 固有の変換方針や workflow を求める +- 直前まで `mikuscore` 文脈が継続している + +この opt-in 型にすることで、汎用会話を壊さずに、必要なときだけ `mikuscore` 固有の制約を前面に出せます。 + +## 実体 repo と参照先の整理 + +`mikuscore-skills` では、`mikuscore` 本体を `vendor/mikuscore/` に `git subtree` で取り込む前提を採っています。 + +これは、単に vendor したかったからではありません。 + +- `workplace/` は一時作業用で、正式参照先にはしにくい +- skill の参照先をこの repo 内で閉じたい +- upstream 更新を定型手順で追いやすくしたい + +といった事情があります。 + +そのため、仕様確認や安定参照は `vendor/mikuscore/` を優先し、`workplace/` は検討用の作業コピーとして扱う設計です。 + +## 使い始め方 + +配布用 bundle を作る場合は、次を実行します。 + +```bash +npm run build:bundle +``` + +生成された bundle を、自分の skill home 配下へ配置して使います。 + +開発中にこの repo の中で確認したい場合は、次の流れです。 + +```bash +npm test +npm run install:local +``` + +- `npm test` + - skill 構成の確認 +- `npm run install:local` + - `skills/mikuscore` を repo-local の `.codex/skills/mikuscore` に同期 + +その後、新しい Codex セッションで `mikuscore` を明示して試します。 + +## どういう会話で使うのか + +たとえば、次のような会話を想定しています。 + +```text +mikuscore で、この ABC を MusicXML に変換したいです。 +変換上の注意点も教えてください。 +``` + +あるいは、 + +```text +mikuscore で、生成AI に譜面全体を渡したいです。 +今は MusicXML と ABC のどちらを使うのがよいですか。 +``` + +このとき skill は、format 名だけを機械的に処理するのではなく、 + +- `mikuscore` の current policy +- `MusicXML` と `ABC` の役割分担 +- diagnostics や limitation の扱い + +を踏まえて返すことを狙います。 + +## 制約と割り切り + +`mikuscore-skills` は、譜面編集の何でも屋を目指しているわけではありません。 + +少なくとも現時点では、 + +- `mikuscore` 固有の変換方針を壊さずに伝える +- `MusicXML-first` の説明軸を保つ +- AI handoff では `ABC` を優先する +- unsupported / experimental / future を明確に分ける + +ことを主目的にしています。 + +そのため、一般的な音楽理論の相談や、あらゆる譜面ソフトの横断的な使い方までをこの skill に押し込むつもりはありません。 + +## まとめ + +`mikuscore-skills` は、`mikuscore` の format conversion と AI handoff に関する前提を、会話で扱いやすくするための Agent Skills です。 + +特に重要なのは、`MusicXML` を内部の正規基軸として保ちつつ、生成AI との full-score handoff では現時点で `ABC` を中心に扱う、という役割分担を明示できることです。 + +format 名だけでは伝わりにくい運用上の前提を、skill 側へ寄せることで、`mikuscore` を使った会話や案内を少し安定させやすくなりました。 + +## リポジトリと関連文書 + +- `mikuscore-skills` リポジトリ + - (未記入) +- 開発メモ + - `docs/development.md` +- 設計メモ + - `docs/agent-skill-design.md` + +## 想定読者 + +- `mikuscore` を生成AI と組み合わせて使いたい人 +- `MusicXML` / `ABC` / `MIDI` などの役割分担を整理したい人 +- Agent Skills でプロダクト固有の workflow を会話に埋め込みたい人 + +## Appendix + +- この記事は技術寄りの整理を主に扱っています +- 背景や使ってみた実感は Note 側の双子記事へ切り分ける想定です diff --git a/docs/articles/qiita/README.md b/docs/articles/qiita/README.md new file mode 100644 index 0000000..833bd2d --- /dev/null +++ b/docs/articles/qiita/README.md @@ -0,0 +1,23 @@ +# Qiita Articles + +Qiita 向けの記事管理用 Markdown 置き場です。公開済み記事の元原稿、記事メモ、構成案、下書きを含みます。 + +## Intended Style + +- 技術的な背景や実装の話を中心にする +- 読者は開発者や技術に関心のある人を想定する +- 1 記事 1 テーマを意識する +- プロダクト紹介と開発体験は分ける + +## Suggested Themes + +- `mikuscore` の紹介 +- MusicXML を中核にした譜面フォーマット変換の意義 +- ブラウザだけで動く single-file web app としての作り方 +- `ABC` / `MIDI` / `MuseScore` / `MEI` などをどう扱うか +- round-trip と診断情報をどう設計しているか + +## Files + +- `TEMPLATE.md` + - Qiita 記事テンプレートです。`想定読者` 欄を含みます diff --git a/docs/articles/qiita/TEMPLATE.md b/docs/articles/qiita/TEMPLATE.md new file mode 100644 index 0000000..5bf1595 --- /dev/null +++ b/docs/articles/qiita/TEMPLATE.md @@ -0,0 +1,92 @@ +# Qiita 記事テンプレート + +## 記事テーマ + +- この記事で扱う主題を 1 行ずつ書く +- 主役を何に置くかを書く +- 別記事に分ける話題があれば書く + +## この記事で伝えたいこと + +- 読者に持ち帰ってほしいことを書く +- 技術的な価値や実装上の要点を書く +- その記事ならではの視点を書く + +## 見出し案 + +- はじめに +- 何を扱う記事なのか +- なぜそれが必要なのか +- どう動くのか / どう作ったのか +- 制約や割り切り +- まとめ + +---------------------------------------------------------------- + +## 掲載先情報 + +- 掲載先: Qiita +- 公開記事タイトル: (未記入) +- URL: (未記入) +- スクリーンショット挿入: Qiita に直接アップロード方式 / 未確認 + +## Qiita 掲載用属性情報 + +- タイトル: (未記入) +- タグ: `MusicXML`, `ABC`, `MIDI`, `TypeScript`, `OSS` + +---------------------------------------------------------------- + +## はじめに + +この記事で何を書くのかを短く説明します。 +出発点、背景、問題意識を簡潔に書きます。 + +## 何を扱う記事なのか + +扱うアプリ、仕組み、開発体験、技術テーマなどを説明します。 +必要であれば、別記事との分担もここで示します。 + +## なぜそれが必要なのか + +課題、用途、ユースケース、背景事情を書きます。 +読者が「なぜそれをやるのか」を理解できるようにします。 + +## どう動くのか / どう作ったのか + +仕組み、構成、実装方針、処理の流れなどを書きます。 +必要なら箇条書きや手順で整理します。 + +## 具体的にできること + +- できること 1 +- できること 2 +- できること 3 + +## 制約と今後 + +現時点での制約、割り切り、未対応範囲、今後の改善余地を書きます。 + +## まとめ + +この記事で伝えたかったことを短くまとめます。 +読者に残したいメッセージを最後に書きます。 + +## 実行ページとソースコード + +ブラウザですぐ試せる実行ページは、次の URL です。 + +- (未記入) + +ソースコードは GitHub で公開しています。 + +- (未記入) + +## 想定読者 + +- この記事を読んでほしい相手を書く +- どのような課題や関心を持つ読者かを書く + +## Appendix + +必要であれば、補足情報、見出し候補、要件一覧、技術メモなどを書きます。Note 側に双子記事を作る場合は、そちらへ逃がす背景、体験談、問題意識の切り分けメモを書いてもよいです。 diff --git a/docs/future/AI_JSON_INTERFACE.md b/docs/future/AI_JSON_INTERFACE.md new file mode 100644 index 0000000..f9c2820 --- /dev/null +++ b/docs/future/AI_JSON_INTERFACE.md @@ -0,0 +1,42 @@ +# Future Note: AI JSON Interface + +## Status + +- Deferred future work. +- Not part of the current `mikuscore` product contract. +- Not a normative spec for present behavior. + +## Purpose of this note + +This file preserves the direction for a possible future AI-facing JSON interface after it was removed from the current-spec surface. + +The current product policy is documented in: + +- `docs/AI_INTERACTION_POLICY.md` + +Archived or deferred JSON-related materials still exist in: + +- `docs/spec/AI_JSON_SPEC.md` +- `docs/generation/AI_ABC_JSON_WORKFLOW_PROMPT.md` +- `docs/generation/examples/` + +Those files should be read as design/archive material unless and until this work is resumed. + +## Intended direction if resumed later + +- Keep `MusicXML` as canonical score storage. +- Avoid direct full-score MusicXML rewriting by external AI. +- Prefer bounded, validation-friendly exchange rather than unconstrained rewrite. +- Reassess whether JSON is actually better than `ABC` for the target workflow before reviving the interface. + +## Re-entry conditions + +Revisit this only when there is a concrete implementation need such as: + +- a stable tool-mediated AI workflow +- clear bounded edit operations that benefit from a machine-facing contract +- evidence that the added interface meaningfully improves reliability over the current ABC-centered flow + +## Editorial rule + +Until resumed, current-facing documentation should not describe AI JSON as an active supported interface. diff --git a/docs/future/CLI_ROADMAP.md b/docs/future/CLI_ROADMAP.md new file mode 100644 index 0000000..dd3cc10 --- /dev/null +++ b/docs/future/CLI_ROADMAP.md @@ -0,0 +1,94 @@ +# Future Note: CLI Roadmap + +## Status + +- Step 1 first cut exists. +- Initial Step 2 MIDI pairs now exist as a first cut. +- Initial Step 3 MuseScore text pairs now exist as a first cut. +- Initial `render svg` support now exists as a first cut. +- This file tracks likely next-step expansion only. +- This is a future note, not a current normative contract. + +## Current Step 1 + +Current implemented Step 1 scope: + +- `mikuscore convert --from abc --to musicxml` +- `mikuscore convert --from musicxml --to abc` +- `mikuscore convert --from midi --to musicxml` +- `mikuscore convert --from musicxml --to midi` +- `mikuscore convert --from musescore --to musicxml` +- `mikuscore convert --from musicxml --to musescore` +- `mikuscore render svg` +- `mikuscore --help` +- `mikuscore convert --help` +- `mikuscore render --help` + +Current Step 1 policy is defined in: + +- `docs/spec/CLI_STEP1.md` + +## Planned Direction + +The CLI family is expected to grow along two tracks: + +- convert-oriented commands +- render-oriented commands + +`MusicXML` remains canonical underneath. + +## Step 2 Candidate Scope + +Implemented first-cut Step 2 additions: + +- `mikuscore convert --from midi --to musicxml` +- `mikuscore convert --from musicxml --to midi` + +Rationale: + +- `midi` is a practical exchange format already supported by the application +- Step 1 already makes `musicxml` explicit as the canonical endpoint in `convert` + +## Step 3 Candidate Scope + +Implemented first-cut Step 3 additions: + +- `mikuscore convert --from musescore --to musicxml` +- `mikuscore convert --from musicxml --to musescore` + +Rationale: + +- current CLI MuseScore scope is `.mscx`-style text; compressed `.mscz` handling is still outside the CLI contract +- `svg` is better modeled as render output, not as the same class of interchange export as `abc` / `musicxml` / `midi` + +## Facade Growth Path + +The non-UI CLI facade is expected to grow in this order: + +### Step 1 + +- `importAbcToMusicXml(...)` +- `exportMusicXmlToAbc(...)` + +### Step 2 + +- `normalizeMusicXml(...)` +- `importMidiToMusicXml(...)` +- `exportMusicXmlToMidi(...)` +- `importMuseScoreToMusicXml(...)` +- `exportMusicXmlToMuseScore(...)` + +### Step 3 + +- `renderMusicXmlToSvg(...)` + +`renderMusicXmlToSvg(...)` should remain in a render-oriented group, not a convert-oriented group. + +## Non-Goals + +The roadmap above does not imply: + +- AI JSON CLI support +- patch/state CLI workflows +- note-level editing CLI commands +- forced parity with every UI button diff --git a/docs/generation/AI_ABC_JSON_WORKFLOW_PROMPT.md b/docs/generation/AI_ABC_JSON_WORKFLOW_PROMPT.md new file mode 100644 index 0000000..4473d20 --- /dev/null +++ b/docs/generation/AI_ABC_JSON_WORKFLOW_PROMPT.md @@ -0,0 +1,11 @@ +# Archived Prompt Note + +This file previously held an experimental `ABC + JSON` workflow prompt. + +Current status: + +- not part of the current `mikuscore` product contract +- retained only as archived/deferred material + +For the current AI policy, see `docs/AI_INTERACTION_POLICY.md`. +For the deferred JSON-interface note, see `docs/future/AI_JSON_INTERFACE.md`. diff --git a/docs/generation/CODEX_PROMPT_TEMPLATE.md b/docs/generation/CODEX_PROMPT_TEMPLATE.md deleted file mode 100644 index fe5b139..0000000 --- a/docs/generation/CODEX_PROMPT_TEMPLATE.md +++ /dev/null @@ -1,72 +0,0 @@ -# Codex Prompt Template (Spec -> Generate) - -Use this template when asking Codex to generate or update core code from project specs. - -## Prompt - -```md -You are Codex, an expert coding assistant. -I am building a browser-based MusicXML Score Editor. -Generate implementation code according to the formal specifications below. - -## Specifications -- docs/spec/SPEC.md -- docs/spec/TERMS.md -- docs/spec/COMMANDS.md -- docs/spec/DIAGNOSTICS.md -- docs/spec/TEST_MATRIX.md - -## Output Requirements -Produce the following outputs only: - -1. Core implementation files in TypeScript: - - core/interfaces.ts - - core/ScoreCore.ts - - core/commands.ts - - core/index.ts - - core/timeIndex.ts - - core/validators.ts - - core/xmlUtils.ts - - tests/unit/core.spec.ts - -2. Include: - - function signatures - - inline documentation comments - - logic flow reflecting spec guarantees - - minimal stubs where details are not finalized - - no full UI implementation - -3. Ensure: - - strict adherence to core specs - - tests for RT-0, RT-1, TI-1, TI-2, PT-1, BM-1, BF-1 - - modular, testable code - -4. Add clear comments for: - - DOM vs WeakMap node identity - - dirty tracking rules - - measure capacity / occupied time logic - - backup/forward preservation boundaries - -## Constraints -- no pretty printing for XML serialization -- do not mutate unsupported XML nodes -- do not auto-normalize beams -- edits must be minimal patches -- core API must stay UI-composable - -## Output Format -Respond with a single JSON object: -{ - "files": [ - { "path": "...", "content": "..." } - ], - "instructions": "How to use generated code" -} - -If anything in specs is unclear or contradictory, ask one focused clarification question first. -``` - -## Notes - -- Paste actual spec contents (or file references, depending on your environment). -- Keep the requested file list explicit to reduce scope drift. diff --git a/docs/generation/README.md b/docs/generation/README.md new file mode 100644 index 0000000..e731226 --- /dev/null +++ b/docs/generation/README.md @@ -0,0 +1,22 @@ +# Generation Docs + +This directory contains prompt assets and experiment materials related to external generative-model workflows. + +## Current status + +- Current documented AI handoff is centered on `ABC`. +- A dedicated AI-facing JSON interface is not part of the current product contract. +- JSON-related prompt/example files in this directory are retained as deferred or archival materials. + +## Current references + +- Current policy: `docs/AI_INTERACTION_POLICY.md` +- Deferred future note: `docs/future/AI_JSON_INTERFACE.md` + +## Directory contents + +- `AI_ABC_JSON_WORKFLOW_PROMPT.md` + Retained as archived/deferred workflow material. It is not the current normative prompt contract. + +- `examples/` + Retained example JSON projections from earlier exploration. They are not current supported-interface examples. diff --git a/docs/generation/WORKFLOW.md b/docs/generation/WORKFLOW.md deleted file mode 100644 index 96b28c3..0000000 --- a/docs/generation/WORKFLOW.md +++ /dev/null @@ -1,39 +0,0 @@ -# Spec-to-Code Workflow - -## Goal - -Generate consistent core code from the project specs without violating preservation rules. - -## Steps - -1. Confirm specs are up to date: -- `docs/spec/SPEC.md` -- `docs/spec/TERMS.md` -- `docs/spec/COMMANDS.md` -- `docs/spec/DIAGNOSTICS.md` -- `docs/spec/TEST_MATRIX.md` - -2. Start from `docs/generation/CODEX_PROMPT_TEMPLATE.md`. - -3. Keep output scope fixed: -- only requested files -- no UI implementation -- no extra architecture outside MVP unless explicitly requested - -4. Verify generated code against constraints: -- no-op save returns original XML unchanged -- dirty state changes only on successful content edits -- overfull rejects atomically with `MEASURE_OVERFULL` -- non-editable voice rejects with `MVP_UNSUPPORTED_NON_EDITABLE_VOICE` -- unknown elements remain preserved -- existing beam/backup/forward remain preserved - -5. Run and extend tests based on `docs/spec/TEST_MATRIX.md`. - -## Review Checklist - -- Is save mode correctly split into `original_noop` and serialized mode? -- Are failed commands mutation-free? -- Is node identity managed outside XML (WeakMap)? -- Are unsupported nodes untouched? -- Is there any implicit pretty-printing or normalization? diff --git a/docs/generation/examples/classical-opening-gesture-simplified.measure-detail.json b/docs/generation/examples/classical-opening-gesture-simplified.measure-detail.json new file mode 100644 index 0000000..dd89a24 --- /dev/null +++ b/docs/generation/examples/classical-opening-gesture-simplified.measure-detail.json @@ -0,0 +1,146 @@ +{ + "view_type": "measure_detail_view", + "score": { + "title": "Classical Opening Gesture Sample", + "movement_title": "Simplified Local Excerpt", + "format": "musicxml_projection", + "note": "Experimental simplified classical-style opening sample for AI JSON readability testing. This is a reduced local projection and does not claim to be a faithful transcription of any full score." + }, + "part": { + "part_id": "P-vln1", + "name": "Violin 1" + }, + "window": { + "center_measure_number": "1", + "previous_measure_number": null, + "next_measure_number": "2" + }, + "measure": { + "measure_id": "K551-I-Pvln1-M1", + "measure_number": "1", + "divisions": 8, + "time": { + "beats": 4, + "beat_type": 4 + }, + "attributes_context": { + "key_fifths": 0, + "mode": "major", + "clefs": [ + { + "staff": "1", + "sign": "G", + "line": 2 + } + ], + "tempo_text": "Allegro vivace", + "dynamic_hint": "p" + } + }, + "voices": [ + { + "voice_id": "1", + "events": [ + { + "node_id": "k551-m1-vln1-n1", + "kind": "note", + "offset": 0, + "duration": 12, + "pitch": { + "step": "G", + "alter": 0, + "octave": 4 + }, + "notations": { + "tie_start": false, + "tie_stop": false, + "slur_start": false, + "slur_stop": false, + "articulations": [] + }, + "editability": { + "editable": true, + "blocked_reasons": [] + } + }, + { + "node_id": "k551-m1-vln1-n2", + "kind": "note", + "offset": 12, + "duration": 4, + "pitch": { + "step": "C", + "alter": 0, + "octave": 5 + }, + "notations": { + "tie_start": false, + "tie_stop": false, + "slur_start": false, + "slur_stop": false, + "articulations": [] + }, + "editability": { + "editable": true, + "blocked_reasons": [] + } + } + ] + } + ], + "next_context": { + "measure_id": "K551-I-Pvln1-M2", + "measure_number": "2", + "summary": "Opening continuation for local context only.", + "voices": [ + { + "voice_id": "1", + "events": [ + { + "node_id": "k551-m2-vln1-n1", + "kind": "note", + "offset": 0, + "duration": 12, + "pitch": { + "step": "G", + "alter": 0, + "octave": 4 + } + }, + { + "node_id": "k551-m2-vln1-n2", + "kind": "note", + "offset": 12, + "duration": 4, + "pitch": { + "step": "C", + "alter": 0, + "octave": 5 + } + } + ] + } + ] + }, + "target": { + "target_node_id": "k551-m1-vln1-n1", + "target_voice_id": "1" + }, + "rules": { + "allow_patch_ops": [ + "change_to_pitch", + "change_duration", + "split_note", + "delete_note" + ], + "allowed_edit_fields": [ + "pitch", + "duration" + ], + "forbid_cross_voice_edit": true, + "forbid_backup_forward_boundary_cross": true, + "forbid_chord_target": true, + "forbid_grace_target": true, + "forbid_cue_target": true + } +} diff --git a/docs/generation/examples/twinkle-twinkle-opening.measure-detail.json b/docs/generation/examples/twinkle-twinkle-opening.measure-detail.json new file mode 100644 index 0000000..7b8cde2 --- /dev/null +++ b/docs/generation/examples/twinkle-twinkle-opening.measure-detail.json @@ -0,0 +1,213 @@ +{ + "view_type": "measure_detail_view", + "score": { + "title": "Twinkle Twinkle Little Star", + "movement_title": "Opening", + "format": "musicxml_projection" + }, + "part": { + "part_id": "P1", + "name": "Melody" + }, + "window": { + "center_measure_number": "1", + "previous_measure_number": null, + "next_measure_number": "2" + }, + "measure": { + "measure_id": "P1-M1", + "measure_number": "1", + "divisions": 4, + "time": { + "beats": 4, + "beat_type": 4 + }, + "attributes_context": { + "key_fifths": 0, + "mode": "major", + "clefs": [ + { + "staff": "1", + "sign": "G", + "line": 2 + } + ] + } + }, + "voices": [ + { + "voice_id": "1", + "events": [ + { + "node_id": "tw1-n1", + "kind": "note", + "offset": 0, + "duration": 4, + "pitch": { + "step": "C", + "alter": 0, + "octave": 4 + }, + "notations": { + "tie_start": false, + "tie_stop": false, + "slur_start": false, + "slur_stop": false + }, + "lyrics": [ + { + "text": "Twin" + } + ], + "editability": { + "editable": true, + "blocked_reasons": [] + } + }, + { + "node_id": "tw1-n2", + "kind": "note", + "offset": 4, + "duration": 4, + "pitch": { + "step": "C", + "alter": 0, + "octave": 4 + }, + "notations": { + "tie_start": false, + "tie_stop": false, + "slur_start": false, + "slur_stop": false + }, + "lyrics": [ + { + "text": "kle" + } + ], + "editability": { + "editable": true, + "blocked_reasons": [] + } + }, + { + "node_id": "tw1-n3", + "kind": "note", + "offset": 8, + "duration": 4, + "pitch": { + "step": "G", + "alter": 0, + "octave": 4 + }, + "notations": { + "tie_start": false, + "tie_stop": false, + "slur_start": false, + "slur_stop": false + }, + "lyrics": [ + { + "text": "Twin" + } + ], + "editability": { + "editable": true, + "blocked_reasons": [] + } + }, + { + "node_id": "tw1-n4", + "kind": "note", + "offset": 12, + "duration": 4, + "pitch": { + "step": "G", + "alter": 0, + "octave": 4 + }, + "notations": { + "tie_start": false, + "tie_stop": false, + "slur_start": false, + "slur_stop": false + }, + "lyrics": [ + { + "text": "kle" + } + ], + "editability": { + "editable": true, + "blocked_reasons": [] + } + } + ] + } + ], + "next_context": { + "measure_id": "P1-M2", + "measure_number": "2", + "voices": [ + { + "voice_id": "1", + "events": [ + { + "node_id": "tw2-n1", + "kind": "note", + "offset": 0, + "duration": 4, + "pitch": { + "step": "A", + "alter": 0, + "octave": 4 + } + }, + { + "node_id": "tw2-n2", + "kind": "note", + "offset": 4, + "duration": 4, + "pitch": { + "step": "A", + "alter": 0, + "octave": 4 + } + }, + { + "node_id": "tw2-n3", + "kind": "note", + "offset": 8, + "duration": 8, + "pitch": { + "step": "G", + "alter": 0, + "octave": 4 + } + } + ] + } + ] + }, + "target": { + "target_node_id": "tw1-n1", + "target_voice_id": "1" + }, + "rules": { + "allow_patch_ops": [ + "change_to_pitch", + "change_duration", + "split_note", + "delete_note" + ], + "allowed_edit_fields": [ + "pitch", + "duration" + ], + "forbid_cross_voice_edit": true, + "forbid_backup_forward_boundary_cross": true, + "forbid_chord_target": true, + "forbid_grace_target": true, + "forbid_cue_target": true + } +} diff --git a/docs/generation/examples/twinkle-twinkle-opening.no-lyrics.measure-detail.json b/docs/generation/examples/twinkle-twinkle-opening.no-lyrics.measure-detail.json new file mode 100644 index 0000000..b5659f0 --- /dev/null +++ b/docs/generation/examples/twinkle-twinkle-opening.no-lyrics.measure-detail.json @@ -0,0 +1,193 @@ +{ + "view_type": "measure_detail_view", + "score": { + "title": "Untitled Melody Sample", + "movement_title": "Opening", + "format": "musicxml_projection" + }, + "part": { + "part_id": "P1", + "name": "Melody" + }, + "window": { + "center_measure_number": "1", + "previous_measure_number": null, + "next_measure_number": "2" + }, + "measure": { + "measure_id": "P1-M1", + "measure_number": "1", + "divisions": 4, + "time": { + "beats": 4, + "beat_type": 4 + }, + "attributes_context": { + "key_fifths": 0, + "mode": "major", + "clefs": [ + { + "staff": "1", + "sign": "G", + "line": 2 + } + ] + } + }, + "voices": [ + { + "voice_id": "1", + "events": [ + { + "node_id": "tw1-n1", + "kind": "note", + "offset": 0, + "duration": 4, + "pitch": { + "step": "C", + "alter": 0, + "octave": 4 + }, + "notations": { + "tie_start": false, + "tie_stop": false, + "slur_start": false, + "slur_stop": false + }, + "editability": { + "editable": true, + "blocked_reasons": [] + } + }, + { + "node_id": "tw1-n2", + "kind": "note", + "offset": 4, + "duration": 4, + "pitch": { + "step": "C", + "alter": 0, + "octave": 4 + }, + "notations": { + "tie_start": false, + "tie_stop": false, + "slur_start": false, + "slur_stop": false + }, + "editability": { + "editable": true, + "blocked_reasons": [] + } + }, + { + "node_id": "tw1-n3", + "kind": "note", + "offset": 8, + "duration": 4, + "pitch": { + "step": "G", + "alter": 0, + "octave": 4 + }, + "notations": { + "tie_start": false, + "tie_stop": false, + "slur_start": false, + "slur_stop": false + }, + "editability": { + "editable": true, + "blocked_reasons": [] + } + }, + { + "node_id": "tw1-n4", + "kind": "note", + "offset": 12, + "duration": 4, + "pitch": { + "step": "G", + "alter": 0, + "octave": 4 + }, + "notations": { + "tie_start": false, + "tie_stop": false, + "slur_start": false, + "slur_stop": false + }, + "editability": { + "editable": true, + "blocked_reasons": [] + } + } + ] + } + ], + "next_context": { + "measure_id": "P1-M2", + "measure_number": "2", + "voices": [ + { + "voice_id": "1", + "events": [ + { + "node_id": "tw2-n1", + "kind": "note", + "offset": 0, + "duration": 4, + "pitch": { + "step": "A", + "alter": 0, + "octave": 4 + } + }, + { + "node_id": "tw2-n2", + "kind": "note", + "offset": 4, + "duration": 4, + "pitch": { + "step": "A", + "alter": 0, + "octave": 4 + } + }, + { + "node_id": "tw2-n3", + "kind": "note", + "offset": 8, + "duration": 8, + "pitch": { + "step": "G", + "alter": 0, + "octave": 4 + } + } + ] + } + ] + }, + "target": { + "target_node_id": "tw1-n1", + "target_voice_id": "1" + }, + "rules": { + "allow_patch_ops": [ + "change_to_pitch", + "change_duration", + "split_note", + "delete_note" + ], + "allowed_edit_fields": [ + "pitch", + "duration" + ], + "forbid_cross_voice_edit": true, + "forbid_backup_forward_boundary_cross": true, + "forbid_chord_target": true, + "forbid_grace_target": true, + "forbid_cue_target": true + } +} diff --git a/docs/spec/ABC_IO.md b/docs/spec/ABC_IO.md index 053cb6e..018c59a 100644 --- a/docs/spec/ABC_IO.md +++ b/docs/spec/ABC_IO.md @@ -13,6 +13,53 @@ The module is responsible for: --- +## Positioning + +`mikuscore` handles ABC in three layers: + +- **Standard ABC surface** + - ordinary ABC headers, body tokens, and supported musical decorations +- **Compatibility behavior** + - pragmatic parsing support for real-world ABC variants commonly seen in `abcjs` / `abcm2ps` style inputs +- **`mikuscore` extension metadata** + - `%@mks ...` comment lines used to preserve roundtrip-relevant information that plain ABC cannot carry reliably + +This distinction is important: + +- compatibility behavior is about accepting real-world ABC variance without failing unnecessarily +- `mikuscore` extension metadata is not part of the standard ABC musical surface +- `%@mks ...` lines are `mikuscore`-specific comment hints for restoration and roundtrip support + +`mikuscore` treats ABC as a supported score interchange format. +Compatibility behavior and extension metadata are support mechanisms for practical import/export and roundtrip stability, not an indication that ABC support is merely experimental. + +### Practical ecosystem note + +In practice, ABC support cannot be defined only by a narrow reading of the base grammar. +Real-world ABC interchange is also shaped by de facto ecosystem behavior, especially inputs and conventions commonly accepted by tools such as `abcjs` and `abcm2ps`. + +For `mikuscore`, these ecosystems are not treated as normative specifications by themselves. +However, they are treated as important evidence for what counts as common, practical ABC interchange behavior in the wild. + +This means: + +- the formal ABC surface remains the baseline reference +- behavior widely accepted by `abcjs` / `abcm2ps` may be adopted as compatibility behavior even when it is better described as de facto practice than narrow core grammar +- such compatibility acceptance must still be documented explicitly in spec text and tests +- de facto compatibility is not the same thing as accepting arbitrary malformed input + +Because of that, `mikuscore` uses the following stance: + +- preserve a clear distinction between standard ABC surface syntax and compatibility-only behavior +- accept widely used real-world variants when their musical intent is clear enough +- avoid silently treating non-body directive leftovers as body note text +- reject or warn on inputs that remain structurally ambiguous or musically unclear + +The goal is not "accept everything". +The goal is to accept broadly used ABC variants without unnecessary failure, while still failing clearly on genuinely broken or uninterpretable input. + +--- + ## Public API ### Types @@ -44,25 +91,225 @@ The module is responsible for: ## ABC -> internal parse (`AbcCompatParser.parseForMusicXml`) -## Input structure +### Accepted input layers + +The parser accepts three categories of input: -Parser reads: +#### 1. Standard ABC surface - headers (`X:`, `T:`, `C:`, `M:`, `L:`, `K:`) +- user-defined decoration header (`U:`) for single-character decoration aliases on import - voice directives (`V:` with optional `name`, `clef`, `transpose`) -- optional `%%score` voice ordering directive -- optional mikuscore metadata comments (`%@mks key ...`, `%@mks measure ...`, `%@mks transpose ...`) - body note/rest/chord tokens -## Compatibility behavior +### Current information-field stance + +`mikuscore` currently treats the following as the supported core ABC field subset: + +- `X:` +- `T:` +- `C:` +- `M:` +- `L:` +- `K:` +- `Q:` +- `V:` (with the bounded voice-property subset documented separately) + +Fields outside that core subset are not currently part of the supported ABC interchange target. +They may be lexically tolerated by the header scan, but they are not claimed as semantically supported import/export behavior. + +### Current inline-field stance + +`mikuscore` currently treats the following as the supported inline-field subset: + +- `[K:...]` +- `[M:...]` +- `[L:...]` +- `[Q:...]` +- `[V:...]` + +Inline fields outside that subset are not currently part of the supported ABC interchange target. +They are skipped with warnings rather than treated as semantically supported behavior. + +### Current body-side standalone core-field compatibility + +`mikuscore` also accepts a narrow compatibility subset where body-side standalone core field lines or tokens are treated like the corresponding inline fields after body parsing has begun: + +- `K:...` +- `M:...` +- `L:...` +- `Q:...` + +This is compatibility behavior, not a broad claim that arbitrary information fields may freely appear as standalone body syntax. + +Body-side standalone single-letter fields outside that bounded compatibility subset are skipped with warnings rather than silently treated as supported body semantics. + +### Current field-continuation stance + +`mikuscore` does not currently treat continued information-field lines as part of the supported ABC interchange subset. + +This means: + +- field continuation is currently unsupported +- lexical tolerance of adjacent header text does not count as continuation support +- continuation support is intentionally deferred unless practical input evidence makes it necessary +- unsupported continued header-field text should be skipped with warnings rather than falling through into body note/rest parsing + +However, `mikuscore` now applies one bounded compatibility rule for body parsing: + +- a trailing body-line continuation marker `\` is stripped before body tokenization +- this avoids treating the continuation marker itself as note/rest text in the next parse stage +- this does not by itself promote full continued-information-field semantics to supported status + +### Current symbol-line stance + +`mikuscore` does not currently treat standard `s:` symbol lines as part of the supported ABC interchange subset. + +This means: + +- `s:` symbol lines are out of practical scope for the present bounded target +- there is no current import/export or roundtrip support claim for them +- this area stays out of scope unless practical input demand changes priority + +#### 2. Compatibility behavior + +- optional `%%score` voice ordering / staff-grouping directive +- unsupported `%%...` directives are skipped with warnings rather than silently treated as supported semantics +- partial/legacy patterns accepted for practical compatibility +- de facto ecosystem conventions commonly accepted by `abcjs` / `abcm2ps` may be supported when the intended musical meaning is clear and implementation behavior can be specified +- trailing body-line continuation marker `\` may be tolerated so it does not leak into note/rest parsing +- body-side standalone core field lines or tokens `K:` / `M:` / `L:` / `Q:` may be accepted as compatibility shorthand for the corresponding inline fields once body parsing has begun +- unsupported standalone body-side single-letter fields or tokens should be skipped with warnings rather than silently treated as supported body semantics +- `V:` directive tails may accept recognized bare clef names / aliases such as `bass`, `treble`, `alto`, `tenor`, `c3`, `c4` as compatibility shorthand for `clef=...` +- unsupported inline text / decoration forms may be skipped with warnings +- overlay marker `&` is imported by splitting one ABC body stream into synthetic overlay voices +- current overlay limitation: these synthetic overlay voices become separate MusicXML parts rather than one part with multiple synchronized voices +- standalone octave marks may be tolerated in unsupported positions + +Current `%%score` handling is intentionally bounded: + +- plain ordered ids continue to control voice order +- parenthesized groups such as `%%score (1 2)` are imported as one MusicXML part with multiple staves +- this currently targets practical multi-staff grouping, not full ABC staff-layout parity +- `brace` / `bracket` / `staves` and related broader `V:` property semantics remain outside the supported standard subset + +#### 3. `mikuscore` extension metadata + +- optional `mikuscore` metadata comments: + - `%@mks key ...` + - `%@mks measure ...` + - `%@mks transpose ...` + +These `%@mks ...` comments are not treated as standard ABC musical notation. +They are extension metadata used to improve roundtrip restoration. + +### Compatibility behavior Parser is intentionally lenient for real-world ABC: - ignores standalone octave marks in unsupported positions +- strips trailing body-line continuation `\` before body tokenization +- accepts body-side standalone `K:` / `M:` / `L:` / `Q:` lines or tokens as compatibility shorthand for the corresponding inline fields +- skips stray body-side continuation markers `\` with warnings when they still appear in token flow +- skips unsupported body-side word-token leftovers with warnings when they are clearly not note/rest syntax, including bounded lower-case word leftovers +- skips stray body-side number tokens with warnings when they are clearly not attached note-length syntax +- skips notes/chord-notes/grace-notes with unsupported octave range using warnings rather than failing the whole tune parse +- skips notes/chords/grace-notes with invalid zero-length results using warnings rather than failing the whole tune parse +- skips malformed accidental leftovers with warnings when they do not lead into a valid note/rest token +- skips bounded stray body punctuation leftovers such as `;`, `` ` ``, `?`, `@`, `#`, `$`, and `*` with warnings rather than failing note/rest parsing - skips unsupported decorations/inline strings with warnings - accepts partial/legacy patterns where possible +- may accept de facto ecosystem forms seen in `abcjs` / `abcm2ps`-style inputs when they are structurally recognizable and musically interpretable +- should not pass unknown directive-tail fragments through as ordinary body note text +- should warn on unsupported bare `V:` tail words instead of letting them fail later as body note/rest parsing errors + +### Current overlay policy + +`mikuscore` currently treats ABC overlay syntax `&` as bounded import-side compatibility behavior: + +- accepted on import +- preserved by expanding overlay material into synthetic overlay voices / parts +- not currently claimed as faithful one-part multi-voice preservation +- not currently claimed as exact standard ABC `&` roundtrip preservation + +This is an intentional scope boundary, not an accidental gap. + +### Current beam / whitespace policy + +`mikuscore` currently uses a bounded beam policy: + +- on import, inter-note whitespace between beamable notes is treated as an explicit beam-break hint +- this affects the current voice/measure parse stream and is used when forming MusicXML beam state +- beat boundaries still split implicit beam runs even when there is no whitespace +- on export, ABC is not currently generated with beam-specific spacing preservation; note tokens are emitted in ordinary measure text and original spacing is not replayed verbatim + +This means: + +- beam-break intent is preserved on ABC import into MusicXML +- exact source whitespace used for beam layout is not currently treated as canonical roundtrip data + +### Current supported `V:` property subset + +In the standard ABC path, `mikuscore` currently treats the following `V:` properties as the supported working subset: + +- `name=...` + - supported on import and export +- `clef=...` + - supported on import and export for the common working subset: `treble`, `bass`, `alto`, `tenor`, `c3`, `c4` +- `transpose=...` + - accepted on import as a bounded chromatic transpose value + - not currently emitted back as standard `V:` metadata on export + - roundtrip export currently relies on `%@mks transpose ...` extension metadata instead + +In other words: + +- standard `V:` transpose support is currently `import-partial` +- transpose-preserving roundtrip is currently `extension-assisted` through `%@mks transpose ...` + +The following standard voice-property family is currently outside the supported standard subset and should be treated as unsupported unless documented otherwise: + +- `staves` +- `brace` +- `bracket` +- `merge` +- `middle` +- `gchords` + +Current handling for unsupported standard `V:` properties: + +- unsupported `key=value` voice-property tokens are skipped in the standard path +- they should produce warnings rather than silently expanding the supported subset +- they should not be reinterpreted as body note text + +Compatibility note: -## Supported musical tokens +- recognized bare clef shorthand such as `V:2 bass` is accepted as compatibility behavior, not as a separate standard property form + +### Current clef / transposition stance + +`mikuscore` currently uses a bounded clef / transposition policy: + +- supported standard clef subset in `V:` metadata: + - `treble` + - `bass` + - `alto` + - `tenor` + - `c3` + - `c4` +- supported compatibility behavior: + - recognized bare clef shorthand such as `V:2 bass` +- partial / extension-assisted: + - standard `V:` transpose is currently import-partial + - transpose-preserving roundtrip currently relies on `%@mks transpose ...` + +Current limits: + +- broader standard clef forms beyond the current recognized subset are not currently claimed +- full standard `V:` transpose export parity is not currently claimed + +### Supported musical tokens + +#### Standard musical content - notes and rests - accidentals (`^`, `_`, `=`) @@ -72,10 +319,84 @@ Parser is intentionally lenient for real-world ABC: - tuplets (`(n[:q][:r]`) - broken rhythm (`>` / `<`) - barlines -- decorations: `!trill!`, `!turn!`, `!invertedturn!`, `!staccato!` + +#### Current quoted chord-symbol subset + +Quoted text attached to notes is split between: + +- harmonic chord-symbol parsing into MusicXML `harmony` +- ordinary quoted annotation text into MusicXML direction words + +Current supported harmonic quoted-chord subset: + +- root / bass spelling + - `A`-`G` + - optional `#` / `b` + - optional slash bass with the same spelling subset +- supported suffixes + - `` + - `m`, `min` + - `6`, `m6`, `min6` + - `7`, `9`, `11`, `13` + - `maj7`, `maj9` + - `m7`, `min7`, `m9`, `min9` + - `7sus4`, `sus4`, `sus2` + - `dim`, `dim7`, `aug`, `+`, `m7b5`, `min7b5`, `ø` + +Current fallback rule: + +- quoted text outside that inventory is treated as annotation/words, not forced into MusicXML `harmony` + +### Current annotation stance + +`mikuscore` currently uses a bounded annotation policy for quoted non-harmonic text: + +- common quoted non-harmonic text attached to notes is supported as MusicXML direction words / annotations +- quoted text that does not fit the supported harmony inventory falls back to annotation/words rather than being forced into `harmony` +- this bounded subset is supported as practical interchange behavior + +Current limits: + +- broader annotation placement semantics are not currently claimed as preserved +- the current support target is ordinary quoted annotation text, not full ABC annotation behavior parity + +### Current order-of-constructs stance + +`mikuscore` currently uses a bounded practical-acceptance stance for ABC construct ordering: + +- common construct orderings already handled by the parser are supported +- practical acceptance of structurally recognizable real-world ABC is preferred over strict rejection based only on narrower construct-order readings +- unsupported order cases should fail only when they become structurally ambiguous or break directive/body interpretation + +Current limits: + +- full formal conformance to every standard order-of-constructs nuance is not currently claimed +- exact acceptance parity with every ABC implementation is not currently claimed +- lexical tolerance of unusual ordering does not by itself widen the supported subset unless the behavior is documented + +#### Supported decorations and grace forms + +- decorations: `!trill!` (also accepts `!tr!` / `!triller!` on import), long-trill delimiters `!trill(!` / `!trill)!`, `!turn!` (also accepts `!lowerturn!` as inverted-turn on import), `!turnx!`, `!invertedturn!`, `!invertedturnx!`, `!mordent!`/`!pralltriller!` (including `!prall!`, `!pralltrill!`, `!uppermordent!`, `!lowermordent!`, `!invertedmordent!`, `!inverted-mordent!` aliases), `!schleifer!`, `!shake!`, `!roll!` (also accepts `!arpeggio!` / `!arpeggiate!` on import), `!slide!` (canonical import/export for MusicXML slide start; explicit stop still uses `mikuscore` extension `!slide-stop!`), phrase marks `!shortphrase!`, `!mediumphrase!`, `!longphrase!` (roundtrip via MusicXML `other-articulation`), `!staccato!` (also accepts `!stacc!` / `!stac!` on import), `!wedge!`/`!staccatissimo!` (also accepts `!spiccato!` on import), `!accent!` (also accepts `!>!` / `!emphasis!` on import), `!tenuto!`, `!stress!`, `!unstress!`, `!fermata!` / `!invertedfermata!` (also accepts `!inverted fermata!` on import), `!marcato!` (also accepts `!strong accent!` / `!strongaccent!` / `!strong-accent!` on import), `!breath!` (also accepts `!breathmark!` / `!breath mark!` / `!breath-mark!` on import), `!caesura!`, `!segno!`, `!coda!`, `!fine!`, `!dacapo!` (also accepts `!da capo!` / `!da-capo!` / `!D.C.!` on import), `!dalsegno!` (also accepts `!dal segno!` / `!dal-segno!` / `!D.S.!` on import), `!tocoda!` (also accepts `!to coda!` / `!to-coda!` on import), `!dacoda!`, fingering decorations `!0!`, `!1!`, `!2!`, `!3!`, `!4!`, `!5!` (single-digit technical fingering export prefers these standard forms over `!fingering:TEXT!`), wedge decorations `!crescendo(!`, `!crescendo)!`, `!diminuendo(!`, `!diminuendo)!` (also accepts aliases `!cresc(!`, `!cresc)!`, `!dim(!`, `!dim)!`, `!decresc(!`, `!decresc)!`, `!decrescendo(!`, `!decrescendo)!`, `!<(!`, `!<)!`, `!>(!`, `!>)!` on import), dynamics `!pppp!`, `!ppp!`, `!pp!`, `!p!`, `!mp!`, `!mf!`, `!f!`, `!ff!`, `!fff!`, `!ffff!`, `!fp!`, `!fz!`, `!rfz!`, `!sf!`, `!sfp!`, `!sfz!`, `!upbow!` / `!downbow!` (also accepts `!up bow!` / `!down bow!` / `!up-bow!` / `!down-bow!` on import), `!doubletongue!` / `!tripletongue!` (also accepts `!double tongue!` / `!triple tongue!` / `!double-tongue!` / `!triple-tongue!` on import), `!heel!` / `!toe!` (also accepts `!heel mark!` / `!toe mark!` on import), `!open!` (also accepts `!openstring!` / `!open string!` / `!open-string!` on import), `!snap!` (also accepts `!snappizzicato!` / `!snap pizzicato!` / `!snap-pizzicato!` on import), `!harmonic!`, `!stopped!` (including `!plus!`, `!stopped horn!`, `!stopped-horn!` aliases), `!thumb!` (also accepts `!thumbposition!` / `!thumb-position!` / `!thumbpos!` / `!thumb pos!` / `!thumb position!` on import) +- standard shorthand decoration symbols on import: `~` (roll), `H` (fermata), `L` (accent), `M` (lowermordent), `O` (coda), `P` (uppermordent), `S` (segno), `T` (trill), `u` (up-bow), `v` (down-bow) +- mikuscore extension decorations: `!delayedturn!`, `!delayedinvertedturn!`, `!tremolo-single-N!`, `!tremolo-start-N!`, `!tremolo-stop-N!`, `!gliss-start!`, `!gliss-stop!`, `!slide-start!` (legacy import alias for standard `!slide!`), `!slide-stop!`, `!rehearsal:TEXT!`, `!fingering:TEXT!`, `!string:TEXT!`, `!pluck:TEXT!` - grace groups `{...}` including slash grace variant (`{/g}`) -## Parse result characteristics +#### Pending standard-decoration policy notes + +- `!arpeggio!` and `!roll!` + - import compatibility remains broad + - canonical export should prefer `!arpeggio!` for the current MusicXML `` carrier + - `!roll!` remains an accepted compatibility alias on import unless a distinct roundtrip carrier is added +- `!+!` / `!plus!` + - current support is a narrow technical/stopped-style interpretation + - canonical export remains `!stopped!`, not `!+!` / `!plus!` +- mordent-family aliases + - import aliases stay broad + - canonical export remains `!mordent!` for lower mordent and `!pralltriller!` for upper/inverted mordent +- `!slide!` + - current standard support is start-side only; explicit stop currently remains a `mikuscore` extension via `!slide-stop!` + +### Parse result characteristics Returned structure includes: @@ -99,7 +420,7 @@ Fatal parse failures (e.g., no body, no notes/rests, unrecoverable token parse) ## MusicXML -> ABC (`exportMusicXmlDomToAbc`) -## Header mapping +### Standard ABC output Exports: @@ -110,19 +431,20 @@ Exports: - `L:1/8` (fixed) - `K:` from key fifths/mode conversion -## Voice / part mapping +### Voice / part mapping - each MusicXML `part` maps to `V:` section - voice id is sanitized from part id - part name exported as `name="..."` - clef mapped to ABC clef suffix when recognized -## Note export policy +### Standard musical export policy - supports rests, pitch notes, chords, durations, ties - supports tuplet roundtrip export (`(n:q:r` style) from MusicXML time-modification/tuplet notations - supports ornament export/import mapping: - `trill-mark` / `wavy-line(start)` <-> `!trill!` + - extended trill line start/stop via `trill-mark` + `wavy-line(type="start")` / `wavy-line(type="stop")` <-> `!trill(!` / `!trill)!` - `turn` <-> `!turn!` - `inverted-turn` <-> `!invertedturn!` - supports grace slash mapping: @@ -131,10 +453,17 @@ Exports: - suppresses redundant naturals in-context - emits required naturals where key/measure context differs - serializes each part as ABC measure stream (`|` separated) -- emits mikuscore metadata lines for lossless roundtrip: - - `%@mks key voice=... measure=... fifths=...` - - `%@mks measure voice=... measure=... number=... implicit=... [repeat=...] [times=...]` - - `%@mks transpose voice=... chromatic=... [diatonic=...]` +- supported standard ornament/decorations now include `trill`, `turn`, `invertedturn`, `mordent`, `pralltriller`, `schleifer`, `shake`, `roll`, selected articulations/technicals/dynamics, and selected jump markers + +### `mikuscore` extension metadata on export + +For lossless or safer roundtrip behavior, `mikuscore` may emit extension comment lines after the ABC body: + +- `%@mks key voice=... measure=... fifths=...` (legacy/import-compatibility path; standard export now prefers `K:` / inline `[K:...]`) +- `%@mks measure voice=... measure=... number=... implicit=... [times=...] [ending-stop=... ending-type=discontinue]` +- `%@mks transpose voice=... chromatic=... [diatonic=...]` + +These lines are `mikuscore` extension metadata, not part of the standard ABC musical surface. --- @@ -145,6 +474,8 @@ Exports: 1. parse ABC via `AbcCompatParser.parseForMusicXml` 2. transform parsed result into MusicXML 4.0 document text +### Restoration policy + Generation policy: - fixed divisions: `960` @@ -153,22 +484,118 @@ Generation policy: - writes first-measure attributes (key/time/clef and optional transpose) - preserves tie semantics using both `` and `` - restores tuplet semantics using both `` and `` -- restores measure metadata (`number`, `implicit`) and repeat barlines from `%@mks measure` +- restores standard repeat/ending barlines and key changes from ABC surface syntax, and restores non-standard measure metadata (`number`, `implicit`, extra repeat hints when needed) from `%@mks measure` + +### Current repeat / ending policy + +`mikuscore` currently uses this bounded repeat / ending policy: + +- standard ABC surface is preferred for common cases: + - `|:` + - `:|` + - `[1`, `[2` + - `|1`, `:|2` +- `%@mks measure ...` is used only for edge semantics not directly represented in the current standard export path, including: + - backward repeat counts beyond the ordinary case via `times=...` + - ending stop type `discontinue` via `ending-stop=... ending-type=discontinue` + +This means: + +- common repeat / ending forms are standard-path behavior +- some edge semantics are currently extension-assisted rather than pure standard-surface roundtrip behavior + +### Current slur policy + +`mikuscore` currently uses a bounded slur policy: + +- ABC `(` / `)` slur markers are supported in common note-to-note cases +- MusicXML note-level slur start/stop presence is exported/imported in simple cases +- slur handling is currently presence-based rather than identity-based + +Current limits: + +- slur numbering / nested-slur identity is not currently claimed as preserved +- a slur stop without a preceding non-rest note is treated as unsupported and yields a warning in the ABC import path +- ties are tracked separately and have stronger preservation guarantees than generic slur span identity + +### Current tuplet stance + +`mikuscore` currently uses a bounded tuplet policy: + +- common ABC tuplet syntax `(n[:q][:r])` is supported in ordinary note sequences +- MusicXML roundtrip through `` and note-level `` start/stop is supported in the current path +- common explicit tuplet export such as `(3:2:3` is supported + +Current limits: + +- broader ratio/edge semantics beyond the current tested subset are not currently claimed +- broader cross-measure or more complex tuplet-span semantics are not currently claimed + +### Current lyric stance + +`mikuscore` currently uses a bounded lyric policy for ABC `w:` underlay: + +- common `w:` lyric import/export is supported +- common single-verse lyric alignment in ordinary note sequences is supported +- ordinary hyphenated lyric tokens are supported in the current `w:` path + +Current limits: + +- full lyric alignment nuance across rests, spacers, grace, and more complex spacing is not currently claimed +- full multi-verse behavior is not currently claimed +- verse numbering semantics are not currently claimed + +### Current ABC 2.2 delta stance + +The following ABC 2.2 decorations are currently supported in a bounded accidental-level subset: + +- `!editorial!` +- `!courtesy!` + +Current bounded interpretation: + +- `!editorial!` + - applies to the following explicit accidental in the ABC import path + - maps to MusicXML `accidental editorial="yes"` +- `!courtesy!` + - applies to the following explicit accidental in the ABC import path + - maps to MusicXML `accidental cautionary="yes"` + +Current limits: + +- support is intentionally bounded to accidental-level editorial/cautionary flags +- broader engraving/layout semantics beyond those accidental attributes are not currently claimed + +### Current `U:` stance + +`mikuscore` currently treats `U:` as bounded import-first functionality: + +- supported + - single-character user-defined decoration aliases on import + - right-hand side decoration text written as either `!decor!` or `+decor+` +- not currently claimed + - export of `U:` declarations as part of standard ABC roundtrip output + - broader parity for redefinable-symbol semantics beyond the current alias-import subset + +Malformed `U:` declarations are ignored rather than treated as fatal parse errors. - restores transpose (`chromatic`, `diatonic`) from `%@mks transpose` -- emits metadata to `attributes/miscellaneous-field` (`mks:abc-meta-*`) by default; disable with `debugMetadata:false` - inserts a fallback whole-rest note for empty measures +### Debug / investigation metadata + +- emits metadata to `attributes/miscellaneous-field` (`mks:dbg:abc:meta:*`) by default; disable with `debugMetadata:false` + ### Incident analysis using `miscellaneous-field` For ABC import troubleshooting, inspect: -- `part > measure > attributes > miscellaneous > miscellaneous-field[name="mks:abc-meta-count"]` -- `part > measure > attributes > miscellaneous > miscellaneous-field[name^="mks:abc-meta-"]` +- `part > measure > attributes > miscellaneous > miscellaneous-field[name="mks:dbg:abc:meta:count"]` +- `part > measure > attributes > miscellaneous > miscellaneous-field[name^="mks:dbg:abc:meta:"]` Recommended flow: 1. identify the problematic measure/event in the rendered score. -2. inspect corresponding `mks:abc-meta-*` rows in MusicXML. +2. inspect corresponding `mks:dbg:abc:meta:*` rows in MusicXML. 3. compare parsed note facts (`r`, `g`, `ch`, `st`, `al`, `oc`, `dd`, `tp`) against expected ABC intent. --- @@ -194,6 +621,7 @@ Supported mappings: ## Scope notes -- This module is compatibility-oriented and intentionally pragmatic. +- This module is intentionally compatibility-oriented and pragmatic. - It does not aim to be a complete strict ABC standard implementation. -- Behavior prioritizes stable import/export for mikuscore workflows. +- ABC is a supported format in `mikuscore`; behavior prioritizes stable import/export and roundtrip reliability for practical workflows. +- `%@mks ...` comments are `mikuscore` extension metadata for roundtrip support, not standard ABC musical notation. diff --git a/docs/spec/ABC_STANDARD_COVERAGE.md b/docs/spec/ABC_STANDARD_COVERAGE.md new file mode 100644 index 0000000..6555716 --- /dev/null +++ b/docs/spec/ABC_STANDARD_COVERAGE.md @@ -0,0 +1,1013 @@ +# ABC Standard Coverage + +## Purpose + +This document tracks `mikuscore` coverage against the ABC standard at a chapter-by-chapter level. + +Unlike `TODO.md`, this file is intended to be the coverage baseline and completion reference. +Implementation TODO items should be derived from this file, not the other way around. + +## Version Policy + +- Latest formal ABC standard at the time of writing: `2.2` +- Current `mikuscore` audit baseline: `2.1` +- Reason: + - most currently implemented/imported behavior and earlier audit work were organized against the widely used `2.1` chapter structure + - `2.2` additions should be tracked explicitly as deltas, not mixed invisibly into the `2.1` baseline table + +Practical rule: + +- use the `2.1` table below as the main completion baseline +- track `2.2` additions separately in a small delta section +- do not mark a chapter fully `supported` if support depends only on `mikuscore` extensions or de facto compatibility behavior outside the standard surface + +## Status Labels + +- `supported` + - implemented in normal import/export flows with no currently known major gap for the scoped item +- `partial` + - some meaningful support exists, but coverage, semantics, roundtrip, or edge-case behavior is still incomplete +- `unsupported` + - not currently supported in the normal ABC import/export path +- `ext-only` + - behavior exists only through `mikuscore` extension metadata or `mikuscore`-specific decorations, not through standard ABC surface syntax + +## Work-Type Labels + +- `impl` + - mainly an implementation / test / roundtrip task +- `policy` + - mainly a scope or semantics decision that should be written down before implementation +- `mixed` + - requires both a policy decision and follow-up implementation + +## Completion Rule by Work Type + +- `impl` + - complete when implementation, regression tests, and coverage-table status update are all done +- `policy` + - complete when a written decision is recorded here and linked specs / TODO wording are updated accordingly +- `mixed` + - complete when both the policy decision and the implementation/test follow-up are done + +## Reading Rule + +- This is a conservative baseline. +- When there is doubt, the status should be `partial`, not `supported`. +- Coverage is judged from practical `mikuscore` import/export behavior, not from parser token acceptance alone. +- For decoration aliases and compatibility forms, see `docs/spec/ABC_IO.md`. + +## Scope + +- Baseline reference: ABC 2.1 standard +- Delta reference: ABC 2.2 additions relevant to score interchange +- Focus: chapters that materially affect score interchange in `mikuscore` +- Out of scope for now: + - stylesheet directives and formatting-only details that `mikuscore` does not aim to preserve + - prose-only appendices and tutorial material + +## Operating Procedure + +Use this document in the following order: + +1. find the affected ABC chapter or delta item +2. check whether a decomposed sub-area table already exists +3. if not, decompose the chapter before creating implementation TODOs +4. choose the intended result mode: + - `support now` + - `support bounded subset` + - `defer intentionally` + - `out of practical scope` +5. if the work is backlog-sized, assign or reuse an `ABC-COV-*` item +6. only then create or update `TODO.md` +7. after implementation or policy closure, update this document first, then `TODO.md`, then narrower specs such as `docs/spec/ABC_IO.md` + +## Exit Condition For This Document + +`ABC_STANDARD_COVERAGE.md` should be considered "sufficiently prepared" when: + +- every major `partial` / `unsupported` ABC area that matters to score interchange has either: + - a decomposed sub-area table, or + - an explicit statement that it is intentionally out of practical scope +- every remaining major unresolved area has an `ABC-COV-*` backlog item +- each `ABC-COV-*` item has: + - work type + - priority + - done condition + - initial stance +- `TODO.md` has a corresponding execution list derived from those `ABC-COV-*` items + +At that point, further progress should usually happen in `TODO.md`, `docs/spec/ABC_IO.md`, and implementation/tests rather than by endlessly refining this file. + +## Coverage Table + +| ABC 2.1 area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| 3.1 Information fields | partial | Core fields such as `X:`, `T:`, `C:`, `M:`, `L:`, `K:`, `Q:`, and `V:` are handled, but not the full field family or all field semantics. | +| 3.2 Use of fields within the tune body | partial | Inline body fields `[K:...]`, `[M:...]`, `[L:...]`, `[Q:...]`, `[V:...]` are supported, and a narrow compatibility subset also accepts standalone body-side `K:` / `M:` / `L:` / `Q:` lines or tokens. Full field-level parity is not yet claimed. | +| 3.3 Field continuation | unsupported | No complete coverage claim yet. | +| 4.1 Pitch | supported | Ordinary pitch spelling and octave notation are core supported behavior. | +| 4.2 Accidentals | supported | Standard accidental forms are supported, with measure/key-context export rules implemented. | +| 4.3 Note lengths | supported | Standard ABC length tokens are part of the normal path. | +| 4.4 Broken rhythm | supported | `>` / `<` handling is implemented. | +| 4.5 Rests | supported | Standard rests are supported. | +| 4.6 Clefs and transposition | partial | Common clefs and some `V:`-level transpose handling exist, but full standard coverage and exact parity are not yet claimed. | +| 4.7 Beams | partial | Import recognizes whitespace as beam-break intent, but export/render behavior still reconstructs beams mainly from durations. | +| 4.8 Repeat/bar symbols | partial | Standard repeat/barline handling is substantially improved, but full coverage is not yet declared. | +| 4.9 First and second repeats | partial | Common alternate-ending forms are supported, but broader variant-ending coverage still needs a stricter audit. | +| 4.10 Variant endings | partial | Standard surface forms now work for common cases, but full closure is not yet claimed. | +| 4.11 Ties and slurs | partial | Ties are solid in common paths; slur reconstruction and exact span semantics still need care. | +| 4.12 Grace notes | supported | Standard grace groups and slash grace are supported. | +| 4.13 Tuplets | partial | Core tuplet parsing/export works, but full standard nuance still needs audit closure. | +| 4.14 Decorations | partial | Large portions of the standard set are now covered, but the full decoration inventory is not yet complete. | +| 4.15 Symbol lines | unsupported | No current standard `s:` symbol-line support claim. | +| 4.16 Redefinable symbols | partial | `U:` single-character decoration aliases import through normal decoration parsing, but full support is not yet claimed. | +| 4.17 Chords and unisons | supported | Standard chord-note group syntax is supported in ordinary paths. | +| 4.18 Chord symbols | partial | Common quoted chord symbols are mapped, but broader harmony quality coverage is still incomplete. | +| 4.19 Annotations | partial | Quoted non-harmonic text is partially mapped, but broader annotation behavior is not yet closed. | +| 4.20 Order of abc constructs | partial | Many common orders are accepted, but there is no complete conformance claim yet. | +| 5.1 Alignment | partial | Lyrics alignment support exists, but not all standard alignment nuance is yet audited. | +| 5.2 Verses | partial | `w:` underlay works in common cases, but full multi-verse coverage is not yet claimed. | +| 5.3 Numbering | unsupported | No complete support claim yet. | +| 6.1 Typesetting | unsupported | Formatting/typesetting directives are not a current parity target. | +| 6.2 Playback | unsupported | ABC playback semantics are not a standard-coverage target for `mikuscore`. | +| 7.1 Voice properties | partial | `V:` handling exists for common voice metadata, but standard voice-property breadth is not fully covered. | +| 7.2 Breaking lines | unsupported | Line-breaking semantics are not a current preserved interchange feature. | +| 7.3 Inline fields | partial | Core inline field support exists, but broader field coverage remains partial. | +| 7.4 Voice overlay | partial | `&` imports into synthetic overlay voices, but this is not yet faithful one-part multi-voice preservation. | + +## Decomposed Coverage + +This section breaks selected `partial` chapters into implementation-sized coverage units. +Start here when converting coverage findings into concrete TODO items. + +### 3. Information Fields + +#### 3.1 Information fields + +| Field group | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Core identification / title / attribution: `X:`, `T:`, `C:` | supported | Supported in ordinary import/export flows. | +| Core musical defaults: `M:`, `L:`, `K:`, `Q:` | supported | Supported in ordinary import/export flows, including inline-core variants where implemented. | +| Voice field: `V:` | partial | Common voice metadata is supported, but full property breadth is not yet covered. | +| Other standard fields outside the current core subset | unsupported | They may be lexically accepted as inert header text, but no supported semantic import/export claim is made for them. | + +### 3.1 Information-Field Policy Notes + +Current bounded subset for `mikuscore` header-field support: + +- supported core subset + - `X:`, `T:`, `C:` + - `M:`, `L:`, `K:`, `Q:` + - `V:` remains covered separately under the voice-property policy +- unsupported non-core field family + - standard information fields outside the current core subset are not part of the supported ABC interchange target + - they may be lexically tolerated in the header scan, but `mikuscore` does not currently claim semantic import/export support for them +- export policy + - standard ABC export emits only the current core subset and `V:` sections needed by the current bounded target + +Practical result mode for `ABC-COV-001`: + +- `support bounded subset` +- keep the supported header-field family explicit +- do not treat lexically accepted but semantically inert fields as supported ABC coverage + +#### 3.2 Use of fields within the tune body + +| Inline field group | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Core inline fields: `[K:...]`, `[M:...]`, `[L:...]`, `[Q:...]`, `[V:...]` | supported | These are supported in the current standard path. | +| Standalone body-side core field lines/tokens: `K:...`, `M:...`, `L:...`, `Q:...` | partial | Accepted as bounded compatibility shorthand for the corresponding inline fields after body parsing has begun. | +| Broader inline-field family beyond the current core subset | unsupported | Unsupported inline fields are skipped with warnings rather than treated as semantically supported. | + +### 3.2 / 7.3 Inline-Field Policy Notes + +Current bounded subset for `mikuscore` inline-field support: + +- supported + - `[K:...]` + - `[M:...]` + - `[L:...]` + - `[Q:...]` + - `[V:...]` +- compatibility-only + - standalone body-side `K:...` + - standalone body-side `M:...` + - standalone body-side `L:...` + - standalone body-side `Q:...` + - these may appear as lines or tokens and are treated as shorthand for the corresponding inline fields only after body parsing has begun +- unsupported + - broader inline-field family beyond that core subset + - other standalone body-side single-letter fields/tokens outside the bounded compatibility subset +- handling rule + - unsupported inline fields are skipped with warnings + - unsupported standalone body-side single-letter fields/tokens are also skipped with warnings + - lexical recognition of an inline field does not count as semantic support + +Practical result mode for `ABC-COV-002`: + +- `support bounded subset` +- keep the inline-field subset explicit at `[K/M/L/Q/V]` +- require deliberate policy work before expanding beyond that subset + +#### 3.3 Field continuation + +| Area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Continued information-field lines | unsupported | No current support claim or dedicated reconstruction policy. | + +### 3.3 Field-Continuation Policy Notes + +Current policy for `mikuscore`: + +- unsupported in the present bounded ABC target + - continued information-field lines are not part of the supported interchange subset + - lexical tolerance of adjacent header text does not count as continuation support + - unsupported continued header-field text should be skipped with warnings rather than later misparsed as body note/rest text +- bounded compatibility safeguard + - a trailing body-line continuation marker `\` is stripped before body tokenization so it does not fall through into note/rest parsing + - this is not a full support claim for continued information-field semantics +- intentionally deferred + - field continuation will not be treated as planned work unless practical input evidence makes it necessary +- rationale + - current core field subset works without continuation support + - continuation support looks low-value relative to other practical ABC interoperability gaps + +Directive-handling note: + +- `%%score` is the current supported working directive subset +- broader `%%...` directive families remain unsupported +- unsupported directives should be skipped with warnings rather than silently treated as supported semantics + +Body-token safety note: + +- stray body-side continuation markers `\` should be skipped with warnings rather than reaching note/rest parsing as unknown tokens +- unsupported body-side word-token leftovers should be skipped with warnings when they are clearly outside note/rest syntax, including bounded lower-case word leftovers +- stray body-side number tokens should be skipped with warnings when they are clearly outside attached note-length syntax +- notes, chord-notes, or grace-notes with unsupported octave range should be skipped with warnings rather than failing the whole tune parse +- notes, chords, or grace-notes with invalid zero-length results should be skipped with warnings rather than failing the whole tune parse +- malformed accidental leftovers should be skipped with warnings when they do not lead into a valid note/rest token +- bounded stray body punctuation leftovers such as `;`, `` ` ``, `?`, `@`, `#`, `$`, and `*` should be skipped with warnings rather than failing note/rest parsing + +Practical result mode for `ABC-COV-003`: + +- `defer intentionally` +- keep field continuation explicitly outside the current supported subset unless real-world demand changes that priority + +### 4.6 Clefs and Transposition + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Common clefs in `V:` metadata (`treble`, `bass`, `alto`, `tenor`, `c3`, `c4`) | supported | Common working set is supported, including compatibility shorthand on import. | +| Broader standard clef forms and exact parity | partial | Full standard breadth and export parity are not yet closed. | +| Voice-level transpose handling | partial | Some `V:`-level transpose behavior exists, but full standard coverage is not yet claimed. | + +### 4.6 Clef / Transposition Policy Notes + +Current policy for `mikuscore`: + +- supported in the bounded subset + - common standard `V:` clef values: `treble`, `bass`, `alto`, `tenor`, `c3`, `c4` + - compatibility shorthand import such as bare `V:2 bass` + - current clef export for the common recognized subset +- partial / extension-assisted + - standard `V:` transpose is import-partial in the current path + - transpose-preserving roundtrip currently relies on `%@mks transpose ...` +- intentionally not claimed + - broader standard clef breadth or exact parity beyond the current recognized subset + - full standard `V:` transpose parity on export +- rationale + - the common working clef subset already covers practical interchange cases seen in current inputs + - explicit boundary-setting is clearer than implying broader clef/transpose parity than the implementation actually provides + +Practical result mode for `ABC-COV-004`: + +- `support bounded subset` +- keep the current common clef subset and extension-assisted transpose story explicit +- do not claim broader clef/transpose parity beyond the current recognized subset + +### 4.7 Beams + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Duration-based beam reconstruction | supported | Normal export reconstructs beams from note values. | +| Whitespace as explicit beam-separation intent | partial | Import recognizes it as a beam-break hint within a voice/measure beam run, but export does not preserve original ABC spacing textually. | +| Exact source whitespace preservation for beam grouping | unsupported | Original ABC inter-note spacing is not currently treated as canonical roundtrip data. | + +### 4.7 Beam Policy Notes + +Current bounded subset for `mikuscore`: + +- import side + - whitespace between beamable notes is treated as an explicit beam-break hint + - this hint applies within the current voice and measure + - beat boundaries still split implicit beam runs even without whitespace +- export side + - canonical export does not currently encode beam grouping through preserved ABC spacing patterns + - exported ABC uses ordinary token spacing and leaves beam reconstruction largely to downstream ABC consumers +- roundtrip claim + - `mikuscore` currently preserves beam-break intent on ABC import into MusicXML + - `mikuscore` does not currently claim export-side preservation of original ABC whitespace used only as beam layout intent + +Practical result mode for `ABC-COV-005`: + +- `support bounded subset` +- preserve import-side beam-break interpretation in the current MusicXML/ABC interchange level +- do not treat exact original inter-note spacing as canonical interchange data unless a future extension carrier is introduced + +### 4.8-4.10 Repeat Structure + +#### 4.8 Repeat / bar symbols + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Common repeat barlines | supported | Standard repeat/barline handling works in common cases. | +| Repeat counts beyond ordinary `:|` behavior | partial | Backward repeat is supported in the standard surface; explicit repeat counts beyond the ordinary case currently rely on `%@mks measure ... times=...` extension metadata. | +| Broader repeat/barline variants and edge reconstruction | partial | Full closure is not yet claimed. | + +#### 4.9 First and second repeats + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Common first/second ending syntax (`[1`, `[2`, `|1`, `:|2`) | supported | Common surface forms are supported. | +| Broader alternate-ending coverage and edge forms | partial | Full closure is not yet claimed. | + +#### 4.10 Variant endings + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Common variant-ending surface syntax | supported | Common standard syntax works in the current path. | +| Ending stop type `discontinue` | partial | Ordinary start/stop endings are supported in the standard surface; `discontinue` currently relies on `%@mks measure ... ending-stop=... ending-type=discontinue` extension metadata. | +| Broader variant-ending semantics | partial | Full semantics and edge-case coverage remain to be audited. | + +### 4.8-4.10 Repeat / Ending Policy Notes + +Current bounded subset for `mikuscore`: + +- standard ABC surface support + - common repeat barlines: `|:` and `:|` + - common alternate-ending starts/stops: `[1`, `[2`, `|1`, `:|2` +- extension-assisted repeat / ending preservation + - backward repeat counts beyond the ordinary case use `%@mks measure ... times=...` + - ending stop type `discontinue` uses `%@mks measure ... ending-stop=... ending-type=discontinue` +- unsupported or not yet claimed + - broader repeat/barline variants beyond the current common subset + - broader variant-ending semantics beyond ordinary start/stop behavior + +Practical result mode for `ABC-COV-006`: + +- `support bounded subset` +- prefer standard ABC surface syntax for common repeat / ending cases +- use `%@mks measure` only for edge semantics that the current standard export path does not encode directly + +### 4.11 Ties and Slurs + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Tie syntax and common reconstruction | supported | Common tie handling is solid, including whole-chord tie paths. | +| Slur syntax acceptance | supported | Common unnumbered slur start/stop syntax is accepted. | +| Exact slur span reconstruction and edge semantics | partial | Cross-format span behavior still needs care; numbered/nested slur identity and broader edge semantics are not fully preserved. | + +### 4.11 Slur Policy Notes + +Current bounded subset for `mikuscore` slur handling: + +- supported + - ordinary ABC `(` / `)` slur markers in common note-to-note cases + - MusicXML note-level slur start/stop presence in simple cases +- current interpretation limits + - slur handling is currently presence-based, not identity-based + - `mikuscore` does not currently claim faithful preservation of slur numbering, nested slur identity, or other exact span-matching semantics + - ABC slur stop without a preceding non-rest note is treated as unsupported and currently yields a warning +- tie distinction + - ties remain stronger than slurs and are tracked separately; chord ties are preserved more faithfully than generic slur span identity + +Practical result mode for `ABC-COV-007`: + +- `support bounded subset` +- preserve common start/stop slur presence +- do not claim numbered/nested slur identity preservation until a stronger span model is implemented + +### 4.13 Tuplets + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Core tuplet syntax and common roundtrip | supported | Core parse/export works in the current path. | +| Full standard ratio nuance and edge semantics | partial | Full audit closure is not yet complete. | + +### 4.13 Tuplet Policy Notes + +Current policy for `mikuscore`: + +- supported in the bounded subset + - common ABC tuplet syntax `(n[:q][:r])` in ordinary note sequences + - common MusicXML roundtrip through `` and note-level `` start/stop + - common explicit tuplet export such as `(3:2:3` in the current MusicXML -> ABC path +- intentionally not claimed + - full standard nuance for broader ratio/edge semantics beyond the currently tested subset + - broader cross-measure or more complex tuplet-span semantics +- rationale + - core tuplet interchange is already useful and covered by focused regression tests + - the remaining work is edge clarification, not basic support + +Practical result mode for `ABC-COV-008`: + +- `support bounded subset` +- keep common tuplet syntax and current MusicXML roundtrip behavior supported and tested +- do not claim broader ratio/span semantics beyond the current bounded subset + +### 4.14 Decorations (ABC 2.1) + +| Decoration group | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Trill family: `!trill!`, `!trill(!`, `!trill)!` | supported | Standard trill and extended trill start/stop now import/export and roundtrip. | +| Turn family: `!turn!`, `!turnx!`, `!invertedturn!`, `!invertedturnx!` | supported | Standard turn and slashed-turn variants now import/export and roundtrip. | +| Mordent family: `!lowermordent!`, `!uppermordent!`, `!mordent!`, `!pralltriller!` | partial | Import aliases are accepted, but export naming policy and exact semantic distinction still need audit closure. | +| `!roll!` / `!arpeggio!` | supported | Standard import acceptance exists, canonical export now prefers `!arpeggio!` for MusicXML `arpeggiate`, and `!roll!` remains a compatibility alias unless a distinct roundtrip carrier is introduced. | +| Accent family: `!>!`, `!accent!`, `!emphasis!` | supported | Import aliases are accepted and canonical export is stable. | +| Fermata family: `!fermata!`, `!invertedfermata!` | supported | Standard forms are supported in common roundtrip paths. | +| `!tenuto!` | supported | Supported in common import/export paths. | +| Fingering shorthand: `!0!`-`!5!` | supported | Standard fingering shorthand now imports/exports and roundtrips. | +| `!+!` / `!plus!` | partial | Import aliases are accepted, but current standard-path policy is the narrow `stopped` technical interpretation with canonical export `!stopped!`. | +| `!snap!` | supported | Supported in common import/export paths. | +| `!slide!` | partial | Standard slide-start form is supported; explicit stop remains outside the standard surface in current policy and uses `mikuscore` extension `!slide-stop!`. | +| `!wedge!` | supported | Supported through the staccatissimo path. | +| `!upbow!` / `!downbow!` | supported | Standard forms and common aliases are supported. | +| `!open!` | supported | Supported in common import/export paths. | +| `!thumb!` | supported | Supported in common import/export paths. | +| `!breath!` | supported | Supported in common import/export paths. | +| Dynamics: `!pppp!`..`!ffff!`, `!sfz!`, etc. | supported | Standard dynamic marks in the currently enumerated subset import/export and roundtrip. | +| Wedges: `!crescendo(!`, `!crescendo)!`, `!diminuendo(!`, `!diminuendo)!`, symbolic aliases | supported | Standard wedge start/stop and symbolic aliases are supported. | +| Repeat-jump marks: `!segno!`, `!coda!`, `!D.S.!`, `!D.C.!`, `!dacoda!`, `!dacapo!`, `!fine!` | supported | Standard/de facto jump tokens in the current subset import/export and roundtrip. | +| Phrase marks: `!shortphrase!`, `!mediumphrase!`, `!longphrase!` | supported | Standard phrase-mark tokens now import/export and roundtrip via MusicXML `other-articulation` preservation. | + +### 4.14 Standard Shorthand Decoration Symbols + +| Symbol | Status | Current interpretation for `mikuscore` | +|---|---|---| +| `~` | supported | Imports as `roll`. | +| `H` | supported | Imports as `fermata`. | +| `L` | supported | Imports as `accent`. | +| `M` | supported | Imports as lowermordent / `mordent` path. | +| `O` | supported | Imports as `coda`. | +| `P` | supported | Imports as uppermordent / `pralltriller` path. | +| `S` | supported | Imports as `segno`. | +| `T` | supported | Imports as `trill`. | +| `u` | supported | Imports as `up-bow`. | +| `v` | supported | Imports as `down-bow`. | + +### 4.14 Canonical Policy Notes + +These notes are the current canonical policy for standard-decoration handling. + +- `!arpeggio!` versus `!roll!` + - keep broad import compatibility for both names + - do not claim they are semantically identical + - canonical export for the current MusicXML `` carrier should prefer `!arpeggio!` + - `!roll!` remains accepted on import as compatibility behavior unless a distinct roundtrip carrier is added +- `!+!` / `!plus!` + - accept them on import as aliases into the current `stopped` technical path + - canonical export remains `!stopped!` + - do not currently claim generalized cross-instrument semantics beyond that narrow interpretation +- Mordent-family export naming + - keep broad import alias acceptance + - canonical export for lower mordent remains `!mordent!` + - canonical export for upper/inverted mordent remains `!pralltriller!` +- `!slide!` + - standard support is start-side only in the current policy + - canonical start-side export remains `!slide!` + - explicit stop remains a `mikuscore` extension via `!slide-stop!` + +### 4.15 Symbol Lines + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| `s:` symbol lines | unsupported | No current support claim. | + +### 4.15 Symbol-Line Policy Notes + +Current policy for `mikuscore`: + +- out of practical scope for the present bounded ABC target + - standard `s:` symbol lines are not part of the supported interchange subset + - there is no current import/export or roundtrip support claim for them +- intentionally frozen out of scope unless real input demand changes priority +- rationale + - symbol lines currently look low-value compared with other musical-structure interoperability work + - leaving them unsupported is clearer than implying partial support without a defined preservation model + +Practical result mode for `ABC-COV-010`: + +- `out of practical scope` +- keep `s:` explicitly outside the current bounded support target unless practical demand changes + +### 4.16 Redefinable Symbols + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| `U:` single-character import aliases | supported | Current import path supports user-defined decoration aliases. | +| Broader `U:` parity, export, and exact standard semantics | partial | Current support is import-first; export parity and broader semantics are not claimed. | + +### 4.16 `U:` Policy Notes + +Current bounded subset for `mikuscore`: + +- supported + - import of `U:` single-character decoration aliases + - both `!decor!` and `+decor+` style right-hand side wrappers in the current import path +- intentionally not claimed + - export of `U:` declarations as a standard ABC roundtrip feature + - exact parity for broader redefinable-symbol semantics beyond the current single-character decoration-alias import behavior +- malformed input handling + - malformed `U:` declarations are ignored rather than treated as fatal parse errors + +Practical result mode for `ABC-COV-011`: + +- `support bounded subset` +- keep `U:` as import-first functionality +- do not currently require `U:` export parity for ABC completion claims + +### 4.18 Chord Symbols + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Common harmonic quoted symbols | supported | The current bounded inventory roundtrips through MusicXML `harmony`. | +| Broader quality inventory and edge spelling | partial | Coverage remains incomplete; unsupported chord-like quoted text falls back to annotation/words instead of being forced into `harmony`. | +| Full standard chord-symbol breadth | unsupported | No full support claim yet. | + +### 4.18 Chord-Symbol Policy Notes + +Current bounded subset for `mikuscore` quoted chord-symbol support: + +- supported root spelling + - `A`-`G` + - optional `#` / `b` + - optional slash bass with the same root spelling subset +- supported suffix inventory + - major: empty suffix + - minor: `m`, `min` + - sixths: `6`, `m6`, `min6` + - sevenths / extensions: `7`, `9`, `11`, `13`, `maj7`, `maj9`, `m7`, `min7`, `m9`, `min9` + - suspended / altered common subset: `7sus4`, `sus4`, `sus2` + - diminished / augmented subset: `dim`, `dim7`, `aug`, `+`, `m7b5`, `min7b5`, `ø` +- export policy + - recognized MusicXML harmony kinds are exported back to canonical ABC quoted chord symbols in the current subset + - unsupported harmony kinds are not claimed as standard quoted-chord coverage +- fallback policy + - quoted text outside the supported chord-symbol inventory is treated as annotation/words rather than forced into MusicXML `harmony` + +Practical result mode for `ABC-COV-012`: + +- `support bounded subset` +- keep the recognized quoted-chord inventory explicit and testable +- treat unsupported chord-like quoted text as annotation fallback unless and until the supported inventory is deliberately expanded + +### 4.19 Annotations + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Common quoted non-harmonic text | supported | Common quoted non-harmonic text is mapped as direction words / annotations in the current bounded subset. | +| Broader annotation placement and behavior | unsupported | No full standard support claim yet. | + +### 4.19 Annotation Policy Notes + +Current bounded subset for `mikuscore` annotation handling: + +- supported + - quoted non-harmonic text attached to notes is imported as MusicXML direction words + - MusicXML direction words are exported as quoted ABC annotations in common cases + - quoted text that does not fit the supported chord-symbol inventory falls back to annotation/words +- intentionally not claimed + - broader annotation placement semantics beyond the current note-attached quoted-text / direction-words path + - full parity for all standard annotation positioning/behavior nuances + +Practical result mode for `ABC-COV-013`: + +- `support bounded subset` +- keep quoted non-harmonic text support explicit through the current direction-words path +- do not claim broader annotation semantics beyond that bounded subset + +### 4.20 Order of abc constructs + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Common construct orderings seen in practical ABC | partial | Many common orders work, but there is no complete conformance claim. | +| Full order-of-constructs conformance | unsupported | Not yet audited to closure. | + +### 4.20 Order-of-Constructs Policy Notes + +Current policy for `mikuscore`: + +- supported in the bounded practical sense + - accept the common construct orderings already handled by the current parser + - prefer practical acceptance of structurally recognizable real-world ABC over strict rejection based only on a narrower reading of construct-order rules + - keep the failure boundary at cases that remain structurally ambiguous or that break note/directive interpretation +- intentionally not claimed + - full formal conformance to every standard order-of-constructs nuance + - exact acceptance parity with every ABC implementation for unusual but technically legal construct orderings +- rationale + - the current ABC target is practical interchange, not a fully validated reference implementation of the standard grammar + - the important boundary is to avoid misparsing or silently reclassifying structurally unclear input as supported music content + +Practical result mode for `ABC-COV-014`: + +- `support bounded subset` +- keep broad practical acceptance where the current parser behavior is stable and musically interpretable +- do not claim complete formal order-of-constructs conformance beyond that bounded subset + +### 5. Lyrics + +#### 5.1 Alignment + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Common lyric alignment for `w:` underlay | partial | Works in common cases. | +| Full alignment nuance across rests, spacers, grace, and complex spacing | unsupported | Not yet audited to closure. | + +#### 5.2 Verses + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Single-verse underlay | supported | Common `w:` import path exists. | +| Multi-verse behavior and edge semantics | partial | Not yet fully audited. | + +#### 5.3 Numbering + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Verse numbering semantics | unsupported | No current support claim. | + +### 5.1-5.3 Lyrics Policy Notes + +Current policy for `mikuscore`: + +- supported in the bounded subset + - common `w:` underlay import/export + - common single-verse lyric alignment in ordinary note sequences + - ordinary hyphenated lyric token handling in the current `w:` path +- intentionally not claimed + - full lyric alignment nuance across rests, spacers, grace, and more complex spacing rules + - full multi-verse behavior parity + - verse numbering semantics +- rationale + - current lyric support is useful for common interchange cases and is already exercised by focused tests + - broader lyric semantics should not be implied until alignment and multi-verse behavior are audited more deeply + +Practical result mode for `ABC-COV-015`: + +- `support bounded subset` +- keep common `w:` lyric behavior supported and tested +- do not claim broader lyric alignment, multi-verse, or numbering semantics beyond that subset + +### 7. Multiple Voices + +#### 7.1 Voice properties + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Voice identity / lane selection (`V:id`) | supported | Standard voice selection and per-voice body routing are supported in normal import/export flow. | +| Voice name (`name=...`) | supported | Import/export of `name=...` is supported in the current standard path. | +| Common clef metadata (`clef=treble`, `clef=bass`, `clef=alto`, `clef=tenor`, `clef=c3`, `clef=c4`) | supported | Common working clef subset is supported on import/export; bare clef shorthand is accepted as compatibility behavior. | +| Voice transpose property (`transpose=...`) | partial | Import path accepts a bounded chromatic transpose value, but standard `V:` transpose is not yet emitted on export; export currently relies on `%@mks transpose ...` extension metadata for roundtrip restoration. | +| Extension-assisted voice transpose roundtrip (`%@mks transpose ...`) | ext-only | Voice transpose can be preserved on export/import roundtrip through `mikuscore` extension metadata even where the standard `V:` property is not emitted. | +| Broader standard voice properties (`staves`, `brace`, `bracket`, `merge`, `middle`, `gchords`, etc.) | unsupported | No current support claim in the standard ABC path; grouped multi-staff import is currently driven by bounded `%%score (...)` handling rather than these `V:` properties, and unsupported properties should still be skipped with warnings. | +| Full standard voice-property breadth | unsupported | No complete support claim yet. | + +#### 7.2 Breaking lines + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Line-breaking semantics | unsupported | Not a current preserved interchange target. | + +#### 7.3 Inline fields + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Core inline-field subset | supported | The current core subset is supported. | +| Broader inline-field breadth | unsupported | No complete support claim yet. | + +#### 7.4 Voice overlay + +| Sub-area | Status | Current interpretation for `mikuscore` | +|---|---|---| +| Import acceptance of `&` overlay syntax | supported | Overlay syntax is accepted on import. | +| Faithful preservation as one part with synchronized voices | unsupported | Current import expands overlays into synthetic parts instead. | + +### 7.4 Overlay Policy Notes + +Current policy for `mikuscore`: + +- supported + - accept ABC overlay syntax `&` on import + - preserve the overlaid musical material by expanding it into synthetic overlay voices / parts +- intentionally not claimed + - faithful preservation as one MusicXML part with synchronized internal voices + - exact overlay identity roundtrip back to standard ABC `&` surface syntax +- rationale + - current synthetic-part expansion preserves musical content well enough for practical import + - faithful same-part overlay preservation would require a stronger internal/roundtrip model than the current bounded ABC support target + +Practical result mode for `ABC-COV-017`: + +- `defer intentionally` +- keep `&` import acceptance as supported compatibility behavior +- do not currently require faithful same-part overlay preservation for ABC completion claims + +## ABC 2.2 Delta + +This section tracks standard items that are better treated as post-2.1 additions rather than silently folded into the baseline table. + +| ABC 2.2 delta item | Status | Current interpretation for `mikuscore` | +|---|---|---| +| `!editorial!` decoration | supported | Supported as a bounded accidental-decoration modifier on the following explicit accidental, mapped to MusicXML `accidental@editorial="yes"`. | +| `!courtesy!` decoration | supported | Supported as a bounded accidental-decoration modifier on the following explicit accidental, mapped to MusicXML `accidental@cautionary="yes"`. | + +### ABC 2.2 Delta Policy Notes + +Current policy for `mikuscore`: + +- `!editorial!` + - now included in the bounded supported roadmap + - interpreted as a modifier for the following explicit accidental +- `!courtesy!` + - now included in the bounded supported roadmap + - interpreted as a modifier for the following explicit accidental + +Rationale: + +- current ABC completion work is organized around the `2.1` baseline plus explicit delta triage +- both decorations fit naturally into the existing accidental import/export path +- both are standard 2.2 decorations with practical musical value, and are narrower than broader deferred engraving/layout areas +- the bounded support target is accidental-level editorial/cautionary flags, not wider engraving semantics + +Practical result mode for `ABC-COV-018`: + +- `support bounded subset` +- keep broader 2.2 delta expansion explicit, but treat these two accidental decorations as in-scope +- do not include them in current ABC completion claims + +## Derived Actionable Backlog + +This section is the direct bridge from coverage to implementation TODOs. +If an item here is completed, update the detailed coverage tables first, then update `TODO.md`. + +| Item | Source area | Work type | Priority | Default direction | Done when | Target outcome | +|---|---|---|---|---|---|---| +| `ABC-COV-001` | `3.1 Information fields` | `policy` | `P2` | bound scope first | non-core field policy is written here and reflected in linked specs | Decide and document which non-core standard fields are intentionally unsupported versus planned. | +| `ABC-COV-002` | `3.2 / 7.3 Inline fields` | `policy` | `P2` | bound scope first | supported inline subset is explicitly bounded in spec text | Decide whether the supported inline-field subset stops at `[K/M/L/Q/V]` or should expand. | +| `ABC-COV-003` | `3.3 Field continuation` | `policy` | `P3` | likely defer or freeze | continuation is either explicitly frozen as unsupported or promoted to planned work | Either implement continuation support or explicitly freeze it as unsupported in the practical scope. | +| `ABC-COV-004` | `4.6 Clefs and transposition` | `mixed` | `P1` | expand common working subset conservatively | supported standard clef/transpose set is enumerated and covered by tests | Close the remaining standard clef/transpose policy beyond the current common subset. | +| `ABC-COV-005` | `4.7 Beams` | `mixed` | `P1` | decide preservation target before code | whitespace-beam preservation target is decided and tested to that level | Decide how far ABC whitespace-as-beam-separation must be preserved on export. | +| `ABC-COV-006` | `4.8-4.10 Repeat structure` | `mixed` | `P1` | finish edge-case audit | remaining repeat/ending edge forms are either supported with tests or explicitly marked unsupported | Audit remaining repeat/ending edge variants and mark what is still unsupported. | +| `ABC-COV-007` | `4.11 Ties and slurs` | `mixed` | `P1` | keep ties strong, define slur limits | slur-span limits are written down and tested, or stronger preservation is implemented | Close the slur-span reconstruction policy or keep it explicitly partial with defined limits. | +| `ABC-COV-008` | `4.13 Tuplets` | `mixed` | `P2` | close edge semantics incrementally | remaining tuplet edge semantics are either tested or explicitly excluded | Audit remaining ratio/edge semantics and mark what is still unsupported. | +| `ABC-COV-009` | `4.14 Decorations` | `mixed` | `P1` | finish pending policy notes | each pending decoration-policy item is resolved in spec text, with implementation/tests if needed | Resolve pending policy items: `!arpeggio!` / `!roll!`, `!+!` / `!plus!`, mordent export naming, `!slide!` stop policy. | +| `ABC-COV-010` | `4.15 Symbol lines` | `policy` | `P3` | likely out of scope unless demanded by real data | `s:` is explicitly marked in-scope or frozen out-of-scope | Decide whether `s:` symbol lines are in scope or intentionally out of scope. | +| `ABC-COV-011` | `4.16 Redefinable symbols` | `policy` | `P2` | likely keep import-first | `U:` support boundary is explicitly written down | Decide whether `U:` remains import-only or needs broader parity/export support. | +| `ABC-COV-012` | `4.18 Chord symbols` | `mixed` | `P1` | expand common inventory, bound the rest | supported chord-symbol inventory is enumerated enough to test and maintain | Expand or explicitly bound the supported chord-symbol inventory. | +| `ABC-COV-013` | `4.19 Annotations` | `policy` | `P2` | define supported subset explicitly | supported annotation subset and exclusions are written down | Define the supported annotation behavior and explicit exclusions. | +| `ABC-COV-014` | `4.20 Order of constructs` | `policy` | `P3` | prefer practical acceptance over formal completeness | acceptance philosophy and any explicit exclusions are written down | Decide whether broad practical acceptance is enough or whether stricter conformance is required. | +| `ABC-COV-015` | `5.1-5.3 Lyrics` | `mixed` | `P2` | strengthen single/multi-verse clarity | lyric scope is bounded and tested for the chosen supported subset | Audit lyrics alignment, multi-verse behavior, and numbering scope. | +| `ABC-COV-016` | `7.1 Voice properties` | `mixed` | `P1` | enumerate supported standard properties explicitly | supported/unsupported voice-property list is explicit and testable | Enumerate which standard voice properties are supported, unsupported, or extension-only. | +| `ABC-COV-017` | `7.4 Voice overlay` | `policy` | `P1` | decide whether current synthetic-part import is acceptable | overlay preservation target is explicitly accepted or rejected | Decide whether faithful same-part overlay preservation is required. | +| `ABC-COV-018` | `ABC 2.2 delta` | `policy` | `P2` | decide roadmap versus explicit defer | 2.2 delta items are either put on roadmap or marked intentionally deferred | Decide whether `!editorial!` and `!courtesy!` are in the supported roadmap or intentionally deferred. | + +## Result Modes + +When closing a backlog item above, prefer one of these explicit outcomes: + +- `support now` + - implement and test it +- `support bounded subset` + - document the exact supported subset and explicit exclusions +- `defer intentionally` + - record that it is not in the current supported roadmap +- `out of practical scope` + - record that `mikuscore` does not currently target this standard area + +## Initial Stance by Backlog Item + +This is a non-binding starting recommendation for turning the backlog into TODOs. + +| Item | Recommended result mode | Rationale | +|---|---|---| +| `ABC-COV-001` | `support bounded subset` | Closed for the current bounded subset: the supported core field family is explicit, and non-core information fields are now explicitly treated as semantically unsupported even if lexically tolerated. | +| `ABC-COV-002` | `support bounded subset` | Closed for the current bounded subset: supported inline fields are explicitly limited to `[K/M/L/Q/V]`, and broader inline fields are now explicitly treated as warning-based skips rather than supported semantics. | +| `ABC-COV-003` | `defer intentionally` | Field continuation looks low-value unless real input data demands it. | +| `ABC-COV-004` | `support bounded subset` | Closed for the current bounded subset: the supported clef set is explicit, compatibility shorthand is documented, and transpose remains explicitly partial/extension-assisted. | +| `ABC-COV-005` | `support bounded subset` | Closed for the current bounded policy: import-side beam-break hints are supported, while exact export-side ABC spacing preservation remains out of scope and is now explicitly documented/tested. | +| `ABC-COV-006` | `support bounded subset` | Closed for the current bounded subset: common repeat / ending forms use standard ABC surface, while edge cases such as repeat counts beyond the ordinary case and `ending type=discontinue` are explicitly extension-assisted and now covered by tests/spec text. | +| `ABC-COV-007` | `support bounded subset` | Closed for the current bounded subset: common unnumbered slur start/stop presence is supported, while numbered/nested slur identity and broader span semantics remain explicitly out of claim and are now documented/tested. | +| `ABC-COV-008` | `support bounded subset` | Tuplets are usable; the remaining work is edge clarification. | +| `ABC-COV-009` | `support now` | Closed in the current series; canonical policy and implementation/tests are aligned for the tracked items. | +| `ABC-COV-010` | `out of practical scope` | `s:` symbol lines currently look like a low-priority notation surface. | +| `ABC-COV-011` | `support bounded subset` | Closed for the current bounded subset: `U:` remains import-first, single-character decoration-alias support is explicit, malformed declarations are ignored, and export parity is intentionally not claimed. | +| `ABC-COV-012` | `support bounded subset` | Closed for the current bounded inventory: supported quoted chord-symbol roots/suffixes are now enumerated in spec text and backed by tests, while unsupported quoted chord-like text explicitly falls back to annotation rather than forced harmony parsing. | +| `ABC-COV-013` | `support bounded subset` | Annotation support should be explicit, not accidental. | +| `ABC-COV-014` | `support bounded subset` | Practical acceptance is likely sufficient, but that should be stated plainly. | +| `ABC-COV-015` | `support bounded subset` | Closed for the current bounded subset: common `w:` underlay and ordinary hyphenation are supported, while broader alignment, multi-verse, and numbering semantics remain explicitly out of claim. | +| `ABC-COV-016` | `support bounded subset` | Closed for the current working subset; supported, partial, ext-only, and unsupported `V:` properties are now enumerated explicitly and backed by tests. | +| `ABC-COV-017` | `defer intentionally` | Closed by policy: `&` import acceptance remains supported via synthetic overlay voices / parts, while faithful same-part overlay preservation and exact `&` roundtrip are intentionally not current completion targets. | +| `ABC-COV-018` | `support bounded subset` | Closed for the current bounded 2.2 subset: `!editorial!` and `!courtesy!` are now supported as accidental-level modifiers with import/export/roundtrip coverage. | + +## Ready-to-Transfer TODO Order + +If the goal is to turn this document into executable TODO items with minimal extra analysis, use this order: + +1. `ABC-COV-009` decorations pending policy +2. `ABC-COV-016` voice-property enumeration +3. `ABC-COV-005` beam-separation preservation target +4. `ABC-COV-006` repeat / ending edge audit +5. `ABC-COV-012` chord-symbol inventory bounds +6. `ABC-COV-007` slur-span policy +7. `ABC-COV-017` overlay preservation decision +8. `ABC-COV-018` ABC 2.2 delta decision +9. `ABC-COV-008`, `ABC-COV-011`, `ABC-COV-015` +10. `ABC-COV-001`, `ABC-COV-002`, `ABC-COV-003`, `ABC-COV-010`, `ABC-COV-013`, `ABC-COV-014` + +Current phase note: + +- this transfer order has been fully consumed for the current bounded-coverage pass +- treat it as historical execution order, not as the current active queue + +## Likely Practical-Scope Freezes + +These are not final decisions, but they currently look like the strongest candidates for "explicitly unsupported unless real-world demand appears": + +- `3.3` field continuation +- `4.15` symbol lines +- `6.1` formatting/typesetting details +- `6.2` playback semantics from ABC notation itself +- `7.2` line-breaking semantics + +## Current High-Priority Follow-Ups + +- `4.14 Decorations` + - canonical decoration policy is closed, but implementation/test follow-up may still be needed where broader parity is intentionally bounded +- `4.7 Beams` + - bounded policy is closed, but exact export-side spacing preservation remains intentionally out of scope +- `4.18 Chord symbols` + - bounded inventory is closed, but broader harmony spelling coverage remains intentionally outside the current subset +- `7.4 Voice overlay` + - policy is closed, but current import still expands overlays into synthetic parts rather than synchronized voices inside one part + +## Recently Closed Backlog Items + +- `ABC-COV-009` + - closed as `support now` + - policy text is settled in this document and `docs/spec/ABC_IO.md` + - current implementation/tests align on: + - canonical `!arpeggio!` export for the current MusicXML `arpeggiate` carrier + - canonical `!stopped!` export for `!+!` / `!plus!` import aliases + - canonical `!mordent!` / `!pralltriller!` export for mordent-family import aliases + - standard `!slide!` as start-side support, with explicit stop kept as `mikuscore` extension `!slide-stop!` +- `ABC-COV-016` + - closed as `support bounded subset` + - `7.1 Voice properties` is now decomposed into: + - supported: `V:id`, `name=...`, common `clef=...` + - partial: standard `transpose=...` import + - ext-only: transpose-preserving roundtrip through `%@mks transpose ...` + - unsupported: broader standard properties such as `staves`, `brace`, `bracket`, `merge`, `middle`, `gchords` + - practical multi-staff import is currently available through bounded `%%score (...)` grouping rather than those `V:` properties + - regression coverage now exists for: + - supported `transpose=...` import + - warnings on unsupported standard `V:` properties +- `ABC-COV-005` + - closed as `support bounded subset` + - bounded policy is now explicit: + - import: whitespace is a beam-break hint within the current voice/measure + - export: exact beam-specific ABC spacing is not preserved + - practical interchange target is beam-break interpretation on import, not verbatim source spacing roundtrip + - regression coverage now exists for: + - import-side whitespace beam-break hints + - current export-side non-preservation of exact beam spacing text +- `ABC-COV-006` + - closed as `support bounded subset` + - bounded policy is now explicit: + - standard surface support covers common repeat / ending forms: `|:`, `:|`, `[1`, `[2`, `|1`, `:|2` + - edge semantics beyond that subset currently rely on `%@mks measure` metadata + - repeat counts beyond the ordinary case use `times=...` + - ending stop type `discontinue` uses `ending-stop=... ending-type=discontinue` + - regression coverage now exists for: + - standard repeat barlines + - standard alternate endings + - extension-assisted repeat counts + - extension-assisted `discontinue` ending stop +- `ABC-COV-012` + - closed as `support bounded subset` + - bounded quoted-chord inventory is now explicit: + - roots/bass: `A`-`G` with optional `#` / `b` + - supported suffix subset: + - `` + - `m`, `min` + - `6`, `m6`, `min6` + - `7`, `9`, `11`, `13` + - `maj7`, `maj9` + - `m7`, `min7`, `m9`, `min9` + - `7sus4`, `sus4`, `sus2` + - `dim`, `dim7`, `aug`, `+`, `m7b5`, `min7b5`, `ø` + - unsupported quoted chord-like text falls back to annotation/words + - regression coverage now exists for: + - supported quoted-chord harmony parsing/export + - unsupported quoted chord-like fallback to annotation +- `ABC-COV-007` + - closed as `support bounded subset` + - bounded slur policy is now explicit: + - supported: common unnumbered start/stop slur presence + - unsupported/not yet claimed: numbered/nested slur identity preservation and broader exact span semantics + - warning-based edge handling: slur stop without a preceding non-rest note + - regression coverage now exists for: + - common slur start/stop roundtrip + - warning-based unsupported edge behavior +- `ABC-COV-017` + - closed as `defer intentionally` + - overlay policy is now explicit: + - supported: import acceptance of `&` via synthetic overlay voices / parts + - intentionally not claimed: faithful same-part multi-voice preservation + - intentionally not claimed: exact standard ABC `&` roundtrip preservation +- `ABC-COV-018` + - closed as `support bounded subset` + - 2.2 delta policy is now explicit: + - `!editorial!` is supported as a bounded accidental-level modifier + - `!courtesy!` is supported as a bounded accidental-level modifier + - broader 2.2 delta work still remains outside the current bounded target +- `ABC-COV-011` + - closed as `support bounded subset` + - `U:` policy is now explicit: + - supported: single-character decoration-alias import + - supported: `!decor!` / `+decor+` right-hand side forms in the current import path + - malformed `U:` declarations are ignored + - export parity for `U:` is intentionally not claimed +- `ABC-COV-001` + - closed as `support bounded subset` + - information-field policy is now explicit: + - supported core subset: `X:`, `T:`, `C:`, `M:`, `L:`, `K:`, `Q:` + - `V:` remains supported only through its separately bounded voice-property subset + - non-core information fields are not semantically supported + - lexical tolerance of an unsupported field does not count as ABC coverage +- `ABC-COV-002` + - closed as `support bounded subset` + - inline-field policy is now explicit: + - supported subset: `[K:...]`, `[M:...]`, `[L:...]`, `[Q:...]`, `[V:...]` + - broader inline fields are not semantically supported + - unsupported inline fields are skipped with warnings +- `ABC-COV-013` + - closed as `support bounded subset` + - annotation policy is now explicit: + - supported: common quoted non-harmonic text as direction words / annotations + - supported: unsupported quoted chord-like text falls back to annotation/words instead of being forced into `harmony` + - not currently claimed: broader annotation placement and behavior semantics +- `ABC-COV-014` + - closed as `support bounded subset` + - order-of-constructs policy is now explicit: + - supported in the practical sense: common construct orderings already handled by the parser + - preferred stance: broad practical acceptance for structurally recognizable real-world ABC + - not currently claimed: full formal conformance to every order-of-constructs nuance +- `ABC-COV-003` + - closed as `defer intentionally` + - field-continuation policy is now explicit: + - continued information-field lines are outside the current supported subset + - lexical tolerance does not count as continuation support + - this area is intentionally deferred unless practical input evidence makes it worth revisiting +- `ABC-COV-010` + - closed as `out of practical scope` + - symbol-line policy is now explicit: + - standard `s:` symbol lines are outside the current bounded support target + - there is no current import/export or roundtrip support claim + - this area stays out of scope unless practical input demand changes priority +- `ABC-COV-015` + - closed as `support bounded subset` + - lyrics policy is now explicit: + - supported: common `w:` underlay import/export and ordinary hyphenated lyric handling + - not currently claimed: full alignment nuance, full multi-verse behavior, or verse numbering semantics + - current support target is useful common lyric interchange, not full lyric-parity coverage +- `ABC-COV-008` + - closed as `support bounded subset` + - tuplet policy is now explicit: + - supported: common `(n[:q][:r])` syntax and common MusicXML roundtrip through `time-modification` plus note-level `tuplet` markers + - supported: current explicit tuplet export such as `(3:2:3` in the common path + - not currently claimed: broader ratio/edge semantics or more complex span behavior beyond the current tested subset +- `ABC-COV-004` + - closed as `support bounded subset` + - clef / transposition policy is now explicit: + - supported: common `V:` clef subset `treble`, `bass`, `alto`, `tenor`, `c3`, `c4` + - supported: bare clef shorthand as compatibility behavior on import + - partial/ext-only: standard `V:` transpose import plus `%@mks transpose ...` for roundtrip preservation + - not currently claimed: broader standard clef breadth or full standard `V:` transpose export parity + +## TODO Derivation Rule + +When creating or updating ABC-related TODO items: + +1. identify the affected `ABC 2.1` chapter or `ABC 2.2 delta` item in this file +2. update the status and note here first if the understanding changed +3. create implementation TODO items only for the delta between current and desired status +4. when possible, reference the `ABC-COV-*` backlog item that the TODO comes from +5. treat this file as the source for completion judgment + +## Related Documents + +- `docs/spec/ABC_IO.md` +- `docs/spec/abc-compat-parser-ebnf.md` +- `docs/FORMAT_COVERAGE.md` +- `TODO.md` diff --git a/docs/spec/AI_JSON_SPEC.md b/docs/spec/AI_JSON_SPEC.md new file mode 100644 index 0000000..3d6b1f3 --- /dev/null +++ b/docs/spec/AI_JSON_SPEC.md @@ -0,0 +1,16 @@ +# AI JSON Spec + +Status: + +- removed from the current normative spec surface +- retained only as a compatibility pointer during the transition + +`mikuscore` does not currently define an active AI-facing JSON interface as part of the present product contract. + +For the current policy, see: + +- `docs/AI_INTERACTION_POLICY.md` + +For the deferred future note, see: + +- `docs/future/AI_JSON_INTERFACE.md` diff --git a/docs/spec/ARCHITECTURE.md b/docs/spec/ARCHITECTURE.md index 35f47a7..a2edb8d 100644 --- a/docs/spec/ARCHITECTURE.md +++ b/docs/spec/ARCHITECTURE.md @@ -4,6 +4,12 @@ This document defines high-level architecture boundaries for mikuscore MVP. +Scope note: + +- This file defines boundaries and invariants at architecture level. +- Detailed runtime build constraints are in `docs/spec/BUILD_PROCESS.md`. +- Detailed UI behavior is in `docs/spec/UI_SPEC.md`. + ## MusicXML Version Baseline - Baseline format: **MusicXML 4.0** diff --git a/docs/spec/BUILD_PROCESS.md b/docs/spec/BUILD_PROCESS.md index ddc226c..3d58b35 100644 --- a/docs/spec/BUILD_PROCESS.md +++ b/docs/spec/BUILD_PROCESS.md @@ -9,15 +9,22 @@ This project adopts: The build process is designed to preserve offline and zero-runtime-dependency behavior. +Scope note: + +- This file defines build/runtime artifact constraints. +- Day-to-day quality gate operation is defined in `docs/spec/LOCAL_WORKFLOW.md`. + ## Target Artifact -- Development template: `mikuscore-src.html` (editable source template) -- Distribution artifact: `mikuscore.html` (generated file, do not edit directly) +- Development templates: `mikuscore-src.html`, `index-src.html` (editable source templates) +- Distribution artifacts: `mikuscore.html`, `index.html` (generated files, do not edit directly) ## Suggested Project Layout (MVP) - `mikuscore-src.html` +- `index-src.html` - `mikuscore.html` (generated) +- `index.html` (generated) - `src/css/app.css` - `src/ts/main.ts` - `src/ts/**/*.ts` (core/ui split modules) @@ -35,24 +42,15 @@ npm run build 1. Compile `src/ts/**/*.ts` to `src/js/**/*.js` 2. Validate `mikuscore-src.html` tag order (CSS and JS include order) -3. Inline local CSS and JS into HTML -4. Output `mikuscore.html` as single-file artifact +3. Inline local CSS and JS into `mikuscore.html` +4. Render static landing templates such as `index-src.html` +5. Output generated HTML artifacts -## Optional Commands +## Related Commands -```bash -npm run typecheck -npm run test:unit -npm run test:property -npm run test:all -npm run clean -``` +For verification and daily commands (`typecheck`, `test:*`, `check:all`, `clean`), see: -- `typecheck`: strict TS check for development quality -- `test:unit`: run unit tests with Vitest -- `test:property`: run property-based invariant tests -- `test:all`: run both unit and property tests -- `clean`: remove generated JS and distribution HTML +- `docs/spec/LOCAL_WORKFLOW.md` ## Toolchain Baseline @@ -75,8 +73,8 @@ npm run clean ## Editing Rules -- `mikuscore.html` is generated; do not edit directly -- edit only `mikuscore-src.html` and files under `src/` +- `mikuscore.html` and `index.html` are generated; do not edit them directly +- edit `mikuscore-src.html`, `index-src.html`, and files under `src/` - PRs SHOULD include regenerated `mikuscore.html` when behavior changes ## Notes diff --git a/docs/spec/CLI_STEP1.md b/docs/spec/CLI_STEP1.md new file mode 100644 index 0000000..8122bf1 --- /dev/null +++ b/docs/spec/CLI_STEP1.md @@ -0,0 +1,234 @@ +# CLI Step 1 Specification + +## Purpose + +This document defines the first-cut CLI scope for `mikuscore`. + +Scope note: + +- This file defines only the initial CLI contract. +- It does not define future AI JSON or patch-based workflows. +- It does not replace the canonical MusicXML-centered architecture. + +## Positioning + +The CLI is a thin external entrypoint for format conversion. + +For Step 1: + +- the CLI exposes one `convert` command with a small supported pair set +- canonical score representation remains `MusicXML` +- the CLI is not an editing surface +- the CLI is not a patch/state/report surface + +## Design Principles + +### 1. Thin Wrapper Rule + +The CLI MUST remain a thin wrapper over existing conversion logic. + +- CLI-specific business logic MUST be minimized +- UI and CLI SHOULD share the same import/export path where practical +- format validation and conversion behavior SHOULD live in reusable modules, not in the CLI script + +### 2. Canonical Format Rule + +- `MusicXML` remains canonical underneath +- `ABC` is the Step 1 external interface layer +- the CLI MUST NOT redefine a second canonical score model + +### 3. Small Surface Rule + +Step 1 MUST stay intentionally narrow. + +The CLI MUST NOT include: + +- AI JSON interface +- patch contract +- note-level edit commands +- partial local view export +- broad report/export families unrelated to `ABC` + +## Step 1 Command Scope + +The initial command family is: + +- `mikuscore convert --from abc --to musicxml` +- `mikuscore convert --from musicxml --to abc` +- `mikuscore convert --help` +- `mikuscore --help` + +Command naming is fixed for Step 1 as: + +- `convert --from abc --to musicxml` +- `convert --from musicxml --to abc` + +### `mikuscore convert --from abc --to musicxml` + +Purpose: + +- convert `ABC` text into `MusicXML` + +Input: + +- `ABC` text from `--in ` or `stdin` + +Output: + +- `MusicXML` text to `--out ` or `stdout` + +Behavior: + +- MUST use the same `ABC -> MusicXML` conversion path as the app where practical +- MUST fail with non-zero exit code on invalid or unsupported input that cannot be converted +- MAY emit warnings/diagnostics to `stderr` + +### `mikuscore convert --from musicxml --to abc` + +Purpose: + +- convert `MusicXML` text into `ABC` + +Input: + +- `MusicXML` text from `--in ` or `stdin` + +Output: + +- `ABC` text to `--out ` or `stdout` + +Behavior: + +- MUST use the same `MusicXML -> ABC` conversion path as the app where practical +- MUST preserve current bounded `ABC` support policy +- MAY emit warnings/diagnostics to `stderr` + +## CLI I/O Contract + +### Input Rule + +- `--in` specifies an input file path +- if `--in` is omitted, the CLI MUST read from `stdin` +- if neither file input nor `stdin` content is available, the CLI MUST fail clearly + +### Output Rule + +- `--out` specifies an output file path +- if `--out` is omitted, the main result MUST be written to `stdout` + +### Help Rule + +- `--help` is part of the Step 1 contract +- `mikuscore --help` MUST print top-level usage/help text +- `mikuscore convert --help` MUST print command-specific help text +- help output SHOULD go to `stdout` +- successful help output MUST exit with code `0` + +### Help Text Baseline + +The Step 1 help surface SHOULD stay compact and explicit. + +Top-level help SHOULD communicate: + +- available command family +- the fixed Step 1 command names +- `stdin` / `stdout` default behavior +- supported options for Step 1 + +Recommended first-cut top-level help shape: + +```text +Usage: + mikuscore convert --from abc --to musicxml [--in ] [--out ] + mikuscore convert --from musicxml --to abc [--in ] [--out ] + mikuscore convert --help + mikuscore --help + +Commands: + convert Convert score text between supported formats + +Options: + --from Source format + --to Target format + --in Read input from file instead of stdin + --out Write output to file instead of stdout + --help Show help +``` + +Recommended first-cut command help shape for `convert`: + +```text +Usage: + mikuscore convert --from abc --to musicxml [--in ] [--out ] + mikuscore convert --from musicxml --to abc [--in ] [--out ] + mikuscore convert --help + +Description: + Convert score text between supported formats. + +Supported pairs: + --from abc --to musicxml + --from musicxml --to abc + +Input: + --in Read source text from file + stdin Used when --in is omitted + +Output: + --out Write converted text to file + stdout Used when --out is omitted + +Options: + --from Source format + --to Target format + --help Show help +``` + +### Stream Rule + +- main conversion result MUST go to `stdout` +- warnings, diagnostics, and summary text SHOULD go to `stderr` +- binary output is out of Step 1 scope + +## Error Contract + +On failure: + +- process exit code MUST be non-zero +- human-readable error text MUST be written to `stderr` +- partial or mixed success text MUST NOT be written to `stdout` as if conversion succeeded + +On success with warnings: + +- process exit code SHOULD remain zero +- warnings MAY be written to `stderr` +- successful converted output MUST remain clean on `stdout` + +On successful `--help`: + +- process exit code MUST be zero +- help text MUST be written to `stdout` +- `stderr` SHOULD remain empty + +## Non-Goals For Step 1 + +The following are explicitly out of scope: + +- automatic input format detection +- multi-format export surface beyond the `ABC` interface target +- command-level score editing +- AI patch application +- JSON projection/export +- CLI parity with every UI button +- alternative Step 1 command naming beyond `convert --from/--to` + +## Recommended Future Direction + +If the CLI grows later, it SHOULD still preserve the same principles: + +- thin wrapper design +- canonical `MusicXML` underneath +- reusable non-UI entrypoints +- narrowly scoped command families + +Any later expansion beyond `ABC` SHOULD be justified by concrete workflow need, not by symmetry with another project. diff --git a/docs/spec/COMMANDS.md b/docs/spec/COMMANDS.md index e077c68..d3ab73d 100644 --- a/docs/spec/COMMANDS.md +++ b/docs/spec/COMMANDS.md @@ -4,6 +4,12 @@ This document defines the minimum command/save contract for core. +Scope note: + +- This file is a compact contract summary. +- Command-by-command normative rules are defined in `docs/spec/COMMAND_CATALOG.md`. +- Diagnostic code semantics are defined in `docs/spec/DIAGNOSTICS.md`. + ## Core API Shape ```ts @@ -24,14 +30,14 @@ type SaveResult = { }; ``` -## Required Behavior +## Required Behavior (Summary) 1. `dispatch(command)` -- MUST reject command/target voice mismatch with `MVP_UNSUPPORTED_NON_EDITABLE_VOICE`. -- MUST reject malformed payload with `MVP_INVALID_COMMAND_PAYLOAD`. -- MUST reject overfull with `MEASURE_OVERFULL`. +- MUST enforce command voice and structural constraints. +- MUST reject malformed payload and invalid target kind. +- MUST reject overfull mutations. - MUST be atomic on failure (DOM unchanged, dirty unchanged). -- MUST set `dirty=true` only when content-changing command succeeds. +- MUST set `dirty=true` only when a content-changing command succeeds. 2. Supported command family (MVP) - `change_to_pitch` @@ -41,16 +47,14 @@ type SaveResult = { - `split_note` - `ui_noop` -3. Note-kind rule -- `grace` / `cue` / `chord` are unsupported for direct edit and SHOULD fail with `MVP_UNSUPPORTED_NOTE_KIND`. -- `rest` is unsupported for most commands, but `change_to_pitch` MAY target rest for rest-to-note conversion. - -4. `save()` +3. `save()` - `dirty === false` -> MUST return original XML (`mode="original_noop"`). - `dirty === true` -> MUST return serialized current DOM (`mode="serialized_dirty"`). -- MUST reject invalid score state (overfull / invalid duration / invalid voice / invalid pitch). +- MUST reject invalid score state. -5. Serialization policy +4. Serialization policy - MUST preserve unknown/unsupported elements. - MUST NOT normalize unrelated ``, ``, existing ``. - pretty-printing MUST NOT be applied. + +For detailed per-command rules, use `docs/spec/COMMAND_CATALOG.md` as the normative source. diff --git a/docs/spec/FORMAT_IO_CHECKLIST.md b/docs/spec/FORMAT_IO_CHECKLIST.md index 5ad2408..e8c422b 100644 --- a/docs/spec/FORMAT_IO_CHECKLIST.md +++ b/docs/spec/FORMAT_IO_CHECKLIST.md @@ -36,6 +36,7 @@ When adding a new format (e.g. ABC / MEI / future formats), use this checklist t - [ ] title - [ ] tempo - [ ] key/time/transpose + - [ ] source-specific key variants that affect written vs concert pitch are documented and tested (e.g. MuseScore `concertKey` / `transposeKey`) - [ ] `miscellaneous-field` equivalent (if representable in source format) - [ ] format-specific roundtrip hints (if used) are explicitly documented (key format, scope, restore rule) - [ ] Unsupported feature handling is explicit: @@ -95,26 +96,26 @@ When adding a new format (e.g. ABC / MEI / future formats), use this checklist t - [ ] Warn vs error boundary is documented - [ ] Console diagnostics and UI diagnostics are consistent - [ ] For bug investigation, preserve and utilize debug metadata through `miscellaneous-field` (or format-equivalent mapping) whenever possible. -- [ ] When conversion applies degradation/auto-fix (e.g. overfull clamped), record it as structured diagnostics in `miscellaneous-field` using `diag:*`. +- [ ] When conversion applies degradation/auto-fix (e.g. overfull clamped), record it as structured diagnostics in `miscellaneous-field` using `mks:diag:*`. ### `miscellaneous-field` Usage Patterns (MUST classify explicitly) - [ ] Classify each `miscellaneous-field` mapping into one of the following: - - **Source-preservation metadata** (`src:*` recommended): - - Purpose: preserve source-format-only information when importing `Format -> MusicXML`. - - Example: fields needed to reconstruct/trace original MEI/ABC semantics not directly representable in core MusicXML path. - - **mikuscore extension metadata** (`mks:*`): + - **mikuscore extension metadata** (`mks:meta:*`): - Purpose: preserve mikuscore-specific semantics/provenance when a target format cannot represent them natively (not debug-only). - Example: mikuscore extension comments/hints and restoration metadata required for compatible roundtrip behavior. - - **Optional debug-only metadata** (`dbg:*` recommended if separated): - - Purpose: investigation/tracing only. - - Example: event-level conversion traces used for incident analysis. - - **Structured conversion diagnostics** (`diag:*`): + - **Structured conversion diagnostics** (`mks:diag:*`): - Purpose: record warnings/repair actions that occurred during conversion, so issues are not silently hidden. - - Example: `diag:0001 = level=warn;code=OVERFULL_CLAMPED;fmt=mei;measure=8;staff=1;action=clamped;droppedTicks=240`. - - Recommended key order inside `diag:NNNN` payload: + - Example: `mks:diag:0001 = level=warn;code=OVERFULL_CLAMPED;fmt=mei;measure=8;staff=1;action=clamped;droppedTicks=240`. + - Recommended key order inside `mks:diag:NNNN` payload: - `level;code;fmt;measure;staff;voice;action;message;sourceTicks;capacityTicks;movedEvents;droppedEvents;droppedTicks` - Omit keys that do not apply, but keep relative order for diff/readability. + - **Source-preservation metadata** (`mks:src:*` recommended): + - Purpose: preserve source-format-only information when importing `Format -> MusicXML`. + - Example: fields needed to reconstruct/trace original MEI/ABC semantics not directly representable in core MusicXML path. + - **Optional debug-only metadata** (`mks:dbg:*`): + - Purpose: investigation/tracing only. + - Example: event-level conversion traces used for incident analysis. - [ ] For each format, document retention policy for both categories: - preserve as-is / transform / drop - roundtrip expectations (`MusicXML -> Format -> MusicXML`, `Format -> MusicXML -> Format`) @@ -123,7 +124,8 @@ When adding a new format (e.g. ABC / MEI / future formats), use this checklist t - event addressing key (`voice + measure + event`) - fallback when hint is absent or invalid - safety against conflicts with existing source comments -- [ ] Keep namespace separation strict (`src:*` vs `mks:*` vs `diag:*` vs optional `dbg:*`) to avoid mixing source data, functional extension metadata, diagnostics, and debug traces. +- [ ] If such hints are `mikuscore`-specific (for example `%@mks ...`), document them explicitly as `mikuscore` extension metadata rather than as standard format syntax. +- [ ] Keep namespace separation strict (`mks:src:*` vs `mks:meta:*` vs `mks:diag:*` vs `mks:dbg:*`) to avoid mixing source data, functional extension metadata, diagnostics, and debug traces. ### LilyPond Note (Current `mks` usage) diff --git a/docs/spec/HARMONY_ANALYSIS_EXTENSION.md b/docs/spec/HARMONY_ANALYSIS_EXTENSION.md new file mode 100644 index 0000000..d26afe1 --- /dev/null +++ b/docs/spec/HARMONY_ANALYSIS_EXTENSION.md @@ -0,0 +1,467 @@ +# Harmony Analysis Extension Spec (v1 Draft) + +## 1. Scope + +This document defines harmonization analysis and performance-expression extensions for mikuscore. + +- Target: MusicXML import/export and in-app playback expression control. +- Non-target: Rewriting existing note structures for analysis. + +## 2. Goals + +1. Add functional harmony analysis for classical harmony (learning to conservatory assignment level). +2. Drive playback expression from harmony analysis (intonation and dynamics adjustments). +3. Preserve MusicXML interoperability by keeping standard data in standard elements and advanced data in `mks:*` extensions. + +## 3. Principles + +### 3.1 Standards First + +- The implementation MUST store base harmony information in MusicXML ``. +- Roman-numeral related data SHOULD use `` and child elements where possible. +- The implementation MUST NOT mutate existing note semantics only for analysis tagging. +- Standard-only readers SHOULD still read meaningful harmony information. + +### 3.2 Extension Isolation + +- Advanced/non-standard metadata MUST be stored under `mks:*` in extension containers. +- The implementation MUST confine harmony extensions to ``. +- The implementation MUST confine playback extensions to ``. +- Unknown extension fields MUST be preserved (round-trip safe). + +## 4. Namespace and Versioning + +- Namespace URI (v1): `https://mikuscore.org/ns/analysis` +- Prefix example: `xmlns:mks="https://mikuscore.org/ns/analysis"` +- `mks:analysis` MUST include `version` attribute. + +Example: + +```xml + + ... + +``` + +## 5. Data Model + +### 5.1 Standard Harmony Block (Required) + +The implementation MUST write base harmonic identity using ``. + +Recommended elements: + +- `` (1..7) +- `` (for altered scale degrees) +- `` (for local key context) +- `` (major/minor/dominant/etc.) +- `` + +Example: + +```xml + + + 5 + + dominant + 1 + +``` + +### 5.2 `mks:analysis` Block (Advanced) + +The implementation MUST place advanced analysis metadata in ``. + +Cardinality (v1): + +- One `` per ``. +- One `` per ``. +- Optional fields MAY be omitted. + +Fields (v1): + +- `mks:function`: `T | S | D` +- `mks:secondary-of`: denominator degree for secondary dominants (for example V/V => `5`) +- `mks:borrowed`: `true | false` +- `mks:cadence`: `PAC | IAC | HC` +- `mks:confidence`: decimal `0.0..1.0` +- `mks:source`: `rule | ai | manual` +- `mks:harmony-id`: unique harmony anchor id +- `mks:special-chord`: `It6 | Fr6 | Gr6 | N6` (for sonorities not cleanly expressible by `` alone) + +Forward-compatibility note: + +- In v1, `mks:secondary-of` is degree-based (`1..7`) for simplicity. +- v2 MAY introduce richer representations (for example `mks:secondary-chain` or altered-degree text forms) for cases such as `V/V/V` or `V/bII`. + +`mks:harmony-id` constraints (v1): + +- MUST be unique per score document. +- MUST match pattern `[A-Za-z0-9_-]+`. +- UUID format MAY be used but is not required. + +Example: + +```xml + + + h23 + D + 5 + false + HC + 0.93 + rule + + +``` + +## 6. Performance Expression Control + +### 6.1 Intonation Offset + +- The implementation MUST NOT change notated pitch for intonation control. +- Playback intonation offsets MUST be stored as cents in ``. +- `mks:unit="cent"` MUST be explicitly attached to `mks:intonation` records. +- `mks:scope` SHOULD be attached (`note | chord | voice | measure`). +- Value range SHOULD be `-100..+100` cents (integer). + +Example: + +```xml + + -12 + +``` + +### 6.2 Dynamics Offset + +- Base dynamics MAY use standard `note@dynamics`. +- Relative harmonic dynamics control MUST be storable in ``. +- Value unit in v1 MUST be additive MIDI velocity offset (integer). +- `mks:unit="velocity"` MUST be explicitly attached to `mks:dynamic-offset` records. +- `mks:scope` SHOULD be attached (`note | chord | voice | measure`). +- Value range SHOULD be `-32..+32`. + +Example: + +```xml + + -8 + +``` + +## 7. Linkage Rules + +- Harmony-level and playback-level extensions MUST be linkable by `mks:harmony-id` and `mks:target-harmony-id`. +- If linkage is missing, the implementation MAY fallback to measure-local nearest harmony. +- If fallback is ambiguous, the implementation SHOULD skip offset application and emit a warning diagnostic. + +## 8. Validation and Diagnostics + +Recommended diagnostics (v1): + +- `HARMONY_PARSE_UNSUPPORTED` +- `HARMONY_EXTENSION_INVALID_VALUE` +- `HARMONY_LINKAGE_NOT_FOUND` +- `HARMONY_LINKAGE_AMBIGUOUS` + +Recommended structured diagnostics payload: + +```xml + + + +``` + +Rules: + +- Invalid extension values MUST NOT crash load flow. +- On invalid extensions, standard `` data SHOULD remain usable. + +## 9. Compatibility and Round-Trip Policy + +- Standard-only consumers MUST be able to ignore `mks:*` safely. +- mikuscore MUST preserve `other-harmony` and `other-play` unknown fields during save. +- If `dirty === false`, XML text MUST remain byte-identical to input. +- If a third-party tool strips `other-*`, mikuscore SHOULD surface a non-fatal warning and MAY re-analyze. + +## 10. Rollback and Failure Semantics + +- Analysis application MUST be atomic. +- On analysis failure, the implementation MUST rollback to pre-analysis state. +- Partial write of analysis metadata MUST NOT occur. + +## 11. Feature Levels + +### Phase 1 (Learning level) + +- Diatonic I..VII recognition +- Inversions +- Borrowed chords +- Secondary dominants +- Basic cadence tags + +### Phase 2 (Conservatory assignment level) + +- Augmented-sixth families (It+6 / Fr+6 / Gr+6) +- Neapolitan (bII) +- Substitute-function tags +- Rule-check diagnostics for prohibited voice-leading +- Voice-leading analysis tags + +## 12. Future Extensions + +- `mks:analysis` v2 with AI-generated explanation blocks +- Auto-generation mode for `mks:intonation` +- Educational export pipelines (analysis-enriched rendering) + +-------- + +# 和声解析拡張 仕様(v1 ドラフト) + +## 1. 対象範囲 + +本仕様は、mikuscore における和声解析と演奏表現拡張を定義する。 + +- 対象: MusicXML の入出力、およびアプリ内再生時の表現制御。 +- 非対象: 解析付与のための既存ノート構造の改変。 + +## 2. 目的 + +1. クラシック和声(学習教材〜音大課題レベル)の機能和声解析を追加する。 +2. 和声解析に基づく演奏表現(音程・強弱補正)を追加する。 +3. MusicXML 互換を維持しつつ、`mks:*` 拡張で高度情報を保持する。 + +## 3. 基本方針 + +### 3.1 標準優先 + +- 基本和声情報は MusicXML の `` に格納しなければならない(MUST)。 +- ローマ数字系情報は可能な限り `` 系要素を使うべきである(SHOULD)。 +- 解析タグ付与のために既存ノートの意味を変更してはならない(MUST NOT)。 +- 標準要素のみの読取環境でも意味ある和声情報を読めるべきである(SHOULD)。 + +### 3.2 拡張分離 + +- 非標準の高度情報は `mks:*` で保持しなければならない(MUST)。 +- 和声拡張は `` 配下に限定しなければならない(MUST)。 +- 演奏拡張は `` 配下に限定しなければならない(MUST)。 +- 未知の拡張フィールドは保存時に保持しなければならない(MUST)。 + +## 4. 名前空間とバージョニング + +- 名前空間 URI(v1): `https://mikuscore.org/ns/analysis` +- プレフィックス例: `xmlns:mks="https://mikuscore.org/ns/analysis"` +- `mks:analysis` は `version` 属性を持たなければならない(MUST)。 + +例: + +```xml + + ... + +``` + +## 5. データモデル + +### 5.1 標準和声ブロック(必須) + +基本和声同定情報は `` に書き込まなければならない(MUST)。 + +推奨要素: + +- ``(1..7) +- ``(変位度数) +- ``(局所調コンテキスト) +- ``(major/minor/dominant 等) +- `` + +例: + +```xml + + + 5 + + dominant + 1 + +``` + +### 5.2 `mks:analysis` ブロック(高度情報) + +高度解析メタデータは `` に格納しなければならない(MUST)。 + +カーディナリティ(v1): + +- `` あたり `` は1つ。 +- `` あたり `` は1つ。 +- 任意項目は省略可。 + +項目(v1): + +- `mks:function`: `T | S | D` +- `mks:secondary-of`: セカンダリードミナント分母度数(例: V/V => `5`) +- `mks:borrowed`: `true | false` +- `mks:cadence`: `PAC | IAC | HC` +- `mks:confidence`: 小数 `0.0..1.0` +- `mks:source`: `rule | ai | manual` +- `mks:harmony-id`: 和声アンカーID +- `mks:special-chord`: `It6 | Fr6 | Gr6 | N6`(`` だけでは厳密区別しづらい和音の識別用) + +将来拡張の注記: + +- v1 の `mks:secondary-of` は簡潔化のため度数(`1..7`)とする。 +- `V/V/V` や `V/bII` などへ対応するため、v2 では `mks:secondary-chain` や変位付きテキスト表現の導入を許容してよい(MAY)。 + +`mks:harmony-id` 制約(v1): + +- スコア文書内で一意でなければならない(MUST)。 +- 文字列は `[A-Za-z0-9_-]+` に一致しなければならない(MUST)。 +- UUID形式は利用してよいが必須ではない(MAY)。 + +例: + +```xml + + + h23 + D + 5 + false + HC + 0.93 + rule + + +``` + +## 6. 演奏表現制御 + +### 6.1 音程補正(イントネーション) + +- 音程補正のために記譜音高を変更してはならない(MUST NOT)。 +- 補正値は `` に cents で格納しなければならない(MUST)。 +- `mks:intonation` には `mks:unit="cent"` を明示しなければならない(MUST)。 +- `mks:scope`(`note | chord | voice | measure`)を付与することを推奨する(SHOULD)。 +- 値範囲は `-100..+100`(整数)を推奨する(SHOULD)。 + +例: + +```xml + + -12 + +``` + +### 6.2 強弱補正 + +- 基本強弱は標準 `note@dynamics` を利用してよい(MAY)。 +- 和声由来の相対強弱は `` で保持できなければならない(MUST)。 +- v1 の単位は MIDI velocity 加算オフセット(整数)とする(MUST)。 +- `mks:dynamic-offset` には `mks:unit="velocity"` を明示しなければならない(MUST)。 +- `mks:scope`(`note | chord | voice | measure`)を付与することを推奨する(SHOULD)。 +- 値範囲は `-32..+32` を推奨する(SHOULD)。 + +例: + +```xml + + -8 + +``` + +## 7. リンク規則 + +- 和声拡張と演奏拡張は `mks:harmony-id` と `mks:target-harmony-id` で対応付け可能でなければならない(MUST)。 +- 明示リンクがない場合、実装は同小節内の最寄り和声へフォールバックしてよい(MAY)。 +- フォールバックが曖昧な場合、補正適用をスキップし警告診断を出すべきである(SHOULD)。 + +## 8. バリデーションと診断 + +推奨診断コード(v1): + +- `HARMONY_PARSE_UNSUPPORTED` +- `HARMONY_EXTENSION_INVALID_VALUE` +- `HARMONY_LINKAGE_NOT_FOUND` +- `HARMONY_LINKAGE_AMBIGUOUS` + +推奨する構造化診断タグ: + +```xml + + + +``` + +規則: + +- 拡張値が不正でもロード処理をクラッシュさせてはならない(MUST NOT)。 +- 拡張値が不正でも標準 `` 情報は利用可能であるべきである(SHOULD)。 + +## 9. 互換性とラウンドトリップ + +- 標準のみを扱うツールは `mks:*` を安全に無視できなければならない(MUST)。 +- mikuscore は未知の `other-harmony` / `other-play` フィールドを保持しなければならない(MUST)。 +- `dirty === false` の場合、XML文字列は入力とバイト一致しなければならない(MUST)。 +- 外部ツールで `other-*` が除去された場合、mikuscore は非致命警告を表示し、必要に応じて再解析してよい(SHOULD/MAY)。 + +## 10. ロールバックと失敗時動作 + +- 解析適用は原子的でなければならない(MUST)。 +- 解析失敗時は解析適用前状態へロールバックしなければならない(MUST)。 +- 部分書き込みは発生してはならない(MUST NOT)。 + +## 11. 機能レベル目標 + +### フェーズ1(学習教材レベル) + +- I..VII の同定 +- 転回形 +- 借用和音 +- セカンダリードミナント +- 基本終止タグ + +### フェーズ2(音大課題レベル) + +- 増六和音(It+6 / Fr+6 / Gr+6) +- ナポリのII(bII) +- 代理機能タグ +- 禁則系の診断タグ +- 声部進行解析タグ + +## 12. 将来拡張 + +- `mks:analysis` v2(AI解析説明ブロック) +- `mks:intonation` の自動生成モード +- 解析情報付き教育出力パイプライン diff --git a/docs/spec/LHT_CMN_FEEDBACK.md b/docs/spec/LHT_CMN_FEEDBACK.md new file mode 100644 index 0000000..6ead3ca --- /dev/null +++ b/docs/spec/LHT_CMN_FEEDBACK.md @@ -0,0 +1,58 @@ +# LHT_CMN_FEEDBACK + +Last updated: 2026-03-08 +Target: `lht-cmn` maintainers +Source project: `mikuscore` + +This note now tracks only open or partially-resolved integration issues. Items already reflected in `lht-cmn` were removed from this file and are tracked historically in `LHT_CMN_FEEDBACK_STATUS.md`. + +## 1. Open component issues + +### 1-1. `lht-help-tooltip` should be fully self-contained, including base positioning CSS + +- Observed: + - `lht-help-tooltip` already has runtime placement logic such as `placement="auto"`, viewport measurement, and resize follow-up. + - However, a later `mikuscore` integration regression showed that hover behavior could still break even when the app used `` normally. + - The root cause was missing component-owned base CSS for tooltip anchoring and visibility, especially around: + - `position: relative` on the anchor container + - `position: absolute` on the tooltip layer + - `overflow: visible` on the relevant host/container +- Impact: + - Integrators can see the help icon hover as "broken" even though the app is not misusing the component. + - This creates a false impression that the host app needs to supply tooltip-layout CSS. +- Request: + - Treat the minimum positioning/visibility CSS as part of the public `lht-help-tooltip` contract. + - Do not consider tooltip support complete based on placement logic alone. + - Verify that a plain `` works correctly in isolation without app-specific tooltip CSS. + +### 1-2. `lht-help-tooltip` needs regression coverage for the complete contract + +- Observed: + - Existing tests cover fallback rendering, `placement="auto"`, and Escape hide behavior. + - They do not clearly prove that the component is self-contained from a CSS/layout point of view. +- Request: + - Add regression coverage that checks the complete tooltip contract, not only JS logic. + - Minimum expectation: + - the tooltip host/group has the positioning needed for anchoring + - hover/focus state can reveal the tooltip without relying on app CSS + - base tooltip styling is bundled in `lht-cmn` + +## 2. Open cross-cutting test request + +### 2-1. Add a clearer two-mode regression matrix + +- Observed: + - New component tests exist and several fallback cases are covered. + - But the test story is still not a clear matrix of: + - Material loaded + - Material not loaded + - for each critical `lht-*` component. +- Request: + - Add an explicit regression matrix, or an equally clear equivalent structure, for critical components. + - The main goal is to make self-contained guarantees easy to verify and hard to regress. + +## Suggested priority order + +1. Finish the `lht-help-tooltip` self-contained contract, including bundled base CSS. +2. Add regression coverage that validates the full tooltip contract. +3. Strengthen the two-mode regression matrix for critical `lht-*` components. diff --git a/docs/spec/LHT_CMN_FEEDBACK_STATUS.md b/docs/spec/LHT_CMN_FEEDBACK_STATUS.md new file mode 100644 index 0000000..772f9af --- /dev/null +++ b/docs/spec/LHT_CMN_FEEDBACK_STATUS.md @@ -0,0 +1,56 @@ +# LHT_CMN_FEEDBACK_STATUS + +Last updated: 2026-03-07 +Target: `lht-cmn` maintainers / integrators +Source project: `mikuscore` + +This note maps the previous `LHT_CMN_FEEDBACK.md` requests to the current `lht-cmn` update status. + +Status labels used in this file: + +- `Reflected`: implemented and/or documented in a way that substantially matches the request. +- `Partially reflected`: some meaningful part was adopted, but the request is not fully covered. +- `Intentionally not adopted for now`: the maintainer appears to have chosen a different design direction for now. + +## Status Table + +| Feedback item | Status | Notes | +|---|---|---| +| `lht-*` must be self-contained from the app's point of view | Reflected | README now states `lht-*` is self-contained and app code should not manage `md-*` registration. See `lht-cmn/README.md:22` and `lht-cmn/README.md:89` | +| Apply the self-contained rule across all components | Reflected | Policy is documented, and `help-tooltip`, `command-block`, `file-select`, `switch-help`, `text-field-help` now have fallbacks. The chosen implementation path is fallback-oriented rather than internal `md-*` registration. See `lht-cmn/js/components.js:23`, `lht-cmn/js/components.js:217`, `lht-cmn/js/components.js:322`, `lht-cmn/js/components.js:1030`, `lht-cmn/js/components.js:1132`, and `lht-cmn/js/components.js:1239` | +| `lht-help-tooltip`: built-in viewport collision handling | Partially reflected | `placement="auto|left|right|top|bottom"` and runtime positioning logic were added, but a later integration regression showed that the component still lacked some self-owned base positioning CSS (`md-tooltip-group` / `md-tooltip` anchoring), so hover behavior could break even when app-side usage was correct. See `lht-cmn/js/components.js:16`, `lht-cmn/README.md:183`, and `lht-cmn/css/components.css:42` | +| `lht-help-tooltip` should bundle the minimum base CSS needed for correct hover/positioning | Partially reflected | `lht-cmn` owns the tooltip behavior conceptually, but this was not fully true in practice until the `mikuscore` integration restored missing base CSS. This should be treated as part of the component contract and covered by regression tests. See `lht-cmn/css/components.css:42` and `docs/spec/LHT_CMN_FEEDBACK.md` | +| Prevent pre-upgrade content flash centrally | Reflected | `components.css` now hides uninitialized `lht-*` until `data-initialized="true"`. See `lht-cmn/css/components.css:13` and `lht-cmn/README.md:101` | +| `lht-file-select`: explicit event ownership | Reflected | `auto-open`, `lht-file-select:before-open`, and `lht-file-select:change` are implemented and documented. See `lht-cmn/js/components.js:1022`, `lht-cmn/js/components.js:1075`, and `lht-cmn/README.md:256` | +| `lht-error-alert`: support `warning` and `info` | Reflected | `variant` support and ARIA behavior are implemented and documented. See `lht-cmn/js/components.js:727`, `lht-cmn/js/components.js:792`, `lht-cmn/css/components.css:382`, and `lht-cmn/README.md:296` | +| `lht-switch-help` should not depend on app-side `md-switch` availability | Reflected | The adopted answer is fallback-based self-containment rather than internal `md-switch` registration. README now documents this explicitly. See `lht-cmn/js/components.js:1132` and `lht-cmn/README.md:223` | +| README: explicit integration contract section | Reflected | `Integration Contract` was added. See `lht-cmn/README.md:89` | +| README: fallback policy and parity table | Reflected | `Fallback / Parity Table` was added. See `lht-cmn/README.md:130` | +| README: clarify `lht-select-help` declarative JSON lifecycle | Reflected | Lifecycle notes now describe declarative detection timing, script consumption, and observer behavior. See `lht-cmn/README.md:204` | +| README: official dynamic-options pattern for `lht-select-help` | Reflected | `setOptions([...])`, `getValue()`, `setValue()`, and value retention rules are documented and implemented. See `lht-cmn/README.md:209` and `lht-cmn/js/components.js:520` | +| Add regression tests for both dependency modes | Partially reflected | New component tests exist and cover several fallback cases, but they do not clearly show a full two-mode matrix of Material-loaded vs Material-not-loaded for every critical `lht-*` component. See `lht-cmn/components.test.js` | +| Internally register required `md-*` elements instead of relying on fallback-oriented branching | Intentionally not adopted for now | Current implementation continues to branch on `customElements.get(...)` and relies on documented fallback/self-contained behavior instead of internal `md-*` registration. This looks like an intentional design choice, not a missed implementation. See `lht-cmn/README.md:26` and `lht-cmn/js/components.js:23` | +| Introduce a full explicit two-mode CI matrix for all critical `lht-*` components | Intentionally not adopted for now | Tests were added, but not as a full framework-level Material-loaded vs Material-not-loaded matrix. The current update suggests incremental test coverage was preferred. See `lht-cmn/components.test.js` | +| Preserve `hasDeclarativeOptions` pre-capture in `LhtSelectHelp.connectedCallback()` | Reflected | The implementation still captures declarative-options state before hydration. See `lht-cmn/js/components.js:320` | +| Treat `LhtTextFieldHelp` fallback as supported behavior | Reflected | Fallback is documented and tested, not just left as an implicit implementation detail. See `lht-cmn/README.md:195` and `lht-cmn/components.test.js` | +| Preserve `LhtSwitchHelp` fallback DOM structure | Reflected | README and implementation both use `input.md-switch-input + span.md-switch`. See `lht-cmn/README.md:223` and `lht-cmn/js/components.js:1182` | + +## Summary + +- Reflected: + - self-contained contract in README + - cross-component fallback-oriented self-contained direction + - pre-upgrade flash prevention + - file-select event ownership API + - error-alert variants + - select-help JSON lifecycle docs + - select-help dynamic options API + - fallback/parity documentation + - preservation of important select/text-field/switch implementation details +- Partially reflected: + - tooltip collision handling, because base positioning CSS completeness was still missing in real integration + - tooltip self-owned base CSS contract and its regression coverage + - regression coverage as an explicit two-mode matrix +- Intentionally not adopted for now: + - internal `md-*` registration as the primary solution + - a full explicit two-mode CI matrix across all critical components diff --git a/docs/spec/LHT_CMN_MIGRATION.md b/docs/spec/LHT_CMN_MIGRATION.md new file mode 100644 index 0000000..193b092 --- /dev/null +++ b/docs/spec/LHT_CMN_MIGRATION.md @@ -0,0 +1,56 @@ +# LHT_CMN_MIGRATION + +Last updated: 2026-03-07 + +This document records Phase 0 inventory for migrating mikuscore UI to `lht-cmn`. +Primary target file: `mikuscore-src.html` +Compatibility anchor: `src/ts/main.ts` DOM contracts (`id`, `name`, and event wiring). + +## Inventory summary (Phase 0) + +- Help tooltip groups (`md-tooltip-group`): 19 +- `select.md-select`: 10 +- `label.md-switch-label`: 10 +- `textarea.md-textarea`: 6 +- `input.md-input` (number fields in new-score form): 2 +- Existing loading/status primitives: + - `#fileLoadOverlay` + - `#inputUiMessage` + - `#uiMessage` +- Existing file-picker contracts: + - `#fileInput`, `#fileSelectBtn`, `#fileNameText` + - ZIP selector: `#zipEntrySelectBlock`, `#zipEntrySelect` + +## Replacement mapping table + +| Current pattern (mikuscore) | Candidate `lht-*` | Preserve IDs / contracts | Compatibility notes | +|---|---|---|---| +| Inline tooltip group (`.md-tooltip-group`, section help and settings help) | `lht-help-tooltip` | none required for tooltip wrapper itself | Replace duplicated icon/tooltip markup first; keep surrounding heading/label structure unchanged. | +| File chooser button + hidden file input + file name text | `lht-file-select` | `fileInput`, `fileSelectBtn`, `fileNameText` | Must keep current click and `change` flow used in `main.ts`; if component-generated IDs differ, migration is blocked. | +| Global file loading overlay (`#fileLoadOverlay`) | `lht-loading-overlay` | `fileLoadOverlay` | `setFileLoadInProgress` currently toggles `md-hidden` and `aria-hidden`; adapt to `active`/`setActive` without breaking behavior. | +| Inline UI message blocks (`#inputUiMessage`, `#uiMessage`) | `lht-error-alert` (+ optional `lht-toast`) | `inputUiMessage`, `uiMessage` | Existing code sets class names and text directly; either keep wrapper IDs or add adapter helper before replacing markup. | +| Source/new input textareas (`#xmlInput`, `#abcInput`, `#museScoreInput`, `#vsqxInput`, `#meiInput`, `#lilyPondInput`) | `lht-text-field-help` | all existing textarea IDs | Multi-line use requires `rows`; migration is low risk if IDs stay on generated field elements. | +| New-score numeric inputs (`#newPartCount`, `#newTimeBeats`) | `lht-text-field-help` | `newPartCount`, `newTimeBeats` | Keep numeric attributes (`min`, `max`, `step`) and live `input/change` listeners. | +| Existing selects in input/edit/output (`#newTimeBeatType`, `#newKeyFifths`, `#zipEntrySelect`, `#durationPreset`, `#graceTimingMode`, `#metricAccentProfile`, `#midiProgramSelect`, `#midiExportProfile`, `#midiImportQuantizeGrid`, `#playbackWaveform`) | `lht-select-help` | all listed IDs | For `#zipEntrySelect`, options are populated dynamically by JS; ensure runtime option append still works after component conversion. | +| Switch rows (`#newTemplatePianoGrandStaff`, `#keepMksMetaMetadataInMusicXml`, `#keepMksSrcMetadataInMusicXml`, `#keepMksDbgMetadataInMusicXml`, `#exportMusicXmlAsXmlExtension`, `#compressXmlMuseScoreExport`, `#metricAccentEnabled`, `#midiImportTripletAware`, `#forceMidiProgramOverride`, `#playbackUseMidiLike`) | `lht-switch-help` | all listed switch IDs | Event wiring is direct (`change` listeners in `main.ts`); keep `checked`/`disabled` semantics identical. | +| Hero/header block at top of page | `lht-page-hero` (later phase) | no direct ID dependency today | Defer to later phase to avoid layout regressions in tab header and GitHub link area. | +| Optional page menu | `lht-page-menu` (if needed) | none currently | Not mandatory for current functionality; only adopt if it simplifies future multi-page consistency. | + +## Risk classification for migration order + +1. Low risk +- Tooltip-only replacement (`lht-help-tooltip`) +- Overlay and status primitives (`lht-loading-overlay`, `lht-error-alert`, `lht-toast`) with adapter layer + +2. Medium risk +- Text fields and most selects/switches with strict ID preservation + +3. High risk +- File picker and ZIP entry selector (tight coupling with current event flow and dynamic option handling) +- Hero/page-frame normalization (`lht-page-hero`) due to layout coupling + +## Non-negotiable constraints + +- Do not change `lht-cmn/js/components.js` or `lht-cmn/css/components.css` without explicit user approval. +- Keep all `src/ts/main.ts` element lookup contracts valid during every migration step. +- Migrate in small, verifiable slices and run UI regression checks after each slice. diff --git a/docs/spec/LOCAL_WORKFLOW.md b/docs/spec/LOCAL_WORKFLOW.md index 76e6a93..fa8f1ef 100644 --- a/docs/spec/LOCAL_WORKFLOW.md +++ b/docs/spec/LOCAL_WORKFLOW.md @@ -43,11 +43,13 @@ 3. fixture・テスト更新(必要時) 4. `npm run check:all` 実行 5. 差分確認 +6. downstream 影響確認 補足: - 回帰不具合は、可能な限り最小 fixture を `tests/fixtures/` に固定する。 - 一時的な検証ファイルは恒久管理しない(調査完了後に除去する)。 +- `mikuscore` の更新が shared behavior、format contract、生成物、AI handoff 前提に影響する場合は、`devel` を連携先とする downstream の `mikuscore-skills` および `miku-abc-player` 側でも追従作業が発生しうることを意識する。 ## 4. 品質ゲート方針 @@ -71,7 +73,7 @@ - 手本付き変換比較(Reference-guided parity test)を任意で実施できる。 - 例: `source.mscx` と MuseScore公式 `reference.musicxml` を比較して、mikuscore 変換結果の差分を意味ベースで分類する。 -- 実データがライセンス上コミット不可の場合は `tests/fixtures-local/` 配下で扱う。 +- 実データがライセンス上コミット不可の場合は `tests/local-data/` 配下で扱う。 - 詳細方針は `docs/spec/MUSESCORE_EXPORT_PARITY_TEST.md` を参照する。 ## 6. 禁止事項(本運用) diff --git a/docs/spec/MIDI_IO.md b/docs/spec/MIDI_IO.md index 578f494..b0c80c8 100644 --- a/docs/spec/MIDI_IO.md +++ b/docs/spec/MIDI_IO.md @@ -186,6 +186,7 @@ The module includes a built-in raw SMF Type-1 writer path in addition to `midi-w - time signature meta (`FF 58`) - key signature meta (`FF 59`) - optional mikuscore SysEx chunks + - optional mikuscore text meta (`FF 01`, `mks:*`) - `MTrk #N` (note tracks by `trackId`): - program change per used channel (except ch10) - note-on / note-off events @@ -216,6 +217,22 @@ For same-tick same-pitch situations, event ordering is configurable: - raw writer path enabled - retrigger policy defaults to `off_before_on` +#### `mks` metadata emission policy + +- `buildMidiBytesForPlayback(..., options)` supports: + - `embedMksSysEx?: boolean` (default: `true`) + - `emitMksTextMeta?: boolean` (default: `true`) +- `embedMksSysEx` controls mikuscore SysEx payload emission on the meta track. +- `emitMksTextMeta` controls text meta lines such as: + - `mks:meta-version:1` + - `mks:title:*` + - `mks:movement-title:*` + - `mks:composer:*` + - `mks:pickup-ticks:*` + - `mks:part-name-track:*` +- In app export flow, `Keep roundtrip metadata (mks:meta:*)` controls `emitMksTextMeta`. +- `Keep roundtrip metadata` does NOT disable `embedMksSysEx`; SysEx diagnostics/statistics remain enabled by default. + #### Known constraints - raw writer currently targets deterministic export parity behavior, not full DAW-grade rendering semantics. @@ -298,13 +315,13 @@ Rules: When analyzing rendering/import issues, inspect: -- `part > measure > attributes > miscellaneous > miscellaneous-field[name="mks:midi-meta-count"]` -- `part > measure > attributes > miscellaneous > miscellaneous-field[name^="mks:midi-meta-"]` +- `part > measure > attributes > miscellaneous > miscellaneous-field[name="mks:dbg:midi:meta:count"]` +- `part > measure > attributes > miscellaneous > miscellaneous-field[name^="mks:dbg:midi:meta:"]` Recommended flow: 1. identify the problematic measure and note on screen. -2. open the same measure in MusicXML and read `mks:midi-meta-*`. +2. open the same measure in MusicXML and read `mks:dbg:midi:meta:*`. 3. compare note duration/type and debug payload (`key`, `vel`, `sd`, `dd`, `tk0`, `tk1`) to detect where conversion diverged. ### Drum note rendering diff --git a/docs/spec/MISCELLANEOUS_FIELDS.md b/docs/spec/MISCELLANEOUS_FIELDS.md new file mode 100644 index 0000000..448e227 --- /dev/null +++ b/docs/spec/MISCELLANEOUS_FIELDS.md @@ -0,0 +1,123 @@ +# miscellaneous-field Metadata (mikuscore) + +このドキュメントは、mikuscore が MusicXML の +`attributes > miscellaneous > miscellaneous-field` に付与する情報を整理したものです。 + +## Scope + +- 対象: mikuscore が生成・追記する `miscellaneous-field` +- 非対象: 外部ツールが独自に付与したフィールド仕様 + +## Namespace Policy + +新規実装の目標は、mikuscore 付与情報を `mks:` 配下に集約すること。 + +- `mks:meta:*`: ラウンドトリップ復元に使う安定メタデータ +- `mks:diag:*`: 変換時の警告/劣化情報 +- `mks:src:*`: 元データ退避(raw payload 断片や由来情報。`mks:dbg:*` に位置付けが近い) +- `mks:dbg:*`: 調査用デバッグ情報(変更されやすい) + +補足: + +- 出力時の `miscellaneous-field` は本ドキュメントの `mks:*` 命名を基準とする。 + +## mks:dbg:* Fields (Target) + +### MEI import debug + +- `mks:dbg:mei:notes:count` +- `mks:dbg:mei:notes:0001` ... `mks:dbg:mei:notes:####` + +Payload keys: + +- 共通: `idx,m,stf,ly,li,k,du,dt` +- `note` のとき: `pn,oc`(必要時 `ac`) +- `chord` のとき: `cn` + +### ABC import debug + +- `mks:dbg:abc:meta:count` +- `mks:dbg:abc:meta:0001` ... `mks:dbg:abc:meta:####` + +Payload keys: + +- `idx,m,v,r,g,ch,st,al,oc,dd,tp` + +### MIDI import debug + +- `mks:dbg:midi:meta:count` +- `mks:dbg:midi:meta:0001` ... `mks:dbg:midi:meta:####` + +Payload keys: + +- `idx,tr,ch,v,stf,key,vel,sd,dd,tk0,tk1` + +## mks:meta:* Fields (Target) + +### MIDI SysEx metadata (roundtrip restore) + +- `mks:meta:midi:sysex:count` +- `mks:meta:midi:sysex:0001` ... `mks:meta:midi:sysex:####` +- `mks:meta:midi:sysex:`(要約キー) + +代表的な ``: + +- `schema,namespace,app,source,tpq` +- `track-count,event-count,tempo-event-count,timesig-event-count` +- `keysig-event-count,control-event-count,channel-count` +- `fingerprint-fnv1a32` + +## mks:src:* Fields (Target) + +### ABC raw source + +- `mks:src:abc:raw-encoding` +- `mks:src:abc:raw-length` +- `mks:src:abc:raw-encoded-length` +- `mks:src:abc:raw-chunks` +- `mks:src:abc:raw-truncated` +- `mks:src:abc:raw-0001` ... `mks:src:abc:raw-####` + +### MIDI raw bytes + +- `mks:src:midi:raw-encoding` +- `mks:src:midi:raw-bytes` +- `mks:src:midi:raw-hex-length` +- `mks:src:midi:raw-chunks` +- `mks:src:midi:raw-truncated` +- `mks:src:midi:raw-0001` ... `mks:src:midi:raw-####` + +### MuseScore raw source + +- `mks:src:musescore:raw-encoding` +- `mks:src:musescore:raw-length` +- `mks:src:musescore:raw-encoded-length` +- `mks:src:musescore:raw-chunks` +- `mks:src:musescore:raw-0001` ... `mks:src:musescore:raw-####` +- `mks:src:musescore:version` + +### MEI-derived source annotations + +- `mks:src:mei:*` + - MEI 側 annot から取り込まれた名称を `mks:src:mei:` プレフィクス化 + +## mks:diag:* Fields (Target) + +- `mks:diag:count` +- `mks:diag:0001` ... `mks:diag:####` + +`mks:diag:0001` 以降は `;` 区切りの構造化文字列。 +例: + +- `level=warn;code=OVERFULL_CLAMPED;fmt=mei;...` +- `level=warn;code=...;fmt=abc;...` +- `level=warn;code=...;fmt=midi;...` +- `level=warn;code=...;fmt=lilypond;...` +- `level=warn;code=...;fmt=musescore;...` + +## Notes + +- `*-count` は対応する連番フィールド数を示す。 +- 連番は `0001` 形式(4桁ゼロ埋め)。 +- `mks:meta:*` は長期互換を優先する。 +- `mks:dbg:*` は将来変更される可能性がある。 diff --git a/docs/spec/MUSESCORE_EXPORT_PARITY_TEST.md b/docs/spec/MUSESCORE_EXPORT_PARITY_TEST.md index 65b3e4a..40fdba4 100644 --- a/docs/spec/MUSESCORE_EXPORT_PARITY_TEST.md +++ b/docs/spec/MUSESCORE_EXPORT_PARITY_TEST.md @@ -1,5 +1,12 @@ # MuseScore Export Parity Test Strategy +## Positioning + +- This document is a parity verification strategy document (test/operation policy). +- It is not the converter behavior specification. +- Converter I/O behavior is defined in: + - `docs/spec/MUSESCORE_IO.md` + ## 背景 - mikuscore の内部正本は MusicXML とする。 - 一方、配布元が MuseScore の曲データでは、作者の実質原本は MuseScore 形式(`.mscz/.mscx`)である可能性が高い。 @@ -67,7 +74,7 @@ ## 当面の運用(CI未導入・repo外) - ライセンスや再配布条件が未確定な間は、実曲fixtureをリポジトリに置かない。 -- 比較データは Git 非管理ディレクトリで管理する(例: `tests/fixtures-local/roundtrip/musescore/` または `~/mikuscore-private-fixtures/`)。 +- 比較データは Git 非管理ディレクトリで管理する(例: `tests/local-data/roundtrip/musescore/` または `~/mikuscore-private-fixtures/`)。 - 当面はローカル実行で次を行う。 1. `MuseScore -> candidate_from_musescore.musicxml` 2. `MIDI -> candidate_from_midi.musicxml` @@ -83,7 +90,7 @@ ### ローカル実行例(Git非管理 fixture) -- 例: `tests/fixtures-local/roundtrip/musescore/paganini/` に `source.mscx` と `reference.musicxml` を置く。 +- 例: `tests/local-data/roundtrip/musescore/paganini/` に `source.mscx` と `reference.musicxml` を置く。 - 実行コマンド: - `npm run test:all -- tests/spot/local-musescore-reference-parity.spot.spec.ts` - `npm run test:all -- tests/spot/local-musicxml-reference-to-musescore.spot.spec.ts` @@ -117,60 +124,11 @@ - 仕様変更時に、どの記譜要素へ影響したかを定量的に追跡できる。 - MusicXML正本方針を維持したまま、MuseScore互換品質を継続改善できる。 -## MIDI -> MusicXML パリティ検証(劣化前提) - -### 位置づけ -- MIDIは記譜情報が大きく失われるため、MuseScore/MusicXMLと同じ完全再現テストにはしない。 -- 目的は「復元できるはずの意味」を比較し、MIDI変換器の改善点を特定すること。 +## MIDI parity note -### テストフロー -1. 同一曲について以下を準備する。 - - `source.mid`(MuseScoreからのエクスポート) - - `reference.musicxml`(MuseScore公式エクスポート) -2. mikuscore変換で `source.mid -> candidate_from_midi.musicxml` を生成する。 -3. `candidate_from_midi.musicxml` と `reference.musicxml` を、MIDIで復元可能な項目に限定して比較する。 - -### 比較対象(MIDIでカバー期待) -- 音高列(概ねの音高・上下関係) -- 発音タイミング(onset順序、拍位置) -- 音価(量子化後の長さ傾向) -- テンポ/拍子(取得可能範囲) -- トラック/チャンネル由来の声部分離(可能な範囲) - -### 比較対象外または低優先 -- 連符番号表示(7/8/9表記) -- スラー形状、タイ形状、アーティキュレーション詳細 -- オッターヴァ線、反復記号、レイアウト情報 -- 表示専用メタデータ - -### 合否・評価指標(例) -- `M0`: 音高/拍の大崩れがない -- `M1`: 小節単位の拍充足が安定している -- `M2`: 量子化誤差が許容範囲内(しきい値管理) -- 差分は「変換器改善で詰められる差分」か「MIDI仕様限界」かに分類する - -### 改善ループ -- 差分レポートを以下カテゴリで蓄積する。 - - 量子化ミス - - 声部分離ミス - - テンポ/拍子解釈ミス - - 仕様限界(対応不要) -- 対応可能カテゴリを優先して修正し、同一fixtureで回帰確認する。 - -### 運用メモ(2026-02-26, moonlight) -- `safe (cand(midi)) practical diff = 307` -- `musescore_parity (cand(parity)) practical diff = 172` -- `playback practical diff = 183`(比較参考) -- MIDI import の同tick同pitch再発音で、`note-off` を最古 `note-on` に対応づける FIFO ペアリングを採用。 - - これにより、イベント順(`on->off` / `off->on`)依存の崩れを抑制できる。 -- 比較サンプリング方針: - - `m12-m16` は既知の局所乖離として、スポット診断サンプリングから除外する。 - - 代わりに `m1-m4` を固定サンプル区間として確認する。 - - `m1-m4` の最新ホットスポット(safe/parity共通傾向): `m1=2, m2=2, m3=4, m4=4` -- 発音・長さの評価方針: - - 発音タイミング(onset)は厳格一致。 - - 長さ(duration)は比率許容(`1/2`〜`2`倍)を別軸で併記する。 - - 最新実測: `onset-strict + durationRatio[1/2..2]` は `parity=167`。 +- MIDI parity policy is intentionally managed outside this document. +- For MIDI import/export behavior and constraints, refer to: + - `docs/spec/MIDI_IO.md` ## 生成AIレビュー運用メモ - 生成AIに渡す入力は「正規化済みdiff」と「小節/声部インデックス付きの意味差分」を優先する。 diff --git a/docs/spec/MUSESCORE_IO.md b/docs/spec/MUSESCORE_IO.md new file mode 100644 index 0000000..5dc2ea3 --- /dev/null +++ b/docs/spec/MUSESCORE_IO.md @@ -0,0 +1,108 @@ +# MuseScore I/O Specification + +## Purpose + +This document defines the behavior of `src/ts/musescore-io.ts`. + +The module is responsible for: + +- importing MuseScore XML (`.mscx` content) into MusicXML +- exporting MusicXML into MuseScore XML (`.mscx` content) +- preserving musically relevant notation where representable +- emitting diagnostics metadata for import-side incident analysis + +--- + +## Public API + +- `convertMuseScoreToMusicXml(mscxSource, options): string` +- `exportMusicXmlDomToMuseScore(doc, options): string` + +### `convertMuseScoreToMusicXml` options + +- `sourceMetadata?: boolean` (default: `true`) +- `debugMetadata?: boolean` (default: `true`) +- `normalizeCutTimeToTwoTwo?: boolean` (default: `false`) +- `applyImplicitBeams?: boolean` (default: `true`) + +### `exportMusicXmlDomToMuseScore` options + +- `normalizeCutTimeToTwoTwo?: boolean` (default: `false`) + +--- + +## Import (`MuseScore -> MusicXML`) + +## Root and baseline + +- Input MUST be parseable XML. +- Root MUST contain `museScore > Score` (or `Score`). +- `Division` defaults to `480` when missing/invalid. + +## Measure and notation mapping + +- Time/key/tempo and staff/voice events are mapped into MusicXML measure structure. +- Tuplet/slur/tie/ottava/trill/dynamic/direction mappings are handled at event level. +- Unknown/unsupported input MAY generate `MUSESCORE_IMPORT_WARNING`. +- MuseScore key signature import accepts multiple `KeySig` representations: + - For non-transposing parts, importer reads `KeySig > accidental` and also accepts `KeySig > concertKey`. + - For transposing parts, importer prefers `KeySig > transposeKey` so that MusicXML `key` remains in written pitch; `concertKey` is not used as the written key when transpose metadata is present. + - `KeySig > accidental` remains a compatibility fallback for legacy/alternate MuseScore exports. + +## Repeat handling + +- Start/end repeat at measure boundary is imported. +- Mid-measure repeat markers from MuseScore `barline/BarLine subtype` variants are imported: + - `start-repeat` + - `end-repeat` + - `end-start-repeat` +- Mid-measure repeat is represented as MusicXML middle barline events. + +## Trill handling + +- Trill spanner transitions are mapped to `trill-mark` and `wavy-line start/stop`. +- Chord-local trill ornament is mapped as trill mark. +- Trill accidental near ornament is mapped to MusicXML `accidental-mark` when available. + +## Accidental spelling policy + +- If explicit accidental subtype is absent, importer MAY use MuseScore `tpc` to recover preferred spelling. +- Preferred spelling is propagated through pitch/accidental resolution to reduce enharmonic drift. + +## Beam policy + +- Explicit MuseScore beam mode is respected when present. +- If beam mode is absent and `applyImplicitBeams !== false`, importer infers implicit beams by beat grouping. +- If `applyImplicitBeams === false`, implicit beam fill is not applied. + +## Import diagnostics metadata + +- Import warnings are exported to `miscellaneous-field` (`mks:diag:*`) when debug metadata is enabled. +- Source chunks MAY be stored in `mks:src:mscx:*` fields when source metadata is enabled. + +--- + +## Export (`MusicXML -> MuseScore`) + +## Root and baseline + +- Export root is `museScore version="4.0"`. +- Global `Division` is computed from source score timing requirements. + +## Repeat handling + +- MusicXML left/right repeats are exported to MuseScore repeat representation. +- Mid-measure repeat information is exported as MuseScore barline subtype: + - `start-repeat` + - `end-repeat` + - `end-start-repeat` + +## Trill handling + +- MusicXML trill ornaments (`trill-mark`, `wavy-line`) are exported to MuseScore trill spanner/events. + +## Scope note + +- This spec defines I/O behavior of the converter implementation. +- Cross-tool parity strategy and fixture operations are defined separately in: + - `docs/spec/MUSESCORE_EXPORT_PARITY_TEST.md` diff --git a/docs/spec/PLAYBACK.md b/docs/spec/PLAYBACK.md index ef8951b..2ffc9ec 100644 --- a/docs/spec/PLAYBACK.md +++ b/docs/spec/PLAYBACK.md @@ -132,6 +132,17 @@ Therefore quick playback in MIDI-like mode MUST reflect the same nuance policy a --- +## Scale limitation and recommended workflow + +- Quick playback is a lightweight in-app preview feature. +- For large scores (long duration, many parts, dense events), playback MAY fail to run correctly or stably. +- This limitation is expected in current architecture and SHOULD be treated as a product constraint. + +When reliable playback is required for large scores: + +- Export to MIDI (`.mid`) from mikuscore. +- Play the exported MIDI in an external MIDI-capable player / DAW / notation app. + ## Error and diagnostics policy - Save failure diagnostics are surfaced through playback status text. diff --git a/docs/spec/SCREEN_SPEC.md b/docs/spec/SCREEN_SPEC.md index 1d3f59d..f139b9b 100644 --- a/docs/spec/SCREEN_SPEC.md +++ b/docs/spec/SCREEN_SPEC.md @@ -4,6 +4,11 @@ ## Purpose Define the current screen specification for `mikuscore` based on the actual UI text and tooltips in `mikuscore-src.html`. +Scope note: + +- This file is a screen text/layout inventory centered on actual UI copy. +- Normative UI behavior and interaction rules are defined in `docs/spec/UI_SPEC.md`. + ## Global Layout - Single-page application. - Top brand header: @@ -17,19 +22,19 @@ Define the current screen specification for `mikuscore` based on the actual UI t - `Export` ### Brand Tooltip `(i)` (`About mikuscore`) -- Browser-based local score editor. -- Preserves existing MusicXML structure while editing. -- Supports loading MusicXML/ABC, score preview, note editing, playback, and export/download (`MusicXML`/`ABC`/`MIDI`) in one screen. -- Intentionally small feature set for practical, fast editing, especially on smartphones. +- Browser-based MusicXML-first score converter. +- Uses MusicXML as the central interchange format for moving score data between formats. +- Supports loading score data, previewing structure, checking diagnostics, playback, and export/download in one screen. +- Intentionally focused on conversion, inspection, and handoff rather than deep notation editing. - Smartphone-centered, but usable on PCs as well. - Workflow guidance: - `1) Choose input and load` - - `2) Select from score preview` - - `3) Edit notes` - - `4) Verify by playback and export/download` + - `2) Inspect the score and diagnostics` + - `3) Verify by playback if needed` + - `4) Export or hand off in another format` - Positioning guidance: - - Use dedicated notation software for large-scale/complex work. - - Use mikuscore for quick input or focused partial tasks. + - Use dedicated notation software for large-scale or complex notation editing. + - Use mikuscore for conversion-oriented tasks. ## Tabs / Interaction - Clicking a top tab opens the corresponding panel. @@ -72,8 +77,8 @@ Define the current screen specification for `mikuscore` based on the actual UI t ### Actions - `Load from file` - `Load` (source mode) -- `Load sample 1` -- `Load sample 2` +- `Load sample 6` +- `Load sample 7` ### Messages - `inputUiMessage` for inline status/error. @@ -244,244 +249,14 @@ Define the current screen specification for `mikuscore` based on the actual UI t --- -## 日本語 -## 目的 -`mikuscore-src.html` の現行文言・ツールチップに合わせて、`mikuscore` の画面仕様を定義する。 - -## 全体レイアウト -- 単一ページ構成。 -- 上部ブランドヘッダ: - - `mikuscore` タイトル - - `About mikuscore` 情報チップ `(i)` - - GitHub リンク -- 4ステップのタブ導線: - - `Input` - - `Score` - - `Edit` - - `Export` - -### ブランドツールチップ `(i)` (`About mikuscore`) -- ブラウザで動くローカル譜面エディタ。 -- 編集時に既存 MusicXML 構造を極力維持。 -- 1画面で `MusicXML/ABC` 読み込み、譜面プレビュー、ノート編集、再生、`MusicXML/ABC/MIDI` 出力に対応。 -- 機能は意図的に絞り、特にスマホでの実用速度を優先。 -- スマホ中心だが PC 利用も可能。 -- ワークフロー案内: - - `1) 入力して読み込む` - - `2) 譜面で対象を選ぶ` - - `3) ノート編集` - - `4) 再生と出力で確認` -- 位置づけ: - - 大規模・複雑作業は専用作譜ソフト。 - - mikuscore はクイック入力や部分作業。 - -## タブ / 操作 -- 上部タブをクリックすると対応パネルを表示。 -- 現在タブは `is-active`。 -- 非表示パネルは `hidden`。 - -## パネル: Input -### セクションタイトル -- `1 Input` - -### ヘッダツールチップ `(i)` (`Input help`) -- まずここで譜面を読み込む(file/source)か新規作成する。 -- このステップ完了後に `Score` / `Edit` / `Export` へ進む。 - -### 入力形式ラジオ -- `MusicXML Input` -- `ABC Input` -- `New Score` - -### 読み込みモードラジオ -- `File input` -- `Source input` - -### ブロック -- `newInputBlock` - - `Use Piano Grand Staff template (treble + bass, single part)` - - `Track count (parts)` - - `Time signature` - - `Key signature` - - partごとの clef 選択 -- `fileInputBlock` - - ファイル選択(`Load from file`) - - 選択ファイル名表示 -- `sourceXmlInputBlock` - - `MusicXML` テキストエリア -- `abcInputBlock` - - `ABC` テキストエリア - -### アクション -- `Load from file` -- `Load`(source モード) -- `Load sample 1` -- `Load sample 2` - -### メッセージ -- `inputUiMessage` に inline の状態/エラーを表示。 -- `localDraftNotice` でローカルドラフトの有無を通知。 - -## パネル: Score -### セクションタイトル -- `2 Score` - -### ヘッダツールチップ `(i)` (`Score preview help`) -- 読み込み済み譜面の確認。 -- 簡易再生の試行。 -- 編集対象小節の選択。 -- 対象小節のノートを選んでから `Edit` で編集反映。 - -### アクション -- `Play` -- `Stop` -- `Add Measure (End)` - -### メイン表示 -- `debugScoreArea` に Verovio SVG 譜面を描画。 -- クリックで SVG 要素 id から内部 `nodeId` へ解決。 - -### ステータス -- `playbackText`(初期値: `Playback: idle`)。 - -## パネル: Edit -### セクションタイトル -- `3 Edit` - -### ヘッダツールチップ `(i)` (`Edit help`) -- 編集は休符を音符化して始める。 -- 選択小節内で次を調整: - - 分割 - - 音高 - - 臨時記号 - - 音価 -- 簡易再生に対応。 -- `Apply` で `Score` へ反映。 -- `Discard` で当該小節の編集中変更を破棄。 -- 矢印ボタンで小節移動。 -- MusicXML 構造破壊リスクを避けるため、編集範囲は意図的に限定。 - -### ナビゲーション / 文脈 -- 選択パート名表示(`measurePartNameText`)。 -- 小節移動ボタン: - - 同一トラック前小節(`←`) - - 同一トラック次小節(`→`) - - 同小節の前トラック(`↑`) - - 同小節の次トラック(`↓`) - -### 未選択状態 -- タイトル: `No measure selected` -- 本文: `Click a measure in the score to select it` -- ボタン: `Go to Score` - -### 選択小節表示 -- `measureEditorArea` に選択小節の Verovio プレビュー。 -- `uiMessage` に inline メッセージを表示。 - -### 小節反映アクション -- `Apply` -- `Discard` - -### ノート編集アクション -- `Convert Rest to Note` -- `Split Note` -- `Delete Note` -- `Play`(小節再生) - -### 音高 / 音価コントロール -- ステップ上下(`↑` / `↓`)と現在 step 表示。 -- 変化記号: - - `None` - - `♭♭` - - `♭` - - `♮` - - `♯` - - `♯♯` -- 音価プリセット: - - `(Select duration)` - -## パネル: Export -### セクションタイトル -- `4 Export` - -### ヘッダツールチップ `(i)` (`Export help`) -- mikuscore から成果物を持ち出す場所。 -- 主経路は `MusicXML` 出力。 -- `ABC` と軽量 `MIDI` はクイック確認用途。 -- 本格制作/書き出しは専用ソフトを想定。 - -### 出力アクション -- `Export MusicXML`(primary) -- `Export ABC` -- `Export MIDI` -- `Discard Draft`(条件付き表示) - -### 設定カード -- アコーディオンタイトル: `MIDI & Playback Settings` - -#### ブロック: `MIDI & Playback Shared Settings` -- `Grace Timing Mode` - - 選択肢: - - `Before beat (appoggiatura-like)` - - `On beat (principal delayed)` - - `Classical equal split` - - ツールチップ: MIDI-like playback と MIDI export の両方に適用。 -- `Use metric beat accents`(スイッチ) - - ツールチップ: - - MIDI-like playback / export で拍感の微小強調を付与。 - - パターン例: - - `4/4: strong-weak-medium-weak` - - `6/8: strong-weak-weak-medium-weak-weak` - - `3-beat: strong-weak-weak` - - `5-beat: strong-weak-medium-weak-weak` - - `others: strong-weak-weak-...` -- `Accent amount` - - 選択肢: - - `Subtle` - - `Balanced` - - `Strong` - - ツールチップ: アクセント有効時の velocity 差を調整。 - -#### ブロック: `MIDI Settings` -- `MIDI Export Instrument` - - ツールチップ: MusicXML 側に楽器指定がない part で使用。 -- `Always override instrument`(スイッチ) - - ツールチップ: MusicXML 楽器指定より選択中出力楽器を常に優先。 - -#### ブロック: `Playback Settings` -- `Use MIDI-like playback`(スイッチ) - - ツールチップ: 簡易再生で MIDI 風の timing/expression を使用。 -- `Quick Playback Tone` - - 選択肢: - - `Sine` - - `Triangle` - - `Square` - -#### 設定アクション / デバッグ -- `Reset to defaults` -- ブロック: `MIDI Debug` - - `Refresh MIDI Debug` - - `midiDebugText` 出力領域 - -#### ブロック: `General Settings` -- `Export MusicXML text as .xml extension`(スイッチ、デフォルトOFF) - - ツールチップ: デフォルトのテキスト出力は `.musicxml`、有効時は `.xml`。 -- `Compress MusicXML / MuseScore export`(スイッチ) - - ツールチップ: 有効時は MusicXML が `.mxl`、MuseScore が `.mscz`。 -- 相互排他ルール: - - `.xml extension` が ON のとき、圧縮出力は強制 OFF。 - - 圧縮出力を ON にしたとき、`.xml extension` は OFF。 - -### ファイル命名規則 -- MusicXMLテキスト: デフォルト `mikuscore-YYYYMMDDhhmm.musicxml`、有効時 `mikuscore-YYYYMMDDhhmm.xml` -- `mikuscore-YYYYMMDDhhmm.abc` -- `mikuscore-YYYYMMDDhhmm.mid` +## 日本語(抄訳) -## 診断 / メッセージ表示 -- `inputUiMessage` / `uiMessage` に inline フィードバックを表示。 -- save/dispatch の診断は core の意味を保ったまま表示。 +- 正本は上記 English セクションです。 +- 本セクションは画面仕様の要点のみを記載します。 +- 例外として、未決定事項や検討中メモは日本語のみで記述する場合があります。 -## 非対象 -- 複雑な作譜ワークフロー。 -- 多段モーダル中心の導線。 -- 画面内高度履歴管理(`undo`/`redo`)。 +### 要点 +- 本文書は `mikuscore-src.html` の画面文言・配置インベントリです。 +- 規範的な UI 挙動は `docs/spec/UI_SPEC.md` を参照してください。 +- 主要導線は `Input / Score / Edit / Export` の4パネルです。 +- `MIDI & Playback Settings` と `General Settings` の詳細仕様は English セクションを参照してください。 diff --git a/docs/spec/SPEC.md b/docs/spec/SPEC.md index d31d607..685eff4 100644 --- a/docs/spec/SPEC.md +++ b/docs/spec/SPEC.md @@ -1,6 +1,13 @@ # Browser-based MusicXML Score Editor ## Core Specification (MVP) +Scope note: + +- This file is the top-level MVP core spec (principles and invariants). +- Detailed command behavior is defined in `docs/spec/COMMAND_CATALOG.md`. +- Diagnostic catalog is defined in `docs/spec/DIAGNOSTICS.md`. +- Architecture boundaries are defined in `docs/spec/ARCHITECTURE.md`. + --- # 1. Design Principles diff --git a/docs/spec/TERMS.md b/docs/spec/TERMS.md index 03316f7..e7b0769 100644 --- a/docs/spec/TERMS.md +++ b/docs/spec/TERMS.md @@ -4,6 +4,20 @@ Normative terms and MVP scope boundaries. +Scope note: + +- This file is a glossary/scope index. +- Normative behavior details are defined in: + - `docs/spec/SPEC.md` + - `docs/spec/COMMAND_CATALOG.md` + - `docs/spec/DIAGNOSTICS.md` + +## Language Policy + +- English text is the normative source unless explicitly noted otherwise. +- Japanese sections are abridged translations for readability. +- Exception: for undecided points or in-progress notes, Japanese-only entries MAY be used temporarily. + ## Normative Keywords - `MUST`: required @@ -18,7 +32,7 @@ Normative terms and MVP scope boundaries. - `Dirty`: successful content-changing edit has occurred. - `No-op save`: `dirty === false`, returns original XML text unchanged. -## MVP In Scope +## MVP In Scope (Summary) - DOM-preserving load/edit/save. - Commands whose voice matches the target note voice. @@ -27,7 +41,7 @@ Normative terms and MVP scope boundaries. - Split-note command (`split_note`). - Rest-to-note conversion via `change_to_pitch`. -## MVP Out of Scope +## MVP Out of Scope (Summary) - Full automatic notation repair across arbitrary contexts. - Cross-voice/global structural reflow. diff --git a/docs/spec/TEST_CFFP.md b/docs/spec/TEST_CFFP.md index 6471255..ca2e2a2 100644 --- a/docs/spec/TEST_CFFP.md +++ b/docs/spec/TEST_CFFP.md @@ -4,6 +4,11 @@ `CFFP` (Cross-Format Focus Parity) defines focused, minimal, cross-format roundtrip tests. +Scope note: + +- This file is the authoritative CFFP case catalog and per-format policy source. +- `docs/spec/TEST_MATRIX.md` tracks required automated gates at matrix level. + One topic at a time: - prepare a minimal `MusicXML` fixture for that topic - run `MusicXML -> format -> MusicXML` for all supported formats diff --git a/docs/spec/TEST_MATRIX.md b/docs/spec/TEST_MATRIX.md index b6eb220..3b101f8 100644 --- a/docs/spec/TEST_MATRIX.md +++ b/docs/spec/TEST_MATRIX.md @@ -4,6 +4,12 @@ Executable test planning mapped from MVP requirements. +Scope note: + +- This file defines required automated quality-gate tests. +- Detailed CFFP case catalog and per-format preserve/degrade policy are maintained in: + - `docs/spec/TEST_CFFP.md` + ## Required Automated Tests 1. `RT-0 No-op save returns original text` diff --git a/docs/spec/UI_SPEC.md b/docs/spec/UI_SPEC.md index 7f7733d..b60bc5d 100644 --- a/docs/spec/UI_SPEC.md +++ b/docs/spec/UI_SPEC.md @@ -6,6 +6,11 @@ This document defines current MVP UI behavior for `mikuscore`. The UI is only an interaction layer; Core remains the single source of truth for score mutation. +Scope note: + +- This file is the normative UI behavior specification. +- Screen text inventory and tooltip copy are maintained in `docs/spec/SCREEN_SPEC.md`. + ## Non-Negotiable Rule - UI MUST NOT mutate XML DOM directly. - UI MUST call core APIs only: `load(xml)`, `dispatch(command)`, `save()`. @@ -86,86 +91,14 @@ Top-level flow is a 4-step tabbed stepper: --- -## 日本語 -## 目的 -本ドキュメントは `mikuscore` の MVP UI 振る舞いを定義する。 - -UI は操作レイヤのみで、譜面変更の正本は Core とする。 - -## 非交渉ルール -- UI は XML DOM を直接変更しない。 -- UI は Core API(`load(xml)`, `dispatch(command)`, `save()`)のみ呼ぶ。 - -## 画面構成 -4ステップのタブ式ステッパー: -1. 入力 (`data-tab="input"`) -2. 譜面 (`data-tab="score"`) -3. 編集 (`data-tab="edit"`) -4. 出力 (`data-tab="save"`) - -## 入力仕様 -- 入力種別ラジオ: - - `MusicXML入力` - - `ABC入力` - - `新規作成` -- 入力モードラジオ: - - `ファイル読み込み` - - `ソース入力` -- `ABC入力` の読み込み時: - - ABC -> MusicXML へ変換 - - 後続処理は MusicXML DOM を正本として継続 - -## 譜面仕様 -- Verovio SVG プレビューを操作対象とする。 -- 音符クリックで `nodeId` を解決する。 -- マッピングは以下の順で解決: - - target/ancestor id 走査 - - `elementsFromPoint` フォールバック -- 再生コントロール(`再生`, `停止`)を提供。 - -## 再生仕様(iPhone Safari 配慮) -- iPhone Safari の autoplay 制約上、音の開始にはユーザー操作起点が必要。 -- UI は `click` 前段の `pointerdown` / `touchstart` で先行アンロックを行う。 -- シンセ再生前に、ユーザー操作に紐づく経路で `AudioContext.resume()` を実行する。 -- `AudioContext` が無い実行環境では `webkitAudioContext` フォールバックを使う。 -- 初回再生安定化のため、極短いほぼ無音バッファ再生でアンロックする。 -- Web Audio 非対応や resume 失敗時は UI を壊さず、状態テキストで失敗を通知する。 - -## 編集仕様 -- 小節未選択時は empty-state カードを表示し、`譜面へ移動` を提供。 -- 小節選択時: - - 小節プレビュー表示 - - 編集コントロール表示 -- コマンド群: - - `休符を音符化` - - `音符分割` - - `音符削除` - - 音名 up/down - - 臨時記号(`なし`, `♭♭`, `♭`, `♮`, `♯`, `♯♯`) - - 音価ドロップダウン -- 診断メッセージは音価ドロップダウン直下(`#uiMessage`)に表示。 - -## 出力仕様 -- 出力ボタン: - - `MusicXML出力` - - `ABC出力` - - `MIDI出力` -- General Settings: - - `Export MusicXML text as .xml extension`(デフォルト: OFF) - - `Compress MusicXML / MuseScore export` - - `Export MusicXML text as .xml extension` が ON の間は、圧縮出力は強制 OFF。 - - 圧縮出力を ON にした場合、`Export MusicXML text as .xml extension` は OFF になる。 -- ファイル名は衝突緩和のためタイムスタンプを付与: - - MusicXMLテキスト出力: デフォルト `mikuscore-YYYYMMDDhhmm.musicxml`、オプション有効時 `mikuscore-YYYYMMDDhhmm.xml` - - `mikuscore-YYYYMMDDhhmm.abc` - - `mikuscore-YYYYMMDDhhmm.mid` +## 日本語(抄訳) -## 選択・コマンド規則 -- 選択キーは `nodeId`。 -- コマンド後に選択ノードが消えた場合は選択解除。 -- 診断情報は Core の結果を正とする。 +- 正本は上記 English セクションです。 +- 本セクションは要点のみを示します。 +- 例外として、未決定事項や検討中メモは日本語のみで記述する場合があります。 -## アクセシビリティ / UX -- ボタンラベルを明示する。 -- empty/disabled 状態を視認可能にする。 -- 編集操作は明示的に実行し、隠れた自動適用は行わない。 +### 要点 +- UI は操作レイヤであり、Core が唯一の変更主体です。 +- UI は `load(xml)` / `dispatch(command)` / `save()` 以外で XML DOM を直接変更しません。 +- 画面は `Input -> Score -> Edit -> Export` の4段構成です。 +- 詳細な挙動・制約は English セクションを参照してください。 diff --git a/docs/spec/abc-compat-parser-ebnf.md b/docs/spec/abc-compat-parser-ebnf.md index 88cfc7b..a97322b 100644 --- a/docs/spec/abc-compat-parser-ebnf.md +++ b/docs/spec/abc-compat-parser-ebnf.md @@ -1,14 +1,56 @@ -# ABC Compat Parser EBNF (draft) +# ABC Compat Parser EBNF ## English -This document defines the grammar baseline for the project ABC parser. +This document defines the current grammar baseline for the project ABC parser. It is based on ABC 2.1 and includes currently supported compatibility behavior observed in real-world `abcjs` / `abcm2ps` style inputs. +Warning: + +- this document is a practical grammar baseline, not a fully synchronized dump of every parser helper and dispatch path in the current implementation +- when this document and implementation detail appear to diverge, treat implementation, regression tests, and `docs/spec/ABC_IO.md` as the more authoritative source for the currently supported bounded behavior +- update this document when the bounded grammar baseline changes materially, but do not assume every internal parser refactor requires line-by-line EBNF churn here + +The parser should be understood in three layers: + +- standard ABC surface +- compatibility behavior for real-world ABC variance +- `mikuscore` extension metadata comments (`%@mks ...`) used for roundtrip support + +ABC is a supported format in `mikuscore`. +This grammar therefore documents the implemented compatibility baseline for supported import behavior, rather than an experimental parser sketch. + +## Practical Interpretation + +ABC interoperability is influenced not only by the narrow core grammar, but also by de facto conventions widely seen in tools such as `abcjs` and `abcm2ps`. + +For that reason, this document should be read as: + +- a grammar baseline for the standard ABC surface actually implemented by `mikuscore` +- a record of compatibility behavior accepted for common real-world inputs +- not a promise that every informal ABC variant in the wild is accepted + +For `mikuscore`, `abcjs` / `abcm2ps` behavior is not itself the normative grammar. +Instead, it is evidence for de facto interoperability expectations that may justify explicit compatibility rules in this document. + +De facto compatibility should therefore be understood as: + +- acceptable to adopt when a pattern is common enough in practice +- acceptable to adopt when the intended musical meaning is sufficiently clear +- required to be documented in spec text and regression tests once adopted +- not a blanket reason to accept arbitrary malformed or ambiguous ABC + +When extending compatibility, the preferred policy is: + +- add support by recognizable pattern classes, not by one-off token hacks +- keep directive/context parsing separate from body note parsing +- fail clearly on input that is still structurally or musically uninterpretable after compatibility handling + ## Scope -- Header: `X,T,C,M,L,K,V` and `%%score` -- Body: note/rest (`z/x`), accidentals, length, tie (`-`), broken rhythm (`>` `<`), barlines, chords, tuplets -- Compatibility extensions: `M:C`, `M:C|`, inline text skip (`"..."`), standalone octave marker tolerance (`,` / `'`), mikuscore `%@mks ...` metadata comments +- Header: `X,T,C,M,L,K,U,V` and `%%score` +- Body: note/rest (`z/x`), accidentals, length, tie (`-`), broken rhythm (`>` `<`), barlines, chords, tuplets, overlay (`&`) +- Compatibility behavior: `M:C`, `M:C|`, inline text skip (`"..."`), standalone octave marker tolerance (`,` / `'`) +- `mikuscore` extension metadata comments: `%@mks ...` ## EBNF @@ -21,7 +63,7 @@ score_expr = { score_group | voice_id | ws } ; score_group = "(" , { ws | voice_id } , ")" ; header = header_key , ":" , ws* , header_value ; -header_key = "X" | "T" | "C" | "M" | "L" | "K" | "V" | letter ; +header_key = "X" | "T" | "C" | "M" | "L" | "K" | "U" | "V" | letter ; header_value = { any_char_except_newline } ; body = { body_token | ws } ; @@ -81,9 +123,19 @@ digit = "0".."9" ; - Treat `x` rest as `z` rest. - Support chords (`[CEG]`, `[A,,CE]`). - Support tuplets (`(3abc`, `(5:4:5abcde`) with duration scaling. -- Accept `%@mks` metadata comments (`key`, `measure`, `transpose`) and feed roundtrip metadata when present. +- Support overlay marker `&` by splitting the body stream into synthetic overlay voices at measure boundaries. +- Support `U:` single-character user-defined decoration aliases on import by expanding them into regular decoration markers before parsing. - Ignore `:` in barline variants (`:|`, `|:`, `||`) without parse failure. - Ignore standalone `,` / `'` for compatibility. +- Allow recognized bare `V:` clef shorthands such as `V:2 bass`, `V:1 treble C D |`, `V:1 c3`, and `V:2 c4`. +- Prefer class-based compatibility rules derived from common `abcjs` / `abcm2ps` practice over one-off special cases. +- Do not let unknown directive-tail fragments silently fall through into body note parsing. +- Prefer warning on unsupported bare `V:` tail words over later note/rest parse failure caused by directive leftovers. + +## `mikuscore` Extension Notes +- Accept `%@mks` metadata comments (`key`, `measure`, `transpose`) and feed roundtrip metadata when present. +- These comments are not part of the standard ABC musical surface. +- They are `mikuscore`-specific extension metadata used for restoration and roundtrip support. ## Growth Policy - Parsing robustness first (warning-first policy). @@ -92,30 +144,15 @@ digit = "0".."9" ; --- -## 日本語 -この文書は、プロジェクトの ABC パーサーにおける文法基準を定義する。 - -ABC 2.1 を土台とし、`abcjs` / `abcm2ps` 系の実データ差を現行実装で吸収している範囲を含む。 +## 日本語(抄訳) -## Scope -- ヘッダ: `X,T,C,M,L,K,V` と `%%score` -- ボディ: 音符、休符(`z/x`)、臨時記号、長さ、タイ(`-`)、broken rhythm(`>` `<`)、小節線、和音、連符 -- 許容拡張: `M:C`, `M:C|`, インライン文字列(`"..."`)のスキップ、単独オクターブ記号(`,`/`'`)の許容、mikuscore の `%@mks ...` メタコメント - -## EBNF -上記 English セクションの EBNF を正本とする。 +- 正本は上記 English セクションです。 +- 本セクションは要点のみを示します。 +- 例外として、未決定事項や検討中メモは日本語のみで記述する場合があります。 -## Compatibility Notes -- `A > B` のような空白入り broken rhythm を許容。 -- `"D"A` のような和音名/注釈は MusicXML 生成対象外としてスキップ(警告のみ)。 -- `x` 休符を `z` と同様に扱う。 -- chord (`[CEG]`, `[A,,CE]` など) を同時発音として扱う。 -- tuplet (`(3abc`, `(5:4:5abcde` など) を音価スケーリングで扱う。 -- `%@mks` メタコメント(`key` / `measure` / `transpose`)を受理し、存在時は往復メタ情報として利用する。 -- `:|`, `|:`, `||` などの `:` は小節補助記号として無視(構文エラー化しない)。 -- 単独の `,` / `'` は互換目的で無視して継続する。 - -## Growth Policy -- まず parse を落とさない(warning first)。 -- 音価・音高の意味解釈を追加する時は回帰テストを同時追加。 -- 実データ差分を吸収したら `Compatibility Notes` を更新する。 +### 要点 +- ABC 2.1 を基準に、実データ互換(`abcjs` / `abcm2ps` 系)を取り込みます。 +- EBNF は English セクションを正本として扱います。 +- 互換挙動(`M:C`, `M:C|`, standalone `,` / `'` など)を許容します。 +- `%@mks` は `mikuscore` 独自拡張コメントとして扱います。 +- 文法・意味解釈の拡張時は回帰テストを追加します。 diff --git a/index-src.html b/index-src.html new file mode 100644 index 0000000..5e27ec4 --- /dev/null +++ b/index-src.html @@ -0,0 +1,220 @@ + + + + + + + + + mikuscore + + + +
+

mikuscore

+

Updated: {{BUILD_DATE}}

+
+

English

+

+ mikuscore is a browser-based score format converter centered on MusicXML. + It runs offline as a single-file web app. +

+
    +
  • MusicXML-first conversion pipeline.
  • +
  • Designed to preserve existing MusicXML as much as possible.
  • +
  • Keeps conversion losses visible via diagnostics / metadata.
  • +
  • No installation required (single HTML, browser only).
  • +
+

Supported formats: MusicXML (`.musicxml` / `.xml` / `.mxl`), MuseScore (`.mscx` / `.mscz`), MIDI (`.mid` / `.midi`), VSQX (`.vsqx`), ABC (`.abc`), MEI (`.mei`, experimental), LilyPond (`.ly`, experimental).

+

+ A convert-first CLI is also available for scripted workflows. Related projects include + mikuscore-skills, which embeds mikuscore into generative-AI workflows, + and miku-abc-player, which makes an ABC-limited subset of mikuscore easier to use. +

+ +
+
+
+

Screenshots / スクリーンショット

+
+ mikuscore screenshot 1 + mikuscore screenshot 2 + mikuscore screenshot 3 + mikuscore screenshot 4 +
+
+
+
+

日本語

+

+ mikuscore は、MusicXML を中核に据えたブラウザベースの譜面フォーマット変換ソフトです。 + 単一 HTML 配布でオフライン動作します。 +

+
    +
  • MusicXML-first の変換パイプライン。
  • +
  • 既存 MusicXML を極力壊さない編集を重視しています。
  • +
  • 変換で生じた欠落を診断情報・メタデータで追跡できます。
  • +
  • インストール不要(単一 HTML、ブラウザのみ)。
  • +
+

対応フォーマット: MusicXML(`.musicxml` / `.xml` / `.mxl`)、MuseScore(`.mscx` / `.mscz`)、MIDI(`.mid` / `.midi`)、VSQX(`.vsqx`)、ABC(`.abc`)、MEI(`.mei`、実験的対応)、LilyPond(`.ly`、実験的対応)。

+

+ スクリプト利用向けには convert-first の CLI もあります。関連プロダクトとして、 + mikuscore-skills は mikuscore を生成 AI ワークフローに組み込むための agent skills、 + miku-abc-player は mikuscore の機能を ABC に限定して使いやすくした companion web app です。 +

+ +
+
+ + + diff --git a/index.html b/index.html index 270e1c5..89a808b 100644 --- a/index.html +++ b/index.html @@ -125,18 +125,25 @@

mikuscore

+

Updated: 2026-04-15

English

- mikuscore is a browser-based score editor for importing and exporting MusicXML, MuseScore, - MIDI, VSQX, ABC, MEI, and LilyPond, with notation preview and note editing. + mikuscore is a browser-based score format converter centered on MusicXML. + It runs offline as a single-file web app.

    +
  • MusicXML-first conversion pipeline.
  • Designed to preserve existing MusicXML as much as possible.
  • -
  • Works offline in a single HTML distribution.
  • -
  • Smartphone-centered workflows, with PC use also supported.
  • -
  • ABC, MEI, and LilyPond support is currently experimental.
  • +
  • Keeps conversion losses visible via diagnostics / metadata.
  • +
  • No installation required (single HTML, browser only).
+

Supported formats: MusicXML (`.musicxml` / `.xml` / `.mxl`), MuseScore (`.mscx` / `.mscz`), MIDI (`.mid` / `.midi`), VSQX (`.vsqx`), ABC (`.abc`), MEI (`.mei`, experimental), LilyPond (`.ly`, experimental).

+

+ A convert-first CLI is also available for scripted workflows. Related projects include + mikuscore-skills, which embeds mikuscore into generative-AI workflows, + and miku-abc-player, which makes an ABC-limited subset of mikuscore easier to use. +

+ + + diff --git a/mikuscore.html b/mikuscore.html index 321216d..b88e8f8 100644 --- a/mikuscore.html +++ b/mikuscore.html @@ -4,63 +4,60 @@ mikuscore + - - + + + +
+
+
+

+ + mikuscore + + mikuscore is a browser-based MusicXML-first score converter for moving score data between formats. + It uses MusicXML as the central interchange format and helps bridge notation tools, exchange files, and AI-oriented workflows. + It supports loading score data, previewing structure, checking diagnostics, and exporting to other formats in one screen. + MEI support is currently experimental. + mikuscore intentionally keeps the feature set focused on conversion, inspection, and handoff rather than deep notation editing. + It is smartphone-centered, but it can also be used on PCs. + Workflow: 1) Choose input and load 2) Inspect the score and diagnostics 3) Verify by playback if needed 4) Export or hand off in another format. + Use tools like MuseScore for large-scale or complex notation editing, and use mikuscore for conversion-oriented tasks. + + + + GitHub + +

+
-.ms-settings-grid { - display: grid; - gap: 0.65rem; - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); -} +
+ + + + +
-.ms-icon-button { - display: inline-flex; - align-items: center; - gap: 0.35rem; -} +
+
+

+ 1Input + + + To use mikuscore, first load your score here (from file/source) or create a new score. + Supported file types: MusicXML (`.musicxml`, `.xml`, `.mxl`), ABC (`.abc`), MIDI (`.mid`, `.midi`), VSQX (`.vsqx`), MEI (`.mei`), LilyPond (`.ly`), MuseScore (`.mscx`, `.mscz`). + You can move to Score/Edit/Output after completing this step. + + +

-.ms-btn-icon { - width: 1.25rem; - height: 1.25rem; - flex: 0 0 auto; -} +
+
+ + + +
+
-.ms-btn-icon--wide { - width: 1.7rem; -} +
+
+ + + + + + +
+
-.ms-status { - margin: 0.35rem 0; - color: var(--md-sys-color-on-surface-variant); -} +
+
+ + + + +
Key signature + + + +
+
+
+
-.ms-empty-state { - border: 1px solid #dfd9e9; - border-radius: 12px; - background: #f4f1f7; - min-height: 140px; - display: flex; - align-items: center; - justify-content: center; - padding: 1rem; - margin-bottom: 0.6rem; -} +
-.ms-empty-state.md-hidden { - display: none !important; -} +
+ + +
-.ms-empty-state-inner { - text-align: center; -} +
+ + +
-.ms-empty-state-title { - font-size: 1rem; - font-weight: 700; - color: #3d3947; -} +
+ + +
-.ms-empty-state-body { - margin-top: 0.35rem; - font-size: 0.9rem; - color: #6a6675; -} +
+ + +
-.ms-empty-state-actions { - margin-top: 0.7rem; -} +
+ + +
-.ms-track-label { - margin: 0.05rem 0 0.35rem; - color: #7a7587; - font-size: 0.72rem; - font-weight: 400; - letter-spacing: 0.005em; -} +
+ + +
-.ms-ui-message { - margin: 0.15rem 0 0.5rem; - padding: 0.55rem 0.7rem; - border-radius: 10px; - border: 1px solid transparent; - font-size: 0.88rem; - line-height: 1.4; -} +
+ + + + + + + + + +
+
+ +
+ +
+
+
+
-.ms-ui-message--inline { - margin-top: 0.35rem; - margin-bottom: 0; -} - -.ms-ui-message--error { - color: #7f1010; - background: #fde9e8; - border-color: #efb3b0; -} - -.ms-ui-message--warning { - color: #6a3f06; - background: #fff4e6; - border-color: #efcf9d; -} - -.ms-grid { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 0.7rem; -} - -.ms-field { - display: grid; - gap: 0.35rem; - font-size: 0.88rem; - color: var(--md-sys-color-on-surface-variant); -} - -.ms-field-label { - display: none; -} - -.ms-settings-card .ms-field-label { - display: inline-flex; - align-items: center; - gap: 0.35rem; - line-height: 1.2; - color: #4f495a; - font-size: 0.8rem; - font-weight: 600; -} - -.ms-settings-card .ms-field-label .md-info-chip { - margin-left: 0; -} - -.ms-settings-card .ms-field { - display: flex; - align-items: center; - justify-content: space-between; - gap: 0.7rem; -} - -.ms-settings-card .ms-field:not(.ms-field--switch) { - margin: 0.45rem 0; -} - -.ms-settings-card .ms-field .md-select { - flex: 0 1 300px; - min-width: 180px; -} - -.ms-check-field { - margin-top: 0.45rem; - display: flex; - align-items: center; - gap: 0.5rem; - font-size: 0.86rem; - color: #4f495a; -} - -.ms-check-field input[type="checkbox"] { - width: 1rem; - height: 1rem; - accent-color: #5f1ee6; -} - -.ms-switch-field { - margin-top: 0.45rem; - font-size: 0.86rem; - color: #4f495a; -} - -.ms-settings-card .ms-field--switch .ms-switch-field { - margin-top: 0; -} - -.ms-settings-card .ms-field--switch { - margin: 0.65rem 0 0.45rem; -} - -.ms-settings-card .ms-switch-field--control { - display: inline-flex; - align-items: center; - justify-content: flex-end; -} - -/* Keep duration selector on its own row for compact editing flow */ -.ms-grid .ms-field:nth-of-type(3) { - grid-column: 1 / -1; -} - -.ms-grid .ms-field:nth-of-type(3) .md-select { - width: min(26rem, 100%); -} - -.ms-grid .ms-field:nth-of-type(1) { - align-self: stretch; - display: flex; - align-items: center; -} - -.ms-grid .ms-field:nth-of-type(2) { - align-self: start; -} - -.ms-step-row { - display: grid; - grid-template-columns: auto auto; - grid-template-rows: auto auto; - column-gap: 0.55rem; - row-gap: 0.32rem; - align-items: center; - align-content: center; - justify-content: start; -} - -.ms-step-value { - grid-column: 1; - grid-row: 1 / span 2; - display: inline-block; - padding: 0.1rem 0.1rem 0.1rem 0; - min-width: 1.2em; - font-size: 1.25rem; - font-weight: 800; - color: var(--md-sys-color-on-surface); - line-height: 1.2; -} - -#pitchStepUpBtn { - grid-column: 2; - grid-row: 1; -} - -#pitchStepDownBtn { - grid-column: 2; - grid-row: 2; -} - -.ms-step-btn { - min-width: 6.3rem; - width: 6.3rem; - height: 6.3rem; - padding: 0; - display: inline-flex; - align-items: center; - justify-content: center; - font-size: 3.42rem; - line-height: 1; - font-weight: 700; -} - -.ms-step-btn.is-pressed { - background: rgba(98, 0, 238, 0.16); - border-color: rgba(98, 0, 238, 0.48); -} - -.ms-alter-row { - display: grid; - grid-template-columns: auto auto; - grid-template-rows: repeat(5, auto); - align-items: center; - justify-content: start; - gap: 0.35rem 0.35rem; - margin-top: 0.35rem; -} - -.ms-alter-btn { - min-width: 2.7rem; - width: 2.7rem; - height: 2.7rem; - padding: 0; - border-radius: 999px; - font-size: 1.1rem; - font-weight: 700; -} - -.ms-alter-btn[data-alter="none"] { - grid-column: 1; - grid-row: 3; - width: auto; - min-width: 3.7rem; - padding: 0 0.9rem; - border-radius: 999px; - font-size: 1rem; -} - -.ms-alter-btn[data-alter="2"] { grid-column: 2; grid-row: 1; } -.ms-alter-btn[data-alter="1"] { grid-column: 2; grid-row: 2; } -.ms-alter-btn[data-alter="0"] { grid-column: 2; grid-row: 3; } -.ms-alter-btn[data-alter="-1"] { grid-column: 2; grid-row: 4; } -.ms-alter-btn[data-alter="-2"] { grid-column: 2; grid-row: 5; } - -.ms-alter-btn.is-active { - background: rgba(98, 0, 238, 0.12); - border-color: rgba(98, 0, 238, 0.45); - color: var(--md-sys-color-primary); -} - -.ms-debug-meta { - margin: 0.35rem 0; - color: var(--md-sys-color-on-surface-variant); -} - -.ms-debug-wrap { - width: 100%; - max-width: 100%; - border: 1px solid var(--md-sys-color-outline); - border-radius: 12px; - padding: 0.55rem; - overflow-x: auto; - overflow-y: hidden; - white-space: nowrap; - background: var(--md-sys-color-surface); - -webkit-overflow-scrolling: touch; -} - -.ms-debug-score { - display: inline-block; - min-height: 100px; - min-width: max-content; -} - -.ms-debug-score svg { - display: block; - max-width: none; - height: auto; -} - -.ms-measure-editor { - border: 1px solid var(--md-sys-color-outline); - border-radius: 12px; - padding: 0.55rem; - overflow-x: auto; - overflow-y: hidden; - white-space: nowrap; - background: var(--md-sys-color-surface); - margin-bottom: 0.6rem; -} - -.ms-measure-editor .ms-note-selected { - fill: #ff0000 !important; - stroke: #ff0000 !important; -} - -.ms-measure-editor .ms-note-selected * { - fill: #ff0000 !important; - stroke: #ff0000 !important; -} - -.ms-debug-score .ms-measure-selected { - fill: #ff0000 !important; - stroke: #ff0000 !important; -} - -.ms-debug-score .ms-measure-selected * { - fill: #ff0000 !important; - stroke: #ff0000 !important; -} - -.ms-dev { - margin-top: 1.1rem; - border: 1px solid #e6e1ee; - border-radius: 14px; - background: var(--md-sys-color-surface-variant); - padding: 0.55rem 0.9rem 0.9rem; -} - -.ms-dev > summary { - cursor: pointer; - color: var(--md-sys-color-primary); - font-weight: 700; -} - -.ms-dev[open] > summary { - margin-bottom: 0.5rem; -} - -#diagArea .diag-error { - color: var(--md-danger); -} - -#diagArea .diag-warning { - color: #8a4b0f; -} - -@media (max-width: 900px) { - .ms-grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .ms-hero-link span { - display: none; - } - - .ms-hero-link { - padding: 0; - } -} - -@media (max-width: 640px) { - html, - body, - .md-page { - overflow-x: clip; - } - - .md-page { - padding: 8px; - } - - .md-card.ms-app { - padding: 14px; - border-radius: 14px; - } - - .ms-settings-card .ms-field { - flex-wrap: wrap; - } - - .ms-settings-card .ms-field .md-select { - flex: 1 1 100%; - } - - .ms-app { - margin: 8px auto; - } - - .ms-hero { - margin: -2px -2px 12px; - padding: 10px 10px 8px; - } - - .ms-grid { - grid-template-columns: auto 1fr; - column-gap: 0.65rem; - row-gap: 0.45rem; - align-items: start; - } - - .ms-top-tab { - min-width: 0; - padding: 0.42rem 0.45rem; - justify-content: center; - width: 100%; - } - - .ms-top-tab-label { - overflow: hidden; - text-overflow: ellipsis; - } - - .ms-edit-nav { - margin-left: 0; - width: 100%; - justify-content: flex-start; - } - - .ms-radio-group { - gap: 0.65rem; - } - - .ms-file-name { - display: block; - overflow-wrap: anywhere; - } - - .ms-debug-wrap, - .ms-measure-editor { - padding: 0.45rem; - } - - .ms-top-tab::after { - display: none; - } - - .ms-grid .ms-field:nth-of-type(2) .ms-alter-row { - justify-content: start; - } - - .ms-grid .ms-field:nth-of-type(3) { - margin-top: 0.15rem; - } - -} - - - - - -
-
-
-

- - mikuscore - - - - - - mikuscore is a browser-based local score editor focused on preserving existing MusicXML structure while editing. - It supports loading MusicXML/ABC/MIDI, score preview, note editing, playback, and export/download as MusicXML/ABC/MEI/MIDI in one screen. - MEI support is currently experimental. - mikuscore intentionally keeps the feature set small to make score editing practical and fast, especially on smartphones. - It is smartphone-centered, but it can also be used on PCs. - Workflow: 1) Choose input and load 2) Select from score preview 3) Edit notes 4) Verify by playback and export/download. - After loading, click notes in the score to select targets, then adjust pitch and duration. - Use tools like MuseScore for large-scale or complex work, and use mikuscore for quick input or focused partial tasks. - - - - - GitHub - -

-
- -
- - - - -
- -
-
-

- 1Input - - - - - - To use mikuscore, first load your score here (from file/source) or create a new score. - Supported file types: MusicXML (`.musicxml`, `.xml`, `.mxl`), ABC (`.abc`), MIDI (`.mid`, `.midi`), VSQX (`.vsqx`), MEI (`.mei`), LilyPond (`.ly`), MuseScore (`.mscx`, `.mscz`). - You can move to Score/Edit/Output after completing this step. - - -

- -
-
- - - -
-
- -
-
- - - - - - -
-
- -
-
- - - - -
-
-
- -
-
- No file selected -
- -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - - - -
-
-
-
-
-
- - +
+ + +