/** * @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 */