mirror of
https://github.com/fabiangreffrath/woof.git
synced 2025-09-26 06:20:16 -04:00
OPL3 Improvements (#1907)
* Use correct OPL3 channel polarity by default * Support multiple OPL3 chips * Use native OPL sample rate and allow OpenAL to resample it * Bind DMX OPL stereo correction to a config variable; default to vanilla * Consolidate num_opl_chips variables; remove menu item Use BETWEEN macro for mix clamping * Disable upper register banks when dmx is in OPL2 mode
This commit is contained in:
parent
a4eb56e4ce
commit
3bee945f2f
69
opl/opl.c
69
opl/opl.c
@ -32,7 +32,7 @@ static opl_driver_t *drivers[] =
|
||||
|
||||
static opl_driver_t *driver = NULL;
|
||||
|
||||
unsigned int opl_sample_rate = 22050;
|
||||
unsigned int opl_sample_rate = OPL_SAMPLE_RATE;
|
||||
|
||||
//
|
||||
// Init/shutdown code.
|
||||
@ -42,11 +42,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;
|
||||
}
|
||||
@ -58,21 +58,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;
|
||||
@ -87,7 +87,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;
|
||||
@ -103,7 +103,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;
|
||||
@ -123,7 +123,7 @@ opl_init_result_t OPL_Init(unsigned int port_base)
|
||||
}
|
||||
else
|
||||
{
|
||||
return AutoSelectDriver(port_base);
|
||||
return AutoSelectDriver(port_base, num_chips);
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ 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)
|
||||
{
|
||||
@ -153,11 +153,11 @@ void OPL_WritePort(opl_port_t port, unsigned int value)
|
||||
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)
|
||||
{
|
||||
@ -168,7 +168,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);
|
||||
@ -188,24 +188,24 @@ 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
|
||||
@ -213,23 +213,25 @@ void OPL_WriteRegister(int reg, int value)
|
||||
|
||||
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)
|
||||
{
|
||||
for (int c = 0; c < num_opl_chips; ++c)
|
||||
{
|
||||
int r;
|
||||
|
||||
@ -237,7 +239,7 @@ void OPL_InitRegisters(int opl3)
|
||||
|
||||
for (r=OPL_REGS_LEVEL; r <= OPL_REGS_LEVEL + OPL_NUM_OPERATORS; ++r)
|
||||
{
|
||||
OPL_WriteRegister(r, 0x3f);
|
||||
OPL_WriteRegister(c, r, 0x3f);
|
||||
}
|
||||
|
||||
// Initialize other registers
|
||||
@ -247,34 +249,34 @@ void OPL_InitRegisters(int opl3)
|
||||
|
||||
for (r=OPL_REGS_ATTACK; r <= OPL_REGS_WAVEFORM + OPL_NUM_OPERATORS; ++r)
|
||||
{
|
||||
OPL_WriteRegister(r, 0x00);
|
||||
OPL_WriteRegister(c, r, 0x00);
|
||||
}
|
||||
|
||||
// More registers ...
|
||||
|
||||
for (r=1; r < OPL_REGS_LEVEL; ++r)
|
||||
{
|
||||
OPL_WriteRegister(r, 0x00);
|
||||
OPL_WriteRegister(c, 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);
|
||||
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(OPL_REG_WAVEFORM_ENABLE, 0x20);
|
||||
OPL_WriteRegister(c, OPL_REG_WAVEFORM_ENABLE, 0x20);
|
||||
|
||||
if (opl3)
|
||||
{
|
||||
OPL_WriteRegister(OPL_REG_NEW, 0x01);
|
||||
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(r | 0x100, 0x3f);
|
||||
OPL_WriteRegister(c, r | 0x100, 0x3f);
|
||||
}
|
||||
|
||||
// Initialize other registers
|
||||
@ -284,23 +286,24 @@ 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 | 0x100, 0x00);
|
||||
}
|
||||
|
||||
// More registers ...
|
||||
|
||||
for (r=1; r < OPL_REGS_LEVEL; ++r)
|
||||
{
|
||||
OPL_WriteRegister(r | 0x100, 0x00);
|
||||
OPL_WriteRegister(c, r | 0x100, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
// Keyboard split point on (?)
|
||||
OPL_WriteRegister(OPL_REG_FM_MODE, 0x40);
|
||||
OPL_WriteRegister(c, OPL_REG_FM_MODE, 0x40);
|
||||
|
||||
if (opl3)
|
||||
{
|
||||
OPL_WriteRegister(OPL_REG_NEW, 0x01);
|
||||
OPL_WriteRegister(c, OPL_REG_NEW, 0x01);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
15
opl/opl.h
15
opl/opl.h
@ -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
|
||||
|
||||
@ -68,13 +71,15 @@ 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.
|
||||
|
||||
@ -86,11 +91,11 @@ 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.
|
||||
@ -98,11 +103,11 @@ unsigned int OPL_ReadPort(opl_port_t port);
|
||||
|
||||
// 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.
|
||||
|
||||
|
@ -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);
|
||||
|
@ -50,7 +50,7 @@ static uint64_t pause_offset;
|
||||
|
||||
// OPL software emulator structure.
|
||||
|
||||
static opl3_chip opl_chip;
|
||||
static opl3_chip opl_chips[OPL_MAX_CHIPS];
|
||||
static int opl_opl3mode;
|
||||
|
||||
// Register number that was written.
|
||||
@ -137,7 +137,23 @@ int OPL_FillBuffer(byte *buffer, int buffer_samples)
|
||||
}
|
||||
|
||||
// Add emulator output to buffer.
|
||||
OPL3_GenerateStream(&opl_chip, (Bit16s *)(buffer + filled * 4), nsamples);
|
||||
Bit16s *cursor = (Bit16s *)(buffer + filled * 4);
|
||||
for (int s = 0; s < nsamples; ++s)
|
||||
{
|
||||
Bit32s mix[2] = {0, 0};
|
||||
for (int c = 0; c < num_opl_chips; ++c)
|
||||
{
|
||||
Bit16s sample[2];
|
||||
OPL3_GenerateResampled(&opl_chips[c], sample);
|
||||
mix[0] += sample[0];
|
||||
mix[1] += sample[1];
|
||||
}
|
||||
|
||||
cursor[0] = BETWEEN(-32768, 32767, mix[0]);
|
||||
cursor[1] = BETWEEN(-32768, 32767, mix[1]);
|
||||
cursor += 2;
|
||||
}
|
||||
//OPL3_GenerateStream(&opl_chip, (Bit16s *)(buffer + filled * 4), nsamples);
|
||||
filled += nsamples;
|
||||
|
||||
// Invoke callbacks for this point in time.
|
||||
@ -161,7 +177,7 @@ static void OPL_SDL_Shutdown(void)
|
||||
*/
|
||||
}
|
||||
|
||||
static int OPL_SDL_Init(unsigned int port_base)
|
||||
static int OPL_SDL_Init(unsigned int port_base, int num_chips)
|
||||
{
|
||||
opl_sdl_paused = 0;
|
||||
pause_offset = 0;
|
||||
@ -179,13 +195,14 @@ static int OPL_SDL_Init(unsigned int port_base)
|
||||
|
||||
// Create the emulator structure:
|
||||
|
||||
OPL3_Reset(&opl_chip, mixing_freq);
|
||||
for (int c = 0; c < num_opl_chips; ++c)
|
||||
OPL3_Reset(&opl_chips[c], mixing_freq);
|
||||
opl_opl3mode = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static unsigned int OPL_SDL_PortRead(opl_port_t port)
|
||||
static unsigned int OPL_SDL_PortRead(int chip, opl_port_t port)
|
||||
{
|
||||
unsigned int result = 0;
|
||||
|
||||
@ -194,6 +211,9 @@ static unsigned int OPL_SDL_PortRead(opl_port_t port)
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
if (chip > 0)
|
||||
return result;
|
||||
|
||||
if (timer1.enabled && current_time > timer1.expire_time)
|
||||
{
|
||||
result |= 0x80; // Either have expired
|
||||
@ -224,18 +244,26 @@ static void OPLTimer_CalculateEndTime(opl_timer_t *timer)
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteRegister(unsigned int reg_num, unsigned int value)
|
||||
static void WriteRegister(int chip, unsigned int reg_num, unsigned int value)
|
||||
{
|
||||
switch (reg_num)
|
||||
{
|
||||
case OPL_REG_TIMER1:
|
||||
// Only allow timers on the first chip
|
||||
if (chip == 0)
|
||||
{
|
||||
timer1.value = value;
|
||||
OPLTimer_CalculateEndTime(&timer1);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPL_REG_TIMER2:
|
||||
// Only allow timers on the first chip
|
||||
if (chip == 0)
|
||||
{
|
||||
timer2.value = value;
|
||||
OPLTimer_CalculateEndTime(&timer2);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPL_REG_TIMER_CTRL:
|
||||
@ -258,19 +286,25 @@ static void WriteRegister(unsigned int reg_num, unsigned int value)
|
||||
OPLTimer_CalculateEndTime(&timer2);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case OPL_REG_NEW:
|
||||
// Keep all chips synchronized with the first chip's opl3 mode
|
||||
if (chip == 0)
|
||||
{
|
||||
for (int c = 0; c < num_opl_chips; ++c)
|
||||
OPL3_WriteRegBuffered(&opl_chips[c], reg_num, value);
|
||||
opl_opl3mode = value & 0x01;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
OPL3_WriteRegBuffered(&opl_chip, reg_num, value);
|
||||
OPL3_WriteRegBuffered(&opl_chips[chip], reg_num, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void OPL_SDL_PortWrite(opl_port_t port, unsigned int value)
|
||||
static void OPL_SDL_PortWrite(int chip, opl_port_t port, unsigned int value)
|
||||
{
|
||||
if (port == OPL_REGISTER_PORT)
|
||||
{
|
||||
@ -282,7 +316,7 @@ static void OPL_SDL_PortWrite(opl_port_t port, unsigned int value)
|
||||
}
|
||||
else if (port == OPL_DATA_PORT)
|
||||
{
|
||||
WriteRegister(register_num, value);
|
||||
WriteRegister(chip, register_num, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "i_printf.h"
|
||||
#include "i_sound.h"
|
||||
#include "m_array.h"
|
||||
#include "m_config.h"
|
||||
#include "m_io.h"
|
||||
#include "m_swap.h"
|
||||
#include "memio.h"
|
||||
@ -327,9 +328,9 @@ static char (*percussion_names)[32];
|
||||
|
||||
// Voices:
|
||||
|
||||
static opl_voice_t voices[OPL_NUM_VOICES * 2];
|
||||
static opl_voice_t *voice_free_list[OPL_NUM_VOICES * 2];
|
||||
static opl_voice_t *voice_alloced_list[OPL_NUM_VOICES * 2];
|
||||
static opl_voice_t voices[OPL_NUM_VOICES * 2 * OPL_MAX_CHIPS];
|
||||
static opl_voice_t *voice_free_list[OPL_NUM_VOICES * 2 * OPL_MAX_CHIPS];
|
||||
static opl_voice_t *voice_alloced_list[OPL_NUM_VOICES * 2 * OPL_MAX_CHIPS];
|
||||
static int voice_free_num;
|
||||
static int voice_alloced_num;
|
||||
static int opl_opl3mode;
|
||||
@ -361,6 +362,7 @@ static unsigned int last_perc_count;
|
||||
|
||||
static char *snd_dmxoption = "-opl3"; // [crispy] default to OPL3 emulation
|
||||
static int opl_io_port = 0x388;
|
||||
int num_opl_chips = 1;
|
||||
|
||||
// If true, OPL sound channels are reversed to their correct arrangement
|
||||
// (as intended by the MIDI standard) rather than the backwards one
|
||||
@ -468,7 +470,7 @@ static void ReleaseVoice(int index)
|
||||
|
||||
// Load data to the specified operator
|
||||
|
||||
static void LoadOperatorData(int operator, genmidi_op_t * data,
|
||||
static void LoadOperatorData(int chip, int operator, genmidi_op_t * data,
|
||||
boolean max_level, unsigned int *volume)
|
||||
{
|
||||
int level;
|
||||
@ -489,11 +491,11 @@ static void LoadOperatorData(int operator, genmidi_op_t * data,
|
||||
|
||||
*volume = level;
|
||||
|
||||
OPL_WriteRegister(OPL_REGS_LEVEL + operator, level);
|
||||
OPL_WriteRegister(OPL_REGS_TREMOLO + operator, data->tremolo);
|
||||
OPL_WriteRegister(OPL_REGS_ATTACK + operator, data->attack);
|
||||
OPL_WriteRegister(OPL_REGS_SUSTAIN + operator, data->sustain);
|
||||
OPL_WriteRegister(OPL_REGS_WAVEFORM + operator, data->waveform);
|
||||
OPL_WriteRegister(chip, OPL_REGS_LEVEL + operator, level);
|
||||
OPL_WriteRegister(chip, OPL_REGS_TREMOLO + operator, data->tremolo);
|
||||
OPL_WriteRegister(chip, OPL_REGS_ATTACK + operator, data->attack);
|
||||
OPL_WriteRegister(chip, OPL_REGS_SUSTAIN + operator, data->sustain);
|
||||
OPL_WriteRegister(chip, OPL_REGS_WAVEFORM + operator, data->waveform);
|
||||
}
|
||||
|
||||
// Set the instrument for a particular voice.
|
||||
@ -526,16 +528,16 @@ static void SetVoiceInstrument(opl_voice_t *voice, genmidi_instr_t *instr,
|
||||
// is set in SetVoiceVolume (below). If we are not using
|
||||
// modulating mode, we must set both to minimum volume.
|
||||
|
||||
LoadOperatorData(voice->op2 | voice->array, &data->carrier, true,
|
||||
LoadOperatorData(voice->array >> 9, voice->op2 | (voice->array & 0x100), &data->carrier, true,
|
||||
&voice->car_volume);
|
||||
LoadOperatorData(voice->op1 | voice->array, &data->modulator, !modulating,
|
||||
LoadOperatorData(voice->array >> 9, voice->op1 | (voice->array & 0x100), &data->modulator, !modulating,
|
||||
&voice->mod_volume);
|
||||
|
||||
// Set feedback register that control the connection between the
|
||||
// two operators. Turn on bits in the upper nybble; I think this
|
||||
// is for OPL3, where it turns on channel A/B.
|
||||
|
||||
OPL_WriteRegister((OPL_REGS_FEEDBACK + voice->index) | voice->array,
|
||||
OPL_WriteRegister(voice->array >> 9, (OPL_REGS_FEEDBACK + voice->index) | (voice->array & 0x100),
|
||||
data->feedback | voice->reg_pan);
|
||||
|
||||
// Calculate voice priority.
|
||||
@ -571,7 +573,7 @@ static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume)
|
||||
{
|
||||
voice->car_volume = car_volume | (voice->car_volume & 0xc0);
|
||||
|
||||
OPL_WriteRegister((OPL_REGS_LEVEL + voice->op2) | voice->array,
|
||||
OPL_WriteRegister(voice->array >> 9, (OPL_REGS_LEVEL + voice->op2) | (voice->array & 0x100),
|
||||
voice->car_volume);
|
||||
|
||||
// If we are using non-modulated feedback mode, we must set the
|
||||
@ -591,7 +593,7 @@ static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume)
|
||||
if (mod_volume != voice->mod_volume)
|
||||
{
|
||||
voice->mod_volume = mod_volume;
|
||||
OPL_WriteRegister((OPL_REGS_LEVEL + voice->op1) | voice->array,
|
||||
OPL_WriteRegister(voice->array >> 9, (OPL_REGS_LEVEL + voice->op1) | (voice->array & 0x100),
|
||||
mod_volume | (opl_voice->modulator.scale & 0xc0));
|
||||
}
|
||||
}
|
||||
@ -605,7 +607,7 @@ static void SetVoicePan(opl_voice_t *voice, unsigned int pan)
|
||||
voice->reg_pan = pan;
|
||||
opl_voice = &voice->current_instr->voices[voice->current_instr_voice];
|
||||
|
||||
OPL_WriteRegister((OPL_REGS_FEEDBACK + voice->index) | voice->array,
|
||||
OPL_WriteRegister(voice->array >> 9, (OPL_REGS_FEEDBACK + voice->index) | (voice->array & 0x100),
|
||||
opl_voice->feedback | pan);
|
||||
}
|
||||
|
||||
@ -627,7 +629,7 @@ static void InitVoices(void)
|
||||
voices[i].index = i % OPL_NUM_VOICES;
|
||||
voices[i].op1 = voice_operators[0][i % OPL_NUM_VOICES];
|
||||
voices[i].op2 = voice_operators[1][i % OPL_NUM_VOICES];
|
||||
voices[i].array = (i / OPL_NUM_VOICES) << 8;
|
||||
voices[i].array = (i / OPL_NUM_VOICES) << (opl_opl3mode ? 8 : 9);
|
||||
voices[i].current_instr = NULL;
|
||||
|
||||
// Add this voice to the freelist.
|
||||
@ -666,7 +668,7 @@ static void I_OPL_SetMusicVolume(int volume)
|
||||
|
||||
static void VoiceKeyOff(opl_voice_t *voice)
|
||||
{
|
||||
OPL_WriteRegister((OPL_REGS_FREQ_2 + voice->index) | voice->array,
|
||||
OPL_WriteRegister(voice->array >> 9, (OPL_REGS_FREQ_2 + voice->index) | (voice->array & 0x100),
|
||||
voice->freq >> 8);
|
||||
}
|
||||
|
||||
@ -883,9 +885,9 @@ static void UpdateVoiceFrequency(opl_voice_t *voice)
|
||||
|
||||
if (voice->freq != freq)
|
||||
{
|
||||
OPL_WriteRegister((OPL_REGS_FREQ_1 + voice->index) | voice->array,
|
||||
OPL_WriteRegister(voice->array >> 9, (OPL_REGS_FREQ_1 + voice->index) | (voice->array & 0x100),
|
||||
freq & 0xff);
|
||||
OPL_WriteRegister((OPL_REGS_FREQ_2 + voice->index) | voice->array,
|
||||
OPL_WriteRegister(voice->array >> 9, (OPL_REGS_FREQ_2 + voice->index) | (voice->array & 0x100),
|
||||
(freq >> 8) | 0x20);
|
||||
|
||||
voice->freq = freq;
|
||||
@ -1196,9 +1198,9 @@ static void PitchBendEvent(opl_track_data_t *track, midi_event_t *event)
|
||||
{
|
||||
opl_channel_data_t *channel;
|
||||
int i;
|
||||
opl_voice_t *voice_updated_list[OPL_NUM_VOICES * 2] = {0};
|
||||
opl_voice_t *voice_updated_list[OPL_NUM_VOICES * 2 * OPL_MAX_CHIPS] = {0};
|
||||
unsigned int voice_updated_num = 0;
|
||||
opl_voice_t *voice_not_updated_list[OPL_NUM_VOICES * 2] = {0};
|
||||
opl_voice_t *voice_not_updated_list[OPL_NUM_VOICES * 2 * OPL_MAX_CHIPS] = {0};
|
||||
unsigned int voice_not_updated_num = 0;
|
||||
|
||||
// Update the channel bend value. Only the MSB of the pitch bend
|
||||
@ -1445,9 +1447,9 @@ static boolean I_OPL_InitStream(int device)
|
||||
char *dmxoption;
|
||||
opl_init_result_t chip_type;
|
||||
|
||||
OPL_SetSampleRate(SND_SAMPLERATE);
|
||||
OPL_SetSampleRate(OPL_SAMPLE_RATE);
|
||||
|
||||
chip_type = OPL_Init(opl_io_port);
|
||||
chip_type = OPL_Init(opl_io_port, num_opl_chips);
|
||||
if (chip_type == OPL_INIT_NONE)
|
||||
{
|
||||
I_Printf(VB_ERROR, "Dude. The Adlib isn't responding.");
|
||||
@ -1457,6 +1459,12 @@ static boolean I_OPL_InitStream(int device)
|
||||
// The DMXOPTION variable must be set to enable OPL3 support.
|
||||
// As an extension, we also allow it to be set from the config file.
|
||||
dmxoption = M_getenv("DMXOPTION");
|
||||
|
||||
// Secret, undocumented DMXOPTION that reverses the stereo channels
|
||||
// into their correct orientation.
|
||||
if (dmxoption != NULL && strstr(dmxoption, "-reverse") != NULL)
|
||||
opl_stereo_correct = true;
|
||||
|
||||
if (dmxoption == NULL)
|
||||
{
|
||||
dmxoption = snd_dmxoption != NULL ? snd_dmxoption : "";
|
||||
@ -1465,18 +1473,14 @@ static boolean I_OPL_InitStream(int device)
|
||||
if (chip_type == OPL_INIT_OPL3 && strstr(dmxoption, "-opl3") != NULL)
|
||||
{
|
||||
opl_opl3mode = 1;
|
||||
num_opl_voices = OPL_NUM_VOICES * 2;
|
||||
num_opl_voices = OPL_NUM_VOICES * 2 * num_opl_chips;
|
||||
}
|
||||
else
|
||||
{
|
||||
opl_opl3mode = 0;
|
||||
num_opl_voices = OPL_NUM_VOICES;
|
||||
num_opl_voices = OPL_NUM_VOICES * num_opl_chips;
|
||||
}
|
||||
|
||||
// Secret, undocumented DMXOPTION that reverses the stereo channels
|
||||
// into their correct orientation.
|
||||
opl_stereo_correct = strstr(dmxoption, "-reverse") != NULL;
|
||||
|
||||
// Initialize all registers.
|
||||
|
||||
OPL_InitRegisters(opl_opl3mode);
|
||||
@ -1550,7 +1554,7 @@ static boolean I_OPL_OpenStream(void *data, ALsizei size, ALenum *format,
|
||||
}
|
||||
|
||||
*format = AL_FORMAT_STEREO16;
|
||||
*freq = SND_SAMPLERATE;
|
||||
*freq = OPL_SAMPLE_RATE;
|
||||
*frame_size = 2 * sizeof(short);
|
||||
|
||||
return true;
|
||||
@ -1670,7 +1674,10 @@ static const char **I_OPL_DeviceList(void)
|
||||
|
||||
static void I_OPL_BindVariables(void)
|
||||
{
|
||||
;
|
||||
BIND_NUM(num_opl_chips, 1, 1, OPL_MAX_CHIPS,
|
||||
"[OPL3 Emulation] Number of chips to emulate (1-6)");
|
||||
BIND_BOOL(opl_stereo_correct, false,
|
||||
"[OPL3 Emulation] Use MIDI-correct stereo channel polarity");
|
||||
}
|
||||
|
||||
stream_module_t stream_opl_module =
|
||||
|
Loading…
x
Reference in New Issue
Block a user