Metadata-Version: 2.2
Name: ay8910_wrapper
Version: 1.0.0
Summary: A Python wrapper for the AY-3-8910, AY-3-8912 and AY-3-8913 sound chip emulators, featuring real-time audio playback and cycle-accurate synthesis.
Author-Email: devfred78 <97401939+devfred78@users.noreply.github.com>
License: MIT
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Topic :: Multimedia :: Sound/Audio
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: C++
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Project-URL: Homepage, https://github.com/devfred78/ay8910
Project-URL: Documentation, https://devfred78.github.io/ay8910
Requires-Python: <3.15,>=3.9
Provides-Extra: tools
Requires-Dist: lhafile; extra == "tools"
Requires-Dist: numpy>=2.0.2; extra == "tools"
Requires-Dist: sounddevice>=0.5.5; extra == "tools"
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: numpy; extra == "test"
Requires-Dist: sounddevice; extra == "test"
Provides-Extra: dev
Requires-Dist: ruff; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocs; extra == "docs"
Requires-Dist: mkdocs-material; extra == "docs"
Requires-Dist: mkdocstrings[python]; extra == "docs"
Description-Content-Type: text/markdown

# AY-3-8910 Standalone Library and Python Wrapper

A Python wrapper for the AY-3-8910, AY-3-8912 and AY-3-8913 sound chip emulators, featuring real-time audio playback and cycle-accurate synthesis.

> **A Note on this Project's Origin**
>
> This project is primarily the result of a series of experiments using various IA Code Assists for code generation and error handling. Rather than using it on academic examples, it seemed more interesting to apply it to a project that could meet a real practical need.
>
> This, therefore, is the reason for `AY8910`'s existence: you can dissect the code to see how Gemini and Junie (with my guidance) went about building it, or you can ignore all that and just use this library for your own needs!

This project contains a standalone C++ library for the AY-3-8910 sound chip. It now features a unified API with three main classes:

- **`ay8910`**: Emulates the 3-channel PSG with 2 I/O ports.
- **`ay8912`**: Emulates the 3-channel PSG with 1 I/O port.
- **`ay8913`**: Emulates the 3-channel PSG with 0 I/O port.

At instantiation, you can choose between three emulation backends:

- **`CAPRICE32` (default)**: The **recommended** engine. High accuracy, stereo mixing, and integrated live audio.
- **`MAME`**: Based on the MAME implementation.
- **`AY_EMUL31`**: A port of Sergey Bulba's Ay_Emul 3.1.

## Quick Start (Live Audio)

```python
import ay8910_wrapper as ay
import time

# Initialize an AY-3-8912 using the Caprice32 backend (default)
psg = ay.ay8912(clock=1000000, sample_rate=44100)
psg.set_stereo_mix(255, 13, 170, 170, 13, 255)

# Start live playback!
psg.play()

# Set registers - sound changes immediately
psg.set_register(0, 254) # Tone A Fine
psg.set_register(1, 0)   # Tone A Coarse
psg.set_register(7, 0x3E) # Enable Tone A, disable others
psg.set_register(8, 15)   # Max volume

time.sleep(1)
psg.stop()
```

```sh
# Play a .ym file using the live player
ym_live_player PATH\TO\YM_FILE.YM

# Explicitly choose a backend
ym_live_player PATH\TO\YM_FILE.YM --backend MAME
ym_live_player PATH\TO\YM_FILE.YM --backend AY_EMUL31
```

## Installation

You can install the library directly from [PyPI](https://pypi.org/project/ay8910-wrapper/):

```sh
# Base installation (emulator only)
pip install ay8910_wrapper

# Full installation with playback tools and LHA support
pip install ay8910_wrapper[tools]
```

The base installation has no external dependencies. The `[tools]` option adds `lhafile`, `numpy`, and `sounddevice` which are required for the command-line players and real-time audio output.

For developers who want to compile from source or contribute, please refer to the [Contributing Guide](https://devfred78.github.io/ay8910/contribute/).

## Usage Examples

### 1. Basic Tone (Live Playback)
The simplest way to hear a sound in real-time.

```python
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.

```python
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.

```python
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.

```python
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()
```

For a complete list of all available functions, classes, and constants, please see the [API Reference](https://devfred78.github.io/ay8910/reference/).

## Scripts and Tools

The project includes several scripts for playing chiptunes and running tests. For a detailed description of how to use them, please see the **[Scripts and Tools](https://devfred78.github.io/ay8910/scripts/)** page.

## Unified Architecture

The new architecture allows you to choose the exact chip model and the emulation engine that best fits your needs.

```python
# Initialize an AY-3-8910 (2 I/O ports) using the Caprice32 backend
psg_8910 = ay.ay8910(backend=ay.Backend.CAPRICE32)

# Initialize an AY-3-8912 (1 I/O port) using the MAME backend
psg_8912 = ay.ay8912(backend=ay.Backend.MAME)

# Initialize an AY-3-8913 (0 I/O ports) using the Ay_Emul31 backend
psg_8913 = ay.ay8913(backend=ay.Backend.AY_EMUL31)
```

## Contributing Guide

If you wish to contribute to the project or compile it from source, please refer to our **[Contributing Guide](https://devfred78.github.io/ay8910/contribute/)**.

It contains all the necessary information about:

- The development workflow (**GitHub Flow**)
- Using **uv** for environment management
- Compilation and test commands
- Continuous integration processes (GitHub Actions)

## Acknowledgments

This project relies on the incredible work of the following open-source projects:

- **[MAME](https://github.com/mamedev/mame)**: The original AY-3-8910 and YM2149 emulation cores were derived from the MAME project. Their commitment to accuracy and historical preservation is a cornerstone of this library.
- **[Caprice32](https://github.com/ColinPitrat/caprice32)**: The Amstrad CPC-specific PSG emulation logic and amplitude tables were integrated from the Caprice32 project, providing authentic sound for CPC-related audio tasks.
- **[Ay_Emul](https://ay.strangled.net/main_e.htm)**: The `ay_emul31` engine is based on the work of **Sergey Bulba**. It's a port of his original Pascal source code (version 3.1) to C++.
- **[Sergey Bulba](https://ay.strangled.net/elect_e.htm)**: Special thanks for the AY/YM amplitude tables used in the Caprice32 and Ay_Emul31 engines, which are essential for reproducing the characteristic sound of these chips.
- **[Gemini & Junie](https://github.com/google-gemini)**: This project was built with the assistance of AI, demonstrating the potential of human-AI collaboration in software development.

## License
This project is licensed under the MIT License - see the [License](https://devfred78.github.io/ay8910/license/) for details.
The original MAME and Caprice32 cores have their own licensing terms (see [LICENSE_MAME.md](https://github.com/devfred78/ay8910/blob/main/ay8910_cpp_lib/LICENSE_MAME.md)).
