Updated Doom oplmusic synth to latest version.

CQTexperiment
Chris Moeller 2017-06-23 16:50:41 -07:00
parent b18222052b
commit 113c52a616
2 changed files with 134 additions and 60 deletions

View File

@ -158,6 +158,13 @@ void DoomOPL::ReleaseVoice(unsigned int id)
unsigned int i;
bool doublev;
// Doom 2 1.666 OPL crash emulation.
if (id >= voice_alloced_num)
{
voice_alloced_num = 0;
voice_free_num = 0;
return;
}
voice = voice_alloced_list[id];
VoiceKeyOff(voice);
@ -180,7 +187,7 @@ void DoomOPL::ReleaseVoice(unsigned int id)
voice_free_list[voice_free_num++] = voice;
if (doublev && opl_drv_ver == opl_v_old)
if (doublev && opl_drv_ver < opl_doom_1_9)
{
ReleaseVoice(id);
}
@ -189,7 +196,7 @@ void DoomOPL::ReleaseVoice(unsigned int id)
// Load data to the specified operator
void DoomOPL::LoadOperatorData(int slot, const genmidi_op_t *data,
bool max_level)
bool max_level, unsigned int *volume)
{
int level;
@ -202,6 +209,12 @@ void DoomOPL::LoadOperatorData(int slot, const genmidi_op_t *data,
{
level |= 0x3f;
}
else
{
level |= data->level;
}
*volume = level;
OPL_WriteRegister(OPL_REGS_LEVEL + slot, level);
OPL_WriteRegister(OPL_REGS_TREMOLO + slot, data->tremolo);
@ -241,8 +254,8 @@ void DoomOPL::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 | voice->array, &data->carrier, true);
LoadOperatorData(voice->op1 | voice->array, &data->modulator, !modulating);
LoadOperatorData(voice->op2 | voice->array, &data->carrier, true, &voice->car_volume);
LoadOperatorData(voice->op1 | voice->array, &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
@ -250,10 +263,6 @@ void DoomOPL::SetVoiceInstrument(opl_voice_t *voice,
OPL_WriteRegister((OPL_REGS_FEEDBACK + voice->index) | voice->array,
data->feedback | voice->reg_pan);
// Hack to force a volume update.
voice->reg_volume = 999;
// Calculate voice priority.
@ -284,24 +293,31 @@ void DoomOPL::SetVoiceVolume(opl_voice_t *voice, unsigned int volume)
// Update the volume register(s) if necessary.
if (car_volume != voice->reg_volume)
if (car_volume != (voice->car_volume & 0x3f))
{
voice->reg_volume = car_volume | (opl_voice->carrier.scale & 0xc0);
voice->car_volume = car_volume | (voice->car_volume & 0xc0);
OPL_WriteRegister((OPL_REGS_LEVEL + voice->op2) | voice->array, voice->reg_volume);
OPL_WriteRegister((OPL_REGS_LEVEL + voice->op2) | voice->array, voice->car_volume);
// If we are using non-modulated feedback mode, we must set the
// volume for both voices.
if ((opl_voice->feedback & 0x01) != 0 && opl_voice->modulator.level != 0x3f)
{
mod_volume = 0x3f - opl_voice->modulator.level;
if (mod_volume >= car_volume)
mod_volume = opl_voice->modulator.level;
if (mod_volume < car_volume)
{
mod_volume = car_volume;
}
OPL_WriteRegister((OPL_REGS_LEVEL + voice->op1) | voice->array,
mod_volume | (opl_voice->modulator.scale & 0xc0));
mod_volume |= voice->mod_volume & 0xc0;
if (mod_volume != voice->mod_volume)
{
voice->mod_volume = mod_volume;
OPL_WriteRegister((OPL_REGS_LEVEL + voice->op1) | voice->array,
voice->mod_volume);
}
}
}
}
@ -427,7 +443,29 @@ void DoomOPL::ReplaceExistingVoice()
ReleaseVoice(result);
}
void DoomOPL::ReplaceExistingVoiceOld(opl_channel_data_t *channel)
// Alternate versions of ReplaceExistingVoice() used when emulating old
// versions of the DMX library used in Doom 1.666, Heretic and Hexen.
void DoomOPL::ReplaceExistingVoiceDoom1(void)
{
int i;
int result;
result = 0;
for (i = 0; i < voice_alloced_num; i++)
{
if (voice_alloced_list[i]->channel
> voice_alloced_list[result]->channel)
{
result = i;
}
}
ReleaseVoice(result);
}
void DoomOPL::ReplaceExistingVoiceDoom2(opl_channel_data_t *channel)
{
unsigned int i;
unsigned int result;
@ -579,6 +617,11 @@ void DoomOPL::VoiceKeyOn(opl_channel_data_t *channel,
voice_alloced_list[voice_alloced_num++] = voice;
if (!opl_new && opl_drv_ver == opl_doom1_1_666)
{
instrument_voice = 0;
}
voice->channel = channel;
voice->key = key;
@ -619,7 +662,7 @@ void DoomOPL::KeyOnEvent(unsigned char channel_num, unsigned char key, unsigned
{
const genmidi_instr_t *instrument;
opl_channel_data_t *channel;
unsigned int note;
unsigned int note, voicenum;
bool doublev;
/*
@ -661,43 +704,67 @@ void DoomOPL::KeyOnEvent(unsigned char channel_num, unsigned char key, unsigned
doublev = ((short)(instrument->flags) & GENMIDI_FLAG_2VOICE) != 0;
if (opl_drv_ver == opl_v_old)
{
if (voice_alloced_num == opl_voices)
{
ReplaceExistingVoiceOld(channel);
}
if (voice_alloced_num == opl_voices - 1 && doublev)
{
ReplaceExistingVoiceOld(channel);
}
switch (opl_drv_ver)
{
case opl_doom1_1_666:
voicenum = doublev + 1;
if (!opl_new)
{
voicenum = 1;
}
while (voice_alloced_num > opl_voices - voicenum)
{
ReplaceExistingVoiceDoom1();
}
// Find and program a voice for this instrument. If this
// is a double voice instrument, we must do this twice.
if (doublev)
{
VoiceKeyOn(channel, instrument, 1, note, key, volume);
}
// Find and program a voice for this instrument. If this
// is a double voice instrument, we must do this twice.
VoiceKeyOn(channel, instrument, 0, note, key, volume);
if (doublev)
{
VoiceKeyOn(channel, instrument, 1, note, key, volume);
}
VoiceKeyOn(channel, instrument, 0, note, key, volume);
break;
case opl_doom2_1_666:
if (voice_alloced_num == opl_voices)
{
ReplaceExistingVoiceDoom2(channel);
}
if (voice_alloced_num == opl_voices - 1 && doublev)
{
ReplaceExistingVoiceDoom2(channel);
}
// Find and program a voice for this instrument. If this
// is a double voice instrument, we must do this twice.
if (doublev)
{
VoiceKeyOn(channel, instrument, 1, note, key, volume);
}
VoiceKeyOn(channel, instrument, 0, note, key, volume);
break;
default:
case opl_doom_1_9:
if (voice_free_num == 0)
{
ReplaceExistingVoice();
}
// Find and program a voice for this instrument. If this
// is a double voice instrument, we must do this twice.
VoiceKeyOn(channel, instrument, 0, note, key, volume);
if (doublev)
{
VoiceKeyOn(channel, instrument, 1, note, key, volume);
}
break;
}
else
{
if (voice_free_num == 0)
{
ReplaceExistingVoice();
}
// Find and program a voice for this instrument. If this
// is a double voice instrument, we must do this twice.
VoiceKeyOn(channel, instrument, 0, note, key, volume);
if (doublev)
{
VoiceKeyOn(channel, instrument, 1, note, key, volume);
}
}
}
void DoomOPL::ProgramChangeEvent(unsigned char channel_num, unsigned char instrument)
@ -948,7 +1015,7 @@ int DoomOPL::midi_init(unsigned int rate, unsigned int bank, unsigned int extp)
voice_free_num = 0;
opl_new = 0;
opl_voices = OPL_NUM_VOICES;
opl_drv_ver = opl_v_new;
opl_drv_ver = opl_doom_1_9;
/*env = getenv("DMXOPTION");
if (env)
@ -958,10 +1025,14 @@ int DoomOPL::midi_init(unsigned int rate, unsigned int bank, unsigned int extp)
opl_new = 1;
opl_voices = OPL_NUM_VOICES * 2;
}/*
if (strstr(env, "-oldalg"))
if (strstr(env, "-doom1"))
{
opl_drv_ver = opl_v_old;
opl_drv_ver = opl_doom1_1_666;
}
if (strstr(env, "-doom2"))
{
opl_drv_ver = opl_doom2_1_666;
}
}*/
OPL_InitRegisters(opl_new);

View File

@ -163,7 +163,8 @@ struct opl_voice_s
unsigned int note_volume;
// The current volume (register value) that has been set for this channel.
unsigned int reg_volume;
unsigned int car_volume;
unsigned int mod_volume;
// The current pan.
unsigned int reg_pan;
@ -173,8 +174,9 @@ struct opl_voice_s
};
typedef enum {
opl_v_old, // hexen heretic
opl_v_new // doom strife
opl_doom1_1_666, // Doom 1 v1.666
opl_doom2_1_666, // Doom 2 v1.666, Hexen, Heretic
opl_doom_1_9 // Doom v1.9, Strife
} opl_driver_ver_t;
// Operators used by the different voices.
@ -331,7 +333,7 @@ class DoomOPL : public midisynth {
private:
fm_chip *opl;
opl_channel_data_t channels[MIDI_CHANNELS_PER_TRACK];
opl_driver_ver_t opl_drv_ver = opl_v_new;
opl_driver_ver_t opl_drv_ver = opl_doom_1_9;
// GENMIDI lump instrument data:
@ -354,7 +356,7 @@ private:
void OPL_InitRegisters(bool opl_new);
bool LoadInstrumentTable(unsigned int bank);
void ReleaseVoice(unsigned int id);
void LoadOperatorData(int slot, const genmidi_op_t *data, bool max_level);
void LoadOperatorData(int slot, const genmidi_op_t *data, bool max_level, unsigned int *volume);
void SetVoiceInstrument(opl_voice_t *voice, const genmidi_instr_t *instr, unsigned int instr_voice);
void SetVoiceVolume(opl_voice_t *voice, unsigned int volume);
void SetVoicePan(opl_voice_t *voice, unsigned int pan);
@ -364,7 +366,8 @@ private:
opl_channel_data_t *TrackChannelForEvent(unsigned char channel_num);
void KeyOffEvent(unsigned char channel_num, unsigned char key);
void ReplaceExistingVoice();
void ReplaceExistingVoiceOld(opl_channel_data_t *channel);
void ReplaceExistingVoiceDoom1();
void ReplaceExistingVoiceDoom2(opl_channel_data_t *channel);
unsigned int FrequencyForVoice(opl_voice_t *voice);
void UpdateVoiceFrequency(opl_voice_t *voice);
void VoiceKeyOn(opl_channel_data_t *channel, const genmidi_instr_t *instrument, unsigned int instrument_voice,