init
This commit is contained in:
commit
6e79d8bf22
743
README.md
Normal file
743
README.md
Normal file
@ -0,0 +1,743 @@
|
||||
Vue3.js prototyping test - Prompt to Claude
|
||||
===========================================
|
||||
|
||||
There are two public interlinked repositories in the [Gitlab account of some
|
||||
guy](https://gitlab.com/flowdy), where the second relies on the first, but the
|
||||
first does not depend on the second, because it can be run stand-alone quite
|
||||
like a Unix tool ("Do one thing and do it well" philosophy) and the second is
|
||||
always to be kept as an optional layer:
|
||||
|
||||
* /sompyler. Sompyler is a text-controlled synthesizer, in the typology
|
||||
between computer-parsible notation systems (MusicML, ABC) and
|
||||
fully-featured audio-programing languages like CSound or ChucK. It proudly
|
||||
documents to cover both the realm of sound and the realm of tone arrangement
|
||||
("music"). The Neusik syntax is specified in `doc/rfc.md`.
|
||||
|
||||
The information below relate to sompyler version v0.43-20-gcb42c3e.
|
||||
Older versions might not emit an ast.log complete enough. Please ensure an
|
||||
existing local repository is uptodate.
|
||||
|
||||
* /neusician. Flask-based web application server, kind of an interface to
|
||||
some server-side sompyler instance, usable via a browser that way.
|
||||
|
||||
Recommended version to deploy: v0.80-75-g023941c or later. Please ensure an
|
||||
existing local repository is uptodate.
|
||||
|
||||
In the current version of Neusician the user basically has a text area to fill
|
||||
with Neusik code, rendered by Sompyler to audio if it is all syntactically
|
||||
valid. At a mobile device however, it is tedious to use in that state, "for
|
||||
nerds only, others keep far off to retain mental health". I want to test Claude
|
||||
Code to develop a vue3js single page application, deployable as a Flask
|
||||
blueprint. Let's regard it as a experimental web-user interface on-top of that
|
||||
"pure Neusician for nerds bare-coding into a text area". By using the
|
||||
blue-print conventions in Flask, people operating Neusician could code there
|
||||
own Neusik coder web-gui environment, or choosing one among a collection of
|
||||
blueprints for this task.
|
||||
|
||||
What I deem common for all those SPA web-guis, and especially for that prototype:
|
||||
|
||||
* They can but do not need to be fed with input from Sompyler abstract syntax
|
||||
tree tracing log (requestable Neusician /sompyle/ast.log). The user can
|
||||
start from scratch, too, but if they want to ingest a prepared Neusik score
|
||||
file, they need to log in via basic auth to /sompyle endpoint and process
|
||||
it once in "check only" mode, no rendering required for ast.log to be
|
||||
generated. There has been tough decision consideration between two kinds of
|
||||
technical debt: dependency vs. redundancy. It is not a requirement, or
|
||||
rather it is a should-not, that the SPA can read that score in the yaml
|
||||
format. The dependency on a sompyler instance is considered rather a win.
|
||||
The ast.log parsing routines are difficult enough to realize, redundancy of
|
||||
yaml parser is an unnecessary burden, while yaml can be written without a
|
||||
dedicated general yaml.js module.
|
||||
|
||||
[Example of how ast.log looks like for Beethovens Pathétique, 1st
|
||||
mov.](fixtures/ast.log) has been the
|
||||
result of syntracer() and deeper_level() throughout the Sompyler
|
||||
score-parsing code, with both defined in Sompyler/syntaxtracer.py module.
|
||||
|
||||
[The "original" Neusik score](fixtures/pathetique.spls)
|
||||
|
||||
* They enable the user to create, manipulate. move and delete any object in
|
||||
the score, i.e. the hierarchical model of that score, and provide
|
||||
user-friendly widget for every property item these objects consists of.
|
||||
|
||||
* They write out a score in the original YAML format. It is not a
|
||||
requirement, or rather it is a should-not, that the SPA can read that score
|
||||
in that format. The dependency on a sompyler instance for that is intended.
|
||||
The ast.log parsing routines are difficult enough to realize.
|
||||
|
||||
|
||||
Concerning the prototype to implement
|
||||
-------------------------------------
|
||||
|
||||
1. The vue3js SPA needs to ingest that log into an internal hierarchical data
|
||||
structure. For every item of that model, the SPA provides following views:
|
||||
|
||||
* A basic view highlighting the identifier, if any, and further identifying
|
||||
items from its properties as simple concatenated text of label and value
|
||||
pairs.
|
||||
|
||||
* A short view consisting only of the identifier. Where none exists,
|
||||
identical with basic views. Should have an arrow-down button to extend
|
||||
the view to basic.
|
||||
|
||||
* An extended view that lists all properties as a DL HTML5 element, each
|
||||
DD element containing an appropriate form element. If a property is
|
||||
optional, say, the envelope of an AM or FM modulation, the on/off
|
||||
slide-switch is off by default. When turning it on, the form element is
|
||||
shown. Turning it off, it gets hidden and any final rendering trigger
|
||||
will skip its data structure, so the property, no matter if filled, is
|
||||
not part of the output score.
|
||||
|
||||
* Some, yet not all custom types according to doc/rfc.md are composite
|
||||
types: e.g. SHAPEs and stressor patterns. Implement appropriate widgets
|
||||
with suitable form controls.
|
||||
|
||||
2. The interface layout of the SPA consists of one or more overlay panes the
|
||||
handles of which are positioned horizontally at the bottom. The handles
|
||||
show icons only, with img alt= attribute being the initials of the pane
|
||||
name:
|
||||
|
||||
* Current position (alt=CP). Header on the top with the (in-place
|
||||
editable) title of the score. Left of the header is the Arrow-Right icon
|
||||
for import function (once a score is imported and any objects are
|
||||
changed, grayed out), right of the header is the export/render-to-score
|
||||
function. The center of the interface covers 70% of the screen and
|
||||
lists vertically, without bullets, the short views of the objects of the
|
||||
current matter of focus. Clicking an object above the bottommost will
|
||||
update the panes and their handles after this pane, reflecting the new
|
||||
state of focus. Any sub-objects remain listed until the user selects
|
||||
another direct sub-object.
|
||||
|
||||
Import function requests endpoint url, username and password on demand.
|
||||
The authentication method is HTTP(S) basic auth. Export function sends
|
||||
the code to the public /sompyle endpoint or
|
||||
/sompyle/reserve-a-worker-for-tests, depending on the optional
|
||||
credentials provided.
|
||||
|
||||
* The second pane (alt=FO) displays and offers editing of the properties
|
||||
of the focus object. Composite properties (e.g. shapes, continua,
|
||||
patterns, pitches, ...) stuff into accordion menu sub-panes to pull down
|
||||
and close up. Include their show/hide switches (optional properties) in
|
||||
the accordion menu property headers, if this is possible.
|
||||
|
||||
* Any sub-objects deserve their own additional panes. Some parent objects
|
||||
have more than one sort of child objects. E.g. variations in instrument
|
||||
specifications have, besides their basic properties ATTR, O, A, S, T, R,
|
||||
FM, AM, WS, VOLUMES, TIMBRE, SPREAD, MORPH, following sorts: labelled
|
||||
groups (alt=LG), PROFILE items (alt=PI), sub-ordinated variations
|
||||
(alt=SV). Read and interprete the rfc.md spec carefully to find out
|
||||
which objects should provide which additional panes. If the user clicks
|
||||
a sub-object in these panes, all panes need to adapt even pane #1
|
||||
(current position) must list the newly focussed object under prior
|
||||
focussed object, and none below. It is not requested, but a nice-to-have
|
||||
to save the old path.
|
||||
|
||||
Registry of objects and their details you found
|
||||
-----------------------------------------------
|
||||
|
||||
(Following text has been extracted as-is from an output in a Claude session,
|
||||
and is perhaps not to be re-fed if kept in context memory. For answers to the
|
||||
doubts see next sections. Yet, look out for exceptions to this noted by "User
|
||||
remark:" and by footnotes.)
|
||||
|
||||
This section is the user's explicit request. Derived from `doc/rfc.md`. For each object: parent context, identifier, simple props, composite props, sub-object kinds (→ additional panes), and known UX doubts.
|
||||
|
||||
> Notation: **R** = required, **O** = optional. **Composite** entries get their own widget or accordion.
|
||||
|
||||
### Score (document root)
|
||||
- Parent: none.
|
||||
- Identifier: none.
|
||||
- Simple: `title` O, `composer` O, `source` O, `encrypter` O.
|
||||
- Composite: `measures`[1], `tuning`, `room`, `articles`.
|
||||
- Sub-objects → panes: **stage entries**, **measures**, **embedded instruments** (`instrument NAME` keys), **embedded room** (if not external), **embedded tuning** (if not external).
|
||||
- UX doubts: should `measures`[1] be edited at score level or always per-measure`_meta`? The RFC permits both.
|
||||
|
||||
[^1]: Frowning upon `_meta` as was suggested by Claude. Is the RFC.md unclear?
|
||||
|
||||
### Stage / Voice entry
|
||||
- Parent: `stage` mapping on Score.
|
||||
- Identifier: the mapping key.
|
||||
- Simple (string form): `direction` R, `distance` R, `instrument-ref` O.
|
||||
- Composite (mapping form): same fields, plus `articles` O and `tuning`[2] O
|
||||
(voice-level).
|
||||
- Sub-objects → panes: **instrument** (either drilled into the embedded def, or
|
||||
a "go to file" pointer if a PATH), **voice-level articles**.
|
||||
- Doubts: how to represent "compact string vs mapping" in the editor? Suggest
|
||||
internal model is always mapping; emit compact form only when neither `articles` nor `tuning`[2] is defined.
|
||||
- Also lives here: `_space` (orchestra cone). Treat as a sibling settings
|
||||
sub-pane.
|
||||
|
||||
[^2]: Added by me in line with freshly committed version of the RFC.
|
||||
|
||||
### Instrument
|
||||
- Parent: score (embedded) or external `.spli`.
|
||||
- Identifier: `name` (key on score level).
|
||||
- Simple: `NOT_CHANGED_SINCE` O[3] .
|
||||
- Composite: `character` R (a MAYBE\_LIST of Variation).
|
||||
- Sub-objects → panes: **variations** (always at least one). When more than one, the panes list them; each variation drills into its own three-pane group below.
|
||||
|
||||
[^3]: Actually not optional, but automatically (re-)set when "dirty" properties
|
||||
are detected in the instrument spec. Set to the iso datetime (resolution:
|
||||
seconds) of when the export is triggered.
|
||||
|
||||
User remarks: Instrument objects cannot be focussed and are to display
|
||||
"disabled" i.e. greyed out when an external specification is referenced or when
|
||||
the ast.log just lists them as `cached=True`. Show a message "Please check
|
||||
'Force refresh of cached embedded instrument specification no matter the
|
||||
timestamp' on re-rendering and import". And no, I am not quite content with
|
||||
that quirk, but at least it is planned.
|
||||
|
||||
### Variation (the heaviest object)
|
||||
- Parent: Instrument's `character`.
|
||||
- Identifier: `ATTR` field (composite: `NAME [= STRING | (STRING|...) ]`), or position-in-list if none.
|
||||
- Basic uppercase-letter properties (each composite, each optional, each with a SHAPE-bearing widget):
|
||||
- `O` Oscillator (enum or identifier)
|
||||
- `A` Attack envelope (DURATION:SHAPE)
|
||||
- `S` Sustain envelope (NOMINAL_DURATION:START;SHAPE)
|
||||
- `T` Tail envelope (DURATION:START;SHAPE)
|
||||
- `R` Release envelope (DURATION:START;SHAPE)
|
||||
- `FM` Frequency modulation (FREQUENCY[f|F][@OSC][[SHAPE]];MOD:BASE)
|
||||
- `AM` Amplitude modulation (same shape)
|
||||
- `FV` Frequency variation (BASE[±MIN][±MAX];SHAPE)
|
||||
- `WS` Wave shape (CENTER;SHAPE)
|
||||
- Variation-named composite props:
|
||||
- `VOLUMES` (LIST | RESOLUTION:SHAPE)
|
||||
- `SPREAD` (same form)
|
||||
- `PROFILE` (LIST of partials)
|
||||
- `TIMBRE` (SPECTRUM\_WIDTH:SHAPE)
|
||||
- `MORPH` (LIST: PARTIAL\_SEQNUMS [WEIGHT] ":" SHAPE)
|
||||
- `RAILSBACK_CURVE` (minF, maxF, 88×INT or 88:SHAPE)
|
||||
- Sub-object kinds → **THREE additional panes** as the brief calls out:
|
||||
1. **Labelled property groups** — keys ≥3 lowercase chars, mapping to basic O/A/S/T/R/AM/FM/FV/WS plus `@LABEL` references.
|
||||
2. **PROFILE items** — the list elements in PROFILE (each can be REVERSED\_DBFS, REVERSED\_DBFS@LABEL, or a mapping with `match`, `deviance`/`D`, `volume`/`V`, plus basic props).
|
||||
3. **Sub-variations** — sibling variations whose ATTR binds to an attribute value or sub-label[4].
|
||||
- Doubts:
|
||||
- Sensible defaults when toggling an envelope ON: A → 0,100;…, etc. Need user guidance per the brief's "approve findings" step.
|
||||
- Implicit attributes (`pitch`, `length`, `stress`) — always available — show as informational/read-only? Or hide?
|
||||
- `@LABEL` resolution UI: dropdown of in-scope labels + manual override?
|
||||
- Circular references must be detected (RFC requires error).
|
||||
|
||||
[^4]: Wait, what do you mean by "sub-label"? Assume you mean "named
|
||||
sub-variation" to be stacked in the order as made explicit here in the
|
||||
specification. The attribute in the article scope must be of type LIST
|
||||
containing, in free order there, which sub-variations need to be stacked.
|
||||
Let us use the name "stacked-var-label", in favour of confusing
|
||||
"sub-label".
|
||||
|
||||
### Room
|
||||
- Parent: score (embedded) or external `.splr`.
|
||||
- Identifier: none.
|
||||
- Simple: none.
|
||||
- Composite (all O except at least one of `levels` / `delays`):
|
||||
- `levels` (POSITIVE_INT:SHAPE | LEFT|RIGHT or mapping with left/right)
|
||||
- `delays` (FLOAT:SHAPE | LEFT|RIGHT or mapping with left/right)
|
||||
- `freq_lanes` (LIST: first BANDS:SHAPE; rest DIST:SHAPE)
|
||||
- `border` (MSECONDS:SHAPE; default ≈35 ms; Haas effect)
|
||||
- `jitter` (SHAPE; 0..1 randomization)
|
||||
- `deldiffs` (LEFT|RIGHT PATTERN or mapping)
|
||||
- `diffusion` (PATTERN)
|
||||
- Sub-objects → panes: each composite gets an accordion in Pane #2; no additional kinds.
|
||||
- Doubts: stereo toggle (mono LEFT|RIGHT form vs explicit left/right mapping) — tab selector vs explicit "Stereo?" switch?
|
||||
|
||||
### Tuning
|
||||
- Parent: score (embedded) or external `.splt`.
|
||||
- Identifier: none.
|
||||
- Simple: `base` (PATH, R if embedded), `ref_key_offset` O, `base_frequency` O, `intervals` O.
|
||||
- Composite: `chords` O (mapping under), `scales` O (mapping under).
|
||||
- Sub-objects → panes: **chord defs** and **scale defs** as two sub-panes.
|
||||
|
||||
### Intonation file (.splt)
|
||||
- Parent: standalone or referenced.
|
||||
- Identifier: filename.
|
||||
- Simple: `ref_frequency`, `ref_key_number`, `ref_octaves_number`, `span_octaves`.
|
||||
- Composite sections: `intervals`, `scales`, `chords`, `tones`.
|
||||
- Doubts: editor for `.splt` — in-scope for v1 or out? The brief focuses on score editing; .splt may be read-only with "open externally" link.
|
||||
|
||||
### Measure
|
||||
- Parent: score (sequence).
|
||||
- Identifier: `_id` O (auto-incremented int otherwise).
|
||||
- Simple: `cut` O, `skip` O, `repeat_unmentioned_voices` O, `is_last` O, `offset_seconds` O.
|
||||
- Composite `_meta` (each inheritable from prior measure or score-level `measures`):
|
||||
- `stress_pattern` (R for first measure)
|
||||
- `beats_per_minute` (POSITIVE_INT | START-END | START;SHAPE)
|
||||
- `lower_stress_bound` O
|
||||
- `upper_stress_bound` O
|
||||
- `elasticks_pattern` O
|
||||
- `elasticks_shape` O
|
||||
- `tuning` O (per-tick base shift / scale type)
|
||||
- Per-voice keys (each becomes a sub-object): voice-specific `_meta`, `articles`, named materials, numeric offsets.
|
||||
- Sub-objects → panes: **voices**, **named materials**, **offsets** (or fold the latter two into the voice pane).
|
||||
- Loop sugar: `_loop` (POSITIVE_INT) — represent as a numeric toggle on the measure with an array of cycle-values for `|`-separated meta/articles.
|
||||
|
||||
### Articles (global, voice-level, measure+voice-level)
|
||||
- Parent: score | stage voice | measure voice.
|
||||
- Identifier: mapping key.
|
||||
- Composite: attribute mapping; each attribute may be:
|
||||
- Static value (INT/FLOAT/STRING/BOOL)
|
||||
- **Continuum** (`START-END` or `START;SHAPE`)
|
||||
- **LPU-Pattern** (`L:SHAPE;P:STRESSOR;U:SHAPE`)
|
||||
- Special keys: `o:` (nested attrs for the `o` article), `:extension`, `all`.
|
||||
- Doubts: how to disambiguate "single-letter heads in chains" vs "extended labels"? A flag on the article entry, or two distinct lists?
|
||||
|
||||
### Stem Note (mapping form)
|
||||
- Parent: voice offsets in measures.
|
||||
- Simple: `pitch`/`P` R, `length`/`L` O, `weight`/`W` O, `overlength` O, `damp` O, `extra_adj_pitch` O, `adj_pitch_cent_per_key` O, `adj_stress` O, `_LRpos` O, `_Zpos` O, `write_to` O.
|
||||
- Composite: `chain` O.
|
||||
- Sub-object → pane: **chain editor** (its own pane because chains are non-trivial).
|
||||
|
||||
### Stem Note (string form)
|
||||
- Same model, render compactly. The editor stores the structured form and decides format at export.
|
||||
|
||||
### Chain
|
||||
- Parent: Stem Note.
|
||||
- Structure: `subchain *("; " subchain)`; subchain = clauses; clauses contain `article_stack` plus `length`, or nested `(chain)`. Quantifiers `*N`.
|
||||
- Sub-objects → pane: chain clauses are visually linear; v1 can use a horizontal list widget with insert/delete/duplicate.
|
||||
|
||||
### Material line
|
||||
- Parent: voice offsets.
|
||||
- Forms: Simple Material Clause (SMC) `<material_ref,…:PITCH …` or Complex Material Clause (CMC) `<…<material_ref…>…`.
|
||||
- Sub-objects → pane: material-ref editor.
|
||||
- Doubts: nesting depth via leading `<` count — display as tree indent? Probably yes.
|
||||
|
||||
### SHAPE
|
||||
- Universal composite. Used everywhere envelope-like behaviour is needed.
|
||||
- Nodes: `x,y[*z][!]`. `x` strictly increasing.
|
||||
- Widget: a single shared `ShapeEditor` component — table input with optional inline curve preview (SVG). The same widget powers A/S/T/R, AM, FM, FV, WS, VOLUMES (resolution form), SPREAD, TIMBRE, MORPH (per-partial SHAPE), elasticks_shape, dynamics/tempo continua, room levels/delays, deldiffs, diffusion, jitter, border, freq_lanes lanes.
|
||||
- Pre-tested by `chain-tool.js` does some of this; not directly reusable but we can cannibalize the SVG render approach.
|
||||
|
||||
### PITCH
|
||||
- Forms: pitch name (`C4`, `A&major7`, `Cis`), key position int, caret position `^28`, frequency float, modifier syntax `C4+2k-50c`.
|
||||
- Widget: `PitchInput` with a tab/radio selector across forms.[3]
|
||||
|
||||
[^3]: Note that modifier appendices also applicable to all mentioned before, so it should not be guarded by a radio check but can accompany each. `
|
||||
|
||||
### Continuum
|
||||
- `START-END` or `START;SHAPE`.
|
||||
- Widget: range form vs SHAPE accordion.
|
||||
|
||||
### LPU-Pattern
|
||||
- `L:SHAPE;P:STRESSOR;U:SHAPE`.
|
||||
- Widget: three sub-fields wrapped in an accordion ("Advanced").
|
||||
|
||||
### Stress Pattern
|
||||
- Recursive `subdivision *(";" division)`, where division = `subdivision *("/" subdivision)` and `level = INT | high-low`.
|
||||
- Widget: visual pattern editor — rows for division levels, cells for ticks, `/` alternatives as an extra row. v1 can ship as a text input with live validation if the visual editor is too much for v1.
|
||||
|
||||
### PROFILE Item
|
||||
- Three forms: scalar REVERSED_DBFS list; `REVERSED_DBFS@LABEL`; mapping with `match`, `deviance`/`D`, `volume`/`V` + basic props.
|
||||
- Widget: form-tagged with kind switch; `match` syntax `2n+1` style needs UX help (preset chips: "even partials", "every 3rd partial", custom).
|
||||
|
||||
### Generic short-view rule
|
||||
- For objects with an identifier: identifier only.
|
||||
- For objects without: short view = basic view.
|
||||
- Down-chevron always toggles to basic view.
|
||||
|
||||
## AST log shape (for the parser)
|
||||
|
||||
Each line: `^(?P<depth>\d{2})\s+(?P<slot>\w+(?:\.\w+)*)\s+(?P<rest>.*)$`. `rest` is a mix of repr'd positionals and `key=repr(value)` pairs. Parsing recipe:
|
||||
|
||||
1. Tokenise `rest` with a simple state machine handling `'…'`, numbers, and bare `Y/N`.
|
||||
2. Build a tree by tracking the previous depth: depth+1 ⇒ child; same depth ⇒ sibling; lower depth ⇒ pop.
|
||||
3. Slot-prefixes (`PARENT.SLOT`) indicate the message is logged under a slotted `deeper_level`; treat them as namespaced children.
|
||||
4. Cross-reference slots against the call-site map established during exploration:
|
||||
|
||||
| Slot | Source | Becomes model node |
|
||||
|-------------------------------|--------------------------------------------------|-------------------------------|
|
||||
| `instrument` | `orchestra/__init__.py` | Instrument |
|
||||
| `label_spec` | `orchestra/instrument/variation.py` | InstrumentLabel |
|
||||
| `variation` | `orchestra/instrument/variation.py` | Variation |
|
||||
| `*.prop` (slot-prefixed) | `orchestra/instrument/protopartial.py` | PropertySpec on variation |
|
||||
| `bar` | `score/measure.py` | Measure |
|
||||
| `article` | `score/measure.py` (deferred) | Article |
|
||||
| `article_shapes.voice_property` | `score/measure.py` | VoiceArticleProperty |
|
||||
| `stressor`, `tempo`, `elasticks`, `lower_stress`, `upper_stress` | `score/measure.py` | MeasureMetaEntry |
|
||||
| `voice` | `score/measure.py` | VoiceInMeasure |
|
||||
| `stem_note` | `score/note.py` | StemNote |
|
||||
| `cluster`, `cluster.number` | `score/note.py` | Cluster + RepeatCount |
|
||||
| `chain` | `score/note.py` | Chain wrapper |
|
||||
| `motif` | `score/chord.py` | Motif |
|
||||
| `shape`, `coords.point` | `synthesizer/shape/__init__.py` | Shape + ShapePoint |
|
||||
| `modulation` | `synthesizer/modulation.py` | Modulation |
|
||||
|
||||
Unknowns flagged by exploration (carry to the open-questions list below):
|
||||
- Whether deferred messages flush on `deeper_level` exit or on next non-deferred call.
|
||||
- Whether `*.prop` prefixing is uniform across all properties.
|
||||
- Whether shape coords are always emitted in `x, y, z, is_sharp` order.
|
||||
|
||||
Your follow-up questions, my answers
|
||||
------------------------------------
|
||||
|
||||
### What I noticed when reading the plan and your commits
|
||||
|
||||
The STRUCTURE dict in syntaxtracer.py is out of date, so ignore it. For the bindings please use in Javascript what you infer as attribute names in the syntracer calls. Originally, syntracer() was to double-check against the structure, but validation is post-poned out of that stage.
|
||||
|
||||
|
||||
Now pondering your design doubts ...
|
||||
|
||||
### Score (Root): should \_meta be edited at score level or always per-measure?
|
||||
|
||||
The RFC permits both for a reason, but in the reference implementation Sompyler
|
||||
this is may be yet to be fixed. So, for this quest session, let's basically
|
||||
pretend all flaws and bugs of Sompyler are fixed, so anyway, whatever
|
||||
discrepancy is not your business but be welcome to notify me about it when
|
||||
stumbling upon and at any rate stick to the authorative source of truth,
|
||||
doc/rfc.md:
|
||||
|
||||
What is defined in "measures" slot, serves as fallback value store for each
|
||||
measure or multi-measure, while definitions in \_meta are inherited from one
|
||||
measure to the next, until it is overwritten. So, prior to adopting fallbacks
|
||||
from the previous measure, it should be looked up in score-level "measures".
|
||||
|
||||
The properties of "measures" are all optional. In Sompyler, there will be
|
||||
sensible calculated defaults. These defaults, however, will have lower priority
|
||||
than the properties inherited from previous measures.
|
||||
|
||||
### how to represent "compact string vs mapping" in the editor? Suggest internal model is always mapping; emit compact form only when no articles.
|
||||
|
||||
Yes, provide compact text input only as last resort here and basically where a
|
||||
compact string form is supported by spec. As part of the overall internal
|
||||
model, I recommend to construct an ordered list of pairs the left-hand item of
|
||||
which is an alphabetically ordered list of VARIABLE\_REFS, the right-hand item
|
||||
the template where all these refs are used in. When selecting a template, find
|
||||
all defined refs, sort them and retrieve the appropriate template from the list
|
||||
of pairs. In Python (unfortunately not in Javascript), you would best use a
|
||||
dictionary of tuples as keys and strings or template objects as values.
|
||||
|
||||
### Sensible defaults when toggling an envelope ON: A → 0,100;…, etc. Need user guidance per the brief's "approve findings" step.
|
||||
|
||||
Not quite sure what is meant by this, but for attack, and release ask for the length separately, as length is required. Attack be "1,1" as default shape (coord 0 is implicitly at 0), release be "1;1,0". Sustain be optional, length is default 1 in Sompyler realm, so let's have it as placeholder in the length field before the shape node entries.
|
||||
|
||||
### Implicit attributes (pitch, length, stress) — always available — show as informational/read-only? Or hide?
|
||||
|
||||
The ATTR field should rather be rendered as drop-down menu with these basic note attributes. Add a "[custom]" entry that, when clicked, provides a modal dialog with a text input that checks its content for all the constraints:
|
||||
|
||||
* name is lower-case alphabetic and not equals any label of a labelled group
|
||||
* that is not entered as ATTR already for a sibling of this variation, its
|
||||
parent variation or of any child variation, and
|
||||
* may be extended by regular expression
|
||||
`\s*=\s*[a-z]+((?:\s*\|\s*)(?:[a-z]+))*`
|
||||
|
||||
Make sure the user provides sub-variations for all the provided labels in
|
||||
whatever order (the fixed stacking order depends on the indications in the ATTR
|
||||
line). Lacking an `=` extension of the line, allow but do not require
|
||||
number-keyed sub-variations. Without an ATTR entry in a variations, disallow
|
||||
labelled as well as number-keyed sub-variations. Check these constraints when
|
||||
the variation object is requested by the user to close.
|
||||
|
||||
### @LABEL resolution UI: dropdown of in-scope labels + manual override?
|
||||
|
||||
#### O like Oscillator
|
||||
|
||||
The following does refer to 'O' / oscillator in a restricted sense: only #1 is possible, but then before the label drop-down insert a bright/inverse-colored toggle labelled "@", optional prefix to the label when exported to convey that the oscillator is taken from the referenced group and enriched with all its properties. The "@" cannot be toggled for the options in the optgroup "primitives" (sine, etc.), so it disables that optgroup or is untoggled with a message when a primitive waveform is currently selected.
|
||||
|
||||
#### A, S, D, R, AM, FM, FV, WS, other
|
||||
|
||||
Split the widget of each 1-2-uppercase-letter optional base props (plus "other"), arranged in an accordion, in two parts each radio-buttoned and labelled:
|
||||
|
||||
1. Refer label(s)
|
||||
|
||||
If checked, provide lines of drop-down menu + integer weight (min: 1).
|
||||
|
||||
Check that labels are not equal to labels of stacked subvariations.
|
||||
In export, normalize a single label ref to `@{label}`.
|
||||
|
||||
2. Literal value
|
||||
|
||||
Choose appropriate widget, e.g. length + shape nodes.
|
||||
|
||||
#### Envelopes for AM/FM
|
||||
|
||||
If in a modulation widget #2 is selected, extend the form fields with sub-heading "envelope" and, seemlessly. with the same widget as defined in #1 above. A literal envelope shape must be exported wrapped in square brackets. Caution, an envelope shape for a modulation is, like a frequency variation envelope shape, a shape, not a multi-shape ENVELOPE.
|
||||
|
||||
#### WS
|
||||
|
||||
Add checks that the coords start with an explicit node at x=0: "0,y;...". Instead of length, require CENTER. After confirming the message but choosing not to change a thing in this widget, do not enerve the user with another warning, they shall hear their probable mistake.
|
||||
|
||||
### Circular references must be detected (RFC requires error).
|
||||
|
||||
Yes, I recommend to move all labels not allowed because of this constraint in a final disabled optgroup of the drop down, label "not possible".
|
||||
|
||||
When the drop-down is realised as an auto-suggest text input, forbid these inputs with following message: "The labelled group '{label}' cannot be referred as following labelled groups referring this, or groups referring those directly or not, would result in circular look-ups: [LIST]"
|
||||
|
||||
Well, I am not sure, double-check there is no braino on my part.
|
||||
|
||||
### stereo toggle (mono LEFT|RIGHT form vs explicit left/right mapping) — tab selector vs explicit "Stereo?" switch?
|
||||
|
||||
Both is stereo. By `LEFT|RIGHT` the RFC means the mapping can be serialized to a string with a vertical bar as separator. But do not use it. Provide one widget, then a "binaural left ↑ / right ↓ side"-labelled check. If checked, show another widget of the same kind. I am cautious with mono/stereo and "ear" terminology here, binaural audio is a different kind of beast than mono/stereo, and understood my way.
|
||||
|
||||
|
||||
### editor for .splt — in-scope for v1 or out? The brief focuses on score editing; .splt may be read-only with "open externally" link.
|
||||
|
||||
For the tuning, provide a drop down, the topmost option being the default, but left unmentioned in the export:
|
||||
|
||||
- tones\_de+en
|
||||
- other .splt files found in lib/ directory and listed in $SOMPYLER/introspectables.txt
|
||||
|
||||
Tone naming specs + property ref\_octave\_number in the file do consider not
|
||||
editable. However, could you ingest the tone names splt files via javascript
|
||||
(fetch and process)? When they provide multiple alternatives of addressing
|
||||
tones (e.g. B3 vs. h in german/russ.), ask which to use to initialize the PITCH
|
||||
widget? Handle this as a virtual i.e. not exported score-level property.
|
||||
|
||||
Do not write many more than 200 LoC for that, more is what I deem complicated and please do not obfuscate just for the sake of the limit. If in doubt that that is too complicated for compliance, just stick to the default file and anglosaxon tone names with octave numbering. After all, it is v1 and a prototype.
|
||||
|
||||
### how to disambiguate "single-letter heads in chains" vs "extended labels"? A flag on the article entry, or two distinct lists?
|
||||
|
||||
The spec should be clear about it, isn't it? Extended labels are attached with prefix colon (no space before or after) to the one-letter note head.
|
||||
|
||||
### nesting depth via leading < count — display as tree indent? Probably yes.
|
||||
|
||||
Yes, but alas, observe the fact that Sompyler reference implementation is yet to enable support for all that. Actually it is under development in a local branch. Apply a warning that it probably chokes. But do not drop it altogether, I am eager to see what the software will export, so let easy-goingly the rendering fail.
|
||||
|
||||
|
||||
### Open questions
|
||||
|
||||
I adopt your question numbering, and am going answer it in Q&A style.
|
||||
|
||||
#### 1. No direct reading of the spls file.
|
||||
|
||||
Q: The brief says the SPA *should not* read the score YAML directly —
|
||||
dependency on Sompyler's ast.log is intended. Confirmed? In that case, an
|
||||
authenticated user who has no existing AST log (fresh session) can't ingest a
|
||||
score they pasted in. Is that acceptable, or should we add a "paste raw .spls,
|
||||
send to /sompyle as draft, fetch ast.log" import sub-flow?
|
||||
|
||||
A: For the sake of relative code simplicity *lol*, do not ingest the YAML
|
||||
directly. The author of Sompyler does not want to happen to change things
|
||||
redundantly at two places, neither to notify contributors (forkers) with syntax
|
||||
changes that do not change the ast\.log while syntax in the Neusik score format
|
||||
established earlier is still supported.
|
||||
|
||||
When it comes to convenience, a change of the analyze button on sompyle/status
|
||||
template is considered. So the score editor blueprint is requested to read
|
||||
prepared ast.log, just as convenience compared to access to the score editor
|
||||
and clicking import. Clicking analyze/edit button, request
|
||||
`/sompyle/score-editor/?import=1` could be issued.
|
||||
|
||||
#### 2. "Litmus test"
|
||||
|
||||
Q: import → export unchanged should equal the input score "modulo whitespace
|
||||
and comments." Does this include comments authored by the user (e.g., the YAML
|
||||
\# … lines our smart-indent allows)? If yes, comments must be preserved through
|
||||
the model — which means parsing the .spls anyway, contradicting point 1. Please
|
||||
clarify which side wins.
|
||||
|
||||
A: I do not consider comments to be important for score editor users, mostly not worth keeping in an import/export round-trip and overcomplicating code. Well, there may be comments worth reading, though, concerning music theory and analysis and stuff, but users interested in these comments are welcome to read the score as is, without score editors in between.
|
||||
|
||||
#### 3. Build tooling
|
||||
|
||||
Q: I propose CDN + native ESM + Vue 3 latest, no build step. OK, or do you want me to set up Vite? The latter unlocks .vue SFCs but adds Node/npm to the dev story.
|
||||
|
||||
A: No build step provided the author of Neusician, who regards himself as a nerd and is a fan of small footprint of the dev tool chain, shall be appealed to look into one's score editor sub-project.
|
||||
|
||||
#### 4. Blueprint URL prefix
|
||||
|
||||
Q: I propose /score-editor as the blueprint URL prefix and score-editor as its
|
||||
Flask name. Acceptable, or do you want something neutral like /gui/<name> so
|
||||
future GUI blueprints share a parent?
|
||||
|
||||
A: The registering of the blueprint should be in the realm of Neusician core
|
||||
configuration by a `SCORE_EDITOR_BLUEPRINT` setting.
|
||||
|
||||
#### 5. Auth UX
|
||||
|
||||
Q: Import dialog asks for username+password and uses HTTP BasicAuth (per
|
||||
brief). Should the SPA persist credentials in sessionStorage for the session,
|
||||
or re-prompt for every state-changing call? Persisting is friendlier;
|
||||
re-prompting is safer on shared devices.
|
||||
|
||||
A: Do not reinvent the wheel, leave it to the browser to cache the BasicAuth
|
||||
credentials.
|
||||
|
||||
As a surplus value in terms of persistence, someone might design their score
|
||||
editor blueprint (not this prototype) with a SQLite3 database in the worker
|
||||
directory of the active user. Let's not think too server-centric. It should not
|
||||
be a problem to import a score from one Neusician instance and export and
|
||||
render it on another.
|
||||
|
||||
Last but not least, in a typical Neusician instance, BasicAuth method supports
|
||||
the registration of new users, via a secret-prefix to password and double
|
||||
prompting. Importing from one user account and exporting to another should not
|
||||
be a trouble for an SPA bound to a single identity. Neusician is identity
|
||||
agnostic, fairness concerning resources is achieved by competing rhythmic tries
|
||||
of access.
|
||||
|
||||
Therefore, rather expect that the export of the score may result in a "Service
|
||||
unavailable error" and offer the user auto-retry in rhythmic intervals. Yet,
|
||||
the server promises that once a worker is seized and assigned to the user, it
|
||||
will remain him for an hour at least.
|
||||
|
||||
#### 6. Status polling
|
||||
|
||||
Q: After export, the server returns Location: /sompyle/status.json. What polling interval do you want — 500 ms, 1 s, 2 s? The status endpoint already supports tail-log to avoid duplicate notes.
|
||||
|
||||
A: At least 2s. Polling is not nothing when the server is busy rendering audio.
|
||||
Consider the ETA time reliable after 50% of progress. Polling does not need to consider that the server gets unavailable, though that is not guaranteed.
|
||||
|
||||
#### 7. Variation editor depth
|
||||
|
||||
Q: Variation is the densest object (≥15 composite props plus 3 sub-object
|
||||
kinds). Do you want all envelopes (A/S/T/R) collapsed by default and only
|
||||
revealed when toggled ON? Brief implies yes (default-off slide-switch).
|
||||
|
||||
A: Yes, this is a good idea. When it is a good idea to offer subordinate
|
||||
show/hide toggles for every envelope, you may also consider the subtleties that
|
||||
attack landing on y=0 should disable S/T/R, otherwise requires release, that
|
||||
omitted sustain disables tail and that R must land on y=0.
|
||||
|
||||
##### BTW: Invest some more UX attention to the shape widget.
|
||||
|
||||
Also, the envelope very much asks for convenience measures. Provide for every
|
||||
node being possibly dropped via a button labelled `−`. Provide
|
||||
add-buttons labelled `+` before the first, after the last, and between all
|
||||
pairs within. If the x-integer of a node is incremented over the next, shift
|
||||
the next so it is greater by 1. If the x-integer of a node is decremented below
|
||||
the previous, shift the previous so it less than it by one but care that it
|
||||
does not get negative. Carry that effect to all nodes in the same direction, as
|
||||
appropriate.
|
||||
|
||||
#### 8. Sensible defaults for each envelope when toggled ON — please confirm or supply:
|
||||
|
||||
Q:
|
||||
|
||||
A: 0;0,100;1,100 (instant attack to full)
|
||||
S: nominal 4 ticks, START=100, flat
|
||||
T: off by default
|
||||
R: 0.1s, START=100, drop to 0
|
||||
WS: CENTER=1, flat SHAPE
|
||||
AM/FM: off by default
|
||||
FV: off by default
|
||||
|
||||
A: My suggestions are as follows:
|
||||
|
||||
A: LENGTH required, single node 1,10 (start y=0 implied)
|
||||
S: LENGTH required, two nodes exported to "100;1,100".
|
||||
R: LENGTH required, "1;1,0"
|
||||
WS: "1;0,0;1,2" (neutral translation)
|
||||
|
||||
#### 9. @LABEL references
|
||||
|
||||
Q: @LABEL references in basic property values should resolve through a dropdown of in-scope labels — do you want a manual text-entry fallback as well?
|
||||
|
||||
A: No. See above for details. Text entry fallback is needed for creation of a new labelled group.
|
||||
|
||||
#### 10. Composite widgets
|
||||
|
||||
Q: SHAPE editor v1 — table-only with live SVG preview, or drag-handles on the
|
||||
SVG too? Drag-handles are nice but mobile-finicky.
|
||||
|
||||
A: Table style. I ponder the orientation of a node: row or column. Let's choose
|
||||
row for now.
|
||||
|
||||
#### 11. Stress-pattern editor v1
|
||||
|
||||
Q: text input with validator, or visual grid? Visual is the better UX but ≥2× the code.
|
||||
|
||||
A: Number input fields. Consider to support cycling (/) and from-to (-) but let
|
||||
go of cycling, then of from-to if the overall javascript code handling this
|
||||
exceeds 100 lines, but offer subdivisions. Details left up to you.
|
||||
|
||||
#### 12. PITCH input
|
||||
|
||||
Q: tab selector across {name, key, caret, Hz, modifier-string}, or a single text field with auto-detection? Auto-detect is more elegant but errors are less explainable.
|
||||
|
||||
A: Let's go for the tab solution.
|
||||
|
||||
#### 13. PROFILE match syntax (2n+1, etc.)
|
||||
|
||||
Q: preset chips ("evens", "odd minus one", "every 3rd") + custom raw input, or
|
||||
only raw input with help bubble?
|
||||
|
||||
A: help bubble preferred.
|
||||
|
||||
#### 14. Sub-pane behaviour
|
||||
|
||||
Q: When the user clicks a sub-object in pane #3+, the CP pane updates to include the new focus. Brief says "save the old path" is a nice-to-have. Implement a back button now or defer?
|
||||
|
||||
A: I would have requested this if I got an idea where to position it best. If in doubt, just prepare it.
|
||||
|
||||
#### 15. Multiple sub-object kinds (Variation has 3).
|
||||
|
||||
Q: One pane per kind, side-by-side handles at the bottom? Or one combined pane with tabs?
|
||||
|
||||
A: No tabs for this, side-by-side handles. And consider the clip-path strategy for a merged look of pane and handle.
|
||||
|
||||
#### 16. External files
|
||||
|
||||
Q: Out of scope for v1: editing .spli, .splr, .splt files standalone. Confirmed?
|
||||
|
||||
A: No. Every user may use the server-provided spl[irt] files as-is.
|
||||
|
||||
#### 17. When the score references an external .spli via PATH, the editor will display the path as read-only.
|
||||
|
||||
Q: Should there be a "fetch and embed" action that pulls the file from
|
||||
/files/lib/... and inlines it? Useful but breaks user intent if they want to
|
||||
keep the reference.
|
||||
|
||||
A: Embedding worth a thought or two, but no, not in v1.
|
||||
|
||||
#### 18. AST log unknowns (raised by exploration of syntaxtracer.py)
|
||||
|
||||
Q: Are deferred tracer messages always flushed before the enclosing
|
||||
deeper\_level exits? The code path looks incomplete — please confirm intended
|
||||
behaviour. If it isn't deterministic, the parser needs heuristics.
|
||||
|
||||
A: Log lines are deferred when they only get a meaning by subordinated objects.
|
||||
When there are no "children", the parent is skipped. So, deferred means logged
|
||||
once a non-deferred child is logged.
|
||||
|
||||
|
||||
#### 19. Properties emitted under deeper\_level(article\_shapes)
|
||||
|
||||
Q: Are they uniformly slot-prefixed, or only some? Affects the regex above.
|
||||
|
||||
A: This is somewhat subtle indeed, a quirk, a "yet-to-deal-with" subject for
|
||||
me. The PARENT part is basically *implied* on level 0 ("score") or when the
|
||||
type of the object in the given SLOT is explicit. When a slot is occupied by
|
||||
type used for different purposes, the type is explicit. I recommend to save in
|
||||
a variable to check against the word after the dot of the prior next higher
|
||||
ordinate subject. Consider equal words before and after the separating dot as
|
||||
syntax error and reason to abort parsing with a message.
|
||||
|
||||
#### 20. Shape lines (syntracer("shape", *coords))
|
||||
|
||||
Q: Are coords always emitted in x, y, z, is\_sharp order?
|
||||
|
||||
A: I cannot guess why this is deemed important, but yes, the order is
|
||||
reasonable and will probably not be changed. This is not a promise for all
|
||||
time, however. In Python, keyword arguments to functions are order-agnostic,
|
||||
two. Positionals without attribute label and equal sign are order-sensitive.
|
||||
|
||||
#### 21. Post-interpolation?
|
||||
|
||||
Q: Do any shapes in the log reflect post-interpolation (synthesised) values? Or
|
||||
always the raw definition? Round-trip needs raw.
|
||||
|
||||
A: No, post-interpolation would be an error that the code is not to detect.
|
||||
|
||||
|
||||
#### 22. Example assets
|
||||
|
||||
Q: The two example URLs in the brief — are they still live? If yes, fine; if
|
||||
not, please supply a current ast.log + .spls pair to use as the fixture for the
|
||||
round-trip test.
|
||||
|
||||
A: They are still live, yes.
|
||||
|
||||
|
||||
To Do Next Prompt
|
||||
-----------------
|
||||
|
||||
`git pull` sompyler anew. A commit has been pushed that also includes measure
|
||||
tuning in the ast.log, another to drop outdated STRUCTURE, a third to get
|
||||
alright embedded instrument specs NOT\_CHANGED\_SINCE slot, if any. A fourth
|
||||
commit updates the doc/rfc.md spec. Pull also neusician anew for the "refresh
|
||||
cached embedded instruments / re-synthesize tones at any rate" checkbox and
|
||||
function. If you cannot find that commit, you have been prompted too early,
|
||||
abort and let me know.
|
||||
|
||||
Do realize the project unless important follow-up questions raise and await
|
||||
clarification or decision affecting many percent of the codebase. Follow-ups
|
||||
not that important try to clarify from the context what is best appealing an
|
||||
end-user, number them in comments in the codebase and refer to them by number
|
||||
in a final summary report of your actions.
|
||||
11467
fixtures/ast.log
Normal file
11467
fixtures/ast.log
Normal file
File diff suppressed because it is too large
Load Diff
4004
fixtures/pathetique.spls
Normal file
4004
fixtures/pathetique.spls
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user