Giuliani studies as own material category; beam-before-draw fix

- NEW material 'giuliani': figures require a real voicing — the generator
  assigns cycle positions (bass root + upper chord tones) to DISTINCT
  strings with valid frets per bar; bars that cannot be voiced are skipped
  (deterministic), clear error when nothing fits. Patterns: p-i-m, p-i-m-a,
  p-a-m-i, a-i-m, p-i-m-a-m-i, p-m-a-m-i-m. Honors the chord pool, string
  restrictions and the tuning; one figure per beat.
- 6/8 meter added (numerator 6) across score model, settings, generators;
  meter selects now offer 4/4, 3/4, 6/8.
- Arpeggio category: Giuliani entries replaced with note-sequence
  broken-chord figures (1-3-2-1, 1-3-2-5(8), 1-5-3-5(8), 1-2-3-5-3) —
  pure pitch sequences, no voicing claims.
- Beam fix (root cause): setBeam now happens BEFORE voice.draw — VexFlow
  decides flag vs beam at draw time; registering after drawing left both
  flag and beam. Beams drawn after notes, flags suppressed correctly.
This commit is contained in:
OpenClaw
2026-09-15 02:44:52 +00:00
parent 9acf32a32f
commit ffb2776c8c
9 changed files with 412 additions and 69 deletions

View File

@@ -42,7 +42,7 @@ export interface RhythmSettings {
volume: number;
}
export type PhraseMaterial = 'melody' | 'scale' | 'arpeggio' | 'library' | 'import';
export type PhraseMaterial = 'melody' | 'scale' | 'arpeggio' | 'giuliani' | 'library' | 'import';
export type PhrasePace = 'step' | 'tempo';
export interface PhraseSettings {
@@ -52,7 +52,7 @@ export interface PhraseSettings {
keyTonic: string;
keyMode: string; // ModeId
bars: number; // 1–8 (melodies)
meterNumerator: 3 | 4;
meterNumerator: 3 | 4 | 6;
rhythmLevel: 1 | 2 | 3;
scaleCoverage: 'one-octave' | 'two-octave' | 'position';
scaleDirection: 'up' | 'down' | 'updown';
@@ -67,6 +67,9 @@ export interface PhraseSettings {
arpeggioBars: number;
arpeggioProgression: 'random' | 'functional' | 'diatonic-cycle';
arpeggioRhythm: 'quarters' | 'eighths';
/** Giuliani study material (own category — voicing-enforced). */
giulianiPattern: 'pim' | 'pima' | 'pami' | 'aim' | 'pimamim' | 'pmamim';
giulianiBars: number;
/** Phrase-local fret window (guitar/bass) — overrides the note set. */
fretWindowEnabled: boolean;
fretMin: number;
@@ -104,6 +107,8 @@ export const DEFAULT_PHRASE_SETTINGS: PhraseSettings = {
arpeggioBars: 1,
arpeggioProgression: 'functional',
arpeggioRhythm: 'quarters',
giulianiPattern: 'pima',
giulianiBars: 4,
fretWindowEnabled: false,
fretMin: 0,
fretMax: 4,