API Reference

AY8912

AY-3-8910 / AY-8912 emulator for CircuitPython with synthio.

Translates AY-3-8910 register writes into synthio.Note property updates. Three synthesizers (one per channel) feed an audiomixer.Mixer for per-channel volume and stereo panning.

  • Author(s): Liz Clark

Implementation Notes

Software and Dependencies:

class adafruit_ay8912.ay8912_emulator.AY8912(sample_rate: int = 22050, clock_rate: int = 1773400, waveform_size: int = 256, noise_size: int = 256, volume: int = 32000)

AY-3-8910 / AY-8912 emulator backed by synthio.

Parameters:
  • sample_rate (int) – Output sample rate in Hz.

  • clock_rate (int) – AY chip clock frequency in Hz. Defaults to the ZX Spectrum 128K clock (1773400 Hz).

  • waveform_size (int) – Number of samples in the square waveform.

  • noise_size (int) – Number of samples in the noise waveform.

  • volume (int) – Peak sample amplitude used when building the waveforms.

begin(audio_out) None

Begin audio signal chain.

Handles audio_out.play(mixer) first, then connects the synth voices:

ay = AY8912(sample_rate=22050)
ay.begin(audio)
Parameters:

audio_out – The audio output object

enable_noise(channel: int, enable: bool = True) None

Enable or disable noise output for a channel via the mixer (R7).

Parameters:
  • channel (int) – Channel index (0-2).

  • enable (bool) – True to enable noise, False to disable.

enable_tone(channel: int, enable: bool = True) None

Enable or disable tone output for a channel via the mixer (R7).

Parameters:
  • channel (int) – Channel index (0-2).

  • enable (bool) – True to enable tone, False to disable.

property mixer: audiomixer.Mixer

The audiomixer.Mixer. Connect to audio output with audio.play(ay.mixer) (or just call begin()).

property notes: Tuple[synthio.Note, ...]

Direct access to the three synthio.Note objects (read-only tuple).

read_register(reg: int) int

Read an AY register.

Parameters:

reg (int) – Register index (0-15).

Returns:

The stored register value, or 0 if reg is out of range.

reset() None

Reset all registers and state to power-on defaults.

set_envelope(period: int, shape: int) None

Set the envelope period (R11/R12) and shape (R13).

Writing R13 resets the envelope generator.

Parameters:
  • period (int) – 16-bit envelope period.

  • shape (int) – Envelope shape (0-15).

set_noise_period(period: int) None

The 5-bit noise period (R6).

Parameters:

period (int) – Noise period (only the low 5 bits are used).

set_pan(channel: int, pan: float) None

Stereo panning for a channel.

Parameters:
  • channel (int) – Channel index (0-2).

  • pan (float) – Pan position: -1.0 = hard left, 0.0 = center, 1.0 = hard right. Values are clamped to that range.

set_tone_period(channel: int, period: int) None

The 12-bit tone period directly (R0/R1, R2/R3, R4/R5).

Parameters:
  • channel (int) – Channel index (0-2).

  • period (int) – Tone period, clamped to 1-4095.

set_volume(channel: int, volume: int, envelope: bool = False) None

Set a channel’s volume (R8/R9/R10).

Parameters:
  • channel (int) – Channel index (0-2).

  • volume (int) – Fixed volume level (0-15).

  • envelope (bool) – If True, the hardware envelope controls the channel volume instead of the fixed level.

tick() None

Advance the envelope generator.

Call this at ~50 Hz from your main loop or a timer interrupt.

write_register(reg: int, value: int) None

Write an AY register (0-13). R14/R15 (I/O ports) are stored but otherwise ignored.

Parameters:
  • reg (int) – Register index (0-15). Out-of-range writes are ignored.

  • value (int) – Byte value to write (masked to 0-255).

VGMFile

VGM chiptune file parser and player for CircuitPython.

Plays VGM (and gzip-compressed VGZ) files through an AY8912 instance.

Only files with a non-zero AY-3-8910 clock (header offset 0x74) are supported. Files targeting other chips (SN76489, YM2612, etc.) are rejected.

  • Author(s): Liz Clark

Implementation Notes

Software and Dependencies:

class adafruit_ay8912.vgm_player.VGMFile(filename: str | None = None)

Parse and play an AY8912 VGM/VGZ file.

Parameters:

filename (str) – Path to a .vgm or .vgz file to load immediately. Pass None to create an empty object and call load() later.

property author: str

Track author from the GD3 tag, or "" if absent.

property clock_hz: int

AY chip clock in Hz.

property duration: float

Song duration in seconds.

property elapsed: float

Elapsed playback time in seconds.

property game: str

Game/source name from the GD3 tag, or "" if absent.

load(filename: str) None

Load a .vgm or .vgz file, decompressing gzip natively.

Parameters:

filename (str) – Path to the file to load.

Raises:

RuntimeError – If the file is not a VGM, cannot be decompressed, or does not target the AY-3-8910.

property loop_count: int

How many times the song has looped back.

property loops: bool

True if this song defines a loop point.

play(ay: AY8912) None

Start playback through the AY8912 instance.

Parameters:

ay (AY8912) – The emulator that register writes will be sent to. It is reset before playback.

property playing: bool

True while playback is active.

property progress: float

Playback progress as a fraction from 0.0 to 1.0.

stop() None

Stop playback and reset the attached AY8912

property title: str

Track title from the GD3 tag, or "" if absent.

property total_samples: int

Total length of the song in 44100 Hz samples.

update() None

Process the command stream with correct timing.

Call repeatedly in the playback loop. It tracks real time internally and only advances the command stream when the accumulated wait has elapsed.

property version: int

VGM format version as a packed BCD integer