foxygit / doom Log in
commit 7c377fc88a3fbb7f69b91a15dc414c8965624a89
Author:     Nuke.YKT <alexeytf2@gmail.com>
AuthorDate: Fri May 29 02:00:45 2015 +0900
Commit:     Nuke.YKT <alexeytf2@gmail.com>
CommitDate: Fri May 29 02:00:45 2015 +0900

    Added OPL3 mode support.
---
 opl/opl.c         |  82 +++++++++++++++++++++++++++++-------
 opl/opl.h         |   6 ++-
 opl/opl_sdl.c     |  43 +++++++++++++++----
 src/i_oplmusic.c  | 123 +++++++++++++++++++++++++++++++++++++++++++++---------
 src/i_sound.c     |   2 +
 src/m_config.c    |   5 +++
 src/setup/sound.c |  53 +++++++++++++++--------
 7 files changed, 254 insertions(+), 60 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);
diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c
index 7715465e..dff9480c 100644
--- a/src/i_oplmusic.c
+++ b/src/i_oplmusic.c
@@ -86,6 +86,10 @@ typedef struct

     int volume;

+    // Pan
+
+    int pan;
+
     // Pitch bend value:

     int bend;
@@ -115,6 +119,9 @@ struct opl_voice_s
     // The operators used by this voice:
     int op1, op2;

+    // Array used by voice:
+    int array;
+
     // Currently-loaded instrument data
     genmidi_instr_t *current_instr;

@@ -143,6 +150,9 @@ struct opl_voice_s
     // The current volume (register value) that has been set for this channel.
     unsigned int reg_volume;

+    // Pan.
+    unsigned int reg_pan;
+
     // Priority.
     unsigned int priority;

@@ -312,10 +322,12 @@ static char (*percussion_names)[32];

 // Voices:

-static opl_voice_t voices[OPL_NUM_VOICES];
+static opl_voice_t voices[OPL_NUM_VOICES * 2];
 static opl_voice_t *voice_free_list;
 static opl_voice_t *voice_alloced_list;
 static int voice_alloced_num;
+static int opl_new;
+static int opl_voice_num;

 // Track data for playing tracks:

@@ -338,6 +350,7 @@ static unsigned int last_perc_count;
 // adlib chip.

 int opl_io_port = 0x388;
+int opl_type = 0;

 // Load instrument table from GENMIDI lump:

@@ -519,15 +532,15 @@ static void SetVoiceInstrument(opl_voice_t *voice,
     // is set in SetVoiceVolume (below).  If we are not using
     // modulating mode, we must set both to minimum volume.

-    LoadOperatorData(voice->op2, &data->carrier, true);
-    LoadOperatorData(voice->op1, &data->modulator, !modulating);
+    LoadOperatorData(voice->op2 | voice->array, &data->carrier, true);
+    LoadOperatorData(voice->op1 | voice->array, &data->modulator, !modulating);

     // 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,
-                      data->feedback | 0x30);
+    OPL_WriteRegister((OPL_REGS_FEEDBACK + voice->index) | voice->array,
+                      data->feedback | voice->reg_pan);

     // Hack to force a volume update.

@@ -568,7 +581,7 @@ static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume)
     {
         voice->reg_volume = car_volume | (opl_voice->carrier.scale & 0xc0);

-        OPL_WriteRegister(OPL_REGS_LEVEL + voice->op2, voice->reg_volume);
+        OPL_WriteRegister((OPL_REGS_LEVEL + voice->op2) | voice->array, voice->reg_volume);

         // If we are using non-modulated feedback mode, we must set the
         // volume for both voices.
@@ -581,13 +594,24 @@ static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume)
             {
                 mod_volume = car_volume;
             }
-            OPL_WriteRegister(OPL_REGS_LEVEL + voice->op1,
+            OPL_WriteRegister((OPL_REGS_LEVEL + voice->op1) | voice->array,
                               mod_volume |
                               (opl_voice->modulator.scale & 0xc0));
         }
     }
 }

+static void SetVoicePan(opl_voice_t *voice, unsigned int pan)
+{
+    genmidi_voice_t *opl_voice;
+
+    voice->reg_pan = pan;
+    opl_voice = &voice->current_instr->voices[voice->current_instr_voice];;
+
+    OPL_WriteRegister((OPL_REGS_FEEDBACK + voice->index) | voice->array,
+                      opl_voice->feedback | pan);
+}
+
 // Initialize the voice table and freelist

 static void InitVoices(void)
@@ -600,11 +624,12 @@ static void InitVoices(void)

     // Initialize each voice.

-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    for (i = 0; i < opl_voice_num; ++i)
     {
-        voices[i].index = i;
-        voices[i].op1 = voice_operators[0][i];
-        voices[i].op2 = voice_operators[1][i];
+        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].current_instr = NULL;

         // Add this voice to the freelist.
@@ -625,7 +650,7 @@ static void I_OPL_SetMusicVolume(int volume)

     // Update the volume of all voices.

