diff options
author | Nuke.YKT | 2015-05-29 02:00:45 +0900 |
---|---|---|
committer | Nuke.YKT | 2015-05-29 02:00:45 +0900 |
commit | 7c377fc88a3fbb7f69b91a15dc414c8965624a89 (patch) | |
tree | 5a33e2533b73715a9de9a63ad11b7c14cf6c594b /src | |
parent | 5082f14944442344030d66f6fbdf86a75a1c1c70 (diff) | |
download | chocolate-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.c | 123 | ||||
-rw-r--r-- | src/i_sound.c | 2 | ||||
-rw-r--r-- | src/m_config.c | 5 | ||||
-rw-r--r-- | src/setup/sound.c | 53 |
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) { |