foxygit / doom Log in
commit a26925cf8f27eb38b3266629a3bc259f098b1e19
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Mon Aug 31 18:18:51 2009 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Mon Aug 31 18:18:51 2009 +0000

    Set the volume on both operators for instruments that use non-modulating
    voice mode.

    Subversion-branch: /branches/opl-branch
    Subversion-revision: 1651
---
 src/i_oplmusic.c | 70 +++++++++++++++++++++++++++++++++++++++++---------------
 1 file 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);
     }
 }