ay8910_wrapper API Reference¶
This document provides a detailed reference for the functions, classes, and constants available in the ay8910_wrapper Python module, automatically generated from the source code.
Main Interface¶
The ay8910_wrapper package provides a high-level interface to the PSG emulators. The following attributes include constants used to configure the emulation during the instantiation of the ay8910, ay8912, and ay8913 classes.
This package provides a Python wrapper for the standalone AY-3-8910 emulators (MAME, Caprice32, and AY_Emul31 versions).
It includes classes to emulate the PSG chip and high-level methods for live audio playback.
PSG Registers Reference (0-15)¶
Tone Period (Registers 0-5)¶
These registers control the pitch of the three square wave channels. Each channel uses two registers (Fine and Coarse) to form a 12-bit period value. Formula: \(f = ext{Clock} / (16 imes ext{Period})\)
| Register | Function | Bits |
|---|---|---|
| 0 | Channel A Fine Tune | 8-bit |
| 1 | Channel A Coarse Tune | 4-bit |
| 2 | Channel B Fine Tune | 8-bit |
| 3 | Channel B Coarse Tune | 4-bit |
| 4 | Channel C Fine Tune | 8-bit |
| 5 | Channel C Coarse Tune | 4-bit |
Noise Period (Register 6)¶
Controls the frequency of the pseudo-random noise generator used for percussion or sound effects.
| Register | Function | Bits |
|---|---|---|
| 6 | Noise Period | 5-bit |
Mixer Control (Register 7)¶
Enables or disables Tone and Noise for each of the three channels. It also controls the I/O port directions. Bits are active-low (0 = Enabled, 1 = Disabled).
| Bit | Function |
|---|---|
| 0 | Tone A (0: On, 1: Off) |
| 1 | Tone B (0: On, 1: Off) |
| 2 | Tone C (0: On, 1: Off) |
| 3 | Noise A (0: On, 1: Off) |
| 4 | Noise B (0: On, 1: Off) |
| 5 | Noise C (0: On, 1: Off) |
| 6 | Port A Direction (0: Input, 1: Output) |
| 7 | Port B Direction (0: Input, 1: Output) |
Amplitude/Volume (Registers 8-10)¶
Controls the volume of each channel. A value of 0-15 sets a fixed volume. If bit 4 is set (value 16), the channel follows the hardware envelope.
| Register | Function | Range |
|---|---|---|
| 8 | Channel A Amplitude | 0-15 (Fixed) or 16 (Envelope) |
| 9 | Channel B Amplitude | 0-15 (Fixed) or 16 (Envelope) |
| 10 | Channel C Amplitude | 0-15 (Fixed) or 16 (Envelope) |
Envelope Period (Registers 11-12)¶
Sets the duration of one envelope cycle (16-bit value). Formula: \(T = (256 imes ext{Period}) / ext{Clock}\)
| Register | Function | Bits |
|---|---|---|
| 11 | Envelope Fine Tune | 8-bit |
| 12 | Envelope Coarse Tune | 8-bit |
Envelope Shape (Register 13)¶
Controls the shape of the volume variation over time. The 4 bits (B3-B0) of this register define the envelope cycle.
| Bit | Name | Function |
|---|---|---|
| 3 | CONT | Continue: If 0, the cycle ends after one attack/decay (Hold is ignored). |
| 2 | ATT | Attack: If 1, volume increases (0 to 15). If 0, volume decreases (15 to 0). |
| 1 | ALT | Alternate: If 1, the direction of the next cycle is reversed (Triangle shape). |
| 0 | HOLD | Hold: If 1, the volume stays at the last level (0 or 15) after one cycle. |
Shape Combinations¶
| B3-B0 | Hex | Graphical Representation | Description |
|---|---|---|---|
| 00xx | 0-3 | \___ |
Single Decay, then Silence |
| 01xx | 4-7 | /___ |
Single Attack, then Silence |
| 1000 | 8 | \\\\ |
Repeating Decay (Sawtooth) |
| 1001 | 9 | \___ |
Single Decay, then Silence |
| 1010 | A | \/\/ |
Repeating Decay-Attack (Triangle) |
| 1011 | B | \¯¯¯ |
Single Decay, then Hold High |
| 1100 | C | //// |
Repeating Attack (Inverse Sawtooth) |
| 1101 | D | /¯¯¯ |
Single Attack, then Hold High |
| 1110 | E | /\/\ |
Repeating Attack-Decay (Inverse Triangle) |
| 1111 | F | /___ |
Single Attack, then Silence |
Note: In the graphical representations, \ indicates Decay, / indicates Attack,
_ indicates Hold Low (Silence), and ¯ indicates Hold High (Full Volume).
I/O Ports (Registers 14-15)¶
Data registers for the two 8-bit parallel ports.
| Register | Function |
|---|---|
| 14 | Port A Data |
| 15 | Port B Data |
Examples¶
1. Basic Tone (Live Playback)¶
The simplest way to hear a sound.
import ay8910_wrapper as ay
import time
# Create an AY-3-8912 (1 I/O port) as used in Amstrad CPC
psg = ay.ay8912(backend=ay.Backend.CAPRICE32, clock=1000000)
# Start live audio
psg.play()
# Set a 440Hz tone on Channel A
# Period = 1000000 / (16 * 440) ≈ 142
psg.set_register(0, 142 & 0xFF)
psg.set_register(1, (142 >> 8) & 0x0F)
psg.set_register(7, 0xFE) # Enable Tone A
psg.set_register(8, 15) # Max volume
time.sleep(1)
psg.stop()
2. Generating Audio Data (WAV Export)¶
Generate samples manually and save them to a file.
import ay8910_wrapper as ay
import wave, struct
psg = ay.ay8910(backend=ay.Backend.MAME, clock=2000000)
# Configure a noise effect (e.g., snare drum)
psg.set_register(6, 15) # Noise period
psg.set_register(7, 0xF7) # Enable Noise on Channel A
psg.set_register(8, 16) # Use envelope
psg.set_register(11, 0) # Envelope period fine
psg.set_register(12, 10) # Envelope period coarse
psg.set_register(13, 0x00) # Decay shape (\___)
# Generate 0.5s of audio at 44100Hz
samples = psg.generate(22050)
with wave.open("noise_effect.wav", "wb") as f:
f.setnchannels(1)
f.setsampwidth(2)
f.setframerate(44100)
f.writeframes(struct.pack('<' + ('h' * len(samples)), *samples))
3. Advanced Configuration (MAME & Resistors)¶
Simulate specific hardware analog characteristics.
import ay8910_wrapper as ay
# Use MAME backend for advanced hardware flags
psg = ay.ay8910(backend=ay.Backend.MAME, clock=1750000)
# Enable resistor-based output modeling (high accuracy)
psg.set_flags(ay.AY8910_RESISTOR_OUTPUT | ay.AY8910_SINGLE_OUTPUT)
# Set specific load resistors for ZX Spectrum (~1k Ohm)
psg.set_resistors_load(1000.0, 1000.0, 1000.0)
psg.play()
# ... program registers ...
4. Using DirectOutput for manual playback control¶
For more fine-grained control over the audio stream, use the DirectOutput class directly.
import ay8910_wrapper as ay
from ay8910_wrapper import DirectOutput
# Create any PSG instance
psg = ay.ay8910(backend=ay.Backend.MAME)
# Initialize and start the audio output manually
audio = DirectOutput(psg)
audio.start()
# ... sound generation ...
# Stop playback when done
audio.stop()
Attributes¶
AY8910_LEGACY_OUTPUT = 1
module-attribute
¶
MAME Backend: Enable legacy volume table. The output samples will be in the range [0, 255] per channel.
AY8910_SINGLE_OUTPUT = 2
module-attribute
¶
MAME Backend: Mix all three channels (A, B, and C) into a single mono output stream.
AY8910_DISCRETE_OUTPUT = 4
module-attribute
¶
MAME Backend: Use discrete voltage levels for output (experimental). The output values reflect raw internal DAC levels (0 to 524287).
AY8910_RESISTOR_OUTPUT = 8
module-attribute
¶
MAME Backend: Enable advanced resistor-based output modeling.
Requires calling set_resistors_load to define external load resistances.
This provides the most accurate simulation of the analog output stage.
PSG_PIN26_IS_CLKSEL = 16
module-attribute
¶
MAME Backend (YM2149 only): Pin 26 is used as a clock selector. When high, the master clock is divided by 2 internally.
PSG_HAS_INTERNAL_DIVIDER = 32
module-attribute
¶
MAME Backend: Forces the use of an internal clock divider (usually /2). Equivalent to tying the CLKSEL pin on a YM2149.
PSG_EXTENDED_ENVELOPE = 64
module-attribute
¶
MAME Backend: Enable extended 10-bit envelope resolution (specific to some YM variants).
PSG_HAS_EXPANDED_MODE = 128
module-attribute
¶
MAME Backend: Enable expanded register mode (extra ports/features on specialized chips).
Classes¶
AYBase
¶
Base class for AY-3-891x wrappers to provide a common interface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend
|
Backend
|
The emulation engine to use ( |
CAPRICE32
|
clock
|
int
|
Master clock frequency in Hz. Default: 1000000. Typical values:
|
1000000
|
sample_rate
|
int
|
Audio sampling rate in Hz (default: 44100). |
44100
|
ioports
|
int
|
Number of I/O ports (default: 2). |
2
|
Functions¶
address_w(value)
¶
Writes a value to the address latch.
This method mimics the behavior of the real hardware bus (pins BC1/BDIR). It
selects which register will be targeted by the next data_w call.
Note: For pure software control, prefer set_register, which is more
direct and avoids the two-step address/data latching process.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
int
|
The address to select (0-15). |
required |
data_w(value)
¶
Writes data to the selected register.
This method mimics the hardware data bus write operation. It writes a value
to the register previously selected with address_w.
Note: Using set_register is recommended instead, as it handles both
selection and writing in a single atomic software call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
int
|
The value to write to the currently selected register. |
required |
generate(num_samples)
¶
Generates a block of audio samples.
This method triggers the emulation for a specific number of audio frames and returns the resulting samples as a list of 16-bit integers.
Output format:
- Caprice32 (Stereo): Returns
num_samples * 2values. The samples are interleaved (Left, Right, Left, Right, ...). - MAME / AY_Emul31 (Mono): Returns
num_samplesvalues.
What to do with the generated list?:
The returned list contains raw 16-bit PCM (Pulse Code Modulation) samples. You can:
- Save to a WAV file: Using the standard
wavemodule. - Process with NumPy: For fast calculations, filtering, or visualization.
- Play back: Using libraries like
sounddevice,pyaudio, orpygame.mixer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_samples
|
int
|
The number of audio frames (samples) to generate. |
required |
Returns:
| Type | Description |
|---|---|
List[int]
|
List[int]: A list of generated 16-bit PCM samples. The length of the list depends on whether the backend is mono or stereo. |
Example
# 1. Set up a simple tone on Channel A (440Hz at 2MHz clock)
# Period = Clock / (16 * Frequency) = 2000000 / (16 * 440) = 284
psg.set_register(0, 284 & 0xFF) # Fine tune
psg.set_register(1, (284 >> 8) & 0x0F) # Coarse tune
psg.set_register(7, 0xFE) # Enable Tone A (Mixer bit 0 = 0)
psg.set_register(8, 15) # Maximum volume on Channel A
# 2. Generate 1024 frames of this sound
samples = psg.generate(1024)
# 3. Save to a WAV file
import wave, struct
with wave.open("melody.wav", "wb") as f:
f.setnchannels(2 if psg._backend == Backend.CAPRICE32 else 1)
f.setsampwidth(2) # 16-bit
f.setframerate(44100)
f.writeframes(struct.pack('<' + ('h' * len(samples)), *samples))
get_register(reg)
¶
get_registers()
¶
play(sample_rate=None, clock=None)
¶
Starts live playback.
Note
Requires numpy and sounddevice libraries.
Install them with: pip install ay8910_wrapper[tools]
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sample_rate
|
Optional[int]
|
Audio sampling rate in Hz (default: same as class init). |
None
|
clock
|
Optional[int]
|
Master clock frequency in Hz (default: same as class init). |
None
|
reset()
¶
Resets the emulator to its initial state.
This method mimics the hardware RESET pin. It clears all internal registers (setting them to 0), stops any ongoing sound, and resets the envelope and noise generators. Use it to ensure a clean state before starting a new song or sound effect.
set_flags(flags)
¶
Set internal flags (MAME backend only).
These flags control how the MAME emulation engine handles audio output and specific hardware features of the chip.
Commonly used flags:
AY8910_LEGACY_OUTPUT(0x01): Legacy output (0 to 32767). Default behavior if no flags are set.AY8910_SINGLE_OUTPUT(0x02): Mixes all three channels into a single mono output stream.AY8910_DISCRETE_OUTPUT(0x04): Raw output level (0 to 524287), where 0 is 0V and 524287 is 5V.AY8910_RESISTOR_OUTPUT(0x08): Uses resistor values to calculate output. Requiresset_resistors_load.YM2149_PIN26_LOW(0x10): Forces pin 26 low for YM2149 (activates internal divider).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
flags
|
int
|
Bitwise OR of flags to set. |
required |
set_register(reg, value)
¶
Writes a value to an internal register (0-15).
This is the recommended way to program the PSG in software. Unlike the
hardware-level address_w and data_w methods, this combined call
is more efficient and atomic in the context of the emulator wrapper.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reg
|
int
|
The register index to write. |
required |
value
|
int
|
The value to write (0-255). |
required |
set_resistors_load(res_load0, res_load1, res_load2)
¶
Set the resistors load for each channel (MAME backend only).
This method is used when the AY8910_RESISTOR_OUTPUT flag is set in set_flags.
It defines the external load resistance (in Ohms) connected to each of the three
analog output pins (A, B, and C).
The PSG's internal output stage can be simplified as a voltage source followed by an internal resistance (\(R_{int}\)) and the chip's MOSFETs, which are then connected to an external pull-up or pull-down resistor (\(R_{load}\)).
Typical values for different systems:
- Amstrad CPC: ~1000.0 Ω (standard pull-up)
- ZX Spectrum: ~1000.0 Ω to 2000.0 Ω
- Arcade Boards: Varies, often 1000.0 Ω or 680.0 Ω
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
res_load0
|
float
|
Resistor load for channel A (Ohms). |
required |
res_load1
|
float
|
Resistor load for channel B (Ohms). |
required |
res_load2
|
float
|
Resistor load for channel C (Ohms). |
required |
set_stereo_mix(al, ar, bl, br, cl, cr)
¶
Set stereo mixing volumes (Caprice32 backend only).
This method defines the volume weights for each of the three PSG channels (A, B, C) on the Left and Right stereo outputs.
The values for each argument range from 0 (silent) to 255 (maximum volume).
Typical configurations for different systems:
- Amstrad CPC (Default): (255, 13, 170, 170, 13, 255) - Standard CPC stereo distribution.
- Full Mono: (255, 255, 255, 255, 255, 255) - All channels mixed equally on both outputs.
- ABC Stereo: (255, 0, 128, 128, 0, 255) - Channel A Left, B Center, C Right.
- ACB Stereo: (255, 0, 0, 255, 128, 128) - Channel A Left, C Right, B Center.
- Sharp X1: Often uses a balanced mix for stereo effects.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
al
|
int
|
Volume for channel A on Left output (0-255). |
required |
ar
|
int
|
Volume for channel A on Right output (0-255). |
required |
bl
|
int
|
Volume for channel B on Left output (0-255). |
required |
br
|
int
|
Volume for channel B on Right output (0-255). |
required |
cl
|
int
|
Volume for channel C on Left output (0-255). |
required |
cr
|
int
|
Volume for channel C on Right output (0-255). |
required |
stop()
¶
ay8910
¶
Bases: AYBase
AY-3-8910: 3 channels, 2 I/O ports (Port A and Port B).
This class provides a full implementation of the AY-3-8910 chip with two
8-bit parallel I/O ports. Inherits from AYBase.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend
|
Backend
|
The emulation engine to use ( |
CAPRICE32
|
clock
|
int
|
Master clock frequency in Hz (default: 1000000). (e.g., 1000000 for Amstrad CPC, 2000000 for Atari ST). |
1000000
|
sample_rate
|
int
|
Audio sampling rate in Hz (default: 44100). |
44100
|
ay8912
¶
Bases: AYBase
AY-3-8912: 3 channels, 1 I/O port (Port A).
This class emulates the AY-3-8912 variant, which is pin-compatible with the
AY-3-8910 but features only one 8-bit parallel I/O port to reduce pin count.
Inherits from AYBase.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend
|
Backend
|
The emulation engine to use ( |
CAPRICE32
|
clock
|
int
|
Master clock frequency in Hz (default: 1000000). (e.g., 1000000 for Amstrad CPC, 1750000 for ZX Spectrum). |
1000000
|
sample_rate
|
int
|
Audio sampling rate in Hz (default: 44100). |
44100
|
ay8913
¶
Bases: AYBase
AY-3-8913: 3 channels, 0 I/O ports.
This class emulates the AY-3-8913 variant, which has no I/O ports.
It was designed for applications where only sound generation is needed.
Inherits from AYBase.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend
|
Backend
|
The emulation engine to use ( |
CAPRICE32
|
clock
|
int
|
Master clock frequency in Hz (default: 1000000). |
1000000
|
sample_rate
|
int
|
Audio sampling rate in Hz (default: 44100). |
44100
|
Backend
¶
Bases: Enum
Enumeration of available emulation backends.
Attributes:
| Name | Type | Description |
|---|---|---|
CAPRICE32 |
Backend derived from the Caprice32 emulator.
Supports stereo mixing via |
|
MAME |
Backend derived from MAME (Multiple Adult Mame Emulator).
Supports advanced features like resistor modeling ( |
|
AY_EMUL31 |
Backend based on the Ay_Emul 3.1 engine.
Supports specific chip type selection via the |
psg_type
¶
Enum for selecting the chip model to emulate.
Attributes:
| Name | Type | Description |
|---|---|---|
PSG_TYPE_AY |
Emulates the General Instrument AY-3-8910. |
|
PSG_TYPE_YM |
Emulates the Yamaha YM2149, with a different volume curve. |
ay_emul31_chip_type
¶
Enum for selecting the chip model to emulate in the Ay_Emul31 engine.
Attributes:
| Name | Type | Description |
|---|---|---|
AY_Chip |
Emulates the AY-3-8910 chip. |
|
YM_Chip |
Emulates the Yamaha YM2149 chip. |
Audio Output¶
The direct_output module handles real-time audio playback using sounddevice.
direct_output
¶
Handles real-time audio output using sounddevice.
DirectOutput
¶
Manages an audio stream to play sound from an emulator in real-time.
Note
Requires numpy and sounddevice libraries.
Install them with: pip install ay8910_wrapper[tools]
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
device
|
Any
|
The emulator instance generating audio. |
required |
sample_rate
|
int
|
Target sample rate for audio output (default: 44100). |
44100
|
channels
|
int
|
1 for mono, 2 for stereo (default: 1). |
1
|
clock
|
int
|
Master clock frequency (default: 1750000). |
1750000
|
Attributes:
| Name | Type | Description |
|---|---|---|
device |
Any
|
The PSG emulator instance. |
sample_rate |
int
|
Output sample rate in Hz. |
channels |
int
|
Number of audio channels. |
stream |
Optional[OutputStream]
|
The active |
Source code in src/ay8910_wrapper/direct_output.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | |
start()
¶
Starts the audio output stream.
Source code in src/ay8910_wrapper/direct_output.py
stop()
¶
Stops the audio output stream.