Add OPL4 playback and analyzer support

This commit is contained in:
2026-09-15 14:59:29 +03:00
commit 1686838e03
553 changed files with 50524 additions and 0 deletions
+135
View File
@@ -0,0 +1,135 @@
/**
* @file opl3.h
* @brief OPL3 (YMF262) — константы регистров и функции записи
* @version 2.0
*
* Самодостаточная библиотека: зависит только от types.h.
* Реализация — asm/opl3.s (чистый inline OUT).
*
* ═══════════════════════════════════════════════════════════════════
* ПОРТЫ TSConfig ДЛЯ OPL3
* ═══════════════════════════════════════════════════════════════════
*
* Порт │ Описание
* ──────┼────────────────────────────
* #C4 │ Bank 0 Address (reg number)
* #C5 │ Bank 0 Data (reg value)
* #C6 │ Bank 1 Address
* #C7 │ Bank 1 Data
*
* Задержка между записью адреса и данных НЕ нужна при 14 МГц
* с wait-states: одна инструкция OUT (C),A занимает достаточно
* тактов чтобы YMF262 обработал адрес до прихода данных.
*
* ═══════════════════════════════════════════════════════════════════
* КАРТА РЕГИСТРОВ OPL3 (Bank 0, то же для Bank 1)
* ═══════════════════════════════════════════════════════════════════
*
* Рег. │ Описание
* ───────────┼────────────────────────────────────────
* 0x01 │ Wavesel enable (бит 5 = 1)
* 0x04 │ Connection select (4-op mode, Bank 0)
* 0x05 (B1) │ OPL3 mode enable (бит 0 = 1)
* 0x08 │ Note select / CSW (только Bank 0)
* 0x20–0x35 │ Operator: AM/VIB/EG type/KSR/MULT
* 0x40–0x55 │ Operator: KSL/Total Level (громкость)
* 0x60–0x75 │ Operator: Attack Rate/Decay Rate
* 0x80–0x95 │ Operator: Sustain Level/Release Rate
* 0xA0–0xA8 │ Channel: F-Number low 8 bits
* 0xB0–0xB8 │ Channel: Key-On + Octave + F-Number hi
* 0xBD │ Percussion mode / AM depth / VIB depth
* 0xC0–0xC8 │ Channel: Feedback + Algorithm + Output
* 0xE0–0xF5 │ Operator: Waveform select
*
* ═══════════════════════════════════════════════════════════════════
* ПРИМЕР
* ═══════════════════════════════════════════════════════════════════
*
* #include "opl3.h"
*
* void play_note(void) {
* opl3_init(); // включить OPL3
* opl3_write_b0(0x20, 0x01); // op1: MULT=1
* opl3_write_b0(0x40, 0x10); // op1: TL=16
* opl3_write_b0(0x60, 0xF0); // op1: AR=F, DR=0
* opl3_write_b0(0x80, 0x77); // op1: SL=7, RR=7
* opl3_write_b0(0xA0, 0x98); // F-num lo
* opl3_write_b0(0xB0, 0x31); // Key-On, Oct=4, F-hi
* }
*/
#ifndef OPL3_H
#define OPL3_H
#include "types.h"
/* ── Порты OPL3 на шине TSConfig ─────────────────────────────────── */
#define OPL3_ADDR0 0xC4 /* Bank 0 register address */
#define OPL3_DATA0 0xC5 /* Bank 0 register data */
#define OPL3_ADDR1 0xC6 /* Bank 1 register address */
#define OPL3_DATA1 0xC7 /* Bank 1 register data */
/* ── Нумерация регистров (часто используемые) ────────────────────── */
#define OPL3_REG_WAVESEL 0x01 /* Waveform select enable (бит 5) */
#define OPL3_REG_CONNSEL 0x04 /* Connection select (4-op, Bank0) */
#define OPL3_REG_OPL3EN 0x05 /* OPL3 mode reg (Bank 1 only!) */
#define OPL3_OPL3EN_ON 0x01 /* NEW=1: OPL3 mode (L/R via C0-C8)*/
#define OPL3_OPL3EN_OFF 0x00 /* NEW=0: OPL2 compat (L+R always) */
#define OPL3_REG_CSW 0x08 /* CSW / Note select (Bank 0) */
#define OPL3_REG_BD 0xBD /* Percussion / AM / VIB depth */
/* Key-On бит в регистрах 0xB0-0xB8 */
#define OPL3_KEY_ON 0x20
/* ── Функции (реализация: asm/opl3.s) ────────────────────────────── */
/** Записать регистр Bank 0: addr -> #C4, data -> #C5 */
void opl3_write_b0(uint8_t addr, uint8_t data);
/** Записать регистр Bank 1: addr -> #C6, data -> #C7 */
void opl3_write_b1(uint8_t addr, uint8_t data);
/**
* Инициализация OPL3:
* 1. Bank1 reg[0x05] = 0x01 — NEW=1, OPL3 mode (регистры C0-C8 управляют L/R)
* 2. Bank0 reg[0x01] = 0x20 — Waveform Select Enable
* 3. Полный сброс всех 18 каналов: KeyOff, TL, F-Num (opl3_reset)
*
* ⚠ После `opl3_init()` чип находится в режиме OPL3 (NEW=1):
* - Регистры C0-C8 задают маршрутизацию L/R (биты 4-5)
* - OPL2/OPL1 VGM файлы НЕ устанавливают биты L/R → тишина!
*
* Для OPL1/OPL2 файлов после init вызовите:
* opl3_write_b1(OPL3_REG_OPL3EN, 0x00); // NEW=0: OPL2-compat mode
* В этом режиме L+R включены автоматически, биты C0-C8[5:4] игнорируются.
*/
void opl3_init(void);
/** Заглушить все 18 каналов (KeyOff: B0-B8 = 0, обе банки) */
void opl3_reset(void);
/** AY-3-8910 / YM2149 chip 1: mixer off + volume 0 */
void ay_silence(void);
/** AY-3-8910 chip 2 (TurboSound): select chip2, silence, switch back */
void ay2_silence(void);
/** AY chip 1: write single register */
void ay_write_reg(uint8_t reg, uint8_t val);
/** AY chip 2 (TurboSound): write single register */
void ay2_write_reg(uint8_t reg, uint8_t val);
/** SAA1099 chip 1: reset + disable + zero amplitudes */
void saa_silence(void);
/** SAA1099 chip 2: reset + disable + zero amplitudes */
void saa2_silence(void);
/** SAA1099 chip 1: write single register */
void saa_write_reg(uint8_t reg, uint8_t val);
/** SAA1099 chip 2: write single register */
void saa2_write_reg(uint8_t reg, uint8_t val);
#endif /* OPL3_H */