Merge pull request #2899 from Cacodemon345/opl4-daughterboard

Add OPL4-ML daughterboard emulation
This commit is contained in:
Miran Grča
2023-08-09 00:38:19 +02:00
committed by GitHub
10 changed files with 1933 additions and 1 deletions

View File

@@ -102,6 +102,7 @@ extern void midi_in_sysex(uint8_t *buffer, uint32_t len);
#ifdef EMU_DEVICE_H
extern const device_t rtmidi_output_device;
extern const device_t rtmidi_input_device;
extern const device_t opl4_midi_device;
# ifdef USE_FLUIDSYNTH
extern const device_t fluidsynth_device;
# endif

View File

@@ -0,0 +1,101 @@
/*
* RoboPlay for MSX
* Copyright (C) 2020 by RoboSoft Inc.
*
* opl4_defines.h
*
*/
#ifndef __OPL4_DEFINES_H
#define __OPL4_DEFINES_H
/*
* Register numbers
*/
#define OPL4_REG_TEST0 0x00
#define OPL4_REG_TEST1 0x01
#define OPL4_REG_MEMORY_CONFIGURATION 0x02
#define OPL4_MODE_BIT 0x01
#define OPL4_MTYPE_BIT 0x02
#define OPL4_TONE_HEADER_MASK 0x1C
#define OPL4_DEVICE_ID_MASK 0xE0
#define OPL4_REG_MEMORY_ADDRESS_HIGH 0x03
#define OPL4_REG_MEMORY_ADDRESS_MID 0x04
#define OPL4_REG_MEMORY_ADDRESS_LOW 0x05
#define OPL4_REG_MEMORY_DATA 0x06
/*
* Offsets to the register banks for voices. To get the
* register number just add the voice number to the bank offset.
*
* Wave Table Number low bits (0x08 to 0x1F)
*/
#define OPL4_REG_TONE_NUMBER 0x08
/* Wave Table Number high bit, F-Number low bits (0x20 to 0x37) */
#define OPL4_REG_F_NUMBER 0x20
#define OPL4_TONE_NUMBER_BIT8 0x01
#define OPL4_F_NUMBER_LOW_MASK 0xFE
/* F-Number high bits, Octave, Pseudo-Reverb (0x38 to 0x4F) */
#define OPL4_REG_OCTAVE 0x38
#define OPL4_F_NUMBER_HIGH_MASK 0x07
#define OPL4_BLOCK_MASK 0xF0
#define OPL4_PSEUDO_REVERB_BIT 0x08
/* Total Level, Level Direct (0x50 to 0x67) */
#define OPL4_REG_LEVEL 0x50
#define OPL4_TOTAL_LEVEL_MASK 0xFE
#define OPL4_LEVEL_DIRECT_BIT 0x01
/* Key On, Damp, LFO RST, CH, Panpot (0x68 to 0x7F) */
#define OPL4_REG_MISC 0x68
#define OPL4_KEY_ON_BIT 0x80
#define OPL4_DAMP_BIT 0x40
#define OPL4_LFO_RESET_BIT 0x20
#define OPL4_OUTPUT_CHANNEL_BIT 0x10
#define OPL4_PAN_POT_MASK 0x0F
/* LFO, VIB (0x80 to 0x97) */
#define OPL4_REG_LFO_VIBRATO 0x80
#define OPL4_LFO_FREQUENCY_MASK 0x38
#define OPL4_VIBRATO_DEPTH_MASK 0x07
#define OPL4_CHORUS_SEND_MASK 0xC0
/* Attack / Decay 1 rate (0x98 to 0xAF) */
#define OPL4_REG_ATTACK_DECAY1 0x98
#define OPL4_ATTACK_RATE_MASK 0xF0
#define OPL4_DECAY1_RATE_MASK 0x0F
/* Decay level / 2 rate (0xB0 to 0xC7) */
#define OPL4_REG_LEVEL_DECAY2 0xB0
#define OPL4_DECAY_LEVEL_MASK 0xF0
#define OPL4_DECAY2_RATE_MASK 0x0F
/* Release rate / Rate correction (0xC8 to 0xDF) */
#define OPL4_REG_RELEASE_CORRECTION 0xC8
#define OPL4_RELEASE_RATE_MASK 0x0F
#define OPL4_RATE_INTERPOLATION_MASK 0xF0
/* AM (0xE0 to 0xF7) */
#define OPL4_REG_TREMOLO 0xE0
#define OPL4_TREMOLO_DEPTH_MASK 0x07
#define OPL4_REVERB_SEND_MASK 0xE0
/* Mixer */
#define OPL4_REG_MIX_CONTROL_FM 0xF8
#define OPL4_REG_MIX_CONTROL_PCM 0xF9
#define OPL4_MIX_LEFT_MASK 0x07
#define OPL4_MIX_RIGHT_MASK 0x38
#define OPL4_REG_ATC 0xFA
#define OPL4_ATC_BIT 0x01
/* Bits in the OPL4 Status register */
#define OPL4_STATUS_BUSY 0x01
#define OPL4_STATUS_LOAD 0x02
#endif /* __OPL4_DEFINES_H */

View File

@@ -38,6 +38,7 @@ typedef struct fm_drv_t {
void (*reset_buffer)(void *priv);
void (*set_do_cycles)(void *priv, int8_t do_cycles);
void *priv;
void (*generate)(void *priv, int32_t *data, uint32_t num_samples); /* daughterboard only. */
} fm_drv_t;
extern uint8_t fm_driver_get(int chip_id, fm_drv_t *drv);

View File

@@ -18,7 +18,7 @@ add_library(snd OBJECT sound.c snd_opl.c snd_opl_nuked.c snd_opl_ymfm.cpp snd_re
snd_lpt_dss.c snd_ps1.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c
snd_azt2316a.c snd_cms.c snd_cmi8x38.c snd_cs423x.c snd_gus.c snd_sb.c snd_sb_dsp.c
snd_emu8k.c snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c
snd_optimc.c)
snd_optimc.c midi_opl4.c midi_opl4_yrw801.c)
if(OPENAL)
if(VCPKG_TOOLCHAIN)

View File

@@ -102,6 +102,7 @@ static const MIDI_OUT_DEVICE devices[] = {
#ifdef USE_RTMIDI
{ &rtmidi_output_device },
#endif
{ &opl4_midi_device },
{ NULL }
// clang-format on
};

732
src/sound/midi_opl4.c Normal file
View File

