Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Teletype Translator

Turns Standard MIDI Files into monome Teletype scenes, and streams MIDI live to the module over WiFi.

The monome Teletype is a scriptable Eurorack sequencer. Its scenes are plain-text files (tt00.txttt31.txt) loaded from a USB stick. Writing them by hand is slow, and there is no native way to get an existing musical idea out of a DAW and onto the module. This compiles MIDI files into valid scenes.

The Teletype also has exactly one USB port and no network interface, so the second half of this repo is a bridge: a Raspberry Pi Zero W that pretends to be a USB-MIDI device and feeds the module live MIDI from a laptop over WiFi.

Both halves are hardware-verified on a real Teletype.

Features

Translator (TeletypeKit + ttx)

Pure Swift, no UI, no dependencies. The pipeline is SMF parser → MusicIR → arranger → scene → serializer/validator. It round-trips byte-identical against monome's eight factory scenes, which is the property the test suite is built around.

  • Grid resolutions from whole notes to 1/32, including triplets
  • 1–4 voices, mapped to CV/TR pairs
  • Output targets: cvtr, Just Friends over i2c, or W/ tape-retrigger over i2c
  • Scene validation against the module's real limits (line counts, script sizes, pattern banks)

macOS app

A SwiftUI workbench in a phosphor-terminal theme.

  • Workbench — import .mid or open an existing tt##.txt; grid 1/1 → 1/32 incl. triplets; tempo and tap tempo; voice count; per-voice mixer with mute/solo/drag-to-reroute and a grid editor; scene paging; a compare tab; export straight to a mounted USB volume
  • Live MIDI out — voices map to MIDI channels 1–4. Note-offs fire at 80% of the step so gates actually close and repeated notes retrigger. PANIC releases everything and sends CC-123 four times. Destination picker plus a synth-mute toggle so only the rack sounds
  • Track paging — files with more than four tracks page through the mixer; arrangement, audition, MIDI out and export all follow the visible page
  • Remote tab — Pi status, USB identity switching, and a remote typing field that types on the Teletype. Disruptive mode switches arm on first tap and fire on the second
  • Synth tab — approximation synth for auditioning before committing to hardware, with swing preview

Pi bridge

A Raspberry Pi Zero W appliance: RTP-MIDI in over WiFi, USB-MIDI gadget out, plus an HTTP control API. Three switchable USB identities — MIDI device, HID keyboard, or FAT16 flash drive — which together replace the USB-stick-and-keyboard juggling the module's single port otherwise forces.

Requirements

  • macOS 13+ and Swift 5.9 (Xcode 15+)
  • xcodegenbrew install xcodegen — to build the app
  • Optional, for live MIDI: a Raspberry Pi Zero W and a monome Teletype

The translator and CLI need none of the hardware.

Build

Engine and CLI:

cd TeletypeKit
swift build
swift test          # 66 tests

The macOS app (the Xcode project is generated, not checked in):

cd app
xcodegen generate
xcodebuild -project TeletypeTranslator.xcodeproj \
  -scheme TeletypeTranslator -configuration Release \
  -derivedDataPath build CODE_SIGNING_ALLOWED=NO build

# the build is unsigned — ad-hoc sign it, then install
codesign --force -s - build/Build/Products/Release/TeletypeTranslator.app
cp -R build/Build/Products/Release/TeletypeTranslator.app /Applications/

There is no notarized release build. You build it yourself, or Gatekeeper will complain.

Usage

ttx — command line

ttx <input.mid> [--out DIR] [--slot N] [--grid N] [--voices N] [--name NAME] [--target T]
flag meaning default
--out DIR output directory current directory
--slot N first scene slot, 0–31 0
--grid N steps per quarter note; 4 = 1/16, 0.25 = whole, 3 = 1/8T 4
--voices N max voices, 1–4 4
--name NAME scene title prefix derived from the filename
--target T cvtr | jf (Just Friends i2c) | w (W/ tape retrig i2c) cvtr
swift run ttx song.mid --out /Volumes/STICK --slot 9 --grid 4 --voices 4

Then on the module: ESC → arrow to the scene → ENTER. Loading is what runs its init script.

The app

Drag in a .mid, set grid/tempo/voices, audition it, then either export to a USB volume or turn on live MIDI and play it straight to the rack.

The Pi bridge

Raspberry Pi Zero W running Raspberry Pi OS Lite 32-bit (armhf — see the gotchas). Setup is: flash the image, fill in bridge/pi/firstrun.sh.template with your own WiFi SSID, password and SSH public key, copy the scripts and systemd units onto the Pi, and enable the services.

The placeholders to replace are __WLANSSID__, __WLANPW__ and __SSHPUB__. The scripts assume the stock pi account; change the paths in midibridge.service, tt-disk-mode and ttremote.py if yours differs.

One USB identity is active at a time:

mode what the Teletype sees command
midi (default) class-compliant USB-MIDI device, fed from RTP-MIDI tt-midi-mode
keyboard USB HID keyboard that can type on the module tt-keyboard-mode
disk FAT16 flash drive holding tt##.txt tt-disk-mode

