Skip to main content

Generate ZX Spectrum AY (PT3) music from MIDI and other sources.

Project description

spectrumizer

CI License: MIT Python Live demos

Generate ZX Spectrum AY music (.pt3) from public sources (MIDI now; MusicXML/scores planned). The output is a standard Vortex Tracker / Sergey Bulba PT3 module, so anything it produces drops straight into a Spectrum game that ships a PT3 replayer.

Instead of typing every arrangement note-by-note in Python, you feed a source file and spectrumizer arranges it down to the AY's 3 channels (+ noise).

▶ Hear it in your browser: demo page · or the Demos section below.

⚠️ Licence: spectrumizer does not launder licences. The licence of the SOURCE governs the OUTPUT — a .pt3 from a copyrighted MIDI is still copyrighted. Only bundle public-domain or your own music into a release. Read LICENSING.md.

Install

pip install -e .            # from a clone — installs the `spectrumizer` command + deps

Or, without installing the package:

python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt

All deps are pure-Python (mido), so the same wheels work on Intel & Apple Silicon — no native build step.

Use

# faithful 3-voice reduction
spectrumizer song.mid -o song.pt3                 # or: python -m spectrumizer song.mid -o song.pt3

# chiptune flavour: octave-doubled leads + synth drums when the source has none
spectrumizer song.mid -o song.pt3 --style chiptune

# tune the AY octave by ear, change grid/tempo
spectrumizer song.mid --transpose -12 --rows-per-beat 4 --speed 6 \
    --name "MY THEME" --author "ME"

# dynamics: MIDI velocity drives per-note volume (on by default)
spectrumizer song.mid -o song.pt3 --no-dynamics      # ...or flat per-channel volume

# generate and immediately hear it (renders through a software AY, then plays)
spectrumizer song.mid -o song.pt3 --play

Run spectrumizer --help for all flags.

How it works

MIDI ─(inputs/midi.py, mido)→ IR ─(arrange/)→ 3 AY channels ─(pt3/)→ .pt3
  • spectrumizer/pt3/ — the proven PT3 emitter (note encoding, channel packer, samples, ornaments, file writer). The byte format is verified against the real player; don't change it blindly.
  • spectrumizer/arrange/ — the hard part:
    • quantize — map time to PT3's row grid (derive speed from tempo).
    • reduce — peel the source polyphony into ≤3 monophonic lines (lead / bass / harmony) via a greedy high/low "skyline".
    • embellish — chiptune passes (octave leads, synth drums; chord arps planned).
    • dynamics — MIDI velocity → per-note AY volume, normalised so the piece's loudest note hits each channel's ceiling (on by default; --no-dynamics).
    • Channel allocation: A = lead, B = bass, C = real drums if present, else synth drums (chiptune), else harmony (faithful).
  • spectrumizer/ir.py — the source-agnostic note model both inputs target.

PT3 invariants baked in (from the player source)

The player ends a pattern when channel A hits its 0x00 terminator and then resets all three channels — so every channel of a pattern encodes exactly ROWS_PER_PATTERN (64) rows, and row 0 is never an empty rest (the packer drops leading rests). arrange/model.py enforces both.

Listen to it (no Spectrum needed)

spectrumizer ships its own playback path: a small software AY-3-8910 that renders a .pt3 to a stereo .wav (classic ABC panning — A left, B centre, C right) and plays it through your system audio player (afplay on macOS; ffplay / aplay / paplay / sox elsewhere).

spectrumizer-play song.pt3            # render song.wav and play it
spectrumizer-play song.pt3 --no-play  # just write the .wav
spectrumizer-play song.pt3 --seconds 30   # cap length, looping the song's tail
spectrumizer-play song.pt3 --rate 22050   # faster render (lower fidelity)
spectrumizer-play song.pt3 --tuning equal # equal-tempered instead of the PT3 table
spectrumizer-play song.pt3 --stereo mono  # mono (default abc = A-left/B-centre/C-right)
spectrumizer-play song.pt3 --noise-period 5  # force a noise period (default: the module's real one)