@@ -0,0 +1,732 @@
// Based off ROBOPLAY's OPL4 MID player code, with some fixes and modifications to make it work well.
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/midi.h>
#include <86box/plat.h>
#include <86box/thread.h>
#include <86box/rom.h>
#include <86box/sound.h>
#include <86box/ui.h>
#include <86box/snd_opl.h>
#include <86box/opl4_defines.h>
#include "yrw801.h"
#define NR_OF_MIDI_CHANNELS 16
#define NR_OF_WAVE_CHANNELS 24
#define DRUM_CHANNEL 9
typedef struct
{
uint8_t instrument;
uint8_t panpot;
uint8_t vibrato;
bool drum_channel;
} MIDI_CHANNEL_DATA;
typedef struct
{
bool is_active;
uint64_t activated;
uint8_t number;
MIDI_CHANNEL_DATA *midi_channel;
uint8_t note;
uint8_t velocity;
const YRW801_WAVE_DATA *wave_data;
uint8_t level_direct;
uint8_t reg_f_number;
uint8_t reg_misc;
uint8_t reg_lfo_vibrato;
} VOICE_DATA;
static const int16_t g_wave_pitch_map[0x600] = {
0x000, 0x000, 0x001, 0x001, 0x002, 0x002, 0x003, 0x003,
0x004, 0x004, 0x005, 0x005, 0x006, 0x006, 0x006, 0x007,
0x007, 0x008, 0x008, 0x009, 0x009, 0x00a, 0x00a, 0x00b,
0x00b, 0x00c, 0x00c, 0x00d, 0x00d, 0x00d, 0x00e, 0x00e,
0x00f, 0x00f, 0x010, 0x010, 0x011, 0x011, 0x012, 0x012,
0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x015, 0x016,
0x016, 0x017, 0x017, 0x018, 0x018, 0x019, 0x019, 0x01a,
0x01a, 0x01b, 0x01b, 0x01c, 0x01c, 0x01d, 0x01d, 0x01e,
0x01e, 0x01e, 0x01f, 0x01f, 0x020, 0x020, 0x021, 0x021,
0x022, 0x022, 0x023, 0x023, 0x024, 0x024, 0x025, 0x025,
0x026, 0x026, 0x027, 0x027, 0x028, 0x028, 0x029, 0x029,
0x029, 0x02a, 0x02a, 0x02b, 0x02b, 0x02c, 0x02c, 0x02d,
0x02d, 0x02e, 0x02e, 0x02f, 0x02f, 0x030, 0x030, 0x031,
0x031, 0x032, 0x032, 0x033, 0x033, 0x034, 0x034, 0x035,
0x035, 0x036, 0x036, 0x037, 0x037, 0x038, 0x038, 0x038,
0x039, 0x039, 0x03a, 0x03a, 0x03b, 0x03b, 0x03c, 0x03c,
0x03d, 0x03d, 0x03e, 0x03e, 0x03f, 0x03f, 0x040, 0x040,
0x041, 0x041, 0x042, 0x042, 0x043, 0x043, 0x044, 0x044,
0x045, 0x045, 0x046, 0x046, 0x047, 0x047, 0x048, 0x048,
0x049, 0x049, 0x04a, 0x04a, 0x04b, 0x04b, 0x04c, 0x04c,
0x04d, 0x04d, 0x04e, 0x04e, 0x04f, 0x04f, 0x050, 0x050,
0x051, 0x051, 0x052, 0x052, 0x053, 0x053, 0x054, 0x054,
0x055, 0x055, 0x056, 0x056, 0x057, 0x057, 0x058, 0x058,
0x059, 0x059, 0x05a, 0x05a, 0x05b, 0x05b, 0x05c, 0x05c,
0x05d, 0x05d, 0x05e, 0x05e, 0x05f, 0x05f, 0x060, 0x060,
0x061, 0x061, 0x062, 0x062, 0x063, 0x063, 0x064, 0x064,
0x065, 0x065, 0x066, 0x066, 0x067, 0x067, 0x068, 0x068,
0x069, 0x069, 0x06a, 0x06a, 0x06b, 0x06b, 0x06c, 0x06c,
0x06d, 0x06d, 0x06e, 0x06e, 0x06f, 0x06f, 0x070, 0x071,
0x071, 0x072, 0x072, 0x073, 0x073, 0x074, 0x074, 0x075,
0x075, 0x076, 0x076, 0x077, 0x077, 0x078, 0x078, 0x079,
0x079, 0x07a, 0x07a, 0x07b, 0x07b, 0x07c, 0x07c, 0x07d,
0x07d, 0x07e, 0x07e, 0x07f, 0x07f, 0x080, 0x081, 0x081,
0x082, 0x082, 0x083, 0x083, 0x084, 0x084, 0x085, 0x085,
0x086, 0x086, 0x087, 0x087, 0x088, 0x088, 0x089, 0x089,
0x08a, 0x08a, 0x08b, 0x08b, 0x08c, 0x08d, 0x08d, 0x08e,
0x08e, 0x08f, 0x08f, 0x090, 0x090, 0x091, 0x091, 0x092,
0x092, 0x093, 0x093, 0x094, 0x094, 0x095, 0x096, 0x096,
0x097, 0x097, 0x098, 0x098, 0x099, 0x099, 0x09a, 0x09a,
0x09b, 0x09b, 0x09c, 0x09c, 0x09d, 0x09d, 0x09e, 0x09f,
0x09f, 0x0a0, 0x0a0, 0x0a1, 0x0a1, 0x0a2, 0x0a2, 0x0a3,
0x0a3, 0x0a4, 0x0a4, 0x0a5, 0x0a6, 0x0a6, 0x0a7, 0x0a7,
0x0a8, 0x0a8, 0x0a9, 0x0a9, 0x0aa, 0x0aa, 0x0ab, 0x0ab,
0x0ac, 0x0ad, 0x0ad, 0x0ae, 0x0ae, 0x0af, 0x0af, 0x0b0,
0x0b0, 0x0b1, 0x0b1, 0x0b2, 0x0b2, 0x0b3, 0x0b4, 0x0b4,
0x0b5, 0x0b5, 0x0b6, 0x0b6, 0x0b7, 0x0b7, 0x0b8, 0x0b8,
0x0b9, 0x0ba, 0x0ba, 0x0bb, 0x0bb, 0x0bc, 0x0bc, 0x0bd,
0x0bd, 0x0be, 0x0be, 0x0bf, 0x0c0, 0x0c0, 0x0c1, 0x0c1,
0x0c2, 0x0c2, 0x0c3, 0x0c3, 0x0c4, 0x0c4, 0x0c5, 0x0c6,
0x0c6, 0x0c7, 0x0c7, 0x0c8, 0x0c8, 0x0c9, 0x0c9, 0x0ca,
0x0cb, 0x0cb, 0x0cc, 0x0cc, 0x0cd, 0x0cd, 0x0ce, 0x0ce,
0x0cf, 0x0d0, 0x0d0, 0x0d1, 0x0d1, 0x0d2, 0x0d2, 0x0d3,
0x0d3, 0x0d4, 0x0d5, 0x0d5, 0x0d6, 0x0d6, 0x0d7, 0x0d7,
0x0d8, 0x0d8, 0x0d9, 0x0da, 0x0da, 0x0db, 0x0db, 0x0dc,
0x0dc, 0x0dd, 0x0de, 0x0de, 0x0df, 0x0df, 0x0e0, 0x0e0,
0x0e1, 0x0e1, 0x0e2, 0x0e3, 0x0e3, 0x0e4, 0x0e4, 0x0e5,
0x0e5, 0x0e6, 0x0e7, 0x0e7, 0x0e8, 0x0e8, 0x0e9, 0x0e9,
0x0ea, 0x0eb, 0x0eb, 0x0ec, 0x0ec, 0x0ed, 0x0ed, 0x0ee,
0x0ef, 0x0ef, 0x0f0, 0x0f0, 0x0f1, 0x0f1, 0x0f2, 0x0f3,
0x0f3, 0x0f4, 0x0f4, 0x0f5, 0x0f5, 0x0f6, 0x0f7, 0x0f7,
0x0f8, 0x0f8, 0x0f9, 0x0f9, 0x0fa, 0x0fb, 0x0fb, 0x0fc,
0x0fc, 0x0fd, 0x0fd, 0x0fe, 0x0ff, 0x0ff, 0x100, 0x100,
0x101, 0x101, 0x102, 0x103, 0x103, 0x104, 0x104, 0x105,
0x106, 0x106, 0x107, 0x107, 0x108, 0x108, 0x109, 0x10a,
0x10a, 0x10b, 0x10b, 0x10c, 0x10c, 0x10d, 0x10e, 0x10e,
0x10f, 0x10f, 0x110, 0x111, 0x111, 0x112, 0x112, 0x113,
0x114, 0x114, 0x115, 0x115, 0x116, 0x116, 0x117, 0x118,
0x118, 0x119, 0x119, 0x11a, 0x11b, 0x11b, 0x11c, 0x11c,
0x11d, 0x11e, 0x11e, 0x11f, 0x11f, 0x120, 0x120, 0x121,
0x122, 0x122, 0x123, 0x123, 0x124, 0x125, 0x125, 0x126,
0x126, 0x127, 0x128, 0x128, 0x129, 0x129, 0x12a, 0x12b,
0x12b, 0x12c, 0x12c, 0x12d, 0x12e, 0x12e, 0x12f, 0x12f,
0x130, 0x131, 0x131, 0x132, 0x132, 0x133, 0x134, 0x134,
0x135, 0x135, 0x136, 0x137, 0x137, 0x138, 0x138, 0x139,
0x13a, 0x13a, 0x13b, 0x13b, 0x13c, 0x13d, 0x13d, 0x13e,
0x13e, 0x13f, 0x140, 0x140, 0x141, 0x141, 0x142, 0x143,
0x143, 0x144, 0x144, 0x145, 0x146, 0x146, 0x147, 0x148,
0x148, 0x149, 0x149, 0x14a, 0x14b, 0x14b, 0x14c, 0x14c,
0x14d, 0x14e, 0x14e, 0x14f, 0x14f, 0x150, 0x151, 0x151,
0x152, 0x153, 0x153, 0x154, 0x154, 0x155, 0x156, 0x156,
0x157, 0x157, 0x158, 0x159, 0x159, 0x15a, 0x15b, 0x15b,
0x15c, 0x15c, 0x15d, 0x15e, 0x15e, 0x15f, 0x160, 0x160,
0x161, 0x161, 0x162, 0x163, 0x163, 0x164, 0x165, 0x165,
0x166, 0x166, 0x167, 0x168, 0x168, 0x169, 0x16a, 0x16a,
0x16b, 0x16b, 0x16c, 0x16d, 0x16d, 0x16e, 0x16f, 0x16f,
0x170, 0x170, 0x171, 0x172, 0x172, 0x173, 0x174, 0x174,
0x175, 0x175, 0x176, 0x177, 0x177, 0x178, 0x179, 0x179,
0x17a, 0x17a, 0x17b, 0x17c, 0x17c, 0x17d, 0x17e, 0x17e,
0x17f, 0x180, 0x180, 0x181, 0x181, 0x182, 0x183, 0x183,
0x184, 0x185, 0x185, 0x186, 0x187, 0x187, 0x188, 0x188,
0x189, 0x18a, 0x18a, 0x18b, 0x18c, 0x18c, 0x18d, 0x18e,
0x18e, 0x18f, 0x190, 0x190, 0x191, 0x191, 0x192, 0x193,
0x193, 0x194, 0x195, 0x195, 0x196, 0x197, 0x197, 0x198,
0x199, 0x199, 0x19a, 0x19a, 0x19b, 0x19c, 0x19c, 0x19d,
0x19e, 0x19e, 0x19f, 0x1a0, 0x1a0, 0x1a1, 0x1a2, 0x1a2,
0x1a3, 0x1a4, 0x1a4, 0x1a5, 0x1a6, 0x1a6, 0x1a7, 0x1a8,
0x1a8, 0x1a9, 0x1a9, 0x1aa, 0x1ab, 0x1ab, 0x1ac, 0x1ad,
0x1ad, 0x1ae, 0x1af, 0x1af, 0x1b0, 0x1b1, 0x1b1, 0x1b2,
0x1b3, 0x1b3, 0x1b4, 0x1b5, 0x1b5, 0x1b6, 0x1b7, 0x1b7,
0x1b8, 0x1b9, 0x1b9, 0x1ba, 0x1bb, 0x1bb, 0x1bc, 0x1bd,
0x1bd, 0x1be, 0x1bf, 0x1bf, 0x1c0, 0x1c1, 0x1c1, 0x1c2,
0x1c3, 0x1c3, 0x1c4, 0x1c5, 0x1c5, 0x1c6, 0x1c7, 0x1c7,
0x1c8, 0x1c9, 0x1c9, 0x1ca, 0x1cb, 0x1cb, 0x1cc, 0x1cd,
0x1cd, 0x1ce, 0x1cf, 0x1cf, 0x1d0, 0x1d1, 0x1d1, 0x1d2,
0x1d3, 0x1d3, 0x1d4, 0x1d5, 0x1d5, 0x1d6, 0x1d7, 0x1d7,
0x1d8, 0x1d9, 0x1d9, 0x1da, 0x1db, 0x1db, 0x1dc, 0x1dd,
0x1dd, 0x1de, 0x1df, 0x1df, 0x1e0, 0x1e1, 0x1e1, 0x1e2,
0x1e3, 0x1e4, 0x1e4, 0x1e5, 0x1e6, 0x1e6, 0x1e7, 0x1e8,
0x1e8, 0x1e9, 0x1ea, 0x1ea, 0x1eb, 0x1ec, 0x1ec, 0x1ed,
0x1ee, 0x1ee, 0x1ef, 0x1f0, 0x1f0, 0x1f1, 0x1f2, 0x1f3,
0x1f3, 0x1f4, 0x1f5, 0x1f5, 0x1f6, 0x1f7, 0x1f7, 0x1f8,
0x1f9, 0x1f9, 0x1fa, 0x1fb, 0x1fb, 0x1fc, 0x1fd, 0x1fe,
0x1fe, 0x1ff, 0x200, 0x200, 0x201, 0x202, 0x202, 0x203,
0x204, 0x205, 0x205, 0x206, 0x207, 0x207, 0x208, 0x209,
0x209, 0x20a, 0x20b, 0x20b, 0x20c, 0x20d, 0x20e, 0x20e,
0x20f, 0x210, 0x210, 0x211, 0x212, 0x212, 0x213, 0x214,
0x215, 0x215, 0x216, 0x217, 0x217, 0x218, 0x219, 0x21a,
0x21a, 0x21b, 0x21c, 0x21c, 0x21d, 0x21e, 0x21e, 0x21f,
0x220, 0x221, 0x221, 0x222, 0x223, 0x223, 0x224, 0x225,
0x226, 0x226, 0x227, 0x228, 0x228, 0x229, 0x22a, 0x22b,
0x22b, 0x22c, 0x22d, 0x22d, 0x22e, 0x22f, 0x230, 0x230,
0x231, 0x232, 0x232, 0x233, 0x234, 0x235, 0x235, 0x236,
0x237, 0x237, 0x238, 0x239, 0x23a, 0x23a, 0x23b, 0x23c,
0x23c, 0x23d, 0x23e, 0x23f, 0x23f, 0x240, 0x241, 0x241,
0x242, 0x243, 0x244, 0x244, 0x245, 0x246, 0x247, 0x247,
0x248, 0x249, 0x249, 0x24a, 0x24b, 0x24c, 0x24c, 0x24d,
0x24e, 0x24f, 0x24f, 0x250, 0x251, 0x251, 0x252, 0x253,
0x254, 0x254, 0x255, 0x256, 0x257, 0x257, 0x258, 0x259,
0x259, 0x25a, 0x25b, 0x25c, 0x25c, 0x25d, 0x25e, 0x25f,
0x25f, 0x260, 0x261, 0x262, 0x262, 0x263, 0x264, 0x265,
0x265, 0x266, 0x267, 0x267, 0x268, 0x269, 0x26a, 0x26a,
0x26b, 0x26c, 0x26d, 0x26d, 0x26e, 0x26f, 0x270, 0x270,
0x271, 0x272, 0x273, 0x273, 0x274, 0x275, 0x276, 0x276,
0x277, 0x278, 0x279, 0x279, 0x27a, 0x27b, 0x27c, 0x27c,
0x27d, 0x27e, 0x27f, 0x27f, 0x280, 0x281, 0x282, 0x282,
0x283, 0x284, 0x285, 0x285, 0x286, 0x287, 0x288, 0x288,
0x289, 0x28a, 0x28b, 0x28b, 0x28c, 0x28d, 0x28e, 0x28e,
0x28f, 0x290, 0x291, 0x291, 0x292, 0x293, 0x294, 0x294,
0x295, 0x296, 0x297, 0x298, 0x298, 0x299, 0x29a, 0x29b,
0x29b, 0x29c, 0x29d, 0x29e, 0x29e, 0x29f, 0x2a0, 0x2a1,
0x2a1, 0x2a2, 0x2a3, 0x2a4, 0x2a5, 0x2a5, 0x2a6, 0x2a7,
0x2a8, 0x2a8, 0x2a9, 0x2aa, 0x2ab, 0x2ab, 0x2ac, 0x2ad,
0x2ae, 0x2af, 0x2af, 0x2b0, 0x2b1, 0x2b2, 0x2b2, 0x2b3,
0x2b4, 0x2b5, 0x2b5, 0x2b6, 0x2b7, 0x2b8, 0x2b9, 0x2b9,
0x2ba, 0x2bb, 0x2bc, 0x2bc, 0x2bd, 0x2be, 0x2bf, 0x2c0,
0x2c0, 0x2c1, 0x2c2, 0x2c3, 0x2c4, 0x2c4, 0x2c5, 0x2c6,
0x2c7, 0x2c7, 0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cb, 0x2cc,
0x2cd, 0x2ce, 0x2ce, 0x2cf, 0x2d0, 0x2d1, 0x2d2, 0x2d2,
0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d6, 0x2d7, 0x2d8, 0x2d9,
0x2da, 0x2da, 0x2db, 0x2dc, 0x2dd, 0x2dd, 0x2de, 0x2df,
0x2e0, 0x2e1, 0x2e1, 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e5,
0x2e6, 0x2e7, 0x2e8, 0x2e9, 0x2e9, 0x2ea, 0x2eb, 0x2ec,
0x2ed, 0x2ed, 0x2ee, 0x2ef, 0x2f0, 0x2f1, 0x2f1, 0x2f2,
0x2f3, 0x2f4, 0x2f5, 0x2f5, 0x2f6, 0x2f7, 0x2f8, 0x2f9,
0x2f9, 0x2fa, 0x2fb, 0x2fc, 0x2fd, 0x2fd, 0x2fe, 0x2ff,
0x300, 0x301, 0x302, 0x302, 0x303, 0x304, 0x305, 0x306,
0x306, 0x307, 0x308, 0x309, 0x30a, 0x30a, 0x30b, 0x30c,
0x30d, 0x30e, 0x30f, 0x30f, 0x310, 0x311, 0x312, 0x313,
0x313, 0x314, 0x315, 0x316, 0x317, 0x318, 0x318, 0x319,
0x31a, 0x31b, 0x31c, 0x31c, 0x31d, 0x31e, 0x31f, 0x320,
0x321, 0x321, 0x322, 0x323, 0x324, 0x325, 0x326, 0x326,
0x327, 0x328, 0x329, 0x32a, 0x32a, 0x32b, 0x32c, 0x32d,
0x32e, 0x32f, 0x32f, 0x330, 0x331, 0x332, 0x333, 0x334,
0x334, 0x335, 0x336, 0x337, 0x338, 0x339, 0x339, 0x33a,
0x33b, 0x33c, 0x33d, 0x33e, 0x33e, 0x33f, 0x340, 0x341,
0x342, 0x343, 0x343, 0x344, 0x345, 0x346, 0x347, 0x348,
0x349, 0x349, 0x34a, 0x34b, 0x34c, 0x34d, 0x34e, 0x34e,
0x34f, 0x350, 0x351, 0x352, 0x353, 0x353, 0x354, 0x355,
0x356, 0x357, 0x358, 0x359, 0x359, 0x35a, 0x35b, 0x35c,
0x35d, 0x35e, 0x35f, 0x35f, 0x360, 0x361, 0x362, 0x363,
0x364, 0x364, 0x365, 0x366, 0x367, 0x368, 0x369, 0x36a,
0x36a, 0x36b, 0x36c, 0x36d, 0x36e, 0x36f, 0x370, 0x370,
0x371, 0x372, 0x373, 0x374, 0x375, 0x376, 0x377, 0x377,
0x378, 0x379, 0x37a, 0x37b, 0x37c, 0x37d, 0x37d, 0x37e,
0x37f, 0x380, 0x381, 0x382, 0x383, 0x383, 0x384, 0x385,
0x386, 0x387, 0x388, 0x389, 0x38a, 0x38a, 0x38b, 0x38c,
0x38d, 0x38e, 0x38f, 0x390, 0x391, 0x391, 0x392, 0x393,
0x394, 0x395, 0x396, 0x397, 0x398, 0x398, 0x399, 0x39a,
0x39b, 0x39c, 0x39d, 0x39e, 0x39f, 0x39f, 0x3a0, 0x3a1,
0x3a2, 0x3a3, 0x3a4, 0x3a5, 0x3a6, 0x3a7, 0x3a7, 0x3a8,
0x3a9, 0x3aa, 0x3ab, 0x3ac, 0x3ad, 0x3ae, 0x3ae, 0x3af,
0x3b0, 0x3b1, 0x3b2, 0x3b3, 0x3b4, 0x3b5, 0x3b6, 0x3b6,
0x3b7, 0x3b8, 0x3b9, 0x3ba, 0x3bb, 0x3bc, 0x3bd, 0x3be,
0x3bf, 0x3bf, 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4, 0x3c5,
0x3c6, 0x3c7, 0x3c7, 0x3c8, 0x3c9, 0x3ca, 0x3cb, 0x3cc,
0x3cd, 0x3ce, 0x3cf, 0x3d0, 0x3d1, 0x3d1, 0x3d2, 0x3d3,
0x3d4, 0x3d5, 0x3d6, 0x3d7, 0x3d8, 0x3d9, 0x3da, 0x3da,
0x3db, 0x3dc, 0x3dd, 0x3de, 0x3df, 0x3e0, 0x3e1, 0x3e2,
0x3e3, 0x3e4, 0x3e4, 0x3e5, 0x3e6, 0x3e7, 0x3e8, 0x3e9,
0x3ea, 0x3eb, 0x3ec, 0x3ed, 0x3ee, 0x3ef, 0x3ef, 0x3f0,
0x3f1, 0x3f2, 0x3f3, 0x3f4, 0x3f5, 0x3f6, 0x3f7, 0x3f8,
0x3f9, 0x3fa, 0x3fa, 0x3fb, 0x3fc, 0x3fd, 0x3fe, 0x3ff
};
/*
* Attenuation according to GM recommendations, in -0.375 dB units.
* table[v] = 40 * log(v / 127) / -0.375
*/
static const uint8_t g_volume_table[128] = {
255, 224, 192, 173, 160, 150, 141, 134,
128, 122, 117, 113, 109, 105, 102, 99,
96, 93, 90, 88, 85, 83, 81, 79,
77, 75, 73, 71, 70, 68, 67, 65,
64, 62, 61, 59, 58, 57, 56, 54,
53, 52, 51, 50, 49, 48, 47, 46,
45, 44, 43, 42, 41, 40, 39, 39,
38, 37, 36, 35, 34, 34, 33, 32,
31, 31, 30, 29, 29, 28, 27, 27,
26, 25, 25, 24, 24, 23, 22, 22,
21, 21, 20, 19, 19, 18, 18, 17,
17, 16, 16, 15, 15, 14, 14, 13,
13, 12, 12, 11, 11, 10, 10, 9,
9, 9, 8, 8, 7, 7, 6, 6,
6, 5, 5, 4, 4, 4, 3, 3,
2, 2, 2, 1, 1, 0, 0, 0
};
#define BUFFER_SEGMENTS 10
#define RENDER_RATE (48000 / 100)
typedef struct opl4_midi {
fm_drv_t opl4;
MIDI_CHANNEL_DATA midi_channel_data[16];
VOICE_DATA voice_data[24];
int16_t buffer[(48000 / 100) * 2 * BUFFER_SEGMENTS];
float buffer_float[(48000 / 100) * 2 * BUFFER_SEGMENTS];
uint32_t midi_pos;
bool on;
atomic_bool gen_in_progress;
thread_t *thread;
event_t *wait_event;
} opl4_midi_t;
static opl4_midi_t *opl4_midi_cur;
static void
opl4_write_wave_register(const uint8_t reg, const uint8_t value, opl4_midi_t *opl4_midi)
{
opl4_midi->opl4.write(0x380, reg, opl4_midi->opl4.priv);
opl4_midi->opl4.write(0x381, value, opl4_midi->opl4.priv);
}
VOICE_DATA *
get_voice(const YRW801_WAVE_DATA *wave_data, opl4_midi_t *opl4_midi)
{
VOICE_DATA *free_voice = &opl4_midi->voice_data[0];
VOICE_DATA *oldest_voice = &opl4_midi->voice_data[0];
for (uint8_t voice = 0; voice < 24; voice++) {
if (opl4_midi_cur->voice_data[voice].is_active) {
if (opl4_midi_cur->voice_data[voice].activated < oldest_voice->activated)
oldest_voice = &opl4_midi_cur->voice_data[voice];
} else {
if (opl4_midi_cur->voice_data[voice].wave_data == wave_data) {
free_voice = &opl4_midi_cur->voice_data[voice];
break;
}
if (opl4_midi_cur->voice_data[voice].activated < free_voice->activated) {
free_voice = &opl4_midi_cur->voice_data[voice];
break;
}
}
}
/* If no free voice is found, look for one with the same instrument */
if (free_voice->is_active) {
for (uint8_t voice = 0; voice < 24; voice++) {
if (opl4_midi_cur->voice_data[voice].is_active
&& opl4_midi_cur->voice_data[voice].wave_data == wave_data) {
free_voice = &opl4_midi_cur->voice_data[voice];
free_voice->is_active = 0;
free_voice->activated = 0;
free_voice->reg_misc &= ~OPL4_KEY_ON_BIT;
opl4_write_wave_register(OPL4_REG_MISC + free_voice->number, free_voice->reg_misc, opl4_midi);
return free_voice;
}
}
}
/* If still no free voice found, deactivate the 'oldest' */
if (free_voice->is_active) {
free_voice = oldest_voice;
free_voice->is_active = 0;
free_voice->activated = 0;
free_voice->reg_misc &= ~OPL4_KEY_ON_BIT;
opl4_write_wave_register(OPL4_REG_MISC + free_voice->number, free_voice->reg_misc, opl4_midi);
}
return free_voice;
}
static void
update_pan(VOICE_DATA *voice, opl4_midi_t *opl4_midi)
{
int8_t pan = voice->wave_data->panpot;
if (!voice->midi_channel->drum_channel)
pan += voice->midi_channel->panpot;
if (pan < -7)
pan = -7;
else if (pan > 7)
pan = 7;
voice->reg_misc = (voice->reg_misc & ~OPL4_PAN_POT_MASK) | (pan & OPL4_PAN_POT_MASK);
opl4_write_wave_register(OPL4_REG_MISC + voice->number, voice->reg_misc, opl4_midi);
}
void
update_pitch(VOICE_DATA *voice, uint16_t pitch_bend, opl4_midi_t *opl4_midi)
{
int32_t pitch = voice->midi_channel->drum_channel ? 0 : (voice->note - 60) * 128;
pitch = pitch * (int) voice->wave_data->key_scaling / 100;
pitch = pitch + 7680;
pitch += voice->wave_data->pitch_offset;
pitch += pitch_bend * 256 / 0x2000;
if (pitch < 0)
pitch = 0;
else if (pitch > 0x5FFF)
pitch = 0x5FFF;
int8_t octave = pitch / 0x600 - 8;
uint16_t fnumber = g_wave_pitch_map[pitch % 0x600];
opl4_write_wave_register(OPL4_REG_OCTAVE + voice->number, (octave << 4) | ((fnumber >> 7) & 0x07), opl4_midi);
voice->reg_f_number = (voice->reg_f_number & OPL4_TONE_NUMBER_BIT8) | ((fnumber << 1) & OPL4_F_NUMBER_LOW_MASK);
opl4_write_wave_register(OPL4_REG_F_NUMBER + voice->number, voice->reg_f_number, opl4_midi);
}
void
update_volume(VOICE_DATA *voice, opl4_midi_t *opl4_midi)
{
int16_t att = voice->wave_data->tone_attenuate;
att += g_volume_table[voice->velocity];
att = 0x7F - (0x7F - att) * (voice->wave_data->volume_factor) / 0xFE;
att -= 16;
if (att < 0)
att = 0;
else if (att > 0x7E)
att = 0x7E;
opl4_write_wave_register(OPL4_REG_LEVEL + voice->number, (att << 1) | voice->level_direct, opl4_midi);
voice->level_direct = 0;
}
void
note_off(uint8_t note, uint8_t velocity, MIDI_CHANNEL_DATA *midi_channel, opl4_midi_t *opl4_midi)
{
/* Velocity not used */
(void) velocity;
while (opl4_midi->gen_in_progress) { }
for (uint8_t i = 0; i < 24; i++) {
VOICE_DATA *voice = &opl4_midi->voice_data[i];
if (voice->is_active && voice->midi_channel == midi_channel && voice->note == note) {
voice->is_active = false;
voice->activated = 0;
voice->reg_misc &= ~OPL4_KEY_ON_BIT;
opl4_write_wave_register(OPL4_REG_MISC + voice->number, voice->reg_misc, opl4_midi);
}
}
}
void
update_vibrato_depth(VOICE_DATA *voice, opl4_midi_t *opl4_midi)
{
uint16_t depth;
depth = (7 - voice->wave_data->vibrato) * (voice->midi_channel->vibrato & 0x7F);
depth = (depth >> 7) + voice->wave_data->vibrato;
voice->reg_lfo_vibrato &= ~OPL4_VIBRATO_DEPTH_MASK;
voice->reg_lfo_vibrato |= depth & OPL4_VIBRATO_DEPTH_MASK;
opl4_write_wave_register(OPL4_REG_LFO_VIBRATO + voice->number, voice->reg_lfo_vibrato, opl4_midi);
}
void
note_on(uint8_t note, uint8_t velocity, MIDI_CHANNEL_DATA *midi_channel, opl4_midi_t *opl4_midi)
{
const YRW801_REGION_DATA_PTR *region_ptr = &snd_yrw801_regions[0];
const YRW801_WAVE_DATA *wave_data[2];
VOICE_DATA *voice[2];
uint8_t i = 0, voices = 0;
uint32_t j = 0;
while (opl4_midi->gen_in_progress) { }
if (midi_channel->drum_channel)
wave_data[voices++] = &region_ptr[0x80].regions[note - 0x1A].wave_data;
else {
/* Determine the number of voices and voice parameters */
const YRW801_REGION_DATA *region = region_ptr[midi_channel->instrument & 0x7F].regions;
while (i < region_ptr[midi_channel->instrument & 0x7F].count) {
if (note >= region[i].key_min && note <= region[i].key_max) {
wave_data[voices] = &region[i].wave_data;
if (++voices >= 2)
break;
}
i++;
}
}
/* Allocate and initialize needed voices */
for (i = 0; i < voices; i++) {
voice[i] = get_voice(wave_data[i], opl4_midi);
voice[i]->is_active = true;
voice[i]->activated = plat_get_ticks();
voice[i]->midi_channel = midi_channel;
voice[i]->note = note;
voice[i]->velocity = velocity & 0x7F;
}
for (i = 0; i < voices; i++) {
voice[i]->reg_f_number = (wave_data[i]->tone >> 8) & OPL4_TONE_NUMBER_BIT8;
opl4_write_wave_register(OPL4_REG_F_NUMBER + voice[i]->number, voice[i]->reg_f_number, opl4_midi);
bool new_wave = (voice[i]->wave_data != wave_data[i]);
/* Set tone number (triggers header loading) */
if (new_wave) {
opl4_write_wave_register(OPL4_REG_TONE_NUMBER + voice[i]->number, wave_data[i]->tone & 0xFF, opl4_midi);
voice[i]->wave_data = wave_data[i];
}
voice[i]->reg_misc = OPL4_LFO_RESET_BIT;
update_pan(voice[i], opl4_midi);
update_pitch(voice[i], 0, opl4_midi);
voice[i]->level_direct = OPL4_LEVEL_DIRECT_BIT;
update_volume(voice[i], opl4_midi);
if (new_wave) {
/* Set remaining parameters */
opl4_write_wave_register(OPL4_REG_ATTACK_DECAY1 + voice[i]->number, voice[i]->wave_data->reg_attack_decay1, opl4_midi);
opl4_write_wave_register(OPL4_REG_LEVEL_DECAY2 + voice[i]->number, voice[i]->wave_data->reg_level_decay2, opl4_midi);
opl4_write_wave_register(OPL4_REG_RELEASE_CORRECTION + voice[i]->number, voice[i]->wave_data->reg_release_correction, opl4_midi);
opl4_write_wave_register(OPL4_REG_TREMOLO + voice[i]->number, voice[i]->wave_data->reg_tremolo, opl4_midi);
voice[i]->reg_lfo_vibrato = voice[i]->wave_data->reg_lfo_vibrato;
if (!midi_channel->drum_channel)
update_vibrato_depth(voice[i], opl4_midi);
}
}
/* Finally, switch on all voices */
for (i = 0; i < voices; i++) {
voice[i]->reg_misc = (voice[i]->reg_misc & 0x1F) | OPL4_KEY_ON_BIT;
opl4_write_wave_register(OPL4_REG_MISC + voice[i]->number, voice[i]->reg_misc, opl4_midi);
}
}
void
control_change(uint8_t midi_channel, uint8_t id, uint8_t value, opl4_midi_t *opl4_midi)
{
int i = 0;
switch (id) {
case 10:
/* Change stereo panning */
if (midi_channel != DRUM_CHANNEL) {
opl4_midi->midi_channel_data[midi_channel].panpot = (value - 0x40) >> 3;
for (i = 0; i < NR_OF_WAVE_CHANNELS; i++) {
if (opl4_midi->voice_data[i].is_active && opl4_midi->voice_data[i].midi_channel == &opl4_midi->midi_channel_data[midi_channel]) {
update_pan(&opl4_midi->voice_data[i], opl4_midi);
}
}
}
break;
}
}
void
pitch_wheel(uint8_t midi_channel, uint16_t value, opl4_midi_t *opl4_midi)
{
int i = 0;
for (i = 0; i < 24; i++) {
if (opl4_midi->voice_data[i].is_active && opl4_midi->voice_data[i].midi_channel == &opl4_midi->midi_channel_data[midi_channel]) {
update_pitch(&opl4_midi->voice_data[i], value, opl4_midi);
}
}
}
void
channel_pressure(uint8_t midi_channel, uint8_t pressure)
{
(void) midi_channel;
(void) pressure;
}
void
key_pressure(uint8_t midi_channel, uint8_t note, uint8_t pressure)
{
(void) midi_channel;
(void) note;
(void) pressure;
}
void
program_change(uint8_t midi_channel, uint8_t program, opl4_midi_t *opl4_midi)
{
opl4_midi->midi_channel_data[midi_channel].instrument = program;
}
static void
opl4_midi_thread(void *arg)
{
opl4_midi_t *opl4_midi = opl4_midi_cur;
uint32_t i = 0;
uint32_t buf_size = RENDER_RATE * 2;
uint32_t buf_size_segments = buf_size * BUFFER_SEGMENTS;
uint32_t buf_pos = 0;
int32_t buffer[RENDER_RATE * 2];
extern void givealbuffer_midi(void *buf, uint32_t size);
while (opl4_midi->on) {
thread_wait_event(opl4_midi->wait_event, -1);
thread_reset_event(opl4_midi->wait_event);
if (!opl4_midi->on)
break;
atomic_store(&opl4_midi->gen_in_progress, true);
opl4_midi->opl4.generate(opl4_midi->opl4.priv, buffer, RENDER_RATE);
atomic_store(&opl4_midi->gen_in_progress, false);
if (sound_is_float) {
for (i = 0; i < (buf_size / 2); i++) {
opl4_midi->buffer_float[(i + buf_pos) * 2] = buffer[i * 2] / 32768.0;
opl4_midi->buffer_float[((i + buf_pos) * 2) + 1] = buffer[(i * 2) + 1] / 32768.0;
}
buf_pos += buf_size / 2;
if (buf_pos >= (buf_size_segments / 2)) {
givealbuffer_midi(opl4_midi->buffer_float, buf_size_segments);
buf_pos = 0;
}
} else {
for (i = 0; i < (buf_size / 2); i++) {
opl4_midi->buffer[(i + buf_pos) * 2] = buffer[i * 2] & 0xFFFF; /* Outputs are clamped beforehand. */
opl4_midi->buffer[((i + buf_pos) * 2) + 1] = buffer[(i * 2) + 1] & 0xFFFF; /* Outputs are clamped beforehand. */
}
buf_pos += buf_size / 2;
if (buf_pos >= (buf_size_segments / 2)) {
givealbuffer_midi(opl4_midi->buffer, buf_size_segments);
buf_pos = 0;
}
}
}
}
static void
opl4_midi_poll(void)
{
opl4_midi_t *opl4_midi = opl4_midi_cur;
opl4_midi->midi_pos++;
if (opl4_midi->midi_pos == RENDER_RATE) {
opl4_midi->midi_pos = 0;
thread_set_event(opl4_midi->wait_event);
}
}
void
opl4_midi_msg(uint8_t *val)
{
opl4_midi_t *opl4_midi = opl4_midi_cur;
uint32_t msg = *(uint32_t *) (val);
uint8_t data_byte_1 = msg & 0xFF;
uint8_t data_byte_2 = (msg >> 8) & 0xFF;
uint8_t data_byte_3 = (msg >> 16) & 0xFF;
uint8_t midi_channel = data_byte_1 & 0x0F;
uint8_t midi_command = data_byte_1 >> 4;
switch (midi_command) {
case 0x8: // Note OFF
note_off(data_byte_2 & 0x7F, data_byte_3, &opl4_midi->midi_channel_data[midi_channel], opl4_midi);
break;
case 0x9: // Note ON
note_on(data_byte_2 & 0x7F, data_byte_3, &opl4_midi->midi_channel_data[midi_channel], opl4_midi);
break;
case 0xA: // Key after-touch
break;
case 0xB: // Control change
control_change(midi_channel, data_byte_2, data_byte_3, opl4_midi);
break;
case 0xC: // Program change
program_change(midi_channel, data_byte_2 & 0x7F, opl4_midi);
break;
case 0xD: // Channel after-touch
break;
case 0xE: // Pitch wheel
pitch_wheel(midi_channel, ((data_byte_3 <<= 7) | data_byte_2), opl4_midi);
break;
}
}
void
opl4_midi_sysex(uint8_t *data, unsigned int len)
{
}
void *
opl4_init(const device_t *info)
{
midi_device_t *dev;
extern void al_set_midi(int freq, int buf_size);
dev = malloc(sizeof(midi_device_t));
memset(dev, 0, sizeof(midi_device_t));
dev->play_msg = opl4_midi_msg;
dev->play_sysex = opl4_midi_sysex;
dev->poll = opl4_midi_poll;
al_set_midi(48000, 4800);
opl4_midi_cur = calloc(1, sizeof(opl4_midi_t));
fm_driver_get(FM_YMF278B, &opl4_midi_cur->opl4);
opl4_midi_cur->opl4.write(0x38A, 0x05, opl4_midi_cur->opl4.priv);
opl4_midi_cur->opl4.write(0x389, 0x3, opl4_midi_cur->opl4.priv);
midi_out_init(dev);
opl4_midi_cur->on = true;
opl4_midi_cur->midi_channel_data[9].drum_channel = true;
atomic_init(&opl4_midi_cur->gen_in_progress, 0);
for (uint8_t voice = 0; voice < NR_OF_WAVE_CHANNELS; voice++) {
opl4_midi_cur->voice_data[voice].number = voice;
opl4_midi_cur->voice_data[voice].is_active = false;
opl4_midi_cur->voice_data[voice].activated = 0;
opl4_midi_cur->voice_data[voice].midi_channel = NULL;
opl4_midi_cur->voice_data[voice].note = 0;
opl4_midi_cur->voice_data[voice].velocity = 0;
opl4_midi_cur->voice_data[voice].wave_data = NULL;
opl4_midi_cur->voice_data[voice].level_direct = 0;
opl4_midi_cur->voice_data[voice].reg_f_number = 0;
opl4_midi_cur->voice_data[voice].reg_misc = 0;
opl4_midi_cur->voice_data[voice].reg_lfo_vibrato = 0;
}
opl4_midi_cur->wait_event = thread_create_event();
opl4_midi_cur->thread = thread_create(opl4_midi_thread, NULL);
return dev;
}
void
opl4_close(void *p)
{
if (!p)
return;
opl4_midi_cur->on = false;
thread_set_event(opl4_midi_cur->wait_event);
thread_wait(opl4_midi_cur->thread);
free(opl4_midi_cur);
opl4_midi_cur = NULL;
}
static int
opl4_midi_available(void)
{
return rom_present("roms/sound/yamaha/yrw801.rom");
}
const device_t opl4_midi_device = {
.name = "OPL4-ML Daughterboard",
.internal_name = "opl4-ml",
.flags = 0,
.local = 0,
.init = opl4_init,
.close = opl4_close,
.reset = NULL,
{ .available = opl4_midi_available },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

1042
src/sound/midi_opl4_yrw801.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1657,4 +1657,5 @@ const fm_drv_t nuked_opl_drv = {
&nuked_drv_reset_buffer,
&nuked_drv_set_do_cycles,
NULL,
NULL,
};

View File

@@ -381,6 +381,13 @@ ymfm_drv_set_do_cycles(void *priv, int8_t do_cycles)
drv->set_do_cycles(do_cycles);
}
static void
ymfm_drv_generate(void *priv, int32_t *data, uint32_t num_samples)
{
YMFMChipBase *drv = (YMFMChipBase *) priv;
drv->generate_resampled(data, num_samples);
}
const device_t ym3812_ymfm_device = {
.name = "Yamaha YM3812 OPL2 (YMFM)",
.internal_name = "ym3812_ymfm",
@@ -444,6 +451,7 @@ const fm_drv_t ymfm_drv {
&ymfm_drv_reset_buffer,
&ymfm_drv_set_do_cycles,
NULL,
ymfm_drv_generate,
};
#ifdef __clang__

45
src/sound/yrw801.h Normal file
View File

@@ -0,0 +1,45 @@
/*
* RoboPlay for MSX
* Copyright (C) 2022 by RoboSoft Inc.
*
* yrw801.h
*/
/* Cacodemon345: Added pointer structs from Linux */
#pragma once
#include <stdint.h>
typedef struct
{
uint16_t tone;
int16_t pitch_offset;
uint8_t key_scaling;
int8_t panpot;
uint8_t vibrato;
uint8_t tone_attenuate;
uint8_t volume_factor;
uint8_t reg_lfo_vibrato;
uint8_t reg_attack_decay1;
uint8_t reg_level_decay2;
uint8_t reg_release_correction;
uint8_t reg_tremolo;
} YRW801_WAVE_DATA;
typedef struct
{
uint8_t key_min;
uint8_t key_max;
YRW801_WAVE_DATA wave_data;
} YRW801_REGION_DATA;
typedef struct
{
int count;
const YRW801_REGION_DATA* regions;
} YRW801_REGION_DATA_PTR;
extern const YRW801_REGION_DATA_PTR snd_yrw801_regions[0x81];