331 lines
5.1 KiB
Markdown
331 lines
5.1 KiB
Markdown
< [Back](chapter-4.md) | [Summary](table-of-contents.md) | [Next](chapter-6.md) >
|
|
|
|
# 🔊 AUDIO Peripheral (Audio System)
|
|
|
|
## 1. Overview
|
|
|
|
The **AUDIO Peripheral** is responsible for **sound generation and mixing** in PROMETEU.
|
|
|
|
Just like the other subsystems:
|
|
|
|
- it is not automatic
|
|
- it is not free
|
|
- it is not magic
|
|
|
|
Each sound is the result of **explicit commands**, executed under a **time and resource budget**.
|
|
|
|
> Sound consumes time.
|
|
> Sound consumes memory.
|
|
|
|
---
|
|
|
|
## 2. Philosophy
|
|
|
|
PROMETEU treats audio as:
|
|
|
|
- an **active peripheral**
|
|
- with **limited channels**
|
|
- **deterministic** behavior
|
|
- **explicit** control
|
|
|
|
Objective: architectural and didactic clarity, not absolute realism.
|
|
|
|
---
|
|
|
|
## 3. General Architecture
|
|
|
|
The audio system is composed of:
|
|
|
|
- **Voices (channels)** — independent players
|
|
- **Samples** — PCM data
|
|
- **Mixer** — summation of voices
|
|
- **Output** — PCM stereo buffer
|
|
|
|
Conceptual separation:
|
|
|
|
- Game sends **commands at 60Hz**
|
|
- Audio is **generated continuously** at 48kHz
|
|
|
|
---
|
|
|
|
## 4. Output Format
|
|
|
|
- Sample rate: **48,000 Hz**
|
|
- Format: **PCM16 stereo (signed i16)**
|
|
- Clipping: saturation/clamp
|
|
|
|
This format is compatible with:
|
|
|
|
- common I2S DACs
|
|
- HDMI audio
|
|
- USB audio
|
|
- DIY SBCs (Raspberry Pi, Orange Pi, etc.)
|
|
|
|
---
|
|
|
|
## 5. Voices (Channels)
|
|
|
|
### 5.1 Quantity
|
|
|
|
```
|
|
MAX_VOICES = 16
|
|
```
|
|
|
|
Each voice:
|
|
|
|
- plays **1 sample at a time**
|
|
- is independent
|
|
- is mixed into the final output
|
|
|
|
---
|
|
|
|
### 5.2 Voice State
|
|
|
|
Each voice maintains:
|
|
|
|
- `sample_id`
|
|
- `pos` (fractional position in the sample)
|
|
- `rate` (pitch)
|
|
- `volume` (0..255)
|
|
- `pan` (0..255, left→right)
|
|
- `loop_mode` (off / on)
|
|
- `loop_start`, `loop_end`
|
|
- `priority` (optional)
|
|
|
|
---
|
|
|
|
### 5.3 Voice Conflict
|
|
|
|
If all voices are occupied:
|
|
|
|
- an explicit policy is applied:
|
|
- `STEAL_OLDEST`
|
|
- `STEAL_QUIETEST`
|
|
- `STEAL_LOWEST_PRIORITY`
|
|
|
|
|
|
PROMETEU does not resolve this automatically without a defined rule.
|
|
|
|
---
|
|
|
|
## 6. Conceptual Model: “Audio CPU”
|
|
|
|
The PROMETEU AUDIO is conceived as an **independent peripheral**, just as classic consoles had:
|
|
|
|
- Main game CPU
|
|
- Dedicated sound CPU
|
|
|
|
In PROMETEU:
|
|
|
|
- The **logical core** assumes this conceptual separation
|
|
- The **host decides** how to implement it:
|
|
- same thread
|
|
- separate thread
|
|
- separate core
|
|
|
|
### 6.1 Hardware Metaphor
|
|
|
|
Conceptually:
|
|
|
|
```
|
|
[Game CPU] → sends 60Hz commands → [AUDIO Peripheral]
|
|
|
|
|
v
|
|
Voices + Mixer
|
|
|
|
|
v
|
|
PCM Output
|
|
```
|
|
|
|
|
|
### 6.2 Implementation is the Host's Role
|
|
|
|
The core:
|
|
|
|
- defines the **model**
|
|
- defines the **commands**
|
|
- defines the **limits**
|
|
|
|
The host:
|
|
|
|
- chooses:
|
|
- threads
|
|
- CPU affinity
|
|
- audio backend
|
|
- guarantees continuous delivery of buffers
|
|
|
|
Thus:
|
|
|
|
> PROMETEU models the hardware.
|
|
> The host decides how to physically realize it.
|
|
|
|
---
|
|
|
|
## 7. Samples
|
|
|
|
### 7.1 Format
|
|
|
|
PROMETEU samples:
|
|
|
|
- **PCM16 mono**
|
|
- own sample_rate (e.g., 22050, 44100, 48000)
|
|
- immutable data at runtime
|
|
|
|
Fields:
|
|
|
|
- `sample_rate`
|
|
- `frames_len`
|
|
- `loop_start`, `loop_end` (optional)
|
|
|
|
---
|
|
|
|
### 7.2 Usage
|
|
|
|
Example:
|
|
|
|
```
|
|
audio.play(sample_id, voice_id, volume, pan, pitch, priority)
|
|
```
|
|
|
|
Or:
|
|
|
|
```
|
|
audio.playAuto(sample_id, volume, pan, pitch, priority)
|
|
```
|
|
|
|
(uses stealing policy)
|
|
|
|
---
|
|
|
|
## 8. Pitch and Interpolation
|
|
|
|
- `rate = 1.0` → normal speed
|
|
- `rate > 1.0` → higher pitch
|
|
- `rate < 1.0` → lower pitch
|
|
|
|
As position becomes fractional:
|
|
|
|
- **linear interpolation** is used between two neighboring samples
|
|
|
|
---
|
|
|
|
## 9. Mixer
|
|
|
|
For each output frame (48kHz):
|
|
|
|
1. For each active voice:
|
|
- read sample at current position
|
|
- apply pitch
|
|
- apply volume
|
|
- apply pan → generates L/R
|
|
2. Sum all voices
|
|
3. Apply clamp
|
|
4. Write to the stereo buffer
|
|
|
|
Cost depends on:
|
|
|
|
- number of active voices
|
|
- use of interpolation
|
|
|
|
---
|
|
|
|
## 10. Synchronization with the Game
|
|
|
|
- Game runs at **60Hz**
|
|
- Audio generates data at **48kHz**
|
|
|
|
Every frame (60Hz):
|
|
|
|
- game sends commands:
|
|
- play
|
|
- stop
|
|
- set_volume
|
|
- set_pan
|
|
- set_pitch
|
|
|
|
The audio applies these commands and continues playing.
|
|
|
|
---
|
|
|
|
## 11. Basic Commands
|
|
|
|
Conceptual examples:
|
|
|
|
```
|
|
audio.play(sample, voice, volume, pan, pitch, priority)
|
|
audio.stop(voice)
|
|
audio.setVolume(voice, v)
|
|
audio.setPan(voice, p)
|
|
audio.setPitch(voice, p)
|
|
audio.isPlaying(voice)
|
|
```
|
|
|
|
|
|
---
|
|
|
|
## 12. Audio and CAP
|
|
|
|
Audio participates in the Execution CAP:
|
|
|
|
- mixing cost per frame
|
|
- cost per active voice
|
|
- command cost
|
|
|
|
Example:
|
|
|
|
```
|
|
Frame 1024:
|
|
voices_active: 9
|
|
mix_cycles: 410
|
|
audio_commands: 6
|
|
```
|
|
|
|
|
|
---
|
|
|
|
## 13. Best Practices
|
|
|
|
Recommended:
|
|
|
|
- reuse samples
|
|
- limit simultaneous voices
|
|
- treat sound as an event
|
|
- separate music and effects
|
|
|
|
Avoid:
|
|
|
|
- playing sound every frame
|
|
- abusing voices
|
|
- giant samples for simple effects
|
|
|
|
---
|
|
|
|
## 14. Historical Inspiration
|
|
|
|
The PROMETEU model is inspired by:
|
|
|
|
- NES: fixed channels
|
|
- SNES: sample playback + mixing
|
|
- CPS2: comfortable polyphony
|
|
- Neo Geo: heavy samples (not fully copied)
|
|
|
|
But abstracted for:
|
|
|
|
- clarity
|
|
- simplicity
|
|
- teaching
|
|
|
|
---
|
|
|
|
## 15. Summary
|
|
|
|
- Output: stereo PCM16 @ 48kHz
|
|
- 16 voices
|
|
- mono PCM16 samples
|
|
- Volume, pan, pitch
|
|
- Linear interpolation
|
|
- Explicit mixer
|
|
- "Audio CPU" concept
|
|
- Implementation is the host's role
|
|
|
|
< [Back](chapter-4.md) | [Summary](table-of-contents.md) | [Next](chapter-6.md) > |