vinsynlib 0.3.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. {vinsynlib-0.3.0/src/vinsynlib.egg-info → vinsynlib-0.4.0}/PKG-INFO +174 -146
  2. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/README.md +174 -146
  3. vinsynlib-0.4.0/docs/unify2.md +534 -0
  4. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/pyproject.toml +5 -1
  5. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/__init__.py +1 -1
  6. vinsynlib-0.4.0/src/vinsynlib/backup.py +182 -0
  7. vinsynlib-0.4.0/src/vinsynlib/catalog.py +381 -0
  8. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/config.py +440 -1
  9. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/devchecks.py +23 -13
  10. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/favorites.py +15 -0
  11. vinsynlib-0.4.0/src/vinsynlib/livenames.py +142 -0
  12. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/midi.py +288 -1
  13. vinsynlib-0.4.0/src/vinsynlib/render.py +79 -0
  14. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/ui/__init__.py +3 -2
  15. vinsynlib-0.4.0/src/vinsynlib/ui/browser.py +65 -0
  16. vinsynlib-0.4.0/src/vinsynlib/ui/confirm.py +108 -0
  17. vinsynlib-0.4.0/src/vinsynlib/ui/modals.py +669 -0
  18. vinsynlib-0.4.0/src/vinsynlib/ui/prompt.py +74 -0
  19. vinsynlib-0.4.0/src/vinsynlib/ui/protocol.py +25 -0
  20. vinsynlib-0.4.0/src/vinsynlib/ui/work.py +149 -0
  21. vinsynlib-0.4.0/src/vinsynlib/undo.py +116 -0
  22. {vinsynlib-0.3.0 → vinsynlib-0.4.0/src/vinsynlib.egg-info}/PKG-INFO +174 -146
  23. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib.egg-info/SOURCES.txt +26 -1
  24. vinsynlib-0.4.0/tests/test_app_contract.py +53 -0
  25. vinsynlib-0.4.0/tests/test_backup.py +100 -0
  26. vinsynlib-0.4.0/tests/test_catalog.py +292 -0
  27. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/tests/test_config.py +322 -0
  28. vinsynlib-0.4.0/tests/test_confirm_screen.py +80 -0
  29. vinsynlib-0.4.0/tests/test_identity.py +199 -0
  30. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/tests/test_midi_and_checks.py +122 -0
  31. vinsynlib-0.4.0/tests/test_modals.py +517 -0
  32. vinsynlib-0.4.0/tests/test_prompt_screen.py +65 -0
  33. vinsynlib-0.4.0/tests/test_rating_cell.py +37 -0
  34. vinsynlib-0.4.0/tests/test_readme_modules.py +29 -0
  35. vinsynlib-0.4.0/tests/test_render.py +57 -0
  36. vinsynlib-0.4.0/tests/test_transport.py +144 -0
  37. vinsynlib-0.4.0/tests/test_undo.py +209 -0
  38. vinsynlib-0.4.0/tests/test_work.py +215 -0
  39. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/COPYING +0 -0
  40. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/DISCLAIMER.md +0 -0
  41. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/LICENSE +0 -0
  42. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/MANIFEST.in +0 -0
  43. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/Makefile +0 -0
  44. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/docs/UX-SPEC.md +0 -0
  45. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/setup.cfg +0 -0
  46. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/cli.py +0 -0
  47. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/conformance.py +0 -0
  48. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/keys.py +0 -0
  49. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/py.typed +0 -0
  50. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/spec.py +0 -0
  51. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/terms.py +0 -0
  52. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib/ui/hints.py +0 -0
  53. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib.egg-info/dependency_links.txt +0 -0
  54. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib.egg-info/requires.txt +0 -0
  55. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/src/vinsynlib.egg-info/top_level.txt +0 -0
  56. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/tests/test_favorites.py +0 -0
  57. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/tests/test_hints.py +0 -0
  58. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/tests/test_ux.py +0 -0
  59. {vinsynlib-0.3.0 → vinsynlib-0.4.0}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vinsynlib
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Shared base for ROMpler instrument browsers: settings, favourites, banks, dumps, CLI and key conventions
5
5
  License-Expression: GPL-2.0-or-later
