Merge branch 'master' of gitlab.kode54.net:kode54/Cog
commit
7a70c1c80e
|
@ -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
|
||||||
|
@ -250,10 +263,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.
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
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);
|
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,43 +704,67 @@ 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;
|
||||||
ReplaceExistingVoiceOld(channel);
|
if (!opl_new)
|
||||||
}
|
{
|
||||||
if (voice_alloced_num == opl_voices - 1 && doublev)
|
voicenum = 1;
|
||||||
{
|
}
|
||||||
ReplaceExistingVoiceOld(channel);
|
while (voice_alloced_num > opl_voices - voicenum)
|
||||||
}
|
{
|
||||||
|
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)
|
|
||||||
{
|
|
||||||
VoiceKeyOn(channel, instrument, 1, note, key, volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
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;
|
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,10 +1025,14 @@ 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;
|
||||||
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
OPL_InitRegisters(opl_new);
|
OPL_InitRegisters(opl_new);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue