Skip to content

Repository files navigation

Strumer

Turn your laptop trackpad into a real instrument.
Strum chords, control MIDI, orchestrate systems — all from your touchpad.

Python 3.9+ MIT License CI Platform

Strumer Demo


Strumer brings the physical "strumming" feel of the legendary Omnichord directly to your laptop trackpad. Select a chord on your keyboard and strum the strings by sliding your finger on the trackpad. It works as a fully functional MIDI controller with your DAW, and can also act as a system orchestration tool.

Table of Contents

Features

Low-Latency Trigger Engine (Piano Mode)

Works with Standard Block Chord logic for advanced VST (Virtual Studio Technology) compatibility. When you slide your finger on the trackpad, the notes of the strings are triggered simultaneously with near-zero latency.

8-Way Vector Snapping (Drift Filter)

Uses a trigonometric drift filter to prevent the natural hand jitters (drift).

  • Your finger's instantaneous X/Y position is calculated using math.atan2
  • It is then locked (quantized) to the nearest 45-degree (8-way) virtual rail
  • Only Dot Product (projection) advancements on this rail are converted into velocity. Reverse deviations or vertical jitters are filtered out. You play smoothly as if there were physical grooves on the trackpad

Hardware Controllers (Sustain & Octave)

Replicates essential MIDI keyboard controls:

  • Sustain Pedal: Hold Shift to send MIDI CC 64 (Value 127) to your DAW. Release to turn off.
  • Octave Gearbox: Shift gears between ±4 octaves using Up Arrow / Down Arrow. The system clips itself within the 0-127 MIDI boundaries.

Zero-Flicker Minimalist TUI

The interface is built with the rich library using a persistent layout architecture:

  • No screen clearing: The skeleton is drawn once; only changing pixels are updated using a delta-render algorithm.
  • Realistic Oscilloscope: Velocity data is passed through a decay filter, creating smoothly gliding waveforms — just like an analog device.

System Management Mode

Launch with --mode system and the trackpad becomes a DevOps orchestration device. Chords map to services (C = Web Server, D = Database); strumming speed controls scale-up and scale-down of Docker containers.

Note

System Mode is experimental / proof-of-concept. It does not execute real infrastructure commands yet — it only simulates and logs the actions that would be taken.

Platform Support

Platform Status Notes
macOS ✅ Full Support Native CoreFoundation patches included
Linux ✅ Supported Requires X11 or Wayland with pynput support
Windows ✅ Supported Works with standard touchpad drivers

Installation

Prerequisites

  • Python 3.9+ (tested up to 3.13)
  • A laptop with a trackpad/touchpad
  • A MIDI-compatible DAW (e.g., Ableton, FL Studio, Logic Pro) for MIDI mode

Quick Start

# Clone the repository
git clone https://github.com/thevalmarch/strumer.git
cd strumer

# Install dependencies
pip install -r requirements.txt

# Run
python src/strumer.py

Using Make (optional)

make install    # Install dependencies
make run        # Run in MIDI mode
make run-system # Run in System mode

Platform-Specific Notes

macOS

You must grant Accessibility permission to your Terminal application:

System Settings → Privacy & Security → Accessibility

Without this, low-level keyboard/mouse events cannot be captured.

Linux

You may need to add your user to the input group:

sudo usermod -aG input $USER

Then log out and back in. Some Wayland compositors may require additional configuration for pynput.

Windows

No special permissions required. Run your terminal as a normal user.

Usage

Launching Modes

Standard MIDI Mode (strum chords, send MIDI to your DAW):

python src/strumer.py

DevOps System Mode (container and log orchestration):

python src/strumer.py --mode system

Controls

Key Action
Q W E R T Y U Major chords (C, D, E, F, G, A, B)
A S D F G H J Minor chords (Cm, Dm, Em, Fm, Gm, Am, Bm)
Z X C V B N M Dominant 7th chords (C7, D7, E7, F7, G7, A7, B7)
Trackpad Swipe Strum — speed and direction are detected
Space Panic / Mute All (kills all hanging notes)
Shift Sustain Pedal
Up / Down Octave shift (±4 range)
ESC Exit

Architecture

