diff --git a/README.md b/README.md index bd2754a..ad05469 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,13 @@ uv sync ## Running -Run the synth with: +Run the synth with the packaged GUI entry script: + +```bash +uv run qwertysynth +``` + +You can also continue using the legacy entry point if you prefer: ```bash uv run python main.py @@ -57,7 +63,7 @@ Then press keys on the keyboard to play or use the GUI controls. Press ESC to qu ## Command line options ```bash -uv run python main.py [OPTIONS] +uv run qwertysynth [OPTIONS] ``` - `--midi FILE` - Load MIDI file on startup @@ -66,7 +72,7 @@ uv run python main.py [OPTIONS] Example: ```bash -uv run python main.py --midi song.mid --play --patch "Bass" +uv run qwertysynth --midi song.mid --play --patch "Bass" ``` ## Input methods diff --git a/main.py b/main.py index 0d52853..7b12eaf 100644 --- a/main.py +++ b/main.py @@ -1,34 +1,11 @@ -"""QWERTY Synth - A simple software synthesizer controlled by your keyboard.""" +"""Backward-compatible entry point for running the QWERTY Synth GUI.""" -import argparse - -from qwerty_synth import gui_qt as gui +from qwerty_synth.entry import main as _launch_gui def main(): - """Start the QWERTY Synth application.""" - parser = argparse.ArgumentParser(description='QWERTY Synth - Software synthesizer') - parser.add_argument('--midi', type=str, help='MIDI file to load on startup') - parser.add_argument('--play', action='store_true', help='Automatically play the MIDI file') - parser.add_argument('--patch', type=str, help='Patch name to load on startup') - args = parser.parse_args() - - print('QWERTY Synth: Play keys A-K, W,E,T,Y,U,O,P etc.') - print('Use Z / X to shift octave down / up') - print('Press ESC to quit') - - if args.midi: - print(f'MIDI file will be loaded: {args.midi}') - if args.play: - print('Auto-play enabled') - - if args.patch: - print(f'Patch will be loaded: {args.patch}') - - print('Starting GUI...') - - # Start the GUI (which handles audio stream and keyboard input) - gui.start_gui(midi_file=args.midi, auto_play=args.play, patch_name=args.patch) + """Launch the QWERTY Synth application.""" + _launch_gui() if __name__ == "__main__": diff --git a/pyproject.toml b/pyproject.toml index 1e8926f..88f6ecb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "qwerty-synth" +name = "qwertysynth" version = "0.1.0" description = "A minimalist real-time synthesizer with QWERTY keyboard input" readme = "README.md" @@ -20,6 +20,12 @@ dependencies = [ "soundfile>=0.13.1", ] +[project.scripts] +qwertysynth = "qwerty_synth.entry:main" + +[tool.uv] +package = true + [dependency-groups] dev = [ "pytest>=8.3.5", diff --git a/qwerty_synth/entry.py b/qwerty_synth/entry.py new file mode 100644 index 0000000..6951ca5 --- /dev/null +++ b/qwerty_synth/entry.py @@ -0,0 +1,34 @@ +"""Entry point for launching the QWERTY Synth GUI.""" + +import argparse + +from qwerty_synth import gui_qt as gui + + +def main(): + """Parse command-line arguments and start the synthesizer GUI.""" + parser = argparse.ArgumentParser(description='QWERTY Synth - Software synthesizer') + parser.add_argument('--midi', help='MIDI file to load on startup') + parser.add_argument('--play', action='store_true', help='Automatically play the MIDI file') + parser.add_argument('--patch', help='Patch name to load on startup') + args = parser.parse_args() + + print('QWERTY Synth: Play keys A-K, W,E,T,Y,U,O,P etc.') + print('Use Z / X to shift octave down / up') + print('Press ESC to quit') + + if args.midi: + print(f'MIDI file will be loaded: {args.midi}') + if args.play: + print('Auto-play enabled') + + if args.patch: + print(f'Patch will be loaded: {args.patch}') + + print('Starting GUI...') + + gui.start_gui(midi_file=args.midi, auto_play=args.play, patch_name=args.patch) + + +if __name__ == "__main__": + main() diff --git a/uv.lock b/uv.lock index 3735596..2c88d7a 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 2 requires-python = ">=3.10" [[package]] @@ -975,6 +975,57 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/69/76/37c0ccd5ab968a6a438f9c623aeecc84c202ab2fabc6a8fd927580c15b5a/QtPy-2.4.3-py3-none-any.whl", hash = "sha256:72095afe13673e017946cc258b8d5da43314197b741ed2890e563cf384b51aa1", size = 95045, upload-time = "2025-02-11T15:09:24.162Z" }, ] +[[package]] +name = "qwertysynth" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "matplotlib" }, + { name = "mido" }, + { name = "numba" }, + { name = "numpy" }, + { name = "pynput" }, + { name = "pyqt5" }, + { name = "pyqtgraph" }, + { name = "python-rtmidi" }, + { name = "pyyaml" }, + { name = "qdarkstyle" }, + { name = "scipy" }, + { name = "sounddevice" }, + { name = "soundfile" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "matplotlib", specifier = ">=3.10.1" }, + { name = "mido", specifier = ">=1.3.3" }, + { name = "numba", specifier = ">=0.61.2" }, + { name = "numpy", specifier = ">=2.2.4" }, + { name = "pynput", specifier = ">=1.8.1" }, + { name = "pyqt5", specifier = ">=5.15.11" }, + { name = "pyqtgraph", specifier = ">=0.13.7" }, + { name = "python-rtmidi", specifier = ">=1.5.8" }, + { name = "pyyaml", specifier = ">=6.0.2" }, + { name = "qdarkstyle", specifier = ">=3.2.3" }, + { name = "scipy", specifier = ">=1.15.3" }, + { name = "sounddevice", specifier = ">=0.5.1" }, + { name = "soundfile", specifier = ">=0.13.1" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.5" }, + { name = "pytest-cov", specifier = ">=6.1.1" }, + { name = "ruff", specifier = ">=0.11.11" }, +] + [[package]] name = "ruff" version = "0.11.11" @@ -1099,57 +1150,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/e9/6b761de83277f2f02ded7e7ea6f07828ec78e4b229b80e4ca55dd205b9dc/soundfile-0.13.1-py2.py3-none-win_amd64.whl", hash = "sha256:1e70a05a0626524a69e9f0f4dd2ec174b4e9567f4d8b6c11d38b5c289be36ee9", size = 1019162, upload-time = "2025-01-25T09:16:59.573Z" }, ] -[[package]] -name = "synth1" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "matplotlib" }, - { name = "mido" }, - { name = "numba" }, - { name = "numpy" }, - { name = "pynput" }, - { name = "pyqt5" }, - { name = "pyqtgraph" }, - { name = "python-rtmidi" }, - { name = "pyyaml" }, - { name = "qdarkstyle" }, - { name = "scipy" }, - { name = "sounddevice" }, - { name = "soundfile" }, -] - -[package.dev-dependencies] -dev = [ - { name = "pytest" }, - { name = "pytest-cov" }, - { name = "ruff" }, -] - -[package.metadata] -requires-dist = [ - { name = "matplotlib", specifier = ">=3.10.1" }, - { name = "mido", specifier = ">=1.3.3" }, - { name = "numba", specifier = ">=0.61.2" }, - { name = "numpy", specifier = ">=2.2.4" }, - { name = "pynput", specifier = ">=1.8.1" }, - { name = "pyqt5", specifier = ">=5.15.11" }, - { name = "pyqtgraph", specifier = ">=0.13.7" }, - { name = "python-rtmidi", specifier = ">=1.5.8" }, - { name = "pyyaml", specifier = ">=6.0.2" }, - { name = "qdarkstyle", specifier = ">=3.2.3" }, - { name = "scipy", specifier = ">=1.15.3" }, - { name = "sounddevice", specifier = ">=0.5.1" }, - { name = "soundfile", specifier = ">=0.13.1" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.5" }, - { name = "pytest-cov", specifier = ">=6.1.1" }, - { name = "ruff", specifier = ">=0.11.11" }, -] - [[package]] name = "tomli" version = "2.2.1"