A modern synthetic drum synthesizer built entirely in Python with algorithmic sound generation—no samples required. It comes with two interfaces on one shared app core: a hardware-style panel (HTML/JS in a Qt window, the default) and the classic tkinter window. Both have MIDI support, a 64-step pattern sequencer with per-step velocity, presets, exports and an optional AI drum generator.
Perfect for producers, sound designers, and developers interested in audio synthesis and digital signal processing.
- 8 Independent Drum Channels with full parameter control
- Oscillator Section
- Sine, Triangle, and Sawtooth waveforms
- Pitch modulation: Decay, Sine (FM), and Random modes
- Attack and decay envelope shaping
- Noise Generator
- Low-pass, Band-pass, High-pass filtering
- Stereo width control
- Exponential, Linear, and Modulated envelope modes
- Advanced Mixing
- Oscillator/Noise blend control
- Soft-clipping distortion
- Parametric EQ per channel
- Level and Pan controls
- Choke groups for realistic hi-hat behavior
- Modulation - Two LFOs and a pump per channel, aimed at any sound parameter, the master level or the sound morph
- Vintage Character - Analog warmth and saturation
- Reverb - Space and ambience
- Delay - Rhythmic echoes and timing effects
- Smoothed Parameters - Anti-zipper noise on parameter changes
- Two interfaces, one core - The web panel and the tkinter window share presets, patterns and preferences
- MIDI Support - Notes, program changes, clock sync, learned CCs with pickup, pitch bend
- Pattern Sequencer - 12 patterns of 1-64 steps with velocity, accents, fills, probability, substeps and chains
- Sound Morph - Blend between two learned sets of sounds
- Undo / Redo - Every edit, drag and preset change
- Preset System - Save and load whole presets and single drum patches
- Exports - Patterns to MIDI or audio, drums to WAV, transfers to and from a PO-32
- Real-time Audio - Low-latency playback via
sounddevice
No Python or terminal needed: download the app for your system from the latest release and start it.
| System | Download | Start |
|---|---|---|
| Windows 10/11 (64-bit) | Pythonic-…-windows-x64.zip |
unzip, double-click Pythonic.exe |
| macOS 14+ (Apple Silicon) | Pythonic-…-macos-arm64.dmg |
drag Pythonic to Applications |
| Linux (64-bit) | Pythonic-…-linux-x86_64.tar.gz |
extract, run Pythonic/Pythonic |
Each comes in two editions: Pythonic, and Pythonic + AI (the -ai
files, 600 to 750 MB instead of 250 to 300 MB), which adds the AI drum generator. The apps are not
signed yet, so the first start asks once: on Windows click More info ▸ Run
anyway; on macOS open System Settings ▸ Privacy & Security and click
Open Anyway.
To run from the source code instead (to change it, or on another system), read on.
- Python 3.10+ (tested up to Python 3.12)
- pip package manager
- MIDI interface (optional, for MIDI control)
- Clone or download this repository
cd pythonic- Start it
On Linux and macOS, one command sets everything up on the first launch and starts the app:
./run.shThe first launch takes a few minutes (about 1 GB to download, 2 GB on disk):
it creates a virtual environment in venv/, installs the app with both
interfaces and the AI drum generator (the CPU build of PyTorch on Linux),
downloads the panel's fonts and, with Git LFS installed, the generator's
models. Later launches start straight away; after an update that changes the
dependencies, the next launch installs them first.
Note: The drum voice engine is compiled with
numba. The first launch takes a few extra seconds while it compiles; the result is cached for later runs.
Setting it up by hand (Windows, or to choose what to install):
python -m venv venv
venv\Scripts\activate # Windows; on macOS/Linux: source venv/bin/activate
pip install -e . # the app and both interfaces
pip install -e ".[ml]" # plus PyTorch for the AI drum generator
pip install -e ".[dev]" # plus the test tools (pytest, pytest-qt, soundfile)
python tools/fetch_fonts.py # the panel's fonts (optional)The base install brings PySide6 with QtWebEngine for the web interface (about 650 MB), except on Windows ARM64 and macOS before 14, where no QtWebEngine exists and the tkinter interface is used.
The web panel is designed for three SIL OFL fonts (Barlow Condensed for
labels, Doto for the green display, DSEG7 for the tempo). They are not in the
repository; tools/fetch_fonts.py downloads them into
pythonic/web/static/fonts/ (sources and licences are listed in
SOURCES.txt there). Without them the panel uses system fonts (DejaVu Sans
Condensed and DejaVu Sans Mono, or the platform's equivalents).
Note: If you encounter issues with
midoorpython-rtmidi, they're only required for MIDI functionality. The synth works without them.
pythonic # the web interface (default)
pythonic --ui tk # the tkinter interface
pythonic --devtools [PORT] # web interface with Chromium DevTools on http://127.0.0.1:9222 (or PORT)
pythonic --quit-after 5 # close after 5 s (start-up checks; the web interface prints its frame timings)
pythonic --helppython run.py, python -m pythonic and ./run.sh take the same arguments.
One interface runs per launch; no interface preference is stored, only the
flag picks it. If the web interface cannot load (a broken install, or
Windows ARM64 where no QtWebEngine exists), the tkinter interface starts
instead and the terminal says why; ./run.sh or pip install -e . repairs
the install.
On first launch, Pythonic automatically creates:
- Configuration directory for preferences
Pythonic Presetsfolder in your Documents- Default factory presets
A fixed-size panel scaled to the window (letterboxed when the window's shape differs; the window cannot shrink below 1280×800):
- Left column: undo / redo, the step modes (trig, accent, velo, fill, prob, sub), last step, all ch, follow, ⊞ matrix, the patterns A-L with chain, menu, lane copy / paste, and KIT / INST / WRITE (below).
- Centre: master, step rate, fill rate and the strip CTRL mode over eight channel strips (patch name, tune, decay, CTRL knob, level fader, channel button showing the drum type).
- Right column: the green display, PRESET ◀ ▶ and the preset menu, edit rack, PO-32, setup, the MUTE latch, morph learn A / B, tempo, swing, the MIDI LED and the sound morph knob.
- Bottom: START/STOP, page bars and the 16 pads, and under the face the edit rack of the selected channel (every sound parameter, the LFO and pump rows). The edit rack button closes it (the window shrinks; the state is remembered). The matrix, the PO-32 page and the AI drum generator open in its place; setup opens as a sheet over the panel.
Controls: drag knobs and faders vertically (Shift for fine steps), turn the mouse wheel over any control, click a fader's track to jump, double-click a knob or fader to type an exact value, right-click for reset to default, MIDI learn, CC mappings and pitch bend. The display shows the touched control and its value. A click on the selected channel's button hits it. The web interface has no keyboard shortcuts.
| Key | Action |
|---|---|
1-8 |
Trigger drum channels 1-8 |
S |
Save preset |
L |
Load preset |
Ctrl+Z / Ctrl+Y |
Undo / redo |
- Knobs and sliders: click and drag vertically (Shift for fine steps), mouse wheel for small steps
- Ctrl+click or double-click a knob: reset to default
- Right-click a control: MIDI learn
- Connect your MIDI controller
- Launch Pythonic—it automatically detects MIDI devices (web: setup ▸ midi)
- Drum channels follow MIDI notes (default: C2-G2, notes 36-43)
- Velocity-sensitive response on all channels; program changes 0-11 select patterns A-L
- Learned CCs move their controls once the controller reaches the value (pickup)
Loading: web: the PRESET menu lists the preset folder and recent files, ◀ ▶ step through the folder; tkinter: the preset combo-box at the top
Saving: save preset as… opens the file browser in your preset folder
Preset Location:
- Windows:
%USERPROFILE%\Documents\Pythonic Presets - macOS:
~/Documents/Pythonic Presets - Linux:
~/Documents/Pythonic Presets
Preset Compatibility:
- Pythonic can import
.mtpresetpresets and load and save.mtdrumdrum patches - Load drums and patterns directly from these presets
Note: Pythonic uses its own synthesis engine. While it can read Microtonic presets, the resulting sounds may differ from the original due to differences in DSP implementation. Pythonic is an independent project and is not affiliated with, endorsed by, or sponsored by Sonic Charge or NuEdge Development. Microtonic™ is a trademark of Sonic Charge/NuEdge Development.
Basic Pattern Editing:
- Click steps to toggle triggers, accents, and fills (web: pick the step mode, then click or paint the pads)
- Per-step velocity (1-127) beside the accent
- Patterns of 1 to 64 steps, shown 16 at a time on 4 pages that can follow the playhead
- Visual step indicator shows current playback position
Per-Step Probability:
- Enable probability mode to control the chance of each step triggering (0-100%)
- 100% = always plays, 50% = plays half the time, 0% = never plays
- Adds organic variation and humanization to patterns
Substeps (Micro-Timing):
- Pick a substep pattern for a step (web: the sub step mode; tkinter: right-click a step)
- Define subdivisions using 'o' (play) and '-' (skip) notation
- Examples: "oo-" = play twice then skip, "o-o-" = alternating hits
- Creates flams, rolls, and complex rhythmic variations within a single step
pythonic/
├── pythonic/ # Core synthesis engine
│ ├── synthesizer.py # Main 8-channel synthesizer
│ ├── drum_channel.py # Individual drum channel
│ ├── drum_generator.py # AI drum generation (CVAE inference)
│ ├── oscillator.py # Waveform generation
│ ├── noise.py # Noise generator
│ ├── envelope.py # ADSR envelope generators
│ ├── filter.py # State-variable filters
│ ├── reverb.py # Reverb effect
│ ├── delay.py # Delay effect
│ ├── vintage.py # Analog character processing
│ ├── app/ # App core (UI-free): audio, transport, undo, MIDI, presets, exports, AI, PO-32
│ ├── web/ # Web interface: Qt window, bridge, static/ (HTML, CSS, JS modules)
│ ├── launch.py # The `pythonic` command
│ ├── pattern_manager.py # Step sequencer
│ ├── preset_manager.py # Preset save/load
│ ├── preferences_manager.py # Settings persistence
│ └── smoothed_parameter.py # Parameter smoothing
├── gui/ # tkinter interface
│ ├── main_window.py # Main application window
│ ├── drum_generator_dialog.py # AI drum generator dialog
│ └── widgets.py # Custom GUI components
├── tests/ # Unit and integration tests (tests/web: the web interface)
├── docs/ # Core interface, web front-end, parity lists, release checklist
├── test_patches/ # Test presets and analysis
├── tools/ # Development utilities (fetch_fonts.py, ...)
├── run.py # Application entry point (same arguments as `pythonic`)
├── run.sh # Shell launcher script
└── pyproject.toml # Package, dependencies and extras ([ml], [dev])
Developer documentation: docs/core-interface.md (the app core both interfaces drive), docs/web-frontend.md (the web interface), docs/release-checklist.md.
MIDI/Key Input
↓
Trigger
↓
┌────────────────────┐
│ Oscillator │──→ Envelope ──┐
│ (Sine/Tri/Saw) │ │
└────────────────────┘ ├──→ Mix ──→ Distortion ──→ EQ ──→ Vintage ──→ Delay ──→ Reverb ──→ Output
┌────────────────────┐ │
│ Noise Generator │──→ Filter ──→─┘
│ (LP/BP/HP) │ Envelope
└────────────────────┘
Kits work as on a TR-8S. A kit (the eight channel sounds under a name) lives
in a kit library of its own: seven read-only factory kits (505, 707, 808,
909, DMX, LM2, TR-8) and your user kits (JSON files in the Kits folder of
the preset folder). A preset plays one kit, and a pattern can recall a kit
when it starts (its menu: recall kit).
- KIT turns the display into the kit selector (
KIT 004* FACTORY/909): ◀ ▶, the wheel over the display or the arrow keys step through the kits, each playing at once; SHIFT jumps between the factory and user kits. Kit 000 is the preset's own sounds. - INST does the same for the selected channel's drum patch, through the
drum patch library by category (BD, SD, TOM, RIM, CLAP, CH, OH, CYM, PERC,
FX, OTHER): the factory drum patches, then the
.mtdrumfiles of the drum patch folder (PRESET ▸ drum patch folder…, defaultDrum Patchesin the preset folder). ◀ ▶ stay inside the sound's category (a BD steps through BDs); SHIFT goes to the next or previous category; a channel button changes the channel. - An edited kit shows
*and keeps its edits when you switch kits. WRITE stores them (over your user kit, or as a new one) and saves the preset; it also turns an old preset's programs into user kits.
The PRESET menu lists seven read-only factory presets, one per drum machine:
505, 707, 808, 909, DMX, LM2 and TR-8 Beats. Each plays its machine's kit
with twelve patterns. The TR-8 kit is made of drum patches fitted to TR-8
samples with tools/fit_samples.py (see below); all 41 of them are factory
drum patches in the INST library.
Pythonic includes 8 built-in drum sounds:
- Kick - Deep bass drum with exponential pitch sweep
- Snare - Punchy snare with noise body
- Closed Hi-Hat - Tight, crisp hi-hat
- Open Hi-Hat - Sustaining open hi-hat
- High Tom - Tuned high tom
- Low Tom - Tuned low tom
- Clap - Hand clap with modulated envelope
- Rim Shot - Sharp rimshot click
Pythonic includes an optional AI-powered drum generator that uses a Conditional Variational Autoencoder (CVAE) trained on hundreds of drum patches.
The generator requires PyTorch. ./run.sh installs it; a hand-made install (pip install -e .) leaves it out to stay lighter. It runs in a separate worker process, so the interface never imports PyTorch.
Pre-trained checkpoint files in this repository are stored with Git LFS. ./run.sh fetches them when Git LFS is installed; otherwise install it and fetch the model payloads before using AI features:
git lfs install
git lfs pullOption A — In-app install: open the AI drum generator (web: PRESET menu → AI drum generator…, then install now; tkinter: Preset menu → AI Drum Generator... → Install ML Support). This runs pip install torch (the [ml] extra) in the current environment after confirmation.
Option B — Manual install:
pip install -e ".[ml]"For GPU acceleration, install the appropriate CUDA/ROCm PyTorch variant first following pytorch.org. The CPU-only build works fine for inference.
The repository includes these pre-trained checkpoints, used by default:
| File | Description |
|---|---|
drum_cvae_best.pt |
Bundled drum-patch CVAE checkpoint used by the AI Drum Generator |
drum_patterns/pattern_cvae_best.pt |
Bundled pattern CVAE checkpoint used for AI pattern generation |
fit_prior.pt |
Starting-patch model of tools/fit_samples.py (see below) |
Other checkpoints can be chosen in setup ▸ ai (models… on the AI page opens it) (tkinter: Load Model... and Preset menu → AI Settings). The chosen paths are saved in preferences.
- Open the PRESET menu and choose AI drum generator…: the page opens under the strips, one lane per channel
- Click gen in a lane (pick its drum type first if you like) or generate 8 sounds: each lane gets one new sound, which plays on the face at once; edit it with the panel's controls, click gen again for another
- Click generate patterns: 12 new patterns (A–L) for the sounds on the face start playing; pick any of them on the face
- old / new switches a lane, or the patterns, back and forth to compare
- keep makes what plays part of the preset (one undo step); revert brings the old sounds and patterns back; leaving the page asks which
- The temperature knobs set how far the new sounds and patterns stray (lower = conservative, higher = experimental)
In the tkinter dialog, candidates are previewed per slot and Apply Selected copies the checked slots into the preset.
tools/fit_samples.py turns a folder of one-shot samples (WAV, AIFF or FLAC) into
.mtdrum drum patches, one per sample, named after it:
pip install -e ".[ml,dev]" # PyTorch for the starting-patch model, soundfile to read samples
python tools/fit_samples.py path/to/samples path/to/patches --wavFor each sample it builds starting patches from the partials it finds and from
the predictions of fit_prior.pt, then refines them with CMA-ES against the
sample's spectrogram, its pitch below 2 kHz and its envelope. Level is set so
every patch peaks at -10 dBFS (--peak-db); hi-hats get choke. --wav also writes
<name>.fit.wav, the sample on the left and the patch on the right, to compare
them by ear; fit_report.csv lists the scores (lower is closer). A sample takes
from one minute (a short rim shot) to half an hour (a long crash) per CPU core;
--jobs sets how many are fitted in parallel, --evals and --screen-evals
trade time for accuracy. One oscillator and one filtered noise match kicks, toms,
snares and other pitched drums closely, cymbals and metallic sounds less so.
tools/fit_prior.py <patches dir> retrains the starting-patch model on your own
.mtdrum patches (one to two hours on 8 CPU cores for the default 60,000).
- Sample Rate: 44.1 kHz (CD quality)
- Bit Depth: 32-bit float internal processing
- Audio Backend: PortAudio via
sounddevice - Latency: ~23.8 ms by default (buffer and sample rate in the audio settings; 512 frames, 11.6 ms, is the safe minimum)
- MIDI Backend: RtMidi via
python-rtmidiandmido - GUI Frameworks: PySide6 QtWebEngine (HTML/CSS/JS ES modules, no build step) and Tkinter, on one app core
Install the dev extra (pip install -e ".[dev]"), then:
python -m pytest tests -q # everything (~2-4 min)
python -m pytest tests/web -q # the web interface only
./run_tests.sh # creates ./venv if needed, installs, runs the testsThe web tests run headless (QT_QPA_PLATFORM=offscreen, set by
tests/web/conftest.py) and need no Node and no display; the tkinter smoke
test needs a display on Linux (it skips without one; use xvfb-run on a
server). Pure JS specs can also run with node --test pythonic/web/static/test/*.test.js.
The test suite includes:
- Synthesis accuracy validation and audio output comparison tests
- App core tests through its interface (addresses, verbs, poll) on a fake audio stream
- Web page tests driving the real page over a fake core, and end-to-end tests over the real core
- A parity guard: every core address is bound by a web control or listed as deliberately absent
- Verify
sounddeviceinstallation:pip install --upgrade sounddevice - Check system audio output device is working
- Pick another output device or a larger buffer: web: setup ▸ audio (then restart audio); tkinter: Preset menu → Audio Settings...
- List available devices:
python -c "import sounddevice; print(sounddevice.query_devices())"
- Ensure your MIDI device is connected before launching (or rescan in setup ▸ midi)
- Check if
midoandpython-rtmidiare installed - On Linux, you may need ALSA MIDI permissions
- Test MIDI:
python test_midi_input.py
- Check that PySide6 with QtWebEngine imports:
python -c "import PySide6.QtWebEngineWidgets"; if not,./run.shorpip install -e .installs it (from PySide6 6.12 it is the separatePySide6_WebEnginewheel).pythonic --ui tkalways works. - Linux: on a locked-down distribution, in a container or as root, Chromium's sandbox may refuse to start;
QTWEBENGINE_DISABLE_SANDBOX=1 pythonicis the fallback. pythonic --devtoolsopens the Chromium DevTools onhttp://127.0.0.1:9222to inspect the page.- Windows: the panel renders without the GPU, because QtWebEngine 6.11's GPU path crashes the app after a minute or two of playing. SETUP ▸ display ▸ use the GPU turns it back on at the next start (to try a newer PySide6, say); turn it off there if the panel crashes on another system.
- Increase audio buffer size (reduces real-time load)
- Disable unused effects (Reverb, Delay)
- Close other audio applications
- Use fewer simultaneous voices
macOS: May need to install PortAudio: brew install portaudio
Linux: Install dependencies: sudo apt install python3-dev portaudio19-dev libasound2-dev libjack-dev
Windows: Usually works out of the box with pip
- QUICK_START.md - First steps, presets and preferences
Built with Python | Educational & Open Source | No Samples Required
Contributions are welcome! Areas for improvement:
- Additional waveforms
- More effects
- Packaged installers per OS
