From 7c377fc88a3fbb7f69b91a15dc414c8965624a89 Mon Sep 17 00:00:00 2001 From: Nuke.YKT Date: Fri, 29 May 2015 02:00:45 +0900 Subject: Added OPL3 mode support. --- opl/opl.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++---------- opl/opl.h | 6 +++-- opl/opl_sdl.c | 43 ++++++++++++++++++++++++++----- 3 files changed, 108 insertions(+), 23 deletions(-) (limited to 'opl') 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 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); -- cgit v1.2.3 From 54c2e6d4e513cd74fa35e05f9de840c4a8647b8d Mon Sep 17 00:00:00 2001 From: Nuke.YKT Date: Fri, 29 May 2015 02:12:23 +0900 Subject: One result checking is enought to detect OPL3. --- opl/opl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'opl') diff --git a/opl/opl.c b/opl/opl.c index 92ed3b5b..a6ad4a9d 100644 --- a/opl/opl.c +++ b/opl/opl.c @@ -321,7 +321,7 @@ int OPL_Detect(void) { result1 = OPL_ReadPort(OPL_REGISTER_PORT); result2 = OPL_ReadPort(OPL_REGISTER_PORT_OPL3); - if (result1 == 0x00 && result2 == 0xff) + if (result1 == 0x00) { return 2; } -- cgit v1.2.3 From 1e516e34911d3a95479c303fe26b59f20e618252 Mon Sep 17 00:00:00 2001 From: Nuke.YKT Date: Fri, 29 May 2015 17:30:12 +0900 Subject: Text formatting. --- opl/opl_sdl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'opl') diff --git a/opl/opl_sdl.c b/opl/opl_sdl.c index 0621995f..1334ac07 100644 --- a/opl/opl_sdl.c +++ b/opl/opl_sdl.c @@ -71,7 +71,7 @@ static uint64_t pause_offset; // OPL software emulator structure. static Chip opl_chip; -static int opl_new; +static int opl_opl3mode; // Temporary mixing buffer used by the mixing callback. @@ -165,7 +165,7 @@ static void FillBuffer(int16_t *buffer, unsigned int nsamples) assert(nsamples < mixing_freq); - if (opl_new) + if (opl_opl3mode) { Chip__GenerateBlock3(&opl_chip, nsamples, mix_buffer); @@ -374,7 +374,7 @@ static int OPL_SDL_Init(unsigned int port_base) DBOPL_InitTables(); Chip__Chip(&opl_chip); Chip__Setup(&opl_chip, mixing_freq); - opl_new = 0; + opl_opl3mode = 0; callback_mutex = SDL_CreateMutex(); callback_queue_mutex = SDL_CreateMutex(); @@ -462,7 +462,7 @@ static void WriteRegister(unsigned int reg_num, unsigned int value) break; case OPL_REG_NEW: - opl_new = value & 0x01; + opl_opl3mode = value & 0x01; default: Chip__WriteReg(&opl_chip, reg_num, value); -- cgit v1.2.3