HTTP control API (port 8044)

method endpoint body does
GET /status returns {"mode": …, "udc": "configured" | …}
POST /mode {"mode":"midi"|"keyboard"|"disk"} switches USB identity
POST /type {"text":"MI.$ 1 1","enter":true} types text (keyboard mode only)
POST /key {"key":"ALT+ENTER"} sends a chord (keyboard mode only)

udc: "configured" means a host has enumerated the gadget.

Signal chain

TeletypeTranslator.app   voices → MIDI channels 1–4, gates close at 80% of step
  ─▶ Network RTP-MIDI session over WiFi
  ─▶ Pi Zero W          pymidi bridge, UDP 5004/5005 → g_midi gadget
  ─▶ USB ─▶ Teletype USB host ─▶ MI.* ops in the loaded scene
  ─▶ CV 1–4 pitch + TR 1–4 gates

bridge/tt10.txt is the four-voice scene that receives it; bridge/tt09.txt is a one-voice MIDI monitor useful for proving the chain works.

Hardware notes

Everything here was learned the expensive way on real hardware. If you are building the bridge, read this section first.

  • The Pi Zero W is ARMv6. An arm64 image LED-bootloops with the config untouched. Use armhf.
  • 2026 Raspberry Pi images ignore custom.toml (ssh and userconf.txt still work). Configure WiFi with a firstrun.sh invoked from cmdline.txt — and cmdline.txt must stay a single line.
  • macOS dials RTP-MIDI over IPv6 first. The bridge is IPv4-only, so you get a session that connects with 0 ms latency and then sits silent. Disable IPv6 on the Pi. Diagnose with tcpdump -i wlan0 -n 'udp port 5004 or udp port 5005'.
  • Do not build a composite (multi-function) USB gadget. MIDI+HID in one device enumerates (configured) but the Teletype's USB host polls nothing, MIDI stops flowing, and the host stack wedges until the module is power-cycled. One function at a time is a hard constraint — which is why the mode dance exists rather than being an oversight.
  • The HID keyboard identity is best-effort. The module only polls a freshly enumerated HID device and stops within seconds. Roughly one enumeration equals one keypress; ttsend re-enumerates and retries six times and still sometimes fails. A real keyboard is the reliable way to type on a Teletype.
  • On the module: ENTER loads a scene and wipes typed state, ALT+ENTER saves. Unsaved LIVE state dies on reboot. In the scene browser use the arrow keys — the PARAM knob does nothing there. F1F8 fire scripts 1–8, which is a MIDI-free way to self-test a scene.
  • One MIDI sender at a time. Two senders fight over the same ops. A two-voice arrangement only ever lights two TRs — mixer rows equal voice count.

Repository layout

TeletypeKit/          swift package — the engine, pure logic
  Sources/TeletypeKit/  SMF parser, MusicIR, arranger, scene serializer/validator
  Sources/ttx/          command-line translator
  Tests/                66 tests, incl. byte-exact round-trip against the corpus
app/                  SwiftUI macOS app (xcodegen project)
bridge/pi/            python appliance: RTP-MIDI → USB gadget, mode scripts, systemd units
bridge/tt09-11.txt    Teletype scenes that receive the live MIDI
bridge/*/*.ino        Teensy 4.1 sketches — experimental wired alternative
corpus/scenes/        monome's 8 factory scenes, round-trip ground truth (CC-BY, see NOTICE.md)
corpus/midi/          small MIDI fixtures
docs/                 design spec, implementation plans, Pi bridge research
site/                 icon and brand concepts
PROJECT.html          long-form project brief

Testing

cd TeletypeKit && swift test

66 tests, no hardware or network required. The suite's backbone is a byte-exact round-trip of monome's eight factory scenes: parse → model → re-serialize must reproduce the original file byte for byte.

One optional test sweeps a large MIDI library for parser robustness. It skips unless you point it at one:

TELETYPE_MIDI_SWEEP_DIR=~/Music/MIDI swift test --filter MIDIImportRobustnessTests

Status and known issues

Version 0.1 — a personal project, shared as-is. It works, and it is not a product.

  • Just Friends pitch is broken. Driving JF over i2c produces sound and CV/TR respond correctly, but every note comes out at the same pitch. JF.NOTE's first argument is pitch relative to C3, which was fixed, and the symptom persisted — so the remaining suspects are on JF's side (its left toggle must be on sound, not shape, and Just Type needs JF 4.0+ firmware). Unresolved.
  • The Teensy sketches are scaffolding, not a finished bridge.
  • No notarized build, no installer, no release binaries.

License

MIT.

The factory scenes in corpus/scenes/ are monome's, redistributed under CC-BY-4.0 — see NOTICE.md. The Teletype firmware itself is not vendored here.

About

MIDI files to monome Teletype scenes, plus a live WiFi-to-USB MIDI bridge for the module

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages