Skip to content
Permalink
Browse files
Changed sample format conversion implementation
We now ensure that integer samples are converted to normalised float samples
as well as float samples are still converted to full-range integer ones.
LA32FloatWaveGenerator now produces output at 0.25 volume that corresponds
to the 8192/32768 ratio used in LA32 for integers.
Still, no clamping is applied in DACInputMode_NICE mode, so the output
samples may overshoot a little for tunes with the volume set too high.
  • Loading branch information
sergm committed May 28, 2017
1 parent 909717e commit db2c53e49b67f0edb413aee18860da66de0c5681
Showing with 30 additions and 11 deletions.
  1. +7 −2 mt32emu/src/LA32FloatWaveGenerator.cpp
  2. +21 −7 mt32emu/src/Synth.cpp
  3. +2 −2 mt32emu/src/Synth.h
@@ -328,8 +328,13 @@ static inline float produceDistortedSample(float sample) {
}

float LA32FloatPartialPair::nextOutSample() {
// Note, LA32FloatWaveGenerator produces each sample normalised in terms of a single playing partial,
// so the unity sample corresponds to the internal LA32 logarithmic fixed-point unity sample.
// However, each logarithmic sample is then unlogged to a 14-bit signed integer value, i.e. the max absolute value is 8192.
// Thus, considering that samples are further mapped to a 16-bit signed integer,
// we apply a conversion factor 0.25 to produce properly normalised float samples.
if (!ringModulated) {
return masterOutputSample + slaveOutputSample;
return 0.25f * (masterOutputSample + slaveOutputSample);
}
/*
* SEMI-CONFIRMED: Ring modulation model derived from sample analysis of specially constructed patches which exploit distortion.
@@ -340,7 +345,7 @@ float LA32FloatPartialPair::nextOutSample() {
* 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;
return 0.25f * (mixed ? masterOutputSample + ringModulatedSample : ringModulatedSample);
}

void LA32FloatPartialPair::deactivate(const PairType useMaster) {
@@ -2017,29 +2017,43 @@ void RendererImpl<IntSample>::convertSamplesToOutput(IntSample *buffer, Bit32u l
}

static inline float produceDistortedSample(float sample) {
if (sample < -2.0f) {
return sample + 4.0f;
} else if (2.0f < sample) {
return sample - 4.0f;
// Here we roughly simulate the distortion caused by the DAC bit shift.
if (sample < -1.0f) {
return sample + 2.0f;
} else if (1.0f < sample) {
return sample - 2.0f;
}
return sample;
}

template <>
void RendererImpl<FloatSample>::produceLA32Output(FloatSample *buffer, Bit32u len) {
if (synth.getDACInputMode() == DACInputMode_GENERATION2) {
switch (synth.getDACInputMode()) {
case DACInputMode_NICE:
// Note, we do not do any clamping for floats here to avoid introducing distortions.
// This means that the output signal may actually overshoot the unity when the volume is set too high.
// We leave it up to the consumer whether the output is to be clamped or properly normalised further on.
while (len--) {
*buffer *= 2.0f;
buffer++;
}
break;
case DACInputMode_GENERATION2:
while (len--) {
*buffer = produceDistortedSample(*buffer);
*buffer = produceDistortedSample(2.0f * *buffer);
buffer++;
}
break;
default:
break;
}
}

template <>
void RendererImpl<FloatSample>::convertSamplesToOutput(FloatSample *buffer, Bit32u len) {
if (synth.getDACInputMode() == DACInputMode_GENERATION1) {
while (len--) {
*buffer = produceDistortedSample(*buffer);
*buffer = produceDistortedSample(2.0f * *buffer);
buffer++;
}
}
@@ -259,11 +259,11 @@ friend class TVP;
}

static inline Bit16s convertSample(float sample) {
return Synth::clipSampleEx(Bit32s(sample * 16384.0f)); // This multiplier takes into account the DAC bit shift
return Synth::clipSampleEx(Bit32s(sample * 32768.0f)); // This multiplier corresponds to normalised floats
}

static inline float convertSample(Bit16s sample) {
return float(sample) / 16384.0f; // This multiplier takes into account the DAC bit shift
return float(sample) / 32768.0f; // This multiplier corresponds to normalised floats
}

// Returns library version as an integer in format: 0x00MMmmpp, where:

0 comments on commit db2c53e

Please sign in to comment.