-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    for (i = 0; i < opl_voice_num; ++i)
     {
         if (voices[i].channel != NULL)
         {
@@ -636,7 +661,7 @@ static void I_OPL_SetMusicVolume(int volume)

 static void VoiceKeyOff(opl_voice_t *voice)
 {
-    OPL_WriteRegister(OPL_REGS_FREQ_2 + voice->index, voice->freq >> 8);
+    OPL_WriteRegister((OPL_REGS_FREQ_2 + voice->index) | voice->array, voice->freq >> 8);
 }

 static opl_channel_data_t *TrackChannelForEvent(opl_track_data_t *track,
@@ -869,8 +894,8 @@ static void UpdateVoiceFrequency(opl_voice_t *voice)

     if (voice->freq != freq)
     {
-        OPL_WriteRegister(OPL_REGS_FREQ_1 + voice->index, freq & 0xff);
-        OPL_WriteRegister(OPL_REGS_FREQ_2 + voice->index, (freq >> 8) | 0x20);
+        OPL_WriteRegister((OPL_REGS_FREQ_1 + voice->index) | voice->array, freq & 0xff);
+        OPL_WriteRegister((OPL_REGS_FREQ_2 + voice->index) | voice->array, (freq >> 8) | 0x20);

         voice->freq = freq;
     }
@@ -913,6 +938,8 @@ static void VoiceKeyOn(opl_channel_data_t *channel,
         voice->note = note;
     }

+    voice->reg_pan = channel->pan;
+
     // Program the voice with the instrument data:

     SetVoiceInstrument(voice, instrument, instrument_voice);
@@ -1041,7 +1068,7 @@ static void SetChannelVolume(opl_channel_data_t *channel, unsigned int volume)

     // Update all voices that this channel is using.

-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    for (i = 0; i < opl_voice_num; ++i)
     {
         if (voices[i].channel == channel)
         {
@@ -1050,6 +1077,39 @@ static void SetChannelVolume(opl_channel_data_t *channel, unsigned int volume)
     }
 }

+static void SetChannelPan(opl_channel_data_t *channel, unsigned int pan)
+{
+    unsigned int reg_pan;
+    unsigned int i;
+
+    if (opl_new)
+    {
+        if (pan >= 96)
+        {
+            reg_pan = 0x10;
+        }
+        else if (pan <= 48)
+        {
+            reg_pan = 0x20;
+        }
+        else
+        {
+            reg_pan = 0x30;
+        }
+        if (channel->pan != reg_pan)
+        {
+            channel->pan = reg_pan;
+            for (i = 0; i < opl_voice_num; i++)
+            {
+                if (voices[i].channel == channel)
+                {
+                    SetVoicePan(&voices[i], reg_pan);
+                }
+            }
+        }
+    }
+}
+
 // Handler for the MIDI_CONTROLLER_ALL_NOTES_OFF channel event.
 static void AllNotesOff(opl_channel_data_t *channel, unsigned int param)
 {
@@ -1108,6 +1168,10 @@ static void ControllerEvent(opl_track_data_t *track, midi_event_t *event)
             SetChannelVolume(channel, param);
             break;

+        case MIDI_CONTROLLER_PAN:
+            SetChannelPan(channel, param);
+            break;
+
         case MIDI_CONTROLLER_ALL_NOTES_OFF:
             AllNotesOff(channel, param);
             break;
@@ -1135,7 +1199,7 @@ static void PitchBendEvent(opl_track_data_t *track, midi_event_t *event)

     // Update all voices for this channel.

-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    for (i = 0; i < opl_voice_num; ++i)
     {
         if (voices[i].channel == channel)
         {
@@ -1323,6 +1387,7 @@ static void InitChannel(opl_track_data_t *track, opl_channel_data_t *channel)

     channel->instrument = &main_instrs[0];
     channel->volume = 127;
+    channel->pan = 0x30;
     channel->bend = 0;
 }

@@ -1397,7 +1462,7 @@ static void I_OPL_PauseSong(void)
     // Turn off all main instrument voices (not percussion).
     // This is what Vanilla does.

-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    for (i = 0; i < opl_voice_num; ++i)
     {
         if (voices[i].channel != NULL
          && voices[i].current_instr < percussion_instrs)
@@ -1434,7 +1499,7 @@ static void I_OPL_StopSong(void)

     // Free all voices.

-    for (i = 0; i < OPL_NUM_VOICES; ++i)
+    for (i = 0; i < opl_voice_num; ++i)
     {
         if (voices[i].channel != NULL)
         {
@@ -1581,14 +1646,32 @@ static void I_OPL_ShutdownMusic(void)

 static boolean I_OPL_InitMusic(void)
 {
+    int opl_chip_type;
+
     OPL_SetSampleRate(snd_samplerate);

-    if (!OPL_Init(opl_io_port))
+    opl_chip_type = OPL_Init(opl_io_port);
+    if (!opl_chip_type)
     {
         printf("Dude.  The Adlib isn't responding.\n");
         return false;
     }

+    if (opl_chip_type == 2 && opl_type)
+    {
+        opl_new = 1;
+        opl_voice_num = OPL_NUM_VOICES * 2;
+    }
+    else
+    {
+        opl_new = 0;
+        opl_voice_num = OPL_NUM_VOICES;
+    }
+
+    // Initialize all registers.
+
+    OPL_InitRegisters(opl_new);
+
     // Load instruments from GENMIDI lump:

     if (!LoadInstrumentTable())
diff --git a/src/i_sound.c b/src/i_sound.c
index 73442cbd..03a9facc 100644
--- a/src/i_sound.c
+++ b/src/i_sound.c
@@ -68,6 +68,7 @@ extern music_module_t music_opl_module;

 extern opl_driver_ver_t opl_drv_ver;
 extern int opl_io_port;
+extern int opl_type;

 // For native music module:

@@ -446,6 +447,7 @@ void I_BindSoundVariables(void)
     M_BindIntVariable("snd_samplerate",          &snd_samplerate);
     M_BindIntVariable("snd_cachesize",           &snd_cachesize);
     M_BindIntVariable("opl_io_port",             &opl_io_port);
+    M_BindIntVariable("opl_type",                &opl_type);

     M_BindStringVariable("timidity_cfg_path",    &timidity_cfg_path);
     M_BindStringVariable("gus_patch_path",       &gus_patch_path);
diff --git a/src/m_config.c b/src/m_config.c
index ad539a7f..3d898705 100644
--- a/src/m_config.c
+++ b/src/m_config.c
@@ -823,6 +823,11 @@ static default_t extra_defaults_list[] =

     CONFIG_VARIABLE_INT_HEX(opl_io_port),

+    //!
+    // OPL chip type.
+	//
+    CONFIG_VARIABLE_INT(opl_type),
+
     //!
     // @game doom heretic strife
     //
diff --git a/src/setup/sound.c b/src/setup/sound.c
index 280a6bc2..bc2bdf33 100644
--- a/src/setup/sound.c
+++ b/src/setup/sound.c
@@ -61,6 +61,12 @@ static char *musicmode_strings[] =
     "CD audio"
 };

+static char *opltype_strings[] =
+{
+    "OPL2",
+    "OPL3"
+};
+
 static char *cfg_extension[] = { "cfg", NULL };

 // Config file variables:
@@ -84,6 +90,7 @@ static float libsamplerate_scale = 0.65;
 static char *timidity_cfg_path = NULL;
 static char *gus_patch_path = NULL;
 static int gus_ram_kb = 1024;
+static int opl_type = 0;

 // DOS specific variables: these are unused but should be maintained
 // so that the config file can be shared between chocolate
@@ -142,26 +149,37 @@ static void UpdateExtraTable(TXT_UNCAST_ARG(widget),
     // Rebuild the GUS table. Start by emptying it, then only add the
     // GUS control widget if we are in GUS music mode.

-    TXT_ClearTable(extra_table);
-
-    if (snd_musicmode == MUSICMODE_GUS)
+    if (snd_musicmode == MUSICMODE_OPL)
     {
+        TXT_InitTable(extra_table, 2);
+        TXT_SetColumnWidths(extra_table, 19, 4);
         TXT_AddWidgets(extra_table,
-                       TXT_NewLabel("GUS patch path:"),
-                       TXT_NewFileSelector(&gus_patch_path, 30,
-                                           "Select path to GUS patches",
-                                           TXT_DIRECTORY),
-                       NULL);
-    }
+                        TXT_NewLabel("OPL type"),
+                        TXT_NewDropdownList(&opl_type, opltype_strings, 2),
+                        NULL);
+	}
+	else
+	{
+		TXT_InitTable(extra_table, 1);
+        if (snd_musicmode == MUSICMODE_GUS)
+        {
+            TXT_AddWidgets(extra_table,
+                           TXT_NewLabel("GUS patch path:"),
+                           TXT_NewFileSelector(&gus_patch_path, 30,
+                                               "Select path to GUS patches",
+                                               TXT_DIRECTORY),
+                           NULL);
+        }

-    if (snd_musicmode == MUSICMODE_NATIVE)
-    {
-        TXT_AddWidgets(extra_table,
-                       TXT_NewLabel("Timidity configuration file:"),
-                       TXT_NewFileSelector(&timidity_cfg_path, 30,
-                                           "Select Timidity config file",
-                                           cfg_extension),
-                       NULL);
+        if (snd_musicmode == MUSICMODE_NATIVE)
+        {
+            TXT_AddWidgets(extra_table,
+                           TXT_NewLabel("Timidity configuration file:"),
+                           TXT_NewFileSelector(&timidity_cfg_path, 30,
+                                               "Select Timidity config file",
+                                               cfg_extension),
+                           NULL);
+        }
     }
 }

@@ -324,6 +342,7 @@ void BindSoundVariables(void)

     M_BindIntVariable("snd_cachesize",            &snd_cachesize);
     M_BindIntVariable("opl_io_port",              &opl_io_port);
+    M_BindIntVariable("opl_type",                 &opl_type);

     if (gamemission == strife)
     {