summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/i_oplmusic.c70
1 files changed, 51 insertions, 19 deletions
diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c
index 1d482595..51a609d9 100644
--- a/src/i_oplmusic.c
+++ b/src/i_oplmusic.c
@@ -137,7 +137,8 @@ struct opl_voice_s
unsigned int note_volume;
// The current volume that has been set for this channel.
- unsigned int volume;
+ unsigned int carrier_volume;
+ unsigned int modulator_volume;
// Next in freelist
opl_voice_t *next;
@@ -442,14 +443,22 @@ static void LoadOperatorData(int operator, genmidi_op_t *data,
static void SetVoiceInstrument(opl_voice_t *voice, genmidi_instr_t *instr)
{
genmidi_voice_t *data;
+ unsigned int modulating;
voice->current_instr = instr;
data = &instr->opl2_voice;
+ // Are we usind modulated feedback mode?
+
+ modulating = (data->feedback & 0x01) == 0;
+
// Doom loads the second operator first, then the first.
+ // The carrier is set to minimum volume until the voice volume
+ // 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, false);
+ LoadOperatorData(voice->op1, &data->modulator, !modulating);
// Set feedback register that control the connection between the
// two operators. Turn on bits in the upper nybble; I think this
@@ -460,38 +469,61 @@ static void SetVoiceInstrument(opl_voice_t *voice, genmidi_instr_t *instr)
// Hack to force a volume update.
- voice->volume = 999;
+ voice->carrier_volume = 999;
+ voice->modulator_volume = 999;
}
-static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume)
+// Calculate the volume level to use for a given operator.
+
+static void SetOperatorVolume(genmidi_op_t *op, unsigned int volume,
+ unsigned int opnum,
+ unsigned int *current_volume)
{
- unsigned int full_volume;
- unsigned int instr_volume;
+ unsigned int op_volume;
unsigned int reg_volume;
- voice->note_volume = volume;
-
- // Multiply note volume and channel volume to get the actual volume.
-
- full_volume = (voice->note_volume * voice->channel->volume) / 127;
-
// The volume of each instrument can be controlled via GENMIDI:
- instr_volume = 0x3f - voice->current_instr->opl2_voice.carrier.level;
+ op_volume = 0x3f - op->level;
// The volume value to use in the register:
- reg_volume = ((instr_volume * volume_mapping_table[full_volume]) / 128);
- reg_volume = (0x3f - reg_volume)
- | voice->current_instr->opl2_voice.carrier.scale;
+ reg_volume = ((op_volume * volume_mapping_table[volume]) / 128);
+ reg_volume = (0x3f - reg_volume) | op->scale;
// Update the register, if necessary:
- if (voice->volume != reg_volume)
+ if (*current_volume != reg_volume)
{
- voice->volume = reg_volume;
+ *current_volume = reg_volume;
+
+ WriteRegister(OPL_REGS_LEVEL + opnum, reg_volume);
+ }
+}
- WriteRegister(OPL_REGS_LEVEL + voice->op2, reg_volume);
+static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume)
+{
+ genmidi_voice_t *opl_voice;
+ unsigned int full_volume;
+
+ voice->note_volume = volume;
+
+ opl_voice = &voice->current_instr->opl2_voice;
+
+ // Multiply note volume and channel volume to get the actual volume.
+
+ full_volume = (voice->note_volume * voice->channel->volume) / 127;
+
+ SetOperatorVolume(&opl_voice->carrier, full_volume,
+ voice->op2, &voice->carrier_volume);
+
+ // If we are using non-modulated feedback mode, we must set the
+ // volume for both voices.
+
+ if ((opl_voice->feedback & 0x01) != 0)
+ {
+ SetOperatorVolume(&opl_voice->modulator, full_volume,
+ voice->op1, &voice->modulator_volume);
}
}