Add Fretboard.keyboard() for piano/synth controllers

Fretboard.keyboard(keys=88, start="A0") — configurable key count:
- 88 keys = full piano (A0-C8)
- 61 keys = standard synth controller
- 49/37/25 keys = compact MIDI controllers

25 instrument presets total. 368 tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-22 06:53:47 -04:00
parent 5e09e64c2d
commit d5beab46f2
2 changed files with 44 additions and 1 deletions
+26
View File
@@ -927,6 +927,32 @@ class Fretboard:
Tone.from_string("E4", system="western"),
])
@classmethod
def keyboard(cls, keys=88, start="A0"):
"""Piano or keyboard with the given number of keys.
Args:
keys: Number of keys (default 88 for a full piano).
Common sizes: 25, 37, 49, 61, 76, 88.
start: The lowest note (default ``"A0"`` for standard piano).
A full 88-key piano spans A0 (27.5 Hz) to C8 (4186 Hz) —
the widest range of any standard acoustic instrument.
Smaller MIDI controllers typically start at C.
Examples::
Fretboard.keyboard() # 88-key piano
Fretboard.keyboard(61, "C2") # 61-key controller
Fretboard.keyboard(25, "C3") # 25-key mini controller
"""
from .tones import Tone
start_tone = Tone.from_string(start, system="western")
tones = []
for i in range(keys - 1, -1, -1):
tones.append(start_tone.add(i))
return cls(tones=tones)
@classmethod
def lute(cls):
"""Renaissance lute in G tuning (6 courses).
+18 -1
View File
@@ -1942,7 +1942,7 @@ def test_all_instruments_create():
"violin", "viola", "cello", "double_bass",
"banjo", "harp", "pedal_steel",
"bouzouki", "oud", "sitar", "shamisen", "erhu",
"charango", "pipa", "balalaika", "lute",
"charango", "pipa", "balalaika", "lute", "keyboard",
]
for name in instruments:
fb = getattr(Fretboard, name)()
@@ -2002,6 +2002,23 @@ def test_fretboard_pipa():
assert len(fb) == 4
def test_keyboard_88():
kb = Fretboard.keyboard()
assert len(kb) == 88
def test_keyboard_25():
kb = Fretboard.keyboard(25, "C3")
assert len(kb) == 25
assert kb.tones[-1].name == "C"
assert kb.tones[-1].octave == 3
def test_keyboard_custom():
kb = Fretboard.keyboard(61, "C2")
assert len(kb) == 61
# ── Ergonomic integration tests ─────────────────────────────────────────────
def test_ergonomic_workflow():