summaryrefslogtreecommitdiff
path: root/opl
diff options
context:
space:
mode:
authorNuke.YKT2015-05-29 02:00:45 +0900
committerNuke.YKT2015-05-29 02:00:45 +0900
commit7c377fc88a3fbb7f69b91a15dc414c8965624a89 (patch)
tree5a33e2533b73715a9de9a63ad11b7c14cf6c594b /opl
parent5082f14944442344030d66f6fbdf86a75a1c1c70 (diff)
downloadchocolate-doom-7c377fc88a3fbb7f69b91a15dc414c8965624a89.tar.gz
chocolate-doom-7c377fc88a3fbb7f69b91a15dc414c8965624a89.tar.bz2
chocolate-doom-7c377fc88a3fbb7f69b91a15dc414c8965624a89.zip
Added OPL3 mode support.
Diffstat (limited to 'opl')
-rw-r--r--opl/opl.c82
-rw-r--r--opl/opl.h6
-rw-r--r--opl/opl_sdl.c43
3 files changed, 108 insertions, 23 deletions
diff --git a/opl/opl.c b/opl/opl.c
index 2800f434..92ed3b5b 100644
--- a/opl/opl.c
+++ b/opl/opl.c
@@ -67,6 +67,8 @@ unsigned int opl_sample_rate = 22050;
static int InitDriver(opl_driver_t *_driver, unsigned int port_base)
{
+ int result1, result2;
+
// Initialize the driver.
if (!_driver->init_func(port_base))
@@ -82,7 +84,9 @@ static int InitDriver(opl_driver_t *_driver, unsigned int port_base)
driver = _driver;
init_stage_reg_writes = 1;
- if (!OPL_Detect() || !OPL_Detect())
+ result1 = OPL_Detect();
+ result2 = OPL_Detect();
+ if (!result1 || !result2)
{
printf("OPL_Init: No OPL detected using '%s' driver.\n", _driver->name);
_driver->shutdown_func();
@@ -90,15 +94,11 @@ static int InitDriver(opl_driver_t *_driver, unsigned int port_base)
return 0;
}
- // Initialize all registers.
-
- OPL_InitRegisters();
-
init_stage_reg_writes = 0;
printf("OPL_Init: Using driver '%s'.\n", driver->name);
- return 1;
+ return result2;
}
// Find a driver automatically by trying each in the list.
@@ -106,12 +106,14 @@ static int InitDriver(opl_driver_t *_driver, unsigned int port_base)
static int AutoSelectDriver(unsigned int port_base)
{
int i;
+ int result;
for (i=0; drivers[i] != NULL; ++i)
{
- if (InitDriver(drivers[i], port_base))
+ result = InitDriver(drivers[i], port_base);
+ if (result)
{
- return 1;
+ return result;
}
}
@@ -127,6 +129,7 @@ int OPL_Init(unsigned int port_base)
{
char *driver_name;
int i;
+ int result;
driver_name = getenv("OPL_DRIVER");
@@ -138,9 +141,10 @@ int OPL_Init(unsigned int port_base)
{
if (!strcmp(driver_name, drivers[i]->name))
{
- if (InitDriver(drivers[i], port_base))
+ result = InitDriver(drivers[i], port_base);
+ if (result)
{
- return 1;
+ return result;
}
else
{
@@ -233,7 +237,14 @@ void OPL_WriteRegister(int reg, int value)
{
int i;
- OPL_WritePort(OPL_REGISTER_PORT, reg);
+ if (reg & 0x100)
+ {
+ OPL_WritePort(OPL_REGISTER_PORT_OPL3, reg);
+ }
+ else
+ {
+ OPL_WritePort(OPL_REGISTER_PORT, reg);
+ }
// For timing, read the register port six times after writing the
// register number to cause the appropriate delay
@@ -306,13 +317,22 @@ int OPL_Detect(void)
// Enable interrupts:
OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x80);
- return (result1 & 0xe0) == 0x00
- && (result2 & 0xe0) == 0xc0;
+ if ((result1 & 0xe0) == 0x00 && (result2 & 0xe0) == 0xc0)
+ {
+ result1 = OPL_ReadPort(OPL_REGISTER_PORT);
+ result2 = OPL_ReadPort(OPL_REGISTER_PORT_OPL3);
+ if (result1 == 0x00 && result2 == 0xff)
+ {
+ return 2;
+ }
+ return 1;
+ }
+ return 0;
}
// Initialize registers on startup
-void OPL_InitRegisters(void)
+void OPL_InitRegisters(int opl3)
{
int r;
@@ -349,8 +369,42 @@ void OPL_InitRegisters(void)
// "Allow FM chips to control the waveform of each operator":
OPL_WriteRegister(OPL_REG_WAVEFORM_ENABLE, 0x20);
+ if (opl3)
+ {
+ OPL_WriteRegister(OPL_REG_NEW, 0x01);
+
+ // Initialize level registers
+
+ for (r=OPL_REGS_LEVEL; r <= OPL_REGS_LEVEL + OPL_NUM_OPERATORS; ++r)
+ {
+ OPL_WriteRegister(r | 0x100, 0x3f);
+ }
+
+ // Initialize other registers
+ // These two loops write to registers that actually don't exist,
+ // but this is what Doom does ...
+ // Similarly, the <= is also intenational.
+
+ for (r=OPL_REGS_ATTACK; r <= OPL_REGS_WAVEFORM + OPL_NUM_OPERATORS; ++r)
+ {
+ OPL_WriteRegister(r | 0x100, 0x00);
+ }
+
+ // More registers ...
+
+ for (r=1; r < OPL_REGS_LEVEL; ++r)
+ {
+ OPL_WriteRegister(r | 0x100, 0x00);
+ }
+ }
+
// Keyboard split point on (?)
OPL_WriteRegister(OPL_REG_FM_MODE, 0x40);
+
+ if (opl3)
+ {
+ OPL_WriteRegister(OPL_REG_NEW, 0x01);
+ }
}
//
diff --git a/opl/opl.h b/opl/opl.h
index c4b91b25..c4bc2c80 100644
--- a/opl/opl.h
+++ b/opl/opl.h
@@ -26,7 +26,8 @@ typedef void (*opl_callback_t)(void *data);
typedef enum
{
OPL_REGISTER_PORT = 0,
- OPL_DATA_PORT = 1
+ OPL_DATA_PORT = 1,
+ OPL_REGISTER_PORT_OPL3 = 2
} opl_port_t;
#define OPL_NUM_OPERATORS 21
@@ -37,6 +38,7 @@ typedef enum
#define OPL_REG_TIMER2 0x03
#define OPL_REG_TIMER_CTRL 0x04
#define OPL_REG_FM_MODE 0x08
+#define OPL_REG_NEW 0x105
// Operator registers (21 of each):
@@ -101,7 +103,7 @@ int OPL_Detect(void);
// Initialize all registers, performed on startup.
-void OPL_InitRegisters(void);
+void OPL_InitRegisters(int opl3);
//
// Timer callback functions.
diff --git a/opl/opl_sdl.c b/opl/opl_sdl.c
index 8834ee07..0621995f 100644
--- a/opl/opl_sdl.c
+++ b/opl/opl_sdl.c
@@ -71,6 +71,7 @@ static uint64_t pause_offset;
// OPL software emulator structure.
static Chip opl_chip;
+static int opl_new;
// Temporary mixing buffer used by the mixing callback.
@@ -164,15 +165,30 @@ static void FillBuffer(int16_t *buffer, unsigned int nsamples)
assert(nsamples < mixing_freq);
- Chip__GenerateBlock2(&opl_chip, nsamples, mix_buffer);
+ if (opl_new)
+ {
+ Chip__GenerateBlock3(&opl_chip, nsamples, mix_buffer);
- // Mix into the destination buffer, doubling up into stereo.
+ // Mix into the destination buffer, doubling up into stereo.
- for (i=0; i<nsamples; ++i)
- {
- buffer[i * 2] = (int16_t) mix_buffer[i];
- buffer[i * 2 + 1] = (int16_t) mix_buffer[i];
+ for (i=0; i<nsamples; ++i)
+ {
+ buffer[i * 2] = (int16_t) mix_buffer[i * 2];
+ buffer[i * 2 + 1] = (int16_t) mix_buffer[i * 2 + 1];
+ }
}
+ else
+ {
+ Chip__GenerateBlock2(&opl_chip, nsamples, mix_buffer);
+
+ // Mix into the destination buffer, doubling up into stereo.
+
+ for (i=0; i<nsamples; ++i)
+ {
+ buffer[i * 2] = (int16_t) mix_buffer[i];
+ buffer[i * 2 + 1] = (int16_t) mix_buffer[i];
+ }
+ }
}
// Callback function to fill a new sound buffer:
@@ -351,13 +367,14 @@ static int OPL_SDL_Init(unsigned int port_base)
// Mix buffer:
- mix_buffer = malloc(mixing_freq * sizeof(uint32_t));
+ mix_buffer = malloc(mixing_freq * sizeof(uint32_t) * 2);
// Create the emulator structure:
DBOPL_InitTables();
Chip__Chip(&opl_chip);
Chip__Setup(&opl_chip, mixing_freq);
+ opl_new = 0;
callback_mutex = SDL_CreateMutex();
callback_queue_mutex = SDL_CreateMutex();
@@ -372,6 +389,11 @@ static unsigned int OPL_SDL_PortRead(opl_port_t port)
{
unsigned int result = 0;
+ if (port == OPL_REGISTER_PORT_OPL3)
+ {
+ return 0xff;
+ }
+
if (timer1.enabled && current_time > timer1.expire_time)
{
result |= 0x80; // Either have expired
@@ -439,6 +461,9 @@ static void WriteRegister(unsigned int reg_num, unsigned int value)
break;
+ case OPL_REG_NEW:
+ opl_new = value & 0x01;
+
default:
Chip__WriteReg(&opl_chip, reg_num, value);
break;
@@ -451,6 +476,10 @@ static void OPL_SDL_PortWrite(opl_port_t port, unsigned int value)
{
register_num = value;
}
+ else if (port == OPL_REGISTER_PORT_OPL3)
+ {
+ register_num = value | 0x100;
+ }
else if (port == OPL_DATA_PORT)
{
WriteRegister(register_num, value);