Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into upstream-merge
Browse files Browse the repository at this point in the history
  • Loading branch information
MrAlaux committed Sep 21, 2024
2 parents bc7f6d5 + 5c952ca commit 04ae706
Show file tree
Hide file tree
Showing 23 changed files with 852 additions and 504 deletions.
142 changes: 69 additions & 73 deletions opl/opl.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ static opl_driver_t *drivers[] =

static opl_driver_t *driver = NULL;

unsigned int opl_sample_rate = 22050;

//
// Init/shutdown code.
//
Expand All @@ -42,11 +40,11 @@ unsigned int opl_sample_rate = 22050;
// true if an OPL is detected.

static opl_init_result_t InitDriver(opl_driver_t *_driver,
unsigned int port_base)
unsigned int port_base, int num_chips)
{
// Initialize the driver.

if (!_driver->init_func(port_base))
if (!_driver->init_func(port_base, num_chips))
{
return OPL_INIT_NONE;
}
Expand All @@ -58,21 +56,21 @@ static opl_init_result_t InitDriver(opl_driver_t *_driver,

driver = _driver;

printf("OPL_Init: Using driver '%s'.\n", driver->name);
printf("OPL_Init: Using driver '%s' with %d chip(s).\n", driver->name, num_opl_chips);

return OPL_INIT_OPL3;
}

// Find a driver automatically by trying each in the list.

static opl_init_result_t AutoSelectDriver(unsigned int port_base)
static opl_init_result_t AutoSelectDriver(unsigned int port_base, int num_chips)
{
int i;
opl_init_result_t result;

for (i=0; drivers[i] != NULL; ++i)
{
result = InitDriver(drivers[i], port_base);
result = InitDriver(drivers[i], port_base, num_chips);
if (result != OPL_INIT_NONE)
{
return result;
Expand All @@ -87,7 +85,7 @@ static opl_init_result_t AutoSelectDriver(unsigned int port_base)
// Initialize the OPL library. Return value indicates type of OPL chip
// detected, if any.

opl_init_result_t OPL_Init(unsigned int port_base)
opl_init_result_t OPL_Init(unsigned int port_base, int num_chips)
{
char *driver_name;
int i;
Expand All @@ -103,7 +101,7 @@ opl_init_result_t OPL_Init(unsigned int port_base)
{
if (!strcmp(driver_name, drivers[i]->name))
{
result = InitDriver(drivers[i], port_base);
result = InitDriver(drivers[i], port_base, num_chips);
if (result)
{
return result;
Expand All @@ -123,7 +121,7 @@ opl_init_result_t OPL_Init(unsigned int port_base)
}
else
{
return AutoSelectDriver(port_base);
return AutoSelectDriver(port_base, num_chips);
}
}

Expand All @@ -140,24 +138,19 @@ void OPL_Shutdown(void)

// Set the sample rate used for software OPL emulation.

void OPL_SetSampleRate(unsigned int rate)
{
opl_sample_rate = rate;
}

void OPL_WritePort(opl_port_t port, unsigned int value)
void OPL_WritePort(int chip, opl_port_t port, unsigned int value)
{
if (driver != NULL)
{
#ifdef OPL_DEBUG_TRACE
printf("OPL_write: %i, %x\n", port, value);
fflush(stdout);
#endif
driver->write_port_func(port, value);
driver->write_port_func(chip, port, value);
}
}

unsigned int OPL_ReadPort(opl_port_t port)
unsigned int OPL_ReadPort(int chip, opl_port_t port)
{
if (driver != NULL)
{
Expand All @@ -168,7 +161,7 @@ unsigned int OPL_ReadPort(opl_port_t port)
fflush(stdout);
#endif

result = driver->read_port_func(port);
result = driver->read_port_func(chip, port);

#ifdef OPL_DEBUG_TRACE
printf("OPL_read: %i -> %x\n", port, result);
Expand All @@ -188,93 +181,58 @@ unsigned int OPL_ReadPort(opl_port_t port)
// (register write, etc).
//

unsigned int OPL_ReadStatus(void)
unsigned int OPL_ReadStatus(int chip)
{
return OPL_ReadPort(OPL_REGISTER_PORT);
return OPL_ReadPort(chip, OPL_REGISTER_PORT);
}

// Write an OPL register value

void OPL_WriteRegister(int reg, int value)
void OPL_WriteRegister(int chip, int reg, int value)
{
int i;

if (reg & 0x100)
{
OPL_WritePort(OPL_REGISTER_PORT_OPL3, reg);
OPL_WritePort(chip, OPL_REGISTER_PORT_OPL3, reg);
}
else
{
OPL_WritePort(OPL_REGISTER_PORT, reg);
OPL_WritePort(chip, OPL_REGISTER_PORT, reg);
}

// For timing, read the register port six times after writing the
// register number to cause the appropriate delay

for (i=0; i<6; ++i)
{
OPL_ReadPort(OPL_DATA_PORT);
OPL_ReadPort(chip, OPL_DATA_PORT);
}

OPL_WritePort(OPL_DATA_PORT, value);
OPL_WritePort(chip, OPL_DATA_PORT, value);

// Read the register port 24 times after writing the value to
// cause the appropriate delay

for (i=0; i<24; ++i)
{
OPL_ReadStatus();
OPL_ReadStatus(chip);
}
}

// Initialize registers on startup

void OPL_InitRegisters(int opl3)
{
int r;

// Initialize level registers

for (r=OPL_REGS_LEVEL; r <= OPL_REGS_LEVEL + OPL_NUM_OPERATORS; ++r)
for (int c = 0; c < num_opl_chips; ++c)
{
OPL_WriteRegister(r, 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, 0x00);
}

// More registers ...

for (r=1; r < OPL_REGS_LEVEL; ++r)
{
OPL_WriteRegister(r, 0x00);
}

// Re-initialize the low registers:

// Reset both timers and enable interrupts:
OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x60);
OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x80);

// "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);
int r;

// Initialize level registers

for (r=OPL_REGS_LEVEL; r <= OPL_REGS_LEVEL + OPL_NUM_OPERATORS; ++r)
{
OPL_WriteRegister(r | 0x100, 0x3f);
OPL_WriteRegister(c, r, 0x3f);
}

// Initialize other registers
Expand All @@ -284,23 +242,61 @@ void OPL_InitRegisters(int opl3)

for (r=OPL_REGS_ATTACK; r <= OPL_REGS_WAVEFORM + OPL_NUM_OPERATORS; ++r)
{
OPL_WriteRegister(r | 0x100, 0x00);
OPL_WriteRegister(c, r, 0x00);
}

// More registers ...

for (r=1; r < OPL_REGS_LEVEL; ++r)
{
OPL_WriteRegister(r | 0x100, 0x00);
OPL_WriteRegister(c, r, 0x00);
}
}

// Keyboard split point on (?)
OPL_WriteRegister(OPL_REG_FM_MODE, 0x40);
// Re-initialize the low registers:

if (opl3)
{
OPL_WriteRegister(OPL_REG_NEW, 0x01);
// Reset both timers and enable interrupts:
OPL_WriteRegister(c, OPL_REG_TIMER_CTRL, 0x60);
OPL_WriteRegister(c, OPL_REG_TIMER_CTRL, 0x80);

// "Allow FM chips to control the waveform of each operator":
OPL_WriteRegister(c, OPL_REG_WAVEFORM_ENABLE, 0x20);

if (opl3)
{
OPL_WriteRegister(c, OPL_REG_NEW, 0x01);

// Initialize level registers

for (r=OPL_REGS_LEVEL; r <= OPL_REGS_LEVEL + OPL_NUM_OPERATORS; ++r)
{
OPL_WriteRegister(c, 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(c, r | 0x100, 0x00);
}

// More registers ...

for (r=1; r < OPL_REGS_LEVEL; ++r)
{
OPL_WriteRegister(c, r | 0x100, 0x00);
}
}

// Keyboard split point on (?)
OPL_WriteRegister(c, OPL_REG_FM_MODE, 0x40);

if (opl3)
{
OPL_WriteRegister(c, OPL_REG_NEW, 0x01);
}
}
}

Expand Down
19 changes: 10 additions & 9 deletions opl/opl.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ typedef enum
OPL_REGISTER_PORT_OPL3 = 2
} opl_port_t;

#define OPL_SAMPLE_RATE 49716
#define OPL_MAX_CHIPS 6

#define OPL_NUM_OPERATORS 21
#define OPL_NUM_VOICES 9

Expand Down Expand Up @@ -68,41 +71,39 @@ typedef enum
#define OPL_MS ((uint64_t) 1000)
#define OPL_US ((uint64_t) 1)

extern int num_opl_chips;

//
// Low-level functions.
//

// Initialize the OPL subsystem.

opl_init_result_t OPL_Init(unsigned int port_base);
opl_init_result_t OPL_Init(unsigned int port_base, int num_chips);

// Shut down the OPL subsystem.

void OPL_Shutdown(void);

// Set the sample rate used for software emulation.

void OPL_SetSampleRate(unsigned int rate);

// Write to one of the OPL I/O ports:

void OPL_WritePort(opl_port_t port, unsigned int value);
void OPL_WritePort(int chip, opl_port_t port, unsigned int value);

// Read from one of the OPL I/O ports:

unsigned int OPL_ReadPort(opl_port_t port);
unsigned int OPL_ReadPort(int chip, opl_port_t port);

//
// Higher-level functions.
//

// Read the cuurrent status byte of the OPL chip.

unsigned int OPL_ReadStatus(void);
unsigned int OPL_ReadStatus(int chip);

// Write to an OPL register.

void OPL_WriteRegister(int reg, int value);
void OPL_WriteRegister(int chip, int reg, int value);

// Initialize all registers, performed on startup.

Expand Down
8 changes: 3 additions & 5 deletions opl/opl_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@

#include "opl.h"

typedef int (*opl_init_func)(unsigned int port_base);
typedef int (*opl_init_func)(unsigned int port_base, int num_chips);
typedef void (*opl_shutdown_func)(void);
typedef unsigned int (*opl_read_port_func)(opl_port_t port);
typedef void (*opl_write_port_func)(opl_port_t port, unsigned int value);
typedef unsigned int (*opl_read_port_func)(int chip, opl_port_t port);
typedef void (*opl_write_port_func)(int chip, opl_port_t port, unsigned int value);
typedef void (*opl_set_callback_func)(uint64_t us,
opl_callback_t callback,
void *data);
Expand All @@ -48,7 +48,5 @@ extern opl_driver_t opl_sdl_driver;

// Sample rate to use when doing software emulation.

extern unsigned int opl_sample_rate;

#endif /* #ifndef OPL_INTERNAL_H */

Loading

0 comments on commit 04ae706

Please sign in to comment.