strumer/
├── src/
│   ├── __init__.py              # Package marker
│   ├── __main__.py              # Entry point for `python -m src`
│   ├── strumer.py               # Backward-compatible wrapper (re-exports public API)
│   ├── app.py                   # main() entry point with arg parsing
│   ├── config.py                # Version and constants
│   ├── math_utils.py            # Pure functions (clamp, velocity, snap_vector, decay)
│   ├── chords.py                # Chord data, key mapping, JSON/YAML config loading
│   ├── ui.py                    # UIState class and Rich TUI rendering
│   ├── midi_engine.py           # MidiEngine class (rtmidi wrapper)
│   ├── midi_mapping.py          # MIDI CC mapping and learn mode
│   ├── input_handler.py         # InputHandler (pynput wrapper)
│   ├── controller.py            # TrackpadController orchestrator
│   ├── platform_patches.py      # macOS Quartz/pynput patches, terminal mgmt
│   ├── recorder.py              # Session recording and playback (.strumer format)
│   ├── gestures.py              # Multi-touch gesture recognition
│   ├── sound_engine.py          # Built-in polyphonic synthesizer (oscillator + ADSR)
│   ├── effects.py               # Audio effects (reverb, chorus)
│   ├── plugins/                 # Plugin system
│   │   ├── __init__.py          # Public API re-exports
│   │   ├── base.py              # ABC base classes (Instrument, Effect, Gesture)
│   │   ├── registry.py          # Singleton plugin registry
│   │   └── loader.py            # Dynamic plugin discovery and loading
│   └── platform_backends/       # Platform-specific multi-touch backends
│       ├── __init__.py          # Backend auto-detection
│       └── macos_multitouch.py  # macOS MultitouchSupport.framework
├── plugins/
│   └── example_instrument/      # Example community plugin
│       ├── plugin.json          # Plugin metadata
│       └── instrument.py        # BrightPiano implementation
├── recordings/                  # User-generated session recordings
├── tests/                       # 116 unit tests
├── config/
│   ├── chords.json              # Chord voicings and key mapping
│   ├── chords.example.json      # Extended voicings example
│   ├── chords.example.yaml      # YAML config example
│   └── midi_map.json            # MIDI CC mapping config
├── .github/
│   ├── workflows/ci.yml         # CI pipeline (lint, test, syntax check)
│   ├── ISSUE_TEMPLATE/          # Bug report & feature request templates
│   └── PULL_REQUEST_TEMPLATE.md
├── pyproject.toml               # Python packaging & metadata
├── requirements.txt             # Pinned dependencies
├── Makefile                     # Developer shortcuts
├── LICENSE                      # MIT License
├── CHANGELOG.md                 # Version history
├── CONTRIBUTING.md              # Contribution guidelines
└── CODE_OF_CONDUCT.md           # Community standards

Core Modules

Module Responsibility
controller.py Orchestrator: ties input, MIDI, recording, and UI together
chords.py Chord data, key mapping, JSON/YAML config with validation
midi_engine.py MIDI output via rtmidi (note on/off, CC, sustain)
midi_mapping.py Configurable gesture-to-CC mapping with learn mode
sound_engine.py Built-in polyphonic synth (sine/saw/square/triangle + ADSR)
effects.py Audio effects (Schroeder reverb, chorus)
recorder.py Session recording and playback (.strumer JSON Lines format)
gestures.py Multi-touch gesture recognition (pinch, rotate)
ui.py Thread-safe TUI state management with persistent layout
math_utils.py 8-way drift filtering via atan2 + dot product
platform_patches.py macOS CoreFoundation fix, Python 3.13 thread fix
plugins/ Plugin system: base classes, registry, dynamic loader

Developer Notes & Architectural Bug Fixes

Because this codebase pushes OS boundaries, several system patches are embedded inside:

  1. Python 3.13 Thread Handle Collision: The TypeError: '_thread._ThreadHandle' object is not callable error caused by a collision between Python 3.13's Thread architecture and pynput's macOS darwin adaptation has been fixed via class-level Method Aliasing (_pynput_handle). This patch only applies on macOS.

  2. Terminal Echo Suppression: On UNIX systems, ECHO and ICANON flags in termios are disabled to prevent keystroke echo from disrupting the TUI. On Windows, this is handled natively by rich.

  3. CoreFoundation Symlink Patch (macOS): Quartz symbols (CFMachPortCreateRunLoopSource, etc.) removed in modern macOS versions are dynamically scanned via CoreFoundation and injected into the Quartz module.

Roadmap

  • Modular architecture (split single-file strumer.py into separate modules)
  • Custom chord voicing editor (JSON/YAML config with key mapping)
  • MIDI learn mode for arbitrary CC mapping
  • Recording and playback of strum sessions
  • Multi-touch gesture support (pinch for velocity curves)
  • Built-in sound engine (no external DAW required)
  • Plugin system for community instruments

Contributing

Contributions are welcome! Please read the Contributing Guide before submitting a Pull Request.

License

This project is licensed under the MIT License.


Keep Strumming. Keep Hacking.
Made by Val March

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages