upiano
What it is
Section titled “What it is”upiano is a piano you can play in your terminal. It draws a full black-and-white piano keyboard as ASCII/block art across the width of the terminal — “the wider you can make it, the more keys you’ll have” — and you play it by clicking keys with the mouse (including drag-to-swipe across keys) or by typing on the computer keyboard, with a hardcoded QWERTY-to-note mapping. It drives a FluidSynth synthesizer loaded with a SoundFont, and it exposes a few synth parameters (volume, reverb, chorus) as on-screen slider widgets. It is the cleanest small example in the corpus of a musical instrument’s physical control surface reproduced as a terminal widget.
UI / interaction
Section titled “UI / interaction”- Piano keyboard as terminal art. White keys are drawn as labeled columns; black keys sit above them rendered with block characters (
██). The layout is the real piano geometry — black keys clustered in 2s and 3s between whites — reproduced in monospace cells. It scales to terminal width. - Mouse play — click a key to sound it; drag across keys to swipe a glissando. Mouse and keyboard work simultaneously.
- Computer-keyboard mapping — a fixed QWERTY layout: white notes on the home/bottom rows (
A S D F G H J K L ; '), black notes on the row above (W E T Y U O P), so the staggered black/white physical layout maps onto the staggered keyboard rows. Acknowledged limitation: terminals don’t deliver key-release events, so true sustained/polyphonic keyboard play is limited — mouse is the richer input, keyboard is the quick path. - Sustain (v0.1.1) extends note duration past the keypress.
- Slider widgets (v0.1.2) — three on-screen sliders for volume, reverb, chorus, adjusted live. This is the batch’s clearest example of a TUI slider control for an audio parameter.
Architecture
Section titled “Architecture”Textual widgets map terminal events (mouse clicks, key presses) to MIDI note-on/off, which drive a spawned FluidSynth instance loaded with a SoundFont; Textual handles the rendering and event loop. The instrument’s sound is entirely FluidSynth+SoundFont; upiano is the control surface and visual.
Toneline-relevance (and Deckline note)
Section titled “Toneline-relevance (and Deckline note)”The Toneline is a music terminal whose fiction already maps the numpad to pitch input across a selectable scale (chromatic/pentatonic/major). upiano is the reference for making that pitch surface visible and playable:
- The piano-keyboard widget is a reusable Toneline component. When the operator is entering notes — picking a pitch for a sequencer step, auditioning a chord, playing the FM voice live — a rendered keyboard strip shows which notes are in play and where the current scale sits. Draw it in the content area (Rows 1–23) as a horizontal keyboard band; highlight the active scale’s in-key notes and mark the currently sounding note. This turns the abstract “digit → pitch” mapping into a spatial, musical surface.
- The QWERTY-to-note mapping is the model for the Sweep-to-pitch mapping. upiano staggers black/white notes across two keyboard rows; the Toneline can stagger its scale across the Ferris Sweep’s key rows the same way, so the physical keys feel like a small keyboard. The Toneline fiction’s Nokia-style digit-to-letter binding (carried from ADR-0016) already establishes that the right-half digit cluster carries semantic input — a scale-to-key layer sits naturally on top.
- The slider widget is a needed Toneline UI primitive. FM synthesis lives or dies on parameter control — operator levels, envelope rates, feedback, the volume/reverb/chorus upiano exposes. The Toneline needs a single-color slider component for every continuous parameter; upiano is the minimal reference for what that widget does (label, track, thumb, live value).
- FluidSynth/SoundFont is the desktop-emulator synthesis pattern, not the device path. On real Toneline hardware the voice is the YM2612 FM chip (per
kn90t-toneline.md); on the Deckline it is the YM2149 PSG (software-emulated, per Canonical Hardware Specification). upiano’s FluidSynth approach is the precedent for how a desktop emulator could host a richer synth for development/preview — useful for the emulator build, not the on-device audio path.
Deckline note: the slider widget and the keyboard-strip widget are general single-color UI components the Deckline can reuse anywhere it needs a continuous control or a pitch surface — they are not Toneline-exclusive.
Single-color adaptation
Section titled “Single-color adaptation”A piano keyboard is naturally a two-tone object — white keys and black keys — which is the friendliest possible case for amber-on-black:
- White keys = amber-outlined cells on black; black keys = filled amber blocks (
██) sitting above. The black/white contrast that defines a piano maps directly onto the deck’s two values (lit vs unlit), no color needed. upiano already proves this reads in a single foreground color. - The currently sounding note uses inversion (the played key flips to a solid amber field), and in-scale vs out-of-scale notes differ by fill density / character, not hue.
- Sliders render as a labeled track with a position marker —
VOL ├────●───────┤— carried entirely by character and position. The thumb is the only state; the rest is static glyphs. This is the canonical single-color slider the Toneline needs.

Source: GitHub social card for eliasdorneles/upiano. Shows the black/white keyboard rendered in terminal cells with the parameter sliders beneath it.
- Two concrete reusable widgets come out of this entry: the keyboard strip (pitch surface) and the slider (continuous parameter). Both are single-color-clean and both are Toneline necessities.
- The terminal-no-key-release limitation is a real input constraint worth noting: the Toneline’s hardware Ferris Sweep does deliver press/release events (it’s a real keyboard, not a terminal), so the Toneline avoids upiano’s polyphony limitation — live multi-note play is actually viable on-device in a way it isn’t in a generic terminal.
- Cross-link line.md —
lineenters notes as text; upiano enters them as a played surface. The Toneline wants both: type a phrase, or play it on the keyboard widget — over the same underlying phrase representation. - Cross-link 4trk.md — 4TRK’s synth panels are the GUI-workstation cousin of upiano’s keyboard+sliders; both inform the Toneline’s voice/patch editing surface.
- Cross-link asak.md — for the recording side of a music terminal (upiano plays; asak captures).