summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNuke.YKT2015-05-29 02:00:45 +0900
committerNuke.YKT2015-05-29 02:00:45 +0900
commit7c377fc88a3fbb7f69b91a15dc414c8965624a89 (patch)
tree5a33e2533b73715a9de9a63ad11b7c14cf6c594b /src
parent5082f14944442344030d66f6fbdf86a75a1c1c70 (diff)
downloadchocolate-doom-7c377fc88a3fbb7f69b91a15dc414c8965624a89.tar.gz
chocolate-doom-7c377fc88a3fbb7f69b91a15dc414c8965624a89.tar.bz2
chocolate-doom-7c377fc88a3fbb7f69b91a15dc414c8965624a89.zip
Added OPL3 mode support.
Diffstat (limited to 'src')
-rw-r--r--src/i_oplmusic.c123
-rw-r--r--src/i_sound.c2
-rw-r--r--src/m_config.c5
-rw-r--r--src/setup/sound.c53
4 files changed, 146 insertions, 37 deletions
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
@@ -824,6 +824,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
//
// If non-zero, the ENDOOM text screen is displayed when exiting the
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)
{