Metadata-Version: 2.4
Name: pyquist
Version: 0.1.0
Summary: Barebones utilities for low-level computer music programming in Python and NumPy. Teaching library for CMU 15-322.
Author: Chris Donahue
License-Expression: MIT
Project-URL: Homepage, https://gclef-cmu.org/pyquist
Project-URL: Documentation, https://gclef-cmu.org/pyquist
Project-URL: Repository, https://github.com/gclef-cmu/pyquist
Project-URL: Issues, https://github.com/gclef-cmu/pyquist/issues
Keywords: audio,music,dsp,midi,numpy,computer-music,education
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Education
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Sound/Audio
Classifier: Topic :: Scientific/Engineering
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: matplotlib
Requires-Dist: mido
Requires-Dist: numpy>=2.0
Requires-Dist: requests
Requires-Dist: resampy
Requires-Dist: sounddevice
Requires-Dist: soundfile
Requires-Dist: tqdm
Provides-Extra: dev
Requires-Dist: mypy>=1.13; extra == "dev"
Requires-Dist: pre-commit>=4.0; extra == "dev"
Requires-Dist: ruff>=0.8; extra == "dev"
Provides-Extra: notebook
Requires-Dist: ipython; extra == "notebook"
Provides-Extra: docs
Requires-Dist: sphinx>=7; extra == "docs"
Requires-Dist: sphinx-autodoc-typehints>=2; extra == "docs"
Dynamic: license-file

# `pyquist`

`pyquist` provides basic utilities for **low-level computer music programming in Python and NumPy**.

`pyquist` is **designed for learning** and is the teaching library for CMU's 15-322 Intro to Computer Music. Its primary purpose is to provide a _barebones foundation_ for working with audio in Python, e.g., allocating sample buffers, audio file decoding and playback. Accordingly, it intentionally lacks a lot of functionality found in full-fledged computer music programming frameworks, such as a rich collection of unit generators.

Want to try it without installing anything? [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/gclef-cmu/pyquist/blob/main/examples/HelloPyquist.ipynb)

## Quick example

```python
import numpy as np
import pyquist as pq

# A 1-second, 440 Hz sine wave at CD quality.
sr = 44100
t = np.arange(sr) / sr
audio = pq.Audio(0.5 * np.sin(2 * np.pi * 440 * t), sample_rate=sr)

pq.play(audio)        # play through default output (or notebook widget)
pq.plot(audio)        # waveform
pq.plot_spec(audio)   # spectrogram
```

Loading and transforming:

```python
riff = pq.Audio.from_url(
    "https://github.com/gclef-cmu/pyquist/raw/refs/heads/main/pyquist/test_data/388954__fullmetaljedi__blues-riff-in-g-nylon.wav"
)
clip = riff.segment(offset=5.0, duration=3.0).resample(8000)
pq.play(clip)
```

Rendering a `Score` with a custom instrument. An instrument is called as `instrument(**event.kwargs)` — declare the kwargs you use and absorb the rest with `**kwargs`:

```python
from pyquist.score import Score, Event, BasicMetronome
from pyquist.helper import pitch_to_frequency

def sine_instrument(pitch, duration, **kwargs):
    sr = 44100
    t = np.arange(int(duration * sr)) / sr
    freq = pitch_to_frequency(pitch)
    return pq.Audio(0.3 * np.sin(2 * np.pi * freq * t) * np.exp(-3 * t), sample_rate=sr)

score = Score([
    Event(0, {"pitch": 60, "duration": 0.5}),
    Event(1, {"pitch": 64, "duration": 0.5}),
    Event(2, {"pitch": 67, "duration": 0.5}),
])
pq.play(score.render(sine_instrument, metronome=BasicMetronome(120)))
```

For a guided walkthrough — visualization, MIDI parsing, scores, instruments — open [`examples/HelloPyquist.ipynb`](examples/HelloPyquist.ipynb) or [run it in Colab](https://colab.research.google.com/github/gclef-cmu/pyquist/blob/main/examples/HelloPyquist.ipynb).

## Installation

Requires **Python 3.10 or later**.

### macOS

```sh
brew install python@3.10          # or 3.11, 3.12, 3.13
python3.10 -m venv .venv
source .venv/bin/activate
pip install --upgrade pyquist
```

If `pq.play(...)` is silent, give Terminal (or your IDE) microphone/audio access in **System Settings → Privacy & Security → Microphone**.

### Linux

Install Python and the PortAudio system library that `sounddevice` wraps:

```sh
# Debian / Ubuntu
sudo apt install python3 python3-venv libportaudio2

# Fedora
sudo dnf install python3 python3-virtualenv portaudio

python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pyquist
```

### Windows

Install [Python](https://www.python.org/downloads/) (3.10 or later, with "Add Python to PATH" checked), then open **Command Prompt**:

```bat
python -m venv .venv
.venv\Scripts\activate.bat
pip install --upgrade pyquist
```

### From source

For hacking on pyquist itself:

```sh
git clone https://github.com/gclef-cmu/pyquist.git
cd pyquist
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev,notebook]"
pre-commit install
```

### Pick default audio devices

Once installed, the `pyquist` CLI lets you choose persistent default input/output devices (handy for laptops with multiple interfaces):

```sh
pyquist devices
```

### Run notebooks

```sh
pip install jupyter ipykernel ipywidgets
python -m ipykernel install --user --name=pyquist --display-name "Pyquist"
cd examples
jupyter notebook
```

Then open [`HelloPyquist.ipynb`](examples/HelloPyquist.ipynb) and select the **Pyquist** kernel.

## Acknowledgements

Inspired in part by:

- [Nyquist](https://sourceforge.net/projects/nyquist/)
- [Tone.js](https://tonejs.github.io/)
- [JUCE](https://juce.com/)
