shithub: choc

Download patch

ref: a26925cf8f27eb38b3266629a3bc259f098b1e19
parent: a43e60ee11f11fa8140b7b22da70f06b598fc49d
author: Simon Howard <fraggle@gmail.com>
date: Mon Aug 31 14:18:51 EDT 2009

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

Subversion-branch: /branches/opl-branch
Subversion-revision: 1651

--- a/src/i_oplmusic.c
+++ b/src/i_oplmusic.c
@@ -137,7 +137,8 @@
     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 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 @@
 
     // 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 + voice->op2, reg_volume);
+        WriteRegister(OPL_REGS_LEVEL + opnum, 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);
     }
 }