This repository contains a Python synthesizer and its accompanying tests.
- When suggesting changes to a file, prefer breaking them into smaller chunks
- Never tell the user "you're absolutely right" or similar affirmations. Assume the user might be wrong and double-check their assumptions before proceeding
- Before addressing big features or complicated bugs, discuss the approach first and consider creating a plan
- Build/Install:
uv sync - Run app:
uv run python main.py - Lint:
uv run ruff check . - Run all tests:
PYNPUT_BACKEND=dummy QT_QPA_PLATFORM=offscreen uv run pytest - Run single test:
PYNPUT_BACKEND=dummy QT_QPA_PLATFORM=offscreen uv run pytest tests/test_file.py::TestClass::test_function -v - Test with coverage:
PYNPUT_BACKEND=dummy QT_QPA_PLATFORM=offscreen uv run pytest --cov=qwerty_synth --cov-report=html
- Use descriptive variable and function names (avoid abbreviations except very common ones)
- Naming conventions:
snake_casefor variables/functions,PascalCasefor classes - Use dataclasses (with
slotswhen appropriate) to define objects with types - Use PEP 585 built-in generic types (
list[str]instead oftyping.List[str]) - Use explicit module imports:
import maththenmath.ceil()(notfrom math import ceil) - Imports: stdlib first, third-party next, local modules last
- Place orchestrator functions before the functions they call
- Write docstrings for module-level and all public classes/functions
- Use Google style docstrings starting immediately after opening quotes
- Explain briefly what the function does and why
- Use clarifying inline comments for complex syntax
- Python 3.10+ required
- Line length: max 100 characters
- Indentation: 4 spaces
- Blank lines should contain no spaces
- Type hints encouraged
- Prefer well maintained and robust libraries over custom code
- Write minimal, readable code
- Each function should do one thing clearly
- Handle errors explicitly - use try/except with specific exceptions
- Thread safety: use locks when modifying shared resources
- Prefer modern Python features (dataclasses with
slots, structural pattern matching, type aliases) when adding or updating code
- Install dependencies with
uv sync. - Ensure the system package
portaudio19-devis installed. - Run the linter using
uv run ruff check .and fix issues when possible. - Execute the tests with
PYNPUT_BACKEND=dummyandQT_QPA_PLATFORM=offscreen:PYNPUT_BACKEND=dummy QT_QPA_PLATFORM=offscreen uv run pytest.
main.py- Application entry pointqwerty_synth/- Main package containing all synthesizer modulessynth.py- Core synthesizer engine with audio generationcontroller.py- Main controller orchestrating all componentsgui_qt.py- PyQt-based graphical user interfaceconfig.py- Configuration management and settingspatch.py- Sound preset management (save/load patches)keyboard_midi.py- QWERTY keyboard to MIDI event translatormidi_input.py- External MIDI controller input handler
adsr.py- Attack/Decay/Sustain/Release envelope generatorfilter.py- Multi-mode filter (low-pass, high-pass, band-pass, notch)drive.py- Distortion/overdrive effectdelay.py- Tempo-synced stereo delay effectchorus.py- Chorus effect for rich, layered soundslfo.py- Low-frequency oscillator for modulationarpeggiator.py- Arpeggiator for automatic note patternsstep_sequencer.py- Step sequencer with scale and rhythm controlsrecord.py- Audio recording functionality (WAV export)
tests/- Comprehensive test suite for all modulessynth_performance_benchmark.py- Performance benchmarking tool
- Real-time polyphonic synthesis with multiple waveforms
- Three input methods:
- QWERTY keyboard (default)
- External MIDI controller input (real-time hardware)
- MIDI file playback (pre-recorded files with tempo control)
- Live audio visualization (waveform, spectrum, ADSR curves)
- Comprehensive effects chain (filter, drive, delay, chorus, reverb)
- Modulation system with LFO and envelope control
- Pattern sequencing and arpeggiator
- Patch management for saving/loading presets
- Audio recording to WAV files
- Always run scripts with uv:
uv run pythonoruv run pytest
- Make sure changes are committed on a feature or fix branch, not directly on main
- Before staging files with
git add, review what changed withgit statusandgit diff - When staging files, verify no unnecessary changes were added and ask the user to confirm
- Group related changes in a single logical commit with a descriptive message
- Commit messages should have a concise title; add a body for complicated commits if needed
- Never add co-authorship attribution or AI-generated markers to commit messages
- Never include line numbers or line counts in documentation
- Reference files by path only, not with specific line numbers
- Always use sentence case in headings