6
6
  Project-URL: Homepage, https://github.com/lentferj/vinsynlib
@@ -34,15 +34,17 @@ SPDX-FileCopyrightText: Copyright (C) 2026 vinsynLib contributors
34
34
  The shared base of a family of terminal instrument browsers.
35
35
 
36
36
  Nine sibling programs browse nine instruments over MIDI from a terminal:
37
- [emorphed](https://github.com/lentferj/emorphed) (E-mu Morpheus),
38
- [ensqsqed](https://github.com/lentferj/ensqsqed) (Ensoniq SQ-R Plus),
39
- [eosed](https://github.com/lentferj/eosed) (E-mu E4XT),
40
- [kwsed](https://github.com/lentferj/kwsed) (Korg Wavestation SR),
41
- [nanosyned](https://github.com/lentferj/nanosyned) (Alesis NanoSynth),
42
- [p2ked](https://github.com/lentferj/p2ked) (E-mu Proteus 2000),
37
+ emorphed (E-mu Morpheus), ensqsqed (Ensoniq SQ-R Plus),
38
+ [eosed](https://github.com/lentferj/eosed) (E-mu E4XT), kwsed (Korg
39
+ Wavestation SR), nanosyned (Alesis NanoSynth), p2ked (E-mu Proteus 2000),
43
40
  [rxved](https://github.com/lentferj/rxved) (Roland XV-2020),
44
- [s3ked](https://github.com/lentferj/s3ked) (Akai S1000/S3000) and
45
- [x5ded](https://github.com/lentferj/x5ded) (Korg X5D/X5DR).
41
+ [s3ked](https://github.com/lentferj/s3ked) (Akai S1000/S3000) and x5ded
42
+ (Korg X5D/X5DR). Several of these repositories are not public yet, which is
43
+ why only some of the names above are links.
44
+
45
+ A tenth project, [k2kremote](https://github.com/lentferj/k2kremote), is a
46
+ remote for the Kurzweil K2000 rather than a browser, and depends on the same
47
+ shared code.
46
48
 
47
49
  They grew separately, which is the right way to learn what an instrument
48
50
  does and the wrong way to arrive at nine copies of the same code. This
@@ -51,93 +53,6 @@ a change to one of them happens once instead of nine times.
51
53
 
52
54
  ---
53
55
 
54
- ## Support this project
55
-
56
- is free software and always will be. Nothing is behind a paywall, no
57
- feature is withheld, and none of what follows changes that.
58
-
59
- But if it has been useful — if it saved you an evening of mapping zones
60
- by hand, or got a library onto a machine that had no way of reading it, or
61
- **best of all, if it has your vintage instrument switched on and in use more often
62
- than it was, and you are having more fun with it** — then please consider
63
- supporting the work.
64
-
65
- **Because here is what it has actually cost:**
66
-
67
- - **Real machines on a real bench.** Much of what these tools know about these
68
- formats was measured on hardware rather than read anywhere, because for most
69
- of it there is nowhere to read it. That needs the machines — the instruments
70
- themselves — and it puts hours of wear on hardware that has been locked up and
71
- recovered more than once in the course of it. Some of these instruments were
72
- bought specifically to add and verify a format; the others were already here,
73
- because the person doing this is a vintage instrument enthusiast first and the
74
- projects exist because the instruments were in the room.
75
- - **Dozens — realistically hundreds — of hours of human time.** Format
76
- reverse-engineering is slow: measure, be wrong, measure again. A single
77
- parameter law in this README can represent an evening at the bench.
78
- - **AI assistance, which is a paid service**, used heavily throughout and not
79
- cheap at this volume.
80
-
81
- **This is support, not a donation — and the distinction is a legal one, not a
82
- turn of phrase.** The maintainer is based in Germany, where payments like these
83
- are *not* `Spenden` in the tax sense: they count as **taxable income** for the
84
- recipient and are **not tax-deductible** for the giver. So this section is
85
- titled *Support*, deliberately, and no receipt for tax purposes can be issued.
86
- (That is a statement of how it is handled here, not tax advice.)
87
-
88
- If the project saved you the work, you can support it through
89
- **[GitHub Sponsors](https://github.com/sponsors/lentferj)** — the *Sponsor*
90
- button at the top of the repository. Payment is handled entirely by GitHub and
91
- Stripe, so bank and tax details are never handed to the person paying.
92
-
93
- **Support is not expected, and it is not the only currency.**
94
-
95
- - **Bug reports** — ideally with the bank, preset or disk image that produced
96
- them. A tool's failures are usually specific to one file rather than
97
- general, and without that file they are very hard to reproduce.
98
- - **Confirmations from hardware that is not on this bench**, which matters more
99
- here than for a single-machine tool. These tools write for whole *families*
100
- of instruments, and the bench holds only a subset. Whether a variant accepts
101
- what we write is genuinely unknown, and several notes say "on this unit" for
102
- that reason. A "loads fine here too", or a "no, mine refuses it", is worth a
103
- great deal.
104
- - **Corrections to the reverse-engineering notes.** The wrong turns are
105
- recorded next to the findings in `docs/RESOLUTION_NOTES.md` — retractions
106
- included, because a finding that was withdrawn is as useful as one that
107
- stood. If any of it is wrong in a way that is still costing someone time,
108
- saying so improves the record.
109
-
110
- ---
111
-
112
- ## AI assistance & human authorship
113
-
114
- was built by its human author together with AI assistance. The
115
- **ideas, the project vision, and every feature** came from the human author;
116
- AI assisted with **writing the code and analyzing the binary formats**.
117
- Crucially, the **reverse engineering rests on hands-on human work** — all testing
118
- and verification on real hardware, creating the reference images/banks on those
119
- instruments (disk saves, SysEx probes), and aural A/B comparison of presets —
120
- which is what makes the results correct.
121
- Full account in [DISCLAIMER.md](DISCLAIMER.md).
122
-
123
- ---
124
-
125
- ---
126
-
127
- ## ⚠️ Use at your own risk — back up first
128
-
129
- is provided **as is, with absolutely no warranty and no liability**
130
- for data loss or **hardware damage**. You assume all risk. Full terms:
131
- [DISCLAIMER.md](DISCLAIMER.md).
132
-
133
- Before you use this software, **make good, current backups of all your files** —
134
- and of any existing banks on your instrument and storage media. These tools can
135
- write to hardware and storage media; a mistake, a bug, or untested output could
136
- overwrite or corrupt data, or be rejected by hardware. Always test on a spare
137
- unit or emulator **before** connecting irreplaceable equipment.
138
-
139
- ---
140
-
141
56
  ## What is in here, and what is not
142
57
 
143
58
  **In here:** how a preference is remembered, where a favourite lives, what
@@ -153,7 +68,7 @@ selects which bank is that instrument's business and stays put.
153
68
 
154
69
  ```
155
70
  vinsynlib/
156
- config.py the settings cache: port, channel, device ID
71
+ config.py the settings cache: port, channel, device ID, UI state
157
72
  favorites.py the favourites database: SQLite, slots, ratings, tags
158
73
  keys.py the keymap and the legend
159
74
  cli.py the command line every tool builds the same way
@@ -162,52 +77,31 @@ vinsynlib/
162
77
  midi.py port listing, the shared error taxonomy, clean exit
163
78
  conformance.py the checks a project runs against itself
164
79
  devchecks.py checks that catch cross-project mistakes
80
+ backup.py the backup envelope: a versioned JSON container
81
+ catalog.py printed names, plus what has been read off the unit
82
+ livenames.py names read off the unit, kept between runs
83
+ render.py table and progress rendering, without Textual
84
+ undo.py the undo log: inspectable records, no threads or locks
165
85
  ui/hints.py the legend widget
86
+ ui/browser.py BrowserApp, the AppProtocol implementation
87
+ ui/protocol.py the App contract screens depend on
88
+ ui/work.py worker infrastructure: busy gate, error set, idle-close
89
+ ui/confirm.py a generic yes/no confirmation modal
90
+ ui/prompt.py a one-line modal text prompt
91
+ ui/modals.py the shared modal screens: picker, search, report, rating
166
92
  ```
167
93
 
168
- ## Installing it, and who depends on it
169
-
170
- This is a library, not a program, and it is **not on PyPI yet**. The ten tools
171
- in the family depend on it, so it has to be a sibling checkout of whichever
172
- one you are building:
173
-
174
- ```
175
- git-repos/
176
- vinsynlib/ <- this one
177
- x5ded/ <- and the ten tools beside it
178
- emorphed/ ensqsqed/ eosed/ kwsed/ ...
179
- ```
180
-
181
- ```sh
182
- cd ../x5ded # or any sibling
183
- git clone https://github.com/lentferj/vinsynlib.git ../vinsynlib
184
- python3 -m venv .venv
185
- .venv/bin/pip install --no-deps -e ../vinsynlib # --no-deps: its deps are theirs
186
- .venv/bin/pip install -e .
187
- ```
188
-
189
- Each of the ten writes those steps out in its own README, because a reader
190
- starts from the tool and rarely from here. For projects that configure
191
- `[tool.uv.sources]` pointing to this library, `uv sync` takes the path
192
- from there, so the checkout only has to exist and neither `pip` line is needed.
193
- For projects that work from an index (like the published tools), the explicit
194
- `pip install -e ../vinsynlib` line remains necessary until the library is
195
- published.
196
-
197
- Publishing this to PyPI would replace all of it with an ordinary dependency
198
- line. Until then, the sibling checkout *is* the install.
199
-
200
94
  ## Why it exists
201
95
 
202
96
  Nine projects each grew a `config.py` (about 190 lines, 90-97% identical),
203
97
  a `favorites.py` (about 620 lines, 85-100% identical), a `KeyHints` widget
204
- and a `wrap_blocks` helper. Measured across the family: **8,101 lines of
205
- cloned code, roughly 6,300 of them duplicates that need not exist.**
98
+ and a `wrap_blocks` helper. Measured across the family: **roughly 6,300
99
+ lines of that were duplicates that need not exist.**
206
100
 
207
101
  Three of those copies had already drifted into bugs worth naming:
208
102
 
209
103
  * `emorphed`'s `LICENSE` file opened with the words "nanosyned — Terminal
210
- browser for the Alesis NanoSynth".
104
+ browser for the E-mu Morpheus".
211
105
  * `emorphed`'s `mypy` and `deptry` configuration still named the `nano`
212
106
  module, and one function imported `nano.config` -- `nanosyned`'s package,
213
107
  which is not installed beside it. That function worked in the project it
@@ -220,6 +114,68 @@ Three of those copies had already drifted into bugs worth naming:
220
114
  None of these were visible in review. They were visible the moment there
221
115
  was a second copy to compare against, which is what this library is.
222
116
 
117
+ ---
118
+
119
+ ## ⚠️ Use at your own risk — back up first
120
+
121
+ vinsynlib is provided **as is, with absolutely no warranty and no liability**
122
+ for data loss or **hardware damage**. You assume all risk. Full terms:
123
+ [DISCLAIMER.md](DISCLAIMER.md).
124
+
125
+ Before you use this software, **make good, current backups of all your files** —
126
+ and of any existing banks on your instrument and storage media. These tools can
127
+ write to hardware and storage media; a mistake, a bug, or untested output could
128
+ overwrite or corrupt data, or be rejected by hardware. Always test on a spare
129
+ unit or emulator **before** connecting irreplaceable equipment.
130
+
131
+ ## Installing it, and who depends on it
132
+
133
+ This is a library, not a program. It is published on PyPI — the current
134
+ release is 0.4.0 — so the ordinary way to depend on it is a dependency
135
+ line:
136
+
137
+ ```toml
138
+ vinsynlib>=0.4.0
139
+ ```
140
+
141
+ ```sh
142
+ python3 -m pip install vinsynlib
143
+ ```
144
+
145
+ The library itself has no dependencies. The parts that need a terminal UI
146
+ or a MIDI backend are behind the `ui` and `midi` extras:
147
+
148
+ ```sh
149
+ python3 -m pip install "vinsynlib[ui,midi]"
150
+ ```
151
+
152
+ Ten projects in the family depend on it: the nine browsers above and
153
+ [k2kremote](https://github.com/lentferj/k2kremote). Each of them writes its
154
+ own install steps out in its README, because a reader starts from the tool
155
+ and rarely from here.
156
+
157
+ **Working on the library itself.** To develop against a checkout rather
158
+ than the published release, put it beside the project that uses it and
159
+ install it editable:
160
+
161
+ ```
162
+ git-repos/
163
+ vinsynlib/ <- this one
164
+ x5ded/ <- a sibling, and the other tools beside it
165
+ ```
166
+
167
+ ```sh
168
+ cd ../x5ded # or any sibling
169
+ git clone https://github.com/lentferj/vinsynlib.git ../vinsynlib
170
+ python3 -m venv .venv
171
+ .venv/bin/pip install --no-deps -e ../vinsynlib # --no-deps: its deps are theirs
172
+ .venv/bin/pip install -e .
173
+ ```
174
+
175
+ For projects that configure `[tool.uv.sources]` pointing to this library,
176
+ `uv sync` takes the path from there, so the checkout only has to exist and
177
+ neither `pip` line is needed.
178
+
223
179
  ## Using it
224
180
 
225
181
  ```python
@@ -245,20 +201,6 @@ parser = cli.make_parser("x5cli", "Browse a Korg X5D's sounds.")
245
201
  cli.add_common_arguments(parser, port=True, scan=True, channel=True)
246
202
  ```
247
203
 
248
- ## Development
249
-
250
- ```console
251
- $ uv venv && uv pip install -e ".[ui,midi]" && uv pip install \
252
- pytest pytest-cov mypy ruff vulture deptry detect-secrets pip-audit
253
- $ make check
254
- ```
255
-
256
- `make check` runs the whole gate in order and stops at the first failure:
257
- ruff, mypy in strict mode, the test suite with coverage, then vulture,
258
- deptry and pip-audit.
259
-
260
- > **Legal:** [DISCLAIMER.md](DISCLAIMER.md) · [LICENSE](LICENSE)
261
-
262
204
  ## Where the rules are written down
263
205
 
264
206
  **[docs/UX-SPEC.md](docs/UX-SPEC.md)** is the contract: terminology, the
@@ -282,3 +224,89 @@ mistranslation is the difference between finding a sound and not.
282
224
  first lives in the working directory and is safe to delete. The second
283
225
  lives in the platform data directory, is keyed on the slot rather than the
284
226
  name, and is the one file here worth backing up.
227
+
228
+ ## Development
229
+
230
+ ```console
231
+ $ uv venv && uv pip install -e ".[ui,midi]" && uv pip install \
232
+ pytest pytest-cov mypy ruff vulture deptry detect-secrets pip-audit
233
+ $ make check
234
+ ```
235
+
236
+ `make check` runs the whole gate in order and stops at the first failure:
237
+ ruff, mypy in strict mode, the test suite with coverage, then vulture,
238
+ deptry and pip-audit.
239
+
240
+ ---
241
+
242
+ ## Support this project
243
+
244
+ vinsynlib is free software and always will be. Nothing is behind a paywall,
245
+ no feature is withheld, and none of what follows changes that.
246
+
247
+ But if it has been useful — if it saved you an evening of mapping zones
248
+ by hand, or got a library onto a machine that had no way of reading it, or
249
+ **best of all, if it has your vintage instrument switched on and in use more often
250
+ than it was, and you are having more fun with it** — then please consider
251
+ supporting the work.
252
+
253
+ **Because here is what it has actually cost:**
254
+
255
+ - **Real machines on a real bench.** Much of what these tools know about these
256
+ formats was measured on hardware rather than read anywhere, because for most
257
+ of it there is nowhere to read it. That needs the machines — the instruments
258
+ themselves — and it puts hours of wear on hardware that has been locked up and
259
+ recovered more than once in the course of it. Some of these instruments were
260
+ bought specifically to add and verify a format; the others were already here,
261
+ because the person doing this is a vintage instrument enthusiast first and the
262
+ projects exist because the instruments were in the room.
263
+ - **Dozens — realistically hundreds — of hours of human time.** Format
264
+ reverse-engineering is slow: measure, be wrong, measure again. A single
265
+ parameter law in one of the projects can represent an evening at the bench.
266
+ - **AI assistance, which is a paid service**, used heavily throughout and not
267
+ cheap at this volume.
268
+
269
+ **This is support, not a donation — and the distinction is a legal one, not a
270
+ turn of phrase.** The maintainer is based in Germany, where payments like these
271
+ are *not* `Spenden` in the tax sense: they count as **taxable income** for the
272
+ recipient and are **not tax-deductible** for the giver. So this section is
273
+ titled *Support*, deliberately, and no receipt for tax purposes can be issued.
274
+ (That is a statement of how it is handled here, not tax advice.)
275
+
276
+ If the project saved you the work, you can support it through
277
+ **[GitHub Sponsors](https://github.com/sponsors/lentferj)** — the *Sponsor*
278
+ button at the top of the repository. Payment is handled entirely by GitHub and
279
+ Stripe, so bank and tax details are never handed to the person paying.
280
+
281
+ **Support is not expected, and it is not the only currency.**
282
+
283
+ - **Bug reports** — ideally with the bank, preset or disk image that produced
284
+ them. A tool's failures are usually specific to one file rather than
285
+ general, and without that file they are very hard to reproduce.
286
+ - **Confirmations from hardware that is not on this bench**, which matters more
287
+ here than for a single-machine tool. These tools write for whole *families*
288
+ of instruments, and the bench holds only a subset. Whether a variant accepts
289
+ what we write is genuinely unknown, and several notes say "on this unit" for
290
+ that reason. A "loads fine here too", or a "no, mine refuses it", is worth a
291
+ great deal.
292
+ - **Corrections to the reverse-engineering notes.** The wrong turns are
293
+ recorded next to the findings — in this repository's `TODO.md`, and in each
294
+ project's own `docs/RESOLUTION_NOTES.md` — retractions included, because a
295
+ finding that was withdrawn is as useful as one that stood. If any of it is
296
+ wrong in a way that is still costing someone time, saying so improves the
297
+ record.
298
+
299
+ ## AI assistance & human authorship
300
+
301
+ vinsynlib was built by its human author together with AI assistance. The
302
+ **ideas, the project vision, and every feature** came from the human author;
303
+ AI assisted with **writing the code and analyzing the binary formats**.
304
+ Crucially, the **reverse engineering rests on hands-on human work** — all testing
305
+ and verification on real hardware, creating the reference images/banks on those
306
+ instruments (disk saves, SysEx probes), and aural A/B comparison of presets —
307
+ which is what makes the results correct.
308
+ Full account in [DISCLAIMER.md](DISCLAIMER.md).
309
+
310
+ ---
311
+
312
+ > **Legal:** [DISCLAIMER.md](DISCLAIMER.md) · [LICENSE](LICENSE)