Files
product-vamp/generator/solo/profiles.py
T
2026-10-05 16:40:22 -05:00

43 lines
1.5 KiB
Python

"""Sounding-register references and hard solo instrument domains."""
from __future__ import annotations
import dataclasses
import functools
from fractions import Fraction as F
import generator.fretboard
import generator.vocabulary
@dataclasses.dataclass(frozen=True)
class Instrument:
part: str = ''
strings: tuple[int, ...] = (1, 2, 3, 4, 5, 6)
reference: int | None = None
melody_range: tuple[int, int] | None = None
@property
def register(self):
tuning = [p for s, p in generator.fretboard.STANDARD_TUNING if s in self.strings]
return min(tuning) + 1, max(tuning) + 12
@functools.lru_cache(maxsize=4096)
def permits(self, number):
return any(p.string_number in self.strings for p in generator.fretboard.single_positions_for_pitch(F(number)))
UNRESTRICTED = Instrument()
def for_part(part, analysis=None):
if part not in ('acoustic', 'electric'):
raise ValueError('unknown solo instrument: ' + part)
strings = (1, 2, 3, 4, 5, 6)
if analysis is None or not analysis.melody:
return Instrument(part, strings)
# Source identity is independent of sounding register. Roles have soft,
# overlapping centers; all legal positions remain available to both guitars.
center=generator.vocabulary.role(part+'_solo').get('register_center',57 if part=='acoustic' else 62)
notes=tuple(n for n in analysis.melody if n.end>analysis.body_offset)
return Instrument(part,strings,center,
(min(n.pitch.number() for n in notes),max(n.pitch.number() for n in notes)))