📄 s_vrc7.c
字号:
#include "..\..\interface.h"
#include "s_vrc7.h"
/* #define REALOPL /* Use real OPL2 instead of software emulation */
#ifndef REALOPL
#include "s_fmopl.h"
#endif
#define REGSET 5
static struct
{
const u8 InstTrans[6];
u8 Instrument[16][8];
u8 Chan1x[6], Chan2x[6], Chan3x[6];
u8 Latch;
} VRC7sound = {
{0x00,0x01,0x02,0x08,0x09,0x0A},
#if (REGSET == 1) // Quietust
{ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* The custom instrument */
{0x03,0x01,0x14,0x80,0xC2,0x90,0x43,0x14}, /* Currently working on this one */
{0x13,0x41,0x10,0x0B,0xFF,0xF2,0x32,0xD6},
{0x01,0x01,0x10,0x08,0xF0,0xF4,0x00,0x04}, /* 90% perfect */
{0x21,0x41,0x1B,0x08,0x66,0x80,0x30,0x85},
{0x22,0x21,0x20,0x03,0x75,0x70,0x24,0x14},
{0x02,0x01,0x06,0x00,0xF0,0xF2,0x03,0x95}, /* Do not touch! 98% perfect! */
{0x21,0x41,0x18,0x10,0x93,0xE0,0x21,0x15},
{0x01,0x22,0x13,0x00,0xF0,0x82,0x00,0x15},
{0x05,0x01,0x22,0x00,0x60,0xE3,0xA0,0xF5}, /* 90% perfect */
{0x85,0x01,0x20,0x00,0xD7,0xA2,0x22,0xF5}, /* 90% perfect */
{0x07,0x81,0x2B,0x05,0xF4,0xF2,0x14,0xF4}, /* 95% perfect */
{0x21,0x41,0x20,0x18,0xF3,0x80,0x13,0x95},
{0x01,0x02,0x20,0x00,0xF9,0x92,0x41,0x75}, /* Do not touch! 98% perfect! */
{0x21,0x62,0x0E,0x00,0x84,0x85,0x45,0x15}, /* 90% perfect */
{0x21,0x62,0x0E,0x00,0xA1,0xA0,0x34,0x16} }
#elif (REGSET == 2) // MAME
{ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x01,0x22,0x23,0x00,0xF0,0xF0,0x07,0x18},
{0x23,0x01,0x68,0x00,0xF2,0x74,0x6C,0x89},
{0x13,0x11,0x25,0x03,0xD2,0xB2,0xF4,0xF4},
{0x22,0x21,0x1B,0x00,0xC0,0xA1,0x18,0x08},
{0x22,0x21,0x2C,0x00,0xD2,0xA1,0x18,0x57},
{0x01,0x22,0xBA,0x03,0xF1,0xF1,0x1E,0x04},
{0x21,0x21,0x28,0x00,0xF1,0xF1,0x6B,0x3E},
{0x27,0x21,0x60,0x00,0xF0,0xF0,0x0D,0x0F},
{0x20,0x21,0x2B,0x00,0x85,0xF1,0x6D,0x89},
{0x01,0x21,0xBF,0x08,0x53,0x62,0x5F,0xAE},
{0x23,0x21,0x70,0x0D,0xD4,0xA3,0x4E,0x64},
{0x2B,0x21,0xA4,0x00,0xF6,0x93,0x5C,0x4D},
{0x21,0x23,0xAD,0x00,0x77,0xF1,0x18,0x37},
{0x21,0x21,0x2A,0x00,0xF3,0xE2,0x29,0x46},
{0x21,0x23,0x37,0x00,0xF3,0xE2,0x29,0x46} }
#elif (REGSET == 3) // EMU2413
{ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x61,0x61,0x1E,0x17,0xF0,0x7F,0x07,0x17},
{0x13,0x41,0x0F,0x0D,0xCE,0xD2,0x43,0x13},
{0x03,0x01,0x99,0x04,0xFF,0xC3,0x03,0x73},
{0x21,0x61,0x1B,0x07,0xAF,0x63,0x40,0x28},
{0x22,0x21,0x1E,0x06,0xF0,0x76,0x08,0x28},
{0x31,0x22,0x16,0x05,0x90,0x7F,0x00,0x08},
{0x21,0x61,0x1D,0x07,0x82,0x81,0x10,0x17},
{0x23,0x21,0x2D,0x16,0xC0,0x70,0x07,0x07},
{0x61,0x21,0x1B,0x06,0x64,0x65,0x18,0x18},
{0x61,0x61,0x0C,0x18,0x85,0xA0,0x79,0x07},
{0x23,0x21,0x87,0x11,0xF0,0xA4,0x00,0xF7},
{0x97,0xE1,0x28,0x07,0xFF,0xF3,0x02,0xF8},
{0x61,0x10,0x0C,0x05,0xF2,0xC4,0x40,0xC8},
{0x01,0x01,0x56,0x03,0xB4,0xB2,0x23,0x58},
{0x49,0x4C,0x4C,0x32,0x00,0x00,0x00,0x00} }
#elif (REGSET == 4) // Allegro
{ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x31,0x21,0x15,0x0C,0xDD,0x56,0x13,0x26},
{0x03,0x11,0x54,0x0E,0xF3,0xF1,0x9A,0xE7},
{0x21,0x21,0x8F,0x04,0xF2,0xF2,0x45,0x76},
{0xE1,0xE1,0x46,0x00,0x88,0x65,0x5F,0x1A},
{0x32,0x21,0x90,0x02,0x9B,0x72,0x21,0x17},
{0x21,0x21,0x4B,0x0C,0xAA,0x8F,0x16,0x0A},
{0x21,0x21,0x92,0x06,0x85,0x8F,0x17,0x09},
{0x23,0xB1,0x93,0x0A,0x97,0x55,0x23,0x14},
{0x21,0x21,0x9B,0x01,0x61,0x7F,0x6A,0x0A},
{0x71,0x72,0x57,0x06,0x54,0x7A,0x05,0x05},
{0x21,0x36,0x80,0x04,0xA2,0xF1,0x01,0xD5},
{0x18,0x81,0x62,0x00,0xF3,0xF2,0xE6,0xF6},
{0x31,0x31,0x8B,0x05,0xF4,0xF1,0xE8,0x78},
{0x21,0xA2,0x1E,0x01,0x94,0xC3,0x06,0xA6},
{0x03,0x21,0x87,0x8B,0xF6,0xF3,0x22,0xF8} }
#elif (REGSET == 5) // Some MSX emulator
{ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x33,0x01,0x09,0x0E,0x94,0x90,0x40,0x01},
{0x13,0x41,0x0F,0x0D,0xCD,0xD3,0x43,0x13},
{0x01,0x12,0x1B,0x06,0xFF,0xD2,0x00,0x32},
{0x61,0x61,0x1B,0x07,0xAF,0x63,0x20,0x28},
{0x22,0x21,0x1E,0x06,0xF0,0x76,0x08,0x28},
// {0x66,0x21,0x15,0x00,0x93,0x94,0x20,0xF8},
{0x02,0x01,0x06,0x00,0xF0,0xF2,0x03,0x95}, /* My version sounds better */
{0x21,0x61,0x1C,0x07,0x82,0x81,0x10,0x17},
{0x23,0x21,0x20,0x1F,0xC0,0x71,0x07,0x47},
{0x25,0x31,0x26,0x05,0x64,0x41,0x18,0xF8},
{0x17,0x21,0x28,0x07,0xFF,0x83,0x02,0xF8},
// {0x97,0x81,0x25,0x07,0xCF,0xC8,0x02,0x14},
{0x07,0x81,0x2B,0x05,0xF4,0xF2,0x14,0xF4}, /* My version sounds better */
{0x21,0x21,0x54,0x0F,0x80,0x7F,0x07,0x07},
// {0x01,0x01,0x56,0x03,0xD3,0xB2,0x43,0x58},
{0x01,0x02,0x20,0x00,0xF9,0x92,0x41,0x75}, /* My version sounds better */
{0x31,0x21,0x0C,0x03,0x82,0xC0,0x40,0x07},
{0x21,0x01,0x0C,0x03,0xD4,0xD3,0x40,0x84} }
#endif
};
#ifndef REALOPL
static FM_OPL *OPL = NULL;
#endif
static void OPL2_setreg (u8 reg,u8 value)
{
#ifdef REALOPL
_outp(0x388,reg);
_outp(0x389,value);
#else
if (OPL)
{
OPLWrite(OPL,0x388,reg);
OPLWrite(OPL,0x389,value);
}
#endif
}
static void VRC7_LoadInstrument(u8 Chan)
{
u8 x = VRC7sound.InstTrans[Chan];
u8 y = (VRC7sound.Chan3x[Chan] >> 4) & 0xF;
OPL2_setreg((u8)(0x20+x),(u8)(VRC7sound.Instrument[y][0]));
OPL2_setreg((u8)(0x23+x),(u8)(VRC7sound.Instrument[y][1]));
OPL2_setreg((u8)(0x40+x),(u8)(VRC7sound.Instrument[y][2]));
/* OPL2_setreg((u8)(0x43+x),(u8)((VRC7sound.Instrument[y][3] & 0xC0) | ((VRC7sound.Chan3x[Chan] << 0) & 0x3C))); /* really loud */
/* OPL2_setreg((u8)(0x43+x),(u8)((VRC7sound.Instrument[y][3] & 0xC0) | ((VRC7sound.Chan3x[Chan] << 1) & 0x3C))); /* loud */
OPL2_setreg((u8)(0x43+x),(u8)((VRC7sound.Instrument[y][3] & 0xC0) | ((VRC7sound.Chan3x[Chan] << 2) & 0x3C))); /* quiet */
OPL2_setreg((u8)(0xe0+x),(u8)((VRC7sound.Instrument[y][3] >> 3) & 0x01));
OPL2_setreg((u8)(0xe3+x),(u8)((VRC7sound.Instrument[y][3] >> 4) & 0x01));
OPL2_setreg((u8)(0xC0+Chan),(u8)((VRC7sound.Instrument[y][3] << 1) & 0x0E));
OPL2_setreg((u8)(0x60+x),(u8)(VRC7sound.Instrument[y][4]));
OPL2_setreg((u8)(0x63+x),(u8)(VRC7sound.Instrument[y][5]));
OPL2_setreg((u8)(0x80+x),(u8)(VRC7sound.Instrument[y][6]));
OPL2_setreg((u8)(0x83+x),(u8)(VRC7sound.Instrument[y][7]));
}
void VRC7sound_Init (void)
{
u8 x;
#ifdef REALOPL
int i;
for (i = 0; i < 256; i++)
{
_outp(0x388,i);
_outp(0x389,0);
}
#else
if (OPL)
{
MessageBox(NULL,"Error! Attempted to initialize more than one OPL2!","NESten",MB_OK | MB_ICONERROR);
return;
}
OPL = OPLCreate(3579545,44100);
if (!OPL)
{
MessageBox(NULL,"Unable to create OPL2!","NESten",MB_OK | MB_ICONERROR);
return;
}
#endif
#ifdef REALOPL
for (x = 0x20; x <= 0xFF; x++)
OPL2_setreg(x,0);
#else
OPLResetChip(OPL);
#endif
OPL2_setreg(0x01,0x20); /* Allow select waveform */
OPL2_setreg(0x08,0x00); /* Clear CSM/keyboard split */
OPL2_setreg(0xBD,0xC0); /* Set tremolo/vibrato depth */
for (x = 0; x < 6; x++)
VRC7sound.Chan1x[x] = VRC7sound.Chan2x[x] = VRC7sound.Chan3x[x] = 0;
VRC7sound.Latch = 0;
}
void VRC7sound_Write (int Where, int What)
{
u8 x = VRC7sound.Latch & 0x0F, y;
switch (Where & 0xF030)
{
case 0x9010: VRC7sound.Latch = What; break;
case 0x9030: switch ((VRC7sound.Latch & 0xF0) >> 4)
{
case 0: if (x & 0x08) break;
VRC7sound.Instrument[0][x] = What;
for (y = 0; y < 6; y++)
if (!(VRC7sound.Chan3x[y] & 0xF0))
VRC7_LoadInstrument(y);
break;
case 1: if (x > 5) break;
VRC7sound.Chan1x[x] = What;
OPL2_setreg((u8)(0xA0 + x),(u8)((VRC7sound.Chan1x[x] << 1) & 0xFE));
OPL2_setreg((u8)(0xB0 + x),(u8)(((VRC7sound.Chan1x[x] >> 7) & 0x01) | ((VRC7sound.Chan2x[x] << 1) & 0x3E)));
break;
case 2: if (x > 5) break;
VRC7sound.Chan2x[x] = What;
OPL2_setreg((u8)(0xB0 + x),(u8)(((VRC7sound.Chan1x[x] >> 7) & 0x01) | ((VRC7sound.Chan2x[x] << 1) & 0x3E)));
break;
case 3: if (x > 5) break;
VRC7sound.Chan3x[x] = What;
VRC7_LoadInstrument(x); break;
} break;
}
}
void VRC7sound_Get (s16 *Target, int Size)
{
#ifndef REALOPL
YM3812UpdateOne(OPL,Target,Size);
#endif
}
int VRC7sound_SaveMI (Ar128 MI, int x)
{
u8 i;
MI[x++] = VRC7sound.Latch;
for (i = 0; i < 8; i++) MI[x++] = VRC7sound.Instrument[0][i];
for (i = 0; i < 6; i++) MI[x++] = VRC7sound.Chan1x[i];
for (i = 0; i < 6; i++) MI[x++] = VRC7sound.Chan2x[i];
for (i = 0; i < 6; i++) MI[x++] = VRC7sound.Chan3x[i];
return x;
}
int VRC7sound_LoadMI (const Ar128 MI, int x)
{
u8 i;
VRC7sound.Latch = MI[x++];
for (i = 0; i < 8; i++) VRC7sound.Instrument[0][i] = MI[x++];
for (i = 0; i < 6; i++) VRC7sound.Chan1x[i] = MI[x++];
for (i = 0; i < 6; i++) VRC7sound.Chan2x[i] = MI[x++];
for (i = 0; i < 6; i++) VRC7sound.Chan3x[i] = MI[x++];
for (x = 0; x < 6; x++){VRC7_LoadInstrument((u8)x);
VRC7sound_Write((u8)(0x10 + x),VRC7sound.Chan1x[x]);}
return x;
}
void VRC7sound_Destroy (void)
{
#ifndef REALOPL
if (OPL)
{
OPLDestroy(OPL);
OPL = NULL;
}
else MessageBox(NULL,"Error! Attempted to destroy nonexistant OPL2!","NESten",MB_OK | MB_ICONERROR);
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -