25 lines
779 B
Python
25 lines
779 B
Python
from __future__ import annotations
|
|
|
|
from fractions import Fraction
|
|
from typing import NamedTuple
|
|
|
|
STANDARD_TUNING = ((6, 40), (5, 45), (4, 50), (3, 55), (2, 59), (1, 64))
|
|
MIN_FRET = 0
|
|
MAX_FRET = 20
|
|
MAX_FRET_SPAN = 4
|
|
WRITTEN_GUITAR_OCTAVE_OFFSET = 12
|
|
|
|
class TabPosition(NamedTuple):
|
|
string_number: int
|
|
fret: int
|
|
midi: int
|
|
|
|
def within_fret_span(positions) -> bool:
|
|
fretted = [position.fret for position in positions if position.fret > 0]
|
|
return not fretted or max(fretted) - min(fretted) <= MAX_FRET_SPAN
|
|
|
|
def positions_for_pitch(midi: Fraction) -> tuple[TabPosition, ...]:
|
|
if midi.denominator != 1:
|
|
return ()
|
|
return tuple(TabPosition(string, int(midi - open_midi), int(midi)) for string, open_midi in STANDARD_TUNING if MIN_FRET <= midi - open_midi <= MAX_FRET)
|