The synth (spectrumizer/audio.py) plus the PT3 interpreter (spectrumizer/pt3/player.py, the inverse of the encoder) only implement the subset of PT3 this tool emits — notes, OFF, sample/ornament/volume, NtSkip. Pitch uses the exact PT3 tone table (the table-1 periods from the real Bulba player, so notes land where the chip puts them; pass --tuning equal for the old equal-tempered approximation). Treat it as a faithful audition, not a cycle-exact emulation. For the real thing, drop the .pt3 into the PT3 slot of a 128K Spectrum build running a Bulba/Vortex replayer, rebuild, and run it in an emulator (e.g. ZEsarUX).

Demos

Hear every mode in your browser on the demo page (GitHub Pages, nothing to install) — or click a clip to play it in GitHub's file viewer. All are examples/ode-to-joy.mid rendered through the built-in software AY; regenerate with pip install -e ".[demos]" && python examples/make_demos.py.

Demo What it shows
Faithful 3-voice reduction
Chiptune octave lead + synth drums
No dynamics flat volume — vs the velocity dynamics
Equal-tempered vs the exact PT3 tone table
Mono vs the default ABC stereo

Tests

pip install -e ".[dev]"     # installs pytest
pytest -q

Status

  • Generate: MIDI → PT3, faithful + chiptune, with velocity-driven dynamics.
  • Audition: built-in software-AY playback to a stereo WAV — exact PT3 tone table, real per-frame noise period, ABC panning (spectrumizer-play / --play).
  • Planned: MusicXML (music21) input, chord arpeggios, AY hardware envelopes (buzzer bass), general PT3 playback (envelope/slides), raw-AY/.vtx export.

Origin

spectrumizer grew out of hand-written, per-track PT3 composer scripts for a ZX Spectrum game, generalising them into a single reusable arranger. It is now a standalone, game-agnostic tool.

Credits

  • Sergey Bulba — the PT3 module format and the Vortex Tracker / PT3 replayer this tool targets, including the NoteTableCreator tone-table data the audition synth uses for exact Spectrum pitches.
  • Ivan Roshin — NoteTableCreator, the source of those packed AY tone tables.

These credits acknowledge the format and reference data; spectrumizer's encoder, decoder and synth are independent implementations (see LICENSE).

Licence

MIT © Miguel Ángel Esteve Marco. Note: the MIT licence covers spectrumizer's own code, not the music you run through it — see LICENSING.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spectrumizer-0.1.0.tar.gz (34.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spectrumizer-0.1.0-py3-none-any.whl (33.6 kB view details)

Uploaded Python 3

File details

Details for the file spectrumizer-0.1.0.tar.gz.

File metadata

  • Download URL: spectrumizer-0.1.0.tar.gz
  • Upload date:
  • Size: 34.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for spectrumizer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 5f8846d524b03c659235e4eb10d2f9428e3559a3478f1676c91d7d07ddcb7c31
MD5 3d6c790094e6c42347a0007e8b35f416
BLAKE2b-256 48878d6ebb1574aec8bcba797e14c87fc395272a73b51f928a7c9d18d4c5b2a5

See more details on using hashes here.

Provenance

The following attestation bundles were made for spectrumizer-0.1.0.tar.gz:

Publisher: publish.yml on revengator/spectrumizer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spectrumizer-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: spectrumizer-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 33.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for spectrumizer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2163717c6ad35a6c8ea0f73925183d433cc8839b476acca2407b22ab7df2124c
MD5 474b538b6c5577f7036285f4489a91ef
BLAKE2b-256 88278c0c779e05d96a9bd62d7ed7ec72faf3ede65d80526c96b1bc03c8aa8c13

See more details on using hashes here.

Provenance

The following attestation bundles were made for spectrumizer-0.1.0-py3-none-any.whl:

Publisher: publish.yml on revengator/spectrumizer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page