Merge branch 'master' of gitlab.kode54.net:kode54/Cog

CQTexperiment
Christopher Snowhill 2017-07-03 16:03:36 -07:00
commit 7a70c1c80e
3 changed files with 136 additions and 62 deletions

View File

@ -158,6 +158,13 @@ void DoomOPL::ReleaseVoice(unsigned int id)
unsigned int i; unsigned int i;
bool doublev; 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]; voice = voice_alloced_list[id];
VoiceKeyOff(voice); VoiceKeyOff(voice);
@ -180,7 +187,7 @@ void DoomOPL::ReleaseVoice(unsigned int id)
voice_free_list[voice_free_num++] = voice; 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); ReleaseVoice(id);
} }
@ -189,7 +196,7 @@ void DoomOPL::ReleaseVoice(unsigned int id)
// Load data to the specified operator // Load data to the specified operator
void DoomOPL::LoadOperatorData(int slot, const genmidi_op_t *data, void DoomOPL::LoadOperatorData(int slot, const genmidi_op_t *data,
bool max_level) bool max_level, unsigned int *volume)
{ {
int level; int level;
@ -202,6 +209,12 @@ void DoomOPL::LoadOperatorData(int slot, const genmidi_op_t *data,
{ {
level |= 0x3f; level |= 0x3f;
} }
else
{
level |= data->level;
}
*volume = level;
OPL_WriteRegister(OPL_REGS_LEVEL + slot, level); OPL_WriteRegister(OPL_REGS_LEVEL + slot, level);
OPL_WriteRegister(OPL_REGS_TREMOLO + slot, data->tremolo); 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 // is set in SetVoiceVolume (below). If we are not using
// modulating mode, we must set both to minimum volume. // modulating mode, we must set both to minimum volume.
LoadOperatorData(voice->op2 | voice->array, &data->carrier, true); LoadOperatorData(voice->op2 | voice->array, &data->carrier, true, &voice->car_volume);
LoadOperatorData(voice->op1 | voice->array, &data->modulator, !modulating); LoadOperatorData(voice->op1 | voice->array, &data->modulator, !modulating, &voice->mod_volume);
// Set feedback register that control the connection between the // Set feedback register that control the connection between the
// two operators. Turn on bits in the upper nybble; I think this // two operators. Turn on bits in the upper nybble; I think this
@ -251,10 +264,6 @@ void DoomOPL::SetVoiceInstrument(opl_voice_t *voice,
OPL_WriteRegister((OPL_REGS_FEEDBACK + voice->index) | voice->array, OPL_WriteRegister((OPL_REGS_FEEDBACK + voice->index) | voice->array,
data->feedback | voice->reg_pan); data->feedback | voice->reg_pan);
// Hack to force a volume update.
voice->reg_volume = 999;
// Calculate voice priority. // Calculate voice priority.
voice->priority = 0x0f - (data->carrier.attack >> 4) voice->priority = 0x0f - (data->carrier.attack >> 4)
@ -284,24 +293,31 @@ void DoomOPL::SetVoiceVolume(opl_voice_t *voice, unsigned int volume)
// Update the volume register(s) if necessary. // 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 // If we are using non-modulated feedback mode, we must set the
// volume for both voices. // volume for both voices.
if ((opl_voice->feedback & 0x01) != 0 && opl_voice->modulator.level != 0x3f) if ((opl_voice->feedback & 0x01) != 0 && opl_voice->modulator.level != 0x3f)
{ {
mod_volume = 0x3f - opl_voice->modulator.level; mod_volume = opl_voice->modulator.level;
if (mod_volume >= car_volume) if (mod_volume < car_volume)
{ {
mod_volume = car_volume; mod_volume = car_volume;
} }
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, OPL_WriteRegister((OPL_REGS_LEVEL + voice->op1) | voice->array,
mod_volume | (opl_voice->modulator.scale & 0xc0)); voice->mod_volume);
}
} }
} }
} }
@ -427,7 +443,29 @@ void DoomOPL::ReplaceExistingVoice()
ReleaseVoice(result); 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 i;
unsigned int result; unsigned int result;
@ -579,6 +617,11 @@ void DoomOPL::VoiceKeyOn(opl_channel_data_t *channel,
voice_alloced_list[voice_alloced_num++] = voice; voice_alloced_list[voice_alloced_num++] = voice;
if (!opl_new && opl_drv_ver == opl_doom1_1_666)
{
instrument_voice = 0;
}
voice->channel = channel; voice->channel = channel;
voice->key = key; voice->key = key;
@ -619,7 +662,7 @@ void DoomOPL::KeyOnEvent(unsigned char channel_num, unsigned char key, unsigned
{ {
const genmidi_instr_t *instrument; const genmidi_instr_t *instrument;
opl_channel_data_t *channel; opl_channel_data_t *channel;
unsigned int note; unsigned int note, voicenum;
bool doublev; bool doublev;
/* /*
@ -661,28 +704,51 @@ void DoomOPL::KeyOnEvent(unsigned char channel_num, unsigned char key, unsigned
doublev = ((short)(instrument->flags) & GENMIDI_FLAG_2VOICE) != 0; doublev = ((short)(instrument->flags) & GENMIDI_FLAG_2VOICE) != 0;
if (opl_drv_ver == opl_v_old) switch (opl_drv_ver)
{ {
if (voice_alloced_num == opl_voices) case opl_doom1_1_666:
voicenum = doublev + 1;
if (!opl_new)
{ {
ReplaceExistingVoiceOld(channel); voicenum = 1;
} }
if (voice_alloced_num == opl_voices - 1 && doublev) while (voice_alloced_num > opl_voices - voicenum)
{ {
ReplaceExistingVoiceOld(channel); ReplaceExistingVoiceDoom1();
} }
// Find and program a voice for this instrument. If this // Find and program a voice for this instrument. If this
// is a double voice instrument, we must do this twice. // is a double voice instrument, we must do this twice.
if (doublev) if (doublev)
{ {
VoiceKeyOn(channel, instrument, 1, note, key, volume); VoiceKeyOn(channel, instrument, 1, note, key, volume);
} }
VoiceKeyOn(channel, instrument, 0, note, key, volume); VoiceKeyOn(channel, instrument, 0, note, key, volume);
} break;
else 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) if (voice_free_num == 0)
{ {
ReplaceExistingVoice(); ReplaceExistingVoice();
@ -697,6 +763,7 @@ void DoomOPL::KeyOnEvent(unsigned char channel_num, unsigned char key, unsigned
{ {
VoiceKeyOn(channel, instrument, 1, note, key, volume); VoiceKeyOn(channel, instrument, 1, note, key, volume);
} }
break;
} }
} }
@ -948,7 +1015,7 @@ int DoomOPL::midi_init(unsigned int rate, unsigned int bank, unsigned int extp)
voice_free_num = 0; voice_free_num = 0;
opl_new = 0; opl_new = 0;
opl_voices = OPL_NUM_VOICES; opl_voices = OPL_NUM_VOICES;
opl_drv_ver = opl_v_new; opl_drv_ver = opl_doom_1_9;
/*env = getenv("DMXOPTION"); /*env = getenv("DMXOPTION");
if (env) if (env)
@ -958,9 +1025,13 @@ int DoomOPL::midi_init(unsigned int rate, unsigned int bank, unsigned int extp)
opl_new = 1; opl_new = 1;
opl_voices = OPL_NUM_VOICES * 2; 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;
} }
}*/ }*/

View File

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

View File

@ -1,4 +1,4 @@
/* generated from /Users/chris/Downloads/GENMIDI.op2: do not edit */ /* generated from /Users/Chris/Downloads/GENMIDI.op2: do not edit */
const unsigned char dmxopl[] = { const unsigned char dmxopl[] = {
0x23,0x4f,0x50,0x4c,0x5f,0x49,0x49,0x23,0x00,0x00,0x82,0x00,0x31,0xf0,0xf3,0x03, 0x23,0x4f,0x50,0x4c,0x5f,0x49,0x49,0x23,0x00,0x00,0x82,0x00,0x31,0xf0,0xf3,0x03,
0x00,0x27,0x0e,0x30,0xf1,0xf4,0x01,0x00,0x00,0x00,0x00,0x00,0x30,0xf0,0xf3,0x03, 0x00,0x27,0x0e,0x30,0xf1,0xf4,0x01,0x00,0x00,0x00,0x00,0x00,0x30,0xf0,0xf3,0x03,
@ -104,7 +104,7 @@ const unsigned char dmxopl[] = {
0x80,0x09,0x06,0x60,0x93,0x05,0x00,0x40,0x00,0x00,0x00,0x00,0x04,0x00,0x8a,0x00, 0x80,0x09,0x06,0x60,0x93,0x05,0x00,0x40,0x00,0x00,0x00,0x00,0x04,0x00,0x8a,0x00,
0x21,0x85,0x84,0x00,0x40,0x29,0x0a,0x11,0xc4,0x74,0x00,0x00,0x00,0x00,0xf4,0xff, 0x21,0x85,0x84,0x00,0x40,0x29,0x0a,0x11,0xc4,0x74,0x00,0x00,0x00,0x00,0xf4,0xff,
0x01,0xa2,0x74,0x00,0x00,0x29,0x0a,0x11,0x64,0x35,0x00,0x00,0x00,0x00,0xf4,0xff, 0x01,0xa2,0x74,0x00,0x00,0x29,0x0a,0x11,0x64,0x35,0x00,0x00,0x00,0x00,0xf4,0xff,
0x00,0x00,0x80,0x00,0x31,0xf3,0xb5,0x00,0x00,0x2e,0x00,0x20,0xf3,0xb3,0x00,0x00, 0x00,0x00,0x80,0x00,0x11,0xf3,0xf5,0x00,0x00,0x2e,0x00,0x00,0xf3,0xf5,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x01,0xa6,0xc7,0x01,0x40,0x10,0x0a,0x10, 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x01,0xa6,0xc7,0x01,0x40,0x10,0x0a,0x10,
0xd2,0xb3,0x00,0x00,0x00,0x00,0xf4,0xff,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x00, 0xd2,0xb3,0x00,0x00,0x00,0x00,0xf4,0xff,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x00,