Fret Limit
This commit is contained in:
@@ -8,6 +8,7 @@ import generator.acoustic
|
||||
import generator.acoustic_voicing
|
||||
import generator.arrange.form
|
||||
import generator.electric
|
||||
import generator.fretboard
|
||||
import generator.guitar
|
||||
import generator.model
|
||||
import generator.parts
|
||||
@@ -122,4 +123,5 @@ def apply(source, parts, *, rhythms, scales, sequences, solos=None):
|
||||
reports.append(generator.solo.report.describe(solo, scales, first, offset))
|
||||
for document in parts.values():
|
||||
generator.model.validate_document(document)
|
||||
generator.fretboard.validate_document(document)
|
||||
return '\n'.join(reports)
|
||||
|
||||
@@ -118,7 +118,7 @@ def validate(solo):
|
||||
raise ValueError(f'{solo.part} solo: overlapping or out-of-bounds note at {note.start}')
|
||||
if note.pitch.number() % 12 not in generator.solo.types.permitted(solo.choices, note.start, note.end):
|
||||
raise ValueError(f'{solo.part} solo: held pitch {note.pitch.label()} violates a scale span at {note.start}-{note.end}')
|
||||
if note.position not in generator.fretboard.positions_for_pitch(fractions.Fraction(note.pitch.number())):
|
||||
if note.position not in generator.fretboard.single_positions_for_pitch(fractions.Fraction(note.pitch.number())):
|
||||
raise ValueError(f'{solo.part} solo: invalid guitar placement at {note.start}')
|
||||
previous = note
|
||||
for phrase in solo.phrases:
|
||||
|
||||
@@ -41,4 +41,4 @@ def place(notes: tuple[generator.solo.types.Note, ...], tempo: fractions.Fractio
|
||||
|
||||
@functools.lru_cache(maxsize=128)
|
||||
def positions(number: int):
|
||||
return generator.fretboard.positions_for_pitch(fractions.Fraction(number))
|
||||
return generator.fretboard.single_positions_for_pitch(fractions.Fraction(number))
|
||||
|
||||
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import dataclasses
|
||||
import fractions
|
||||
|
||||
import generator.fretboard
|
||||
import generator.harmony
|
||||
import generator.model
|
||||
import generator.scales.selection
|
||||
@@ -50,7 +51,7 @@ def new_motif(sequences: generator.solo.sequences.Library, length: fractions.Fra
|
||||
for path in paths:
|
||||
for start in range(-14, 15):
|
||||
pitches = tuple(generator.solo.types.scale_pitch(scale, start + offset) for offset in path.offsets())
|
||||
if not all(register[0] <= pitch.number() <= register[1] for pitch in pitches):
|
||||
if not all(register[0] <= pitch.number() <= register[1] and generator.fretboard.single_positions_for_pitch(fractions.Fraction(pitch.number())) for pitch in pitches):
|
||||
continue
|
||||
score = (generator.solo.sequences.family(path.steps) != shape, pitches[-1].number() % 12 not in target, abs(path.offsets()[-1] - displacement), abs(pitches[0].number() - (register[0] + 5)), generator.solo.policy.stable_rank(seed, (variant, path.steps, start)))
|
||||
candidates.append((score, pitches, path))
|
||||
@@ -137,7 +138,7 @@ def anchor_backbones(identifier, start, end, release, register, choices, bar, se
|
||||
duration = terminal_duration if role == 'terminal' else fractions.Fraction(1, 2)
|
||||
latest = time if role == 'terminal' else min(time + fractions.Fraction(3, 2), choice.span.end - duration, terminal_start - duration)
|
||||
pitches = [generator.solo.types.scale_pitch(choice.scale, degree) for degree in range(-21, 28)]
|
||||
pitches = [p for p in pitches if register[0] <= p.number() <= register[1] and p.number() % 12 in eligible]
|
||||
pitches = [p for p in pitches if register[0] <= p.number() <= register[1] and p.number() % 12 in eligible and generator.fretboard.single_positions_for_pitch(fractions.Fraction(p.number()))]
|
||||
desired = register[0] + (5 if index == 0 else 8 if role == 'terminal' else 11)
|
||||
following = []
|
||||
for cost, anchors in states:
|
||||
@@ -182,6 +183,7 @@ def plans(analysis: generator.solo.analysis.Analysis, measures: list[dict], choi
|
||||
low, high = (55, 74) if part == 'acoustic' else (59, 79)
|
||||
phase = (start + finish) / (2 * end)
|
||||
register = (low + (5 if fractions.Fraction(1, 2) <= phase < fractions.Fraction(3, 4) else 0), high if phase >= fractions.Fraction(1, 2) else high - 4)
|
||||
register = generator.fretboard.single_register(register)
|
||||
bar = boundaries[index + 1] - start
|
||||
release = fractions.Fraction(1, 2) if decision(passage_seed, 'breathing') % 3 == 0 else fractions.Fraction()
|
||||
release = min(release, (finish - start) / 8)
|
||||
|
||||
@@ -103,7 +103,7 @@ def cells(plan, measures, rhythms, choices=()):
|
||||
|
||||
@functools.lru_cache(maxsize=2048)
|
||||
def scale_options(scale, allowed, low, high):
|
||||
return tuple(generator.solo.types.scale_pitch(scale, index) for index in range(-21, 28) if low <= generator.solo.types.scale_pitch(scale, index).number() <= high and generator.solo.types.scale_pitch(scale, index).number() % 12 in allowed and generator.fretboard.positions_for_pitch(fractions.Fraction(generator.solo.types.scale_pitch(scale, index).number())))
|
||||
return tuple(generator.solo.types.scale_pitch(scale, index) for index in range(-21, 28) if low <= generator.solo.types.scale_pitch(scale, index).number() <= high and generator.solo.types.scale_pitch(scale, index).number() % 12 in allowed and generator.fretboard.single_positions_for_pitch(fractions.Fraction(generator.solo.types.scale_pitch(scale, index).number())))
|
||||
|
||||
def valid_notes(notes, choices):
|
||||
return all(n.pitch.number() % 12 in generator.solo.types.permitted(choices, n.start, n.end) for n in notes)
|
||||
@@ -111,7 +111,7 @@ def valid_notes(notes, choices):
|
||||
def options(choices, start, end, register):
|
||||
scale = next((c.scale for c in choices if c.span.start <= start < c.span.end), None)
|
||||
allowed = generator.solo.types.permitted(choices, start, end)
|
||||
return scale_options(scale, allowed, max(41, register[0] - 7), min(84, register[1] + 5)) if scale and allowed else ()
|
||||
return scale_options(scale, allowed, *generator.fretboard.single_register((register[0] - 7, register[1] + 5))) if scale and allowed else ()
|
||||
|
||||
def target_ok(notes, target):
|
||||
return target is None or any(target.earliest <= n.start <= target.latest and n.pitch.number() % 12 in target.pitches for n in notes)
|
||||
|
||||
Reference in New Issue
Block a user