aboutsummaryrefslogtreecommitdiff
path: root/audio/softsynth
diff options
context:
space:
mode:
authorFilippos Karapetis2013-09-24 11:25:21 +0300
committerFilippos Karapetis2013-09-24 11:30:46 +0300
commiteb84b9fc02976c220b4b1d573d8ca84041de2e49 (patch)
tree4764999248c42c8d21bed02942bc4bee465ee0b5 /audio/softsynth
parent8fe2fe8a15a6f3db61f7dbe101ef5edd64b51d46 (diff)
downloadscummvm-rg350-eb84b9fc02976c220b4b1d573d8ca84041de2e49.tar.gz
scummvm-rg350-eb84b9fc02976c220b4b1d573d8ca84041de2e49.tar.bz2
scummvm-rg350-eb84b9fc02976c220b4b1d573d8ca84041de2e49.zip
MT-32: Update to munt 1.3.0
Diffstat (limited to 'audio/softsynth')
-rw-r--r--audio/softsynth/mt32/LA32FloatWaveGenerator.cpp28
-rw-r--r--audio/softsynth/mt32/LA32WaveGenerator.cpp51
-rw-r--r--audio/softsynth/mt32/LA32WaveGenerator.h2
-rw-r--r--audio/softsynth/mt32/Partial.cpp119
-rw-r--r--audio/softsynth/mt32/Partial.h15
-rw-r--r--audio/softsynth/mt32/Synth.cpp52
-rw-r--r--audio/softsynth/mt32/Synth.h11
7 files changed, 173 insertions, 105 deletions
diff --git a/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp b/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp
index 486942b75c..0c9687b4d8 100644
--- a/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp
+++ b/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp
@@ -315,15 +315,29 @@ void LA32PartialPair::generateNextSample(const PairType useMaster, const Bit32u
}
}
+static inline float produceDistortedSample(float sample) {
+ if (sample < -1.0f) {
+ return sample + 2.0f;
+ } else if (1.0f < sample) {
+ return sample - 2.0f;
+ }
+ return sample;
+}
+
float LA32PartialPair::nextOutSample() {
- float outputSample;
- if (ringModulated) {
- float ringModulatedSample = masterOutputSample * slaveOutputSample;
- outputSample = mixed ? masterOutputSample + ringModulatedSample : ringModulatedSample;
- } else {
- outputSample = masterOutputSample + slaveOutputSample;
+ if (!ringModulated) {
+ return masterOutputSample + slaveOutputSample;
}
- return outputSample;
+ /*
+ * SEMI-CONFIRMED: Ring modulation model derived from sample analysis of specially constructed patches which exploit distortion.
+ * LA32 ring modulator found to produce distorted output in case if the absolute value of maximal amplitude of one of the input partials exceeds 8191.
+ * This is easy to reproduce using synth partials with resonance values close to the maximum. It looks like an integer overflow happens in this case.
+ * As the distortion is strictly bound to the amplitude of the complete mixed square + resonance wave in the linear space,
+ * it is reasonable to assume the ring modulation is performed also in the linear space by sample multiplication.
+ * Most probably the overflow is caused by limited precision of the multiplication circuit as the very similar distortion occurs with panning.
+ */
+ float ringModulatedSample = produceDistortedSample(masterOutputSample) * produceDistortedSample(slaveOutputSample);
+ return mixed ? masterOutputSample + ringModulatedSample : ringModulatedSample;
}
void LA32PartialPair::deactivate(const PairType useMaster) {
diff --git a/audio/softsynth/mt32/LA32WaveGenerator.cpp b/audio/softsynth/mt32/LA32WaveGenerator.cpp
index 9ffc2ca32e..1d115c12ef 100644
--- a/audio/softsynth/mt32/LA32WaveGenerator.cpp
+++ b/audio/softsynth/mt32/LA32WaveGenerator.cpp
@@ -370,18 +370,12 @@ void LA32PartialPair::generateNextSample(const PairType useMaster, const Bit32u
}
}
-Bit16s LA32PartialPair::unlogAndMixWGOutput(const LA32WaveGenerator &wg, const LogSample * const ringModulatingLogSample) {
- if (!wg.isActive() || ((ringModulatingLogSample != NULL) && (ringModulatingLogSample->logValue == SILENCE.logValue))) {
+Bit16s LA32PartialPair::unlogAndMixWGOutput(const LA32WaveGenerator &wg) {
+ if (!wg.isActive()) {
return 0;
}
- LogSample firstLogSample = wg.getOutputLogSample(true);
- LogSample secondLogSample = wg.getOutputLogSample(false);
- if (ringModulatingLogSample != NULL) {
- LA32Utilites::addLogSamples(firstLogSample, *ringModulatingLogSample);
- LA32Utilites::addLogSamples(secondLogSample, *ringModulatingLogSample);
- }
- Bit16s firstSample = LA32Utilites::unlog(firstLogSample);
- Bit16s secondSample = LA32Utilites::unlog(secondLogSample);
+ Bit16s firstSample = LA32Utilites::unlog(wg.getOutputLogSample(true));
+ Bit16s secondSample = LA32Utilites::unlog(wg.getOutputLogSample(false));
if (wg.isPCMWave()) {
return Bit16s(firstSample + ((Bit32s(secondSample - firstSample) * wg.getPCMInterpolationFactor()) >> 7));
}
@@ -389,19 +383,32 @@ Bit16s LA32PartialPair::unlogAndMixWGOutput(const LA32WaveGenerator &wg, const L
}
Bit16s LA32PartialPair::nextOutSample() {
- if (ringModulated) {
- LogSample slaveFirstLogSample = slave.getOutputLogSample(true);
- LogSample slaveSecondLogSample = slave.getOutputLogSample(false);
- Bit16s sample = unlogAndMixWGOutput(master, &slaveFirstLogSample);
- if (!slave.isPCMWave()) {
- sample += unlogAndMixWGOutput(master, &slaveSecondLogSample);
- }
- if (mixed) {
- sample += unlogAndMixWGOutput(master, NULL);
- }
- return sample;
+ if (!ringModulated) {
+ return unlogAndMixWGOutput(master) + unlogAndMixWGOutput(slave);
}
- return unlogAndMixWGOutput(master, NULL) + unlogAndMixWGOutput(slave, NULL);
+
+ /*
+ * SEMI-CONFIRMED: Ring modulation model derived from sample analysis of specially constructed patches which exploit distortion.
+ * LA32 ring modulator found to produce distorted output in case if the absolute value of maximal amplitude of one of the input partials exceeds 8191.
+ * This is easy to reproduce using synth partials with resonance values close to the maximum. It looks like an integer overflow happens in this case.
+ * As the distortion is strictly bound to the amplitude of the complete mixed square + resonance wave in the linear space,
+ * it is reasonable to assume the ring modulation is performed also in the linear space by sample multiplication.
+ * Most probably the overflow is caused by limited precision of the multiplication circuit as the very similar distortion occurs with panning.
+ */
+ Bit16s nonOverdrivenMasterSample = unlogAndMixWGOutput(master); // Store master partial sample for further mixing
+ Bit16s masterSample = nonOverdrivenMasterSample << 2;
+ masterSample >>= 2;
+
+ /* SEMI-CONFIRMED from sample analysis:
+ * We observe that for partial structures with ring modulation the interpolation is not applied to the slave PCM partial.
+ * It's assumed that the multiplication circuitry intended to perform the interpolation on the slave PCM partial
+ * is borrowed by the ring modulation circuit (or the LA32 chip has a similar lack of resources assigned to each partial pair).
+ */
+ Bit16s slaveSample = slave.isPCMWave() ? LA32Utilites::unlog(slave.getOutputLogSample(true)) : unlogAndMixWGOutput(slave);
+ slaveSample <<= 2;
+ slaveSample >>= 2;
+ Bit16s ringModulatedSample = Bit16s(((Bit32s)masterSample * (Bit32s)slaveSample) >> 13);
+ return mixed ? nonOverdrivenMasterSample + ringModulatedSample : ringModulatedSample;
}
void LA32PartialPair::deactivate(const PairType useMaster) {
diff --git a/audio/softsynth/mt32/LA32WaveGenerator.h b/audio/softsynth/mt32/LA32WaveGenerator.h
index 4bc04c78d3..b5f4dedff4 100644
--- a/audio/softsynth/mt32/LA32WaveGenerator.h
+++ b/audio/softsynth/mt32/LA32WaveGenerator.h
@@ -209,7 +209,7 @@ class LA32PartialPair {
bool ringModulated;
bool mixed;
- static Bit16s unlogAndMixWGOutput(const LA32WaveGenerator &wg, const LogSample * const ringModulatingLogSample);
+ static Bit16s unlogAndMixWGOutput(const LA32WaveGenerator &wg);
public:
enum PairType {
diff --git a/audio/softsynth/mt32/Partial.cpp b/audio/softsynth/mt32/Partial.cpp
index c7848f02d8..75e674074f 100644
--- a/audio/softsynth/mt32/Partial.cpp
+++ b/audio/softsynth/mt32/Partial.cpp
@@ -24,15 +24,10 @@
namespace MT32Emu {
-#ifdef INACCURATE_SMOOTH_PAN
-// Mok wanted an option for smoother panning, and we love Mok.
-static const float PAN_NUMERATOR_NORMAL[] = {0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 5.5f, 6.0f, 6.5f, 7.0f};
-#else
-// CONFIRMED by Mok: These NUMERATOR values (as bytes, not floats, obviously) are sent exactly like this to the LA32.
-static const float PAN_NUMERATOR_NORMAL[] = {0.0f, 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 6.0f, 7.0f};
-#endif
-static const float PAN_NUMERATOR_MASTER[] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f};
-static const float PAN_NUMERATOR_SLAVE[] = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 7.0f, 7.0f, 7.0f, 7.0f, 7.0f, 7.0f, 7.0f};
+static const Bit8u PAN_NUMERATOR_MASTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7};
+static const Bit8u PAN_NUMERATOR_SLAVE[] = {0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7};
+
+static const Bit32s PAN_FACTORS[] = {0, 18, 37, 55, 73, 91, 110, 128, 146, 165, 183, 201, 219, 238, 256};
Partial::Partial(Synth *useSynth, int useDebugPartialNum) :
synth(useSynth), debugPartialNum(useDebugPartialNum), sampleNum(0) {
@@ -116,24 +111,30 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us
structurePosition = patchCache->structurePosition;
Bit8u panSetting = rhythmTemp != NULL ? rhythmTemp->panpot : part->getPatchTemp()->panpot;
- float panVal;
if (mixType == 3) {
if (structurePosition == 0) {
- panVal = PAN_NUMERATOR_MASTER[panSetting];
+ panSetting = PAN_NUMERATOR_MASTER[panSetting] << 1;
} else {
- panVal = PAN_NUMERATOR_SLAVE[panSetting];
+ panSetting = PAN_NUMERATOR_SLAVE[panSetting] << 1;
}
// Do a normal mix independent of any pair partial.
mixType = 0;
pairPartial = NULL;
} else {
- panVal = PAN_NUMERATOR_NORMAL[panSetting];
+ // Mok wanted an option for smoother panning, and we love Mok.
+#ifndef INACCURATE_SMOOTH_PAN
+ // CONFIRMED by Mok: exactly bytes like this (right shifted?) are sent to the LA32.
+ panSetting &= 0x0E;
+#endif
}
- // FIXME: Sample analysis suggests that the use of panVal is linear, but there are some some quirks that still need to be resolved.
- // FIXME: I suppose this should be panVal / 8 and undoubtly integer, clarify ASAP
- stereoVolume.leftVol = panVal / 7.0f;
- stereoVolume.rightVol = 1.0f - stereoVolume.leftVol;
+ leftPanValue = synth->reversedStereoEnabled ? 14 - panSetting : panSetting;
+ rightPanValue = 14 - leftPanValue;
+
+#if !MT32EMU_USE_FLOAT_SAMPLES
+ leftPanValue = PAN_FACTORS[leftPanValue];
+ rightPanValue = PAN_FACTORS[rightPanValue];
+#endif
// SEMI-CONFIRMED: From sample analysis:
// Found that timbres with 3 or 4 partials (i.e. one using two partial pairs) are mixed in two different ways.
@@ -150,8 +151,8 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us
// For my personal taste, this behaviour rather enriches the sounding and should be emulated.
// Also, the current partial allocator model probably needs to be refined.
if (debugPartialNum & 8) {
- stereoVolume.leftVol = -stereoVolume.leftVol;
- stereoVolume.rightVol = -stereoVolume.rightVol;
+ leftPanValue = -leftPanValue;
+ rightPanValue = -rightPanValue;
}
if (patchCache->PCMPartial) {
@@ -230,39 +231,6 @@ Bit32u Partial::getCutoffValue() {
return (tvf->getBaseCutoff() << 18) + cutoffModifierRampVal;
}
-unsigned long Partial::generateSamples(Sample *partialBuf, unsigned long length) {
- if (!isActive() || alreadyOutputed) {
- return 0;
- }
- if (poly == NULL) {
- synth->printDebug("[Partial %d] *** ERROR: poly is NULL at Partial::generateSamples()!", debugPartialNum);
- return 0;
- }
- alreadyOutputed = true;
-
- for (sampleNum = 0; sampleNum < length; sampleNum++) {
- if (!tva->isPlaying() || !la32Pair.isActive(LA32PartialPair::MASTER)) {
- deactivate();
- break;
- }
- la32Pair.generateNextSample(LA32PartialPair::MASTER, getAmpValue(), tvp->nextPitch(), getCutoffValue());
- if (hasRingModulatingSlave()) {
- la32Pair.generateNextSample(LA32PartialPair::SLAVE, pair->getAmpValue(), pair->tvp->nextPitch(), pair->getCutoffValue());
- if (!pair->tva->isPlaying() || !la32Pair.isActive(LA32PartialPair::SLAVE)) {
- pair->deactivate();
- if (mixType == 2) {
- deactivate();
- break;
- }
- }
- }
- *(partialBuf++) = la32Pair.nextOutSample();
- }
- unsigned long renderedSamples = sampleNum;
- sampleNum = 0;
- return renderedSamples;
-}
-
bool Partial::hasRingModulatingSlave() const {
return pair != NULL && structurePosition == 0 && (mixType == 1 || mixType == 2);
}
@@ -305,19 +273,52 @@ bool Partial::produceOutput(Sample *leftBuf, Sample *rightBuf, unsigned long len
synth->printDebug("[Partial %d] *** ERROR: poly is NULL at Partial::produceOutput()!", debugPartialNum);
return false;
}
- Sample buffer[MAX_SAMPLES_PER_RUN];
- unsigned long numGenerated = generateSamples(buffer, length);
- for (unsigned int i = 0; i < numGenerated; i++) {
+ alreadyOutputed = true;
+
+ for (sampleNum = 0; sampleNum < length; sampleNum++) {
+ if (!tva->isPlaying() || !la32Pair.isActive(LA32PartialPair::MASTER)) {
+ deactivate();
+ break;
+ }
+ la32Pair.generateNextSample(LA32PartialPair::MASTER, getAmpValue(), tvp->nextPitch(), getCutoffValue());
+ if (hasRingModulatingSlave()) {
+ la32Pair.generateNextSample(LA32PartialPair::SLAVE, pair->getAmpValue(), pair->tvp->nextPitch(), pair->getCutoffValue());
+ if (!pair->tva->isPlaying() || !la32Pair.isActive(LA32PartialPair::SLAVE)) {
+ pair->deactivate();
+ if (mixType == 2) {
+ deactivate();
+ break;
+ }
+ }
+ }
+
+ // Although, LA32 applies panning itself, we assume here it is applied in the mixer, not within a pair.
+ // Applying the pan value in the log-space looks like a waste of unlog resources. Though, it needs clarification.
+ Sample sample = la32Pair.nextOutSample();
+
+ // FIXME: Sample analysis suggests that the use of panVal is linear, but there are some quirks that still need to be resolved.
#if MT32EMU_USE_FLOAT_SAMPLES
- *(leftBuf++) += buffer[i] * stereoVolume.leftVol;
- *(rightBuf++) += buffer[i] * stereoVolume.rightVol;
+ Sample leftOut = (sample * (float)leftPanValue) / 14.0f;
+ Sample rightOut = (sample * (float)rightPanValue) / 14.0f;
+ *(leftBuf++) += leftOut;
+ *(rightBuf++) += rightOut;
#else
- *leftBuf = Synth::clipBit16s((Bit32s)*leftBuf + Bit32s(buffer[i] * stereoVolume.leftVol));
- *rightBuf = Synth::clipBit16s((Bit32s)*rightBuf + Bit32s(buffer[i] * stereoVolume.rightVol));
+ // FIXME: Dividing by 7 (or by 14 in a Mok-friendly way) looks of course pointless. Need clarification.
+ // FIXME2: LA32 may produce distorted sound in case if the absolute value of maximal amplitude of the input exceeds 8191
+ // when the panning value is non-zero. Most probably the distortion occurs in the same way it does with ring modulation,
+ // and it seems to be caused by limited precision of the common multiplication circuit.
+ // From analysis of this overflow, it is obvious that the right channel output is actually found
+ // by subtraction of the left channel output from the input.
+ // Though, it is unknown whether this overflow is exploited somewhere.
+ Sample leftOut = Sample((sample * leftPanValue) >> 8);
+ Sample rightOut = Sample((sample * rightPanValue) >> 8);
+ *leftBuf = Synth::clipBit16s((Bit32s)*leftBuf + (Bit32s)leftOut);
+ *rightBuf = Synth::clipBit16s((Bit32s)*rightBuf + (Bit32s)rightOut);
leftBuf++;
rightBuf++;
#endif
}
+ sampleNum = 0;
return true;
}
diff --git a/audio/softsynth/mt32/Partial.h b/audio/softsynth/mt32/Partial.h
index 358cb9d2d9..05c1c740c4 100644
--- a/audio/softsynth/mt32/Partial.h
+++ b/audio/softsynth/mt32/Partial.h
@@ -25,24 +25,22 @@ class Part;
class TVA;
struct ControlROMPCMStruct;
-struct StereoVolume {
- float leftVol;
- float rightVol;
-};
-
// A partial represents one of up to four waveform generators currently playing within a poly.
class Partial {
private:
Synth *synth;
const int debugPartialNum; // Only used for debugging
- // Number of the sample currently being rendered by generateSamples(), or 0 if no run is in progress
+ // Number of the sample currently being rendered by produceOutput(), or 0 if no run is in progress
// This is only kept available for debugging purposes.
unsigned long sampleNum;
+ // Actually, this is a 4-bit register but we abuse this to emulate inverted mixing.
+ // Also we double the value to enable INACCURATE_SMOOTH_PAN, with respect to MoK.
+ Bit32s leftPanValue, rightPanValue;
+
int ownerPart; // -1 if unassigned
int mixType;
int structurePosition; // 0 or 1 of a structure pair
- StereoVolume stereoVolume;
// Only used for PCM partials
int pcmNum;
@@ -103,9 +101,6 @@ public:
// This function (unlike the one below it) returns processed stereo samples
// made from combining this single partial with its pair, if it has one.
bool produceOutput(Sample *leftBuf, Sample *rightBuf, unsigned long length);
-
- // This function writes mono sample output to the provided buffer, and returns the number of samples written
- unsigned long generateSamples(Sample *partialBuf, unsigned long length);
};
}
diff --git a/audio/softsynth/mt32/Synth.cpp b/audio/softsynth/mt32/Synth.cpp
index b76dc58b5f..efba9b7514 100644
--- a/audio/softsynth/mt32/Synth.cpp
+++ b/audio/softsynth/mt32/Synth.cpp
@@ -76,6 +76,7 @@ Synth::Synth(ReportHandler *useReportHandler) {
isOpen = false;
reverbEnabled = true;
reverbOverridden = false;
+ partialCount = DEFAULT_MAX_PARTIALS;
if (useReportHandler == NULL) {
reportHandler = new ReportHandler;
@@ -95,6 +96,7 @@ Synth::Synth(ReportHandler *useReportHandler) {
setMIDIDelayMode(MIDIDelayMode_DELAY_SHORT_MESSAGES_ONLY);
setOutputGain(1.0f);
setReverbOutputGain(1.0f);
+ setReversedStereoEnabled(false);
partialManager = NULL;
midiQueue = NULL;
lastReceivedMIDIEventTimestamp = 0;
@@ -172,6 +174,8 @@ MIDIDelayMode Synth::getMIDIDelayMode() const {
return midiDelayMode;
}
+#if MT32EMU_USE_FLOAT_SAMPLES
+
void Synth::setOutputGain(float newOutputGain) {
outputGain = newOutputGain;
}
@@ -188,6 +192,39 @@ float Synth::getReverbOutputGain() const {
return reverbOutputGain;
}
+#else // #if MT32EMU_USE_FLOAT_SAMPLES
+
+void Synth::setOutputGain(float newOutputGain) {
+ if (newOutputGain < 0.0f) newOutputGain = -newOutputGain;
+ if (256.0f < newOutputGain) newOutputGain = 256.0f;
+ outputGain = int(newOutputGain * 256.0f);
+}
+
+float Synth::getOutputGain() const {
+ return outputGain / 256.0f;
+}
+
+void Synth::setReverbOutputGain(float newReverbOutputGain) {
+ if (newReverbOutputGain < 0.0f) newReverbOutputGain = -newReverbOutputGain;
+ float maxValue = 256.0f / CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR;
+ if (maxValue < newReverbOutputGain) newReverbOutputGain = maxValue;
+ reverbOutputGain = int(newReverbOutputGain * 256.0f);
+}
+
+float Synth::getReverbOutputGain() const {
+ return reverbOutputGain / 256.0f;
+}
+
+#endif // #if MT32EMU_USE_FLOAT_SAMPLES
+
+void Synth::setReversedStereoEnabled(bool enabled) {
+ reversedStereoEnabled = enabled;
+}
+
+bool Synth::isReversedStereoEnabled() {
+ return reversedStereoEnabled;
+}
+
bool Synth::loadControlROM(const ROMImage &controlROMImage) {
if (&controlROMImage == NULL) return false;
Common::File *file = controlROMImage.getFile();
@@ -1445,16 +1482,19 @@ void Synth::convertSamplesToOutput(Sample *target, const Sample *source, Bit32u
*(target++) = *(source++) * gain;
}
#else
- float gain = reverb ? reverbOutputGain * CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR : outputGain;
- if (!reverb) {
+ int gain;
+ if (reverb) {
+ gain = int(reverbOutputGain * CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR);
+ } else {
+ gain = outputGain;
switch (dacInputMode) {
case DACInputMode_NICE:
// Since we're not shooting for accuracy here, don't worry about the rounding mode.
- gain *= 2.0f;
+ gain <<= 1;
break;
case DACInputMode_GENERATION1:
while (len--) {
- *target = clipBit16s(Bit32s(*source * gain));
+ *target = clipBit16s(Bit32s((*source * gain) >> 8));
*target = (*target & 0x8000) | ((*target << 1) & 0x7FFE);
source++;
target++;
@@ -1462,7 +1502,7 @@ void Synth::convertSamplesToOutput(Sample *target, const Sample *source, Bit32u
return;
case DACInputMode_GENERATION2:
while (len--) {
- *target = clipBit16s(Bit32s(*source * gain));
+ *target = clipBit16s(Bit32s((*source * gain) >> 8));
*target = (*target & 0x8000) | ((*target << 1) & 0x7FFE) | ((*target >> 14) & 0x0001);
source++;
target++;
@@ -1473,7 +1513,7 @@ void Synth::convertSamplesToOutput(Sample *target, const Sample *source, Bit32u
}
}
while (len--) {
- *(target++) = clipBit16s(Bit32s(*(source++) * gain));
+ *(target++) = clipBit16s(Bit32s((*(source++) * gain) >> 8));
}
#endif
}
diff --git a/audio/softsynth/mt32/Synth.h b/audio/softsynth/mt32/Synth.h
index 783d6e2747..8816711bf3 100644
--- a/audio/softsynth/mt32/Synth.h
+++ b/audio/softsynth/mt32/Synth.h
@@ -343,8 +343,16 @@ private:
MIDIDelayMode midiDelayMode;
DACInputMode dacInputMode;
+
+#if MT32EMU_USE_FLOAT_SAMPLES
float outputGain;
float reverbOutputGain;
+#else
+ int outputGain;
+ int reverbOutputGain;
+#endif
+
+ bool reversedStereoEnabled;
bool isOpen;
@@ -477,6 +485,9 @@ public:
void setReverbOutputGain(float);
float getReverbOutputGain() const;
+ void setReversedStereoEnabled(bool enabled);
+ bool isReversedStereoEnabled();
+
// Renders samples to the specified output stream.
// The length is in frames, not bytes (in 16-bit stereo,
// one frame is 4 bytes).