Live Performance

Real-time MIDI synthesis. See the Live Performance guide for a tutorial.

Note

Live MIDI input requires python-rtmidi — install with pip install "pytheory[live]".

Ableton Link sync (LiveEngine.enable_link()) requires LinkPython-extern — install with pip install "pytheory[link]".

Real-time MIDI-driven synthesis engine.

Listens for MIDI input (e.g. from an OP-XY, keyboard, or DAW) and synthesizes audio in real-time through pytheory’s synth engine.

Usage:

from pytheory.live import LiveEngine

engine = LiveEngine()
engine.channel(1, instrument="electric_piano")
engine.channel(2, instrument="bass_guitar", lowpass=800)
engine.channel(10, drums=True)
engine.start()  # blocks until Ctrl-C

Notes are pre-rendered to a 3-second wavetable. Sustaining instruments (organ, pads, strings — any envelope with a nonzero sustain level) loop seamlessly inside the wavetable, so held keys ring for as long as you hold them. Percussive instruments (piano, plucks) decay naturally and end.

Effects (lowpass, reverb, chorus, delay, tremolo, distortion, saturation) run on each channel’s bus in real time, so MIDI CC sweeps are smooth and instant — no wavetable re-rendering.

To play in time with Ableton Live, iOS apps, or anything else that speaks Ableton Link (requires pip install pytheory[link]):

engine.enable_link()
engine.start()

Tempo, the drum-pattern beat grid, and transport start/stop all sync with the Link session — peer-to-peer, no master.

class pytheory.live.LiveEngine(buffer_size=512, sample_rate=44100)[source]

Bases: object

Real-time MIDI-to-audio engine.

Maps MIDI channels to pytheory instruments and synthesizes audio in real-time via sounddevice.

Example:

engine = LiveEngine()
engine.channel(1, instrument="electric_piano")
engine.channel(2, instrument="bass_guitar")
engine.channel(10, drums=True)
engine.start()
channel(ch, *, instrument=None, synth=None, envelope=None, drums=False, **kwargs)[source]

Configure a MIDI channel.

Parameters:
  • ch – MIDI channel number (1-16). Channel 10 = drums by convention.

  • instrument – Instrument preset name (e.g. “electric_piano”).

  • synth – Synth waveform name (overrides instrument).

  • envelope – Envelope name (overrides instrument).

  • drums – If True, this channel triggers drum sounds by MIDI note.

  • **kwargs – Any Part parameter (lowpass, reverb, volume, etc.)

drums(pattern_name, *, volume=0.5)[source]

Add a drum pattern that syncs to MIDI clock.

The pattern plays in sync with the OP-XY’s transport - starts on Start, stops on Stop, tempo from MIDI clock.

Parameters:
  • pattern_name – Drum pattern preset name (e.g. “rock”, “house”).

  • volume – Drum volume (0.0-1.0).

cc(cc_number, param, *, min_val=0.0, max_val=1.0, ch=None)[source]

Map a MIDI CC to a channel parameter.

Parameters:
  • cc_number – MIDI CC number (0-127).

  • param – Parameter name (“volume”, “lowpass”, “reverb”, etc.)

  • min_val – Value when CC = 0.

  • max_val – Value when CC = 127.

  • ch – MIDI channel (None = all channels).

Example:

>>> engine.cc(11, "lowpass", min_val=200, max_val=8000)
>>> engine.cc(12, "volume", min_val=0.0, max_val=1.0)
>>> engine.cc(13, "reverb", min_val=0.0, max_val=0.8)
>>> engine.cc(14, "distortion", min_val=0.0, max_val=0.8)

Sync with an Ableton Link session on the local network.

Tempo follows the session (and the session follows you — Link is peer-to-peer), the drum pattern locks to the shared beat grid, and transport start/stop syncs with peers that support it (Ableton Live, most iOS apps).

Parameters:
  • quantum – Bar length in beats for phase alignment (default 4 — drums land on the same downbeat as everyone else’s bar).

  • start_stop_sync – Follow Link transport start/stop.

Requires the link extra:

pip install pytheory[link]

Number of Link peers currently on the network (0 if Link is not enabled).

list_ports()[source]

List available MIDI input ports.

start(port=None)[source]

Start the engine - opens MIDI input and audio output.

Parameters:

port – MIDI port index or name. None = first available.

Blocks until Ctrl-C or stop() is called.

keyboard_play(ch=1)[source]

Enable computer keyboard as MIDI input on a channel.

keyboard_note(key, on=True)[source]

Translate a keyboard key to a MIDI note and play it.

QWERTY layout: ZSXDCVGBHNJM = C through B (lower octave)

Q2W3ER5T6Y7U = C through B (upper octave)

start_recording()[source]

Start recording MIDI events.

stop_recording()[source]

Stop recording.

export_recording(filename='recording.mid', bpm=None)[source]

Export recorded events to a MIDI file.

Returns a pytheory Score if no filename given.

save_config(filename)[source]

Save current configuration to JSON.

load_config(filename)[source]

Load configuration from JSON.

stop()[source]

Stop the engine.