DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/mt32/LA32WaveGenerator.h
00001 /* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
00002  * Copyright (C) 2011, 2012, 2013 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
00003  *
00004  *  This program is free software: you can redistribute it and/or modify
00005  *  it under the terms of the GNU Lesser General Public License as published by
00006  *  the Free Software Foundation, either version 2.1 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU Lesser General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Lesser General Public License
00015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00018 #if MT32EMU_ACCURATE_WG == 0
00019 
00020 #ifndef MT32EMU_LA32_WAVE_GENERATOR_H
00021 #define MT32EMU_LA32_WAVE_GENERATOR_H
00022 
00023 namespace MT32Emu {
00024 
00035 struct LogSample {
00036         // 16-bit fixed point value, includes 12-bit fractional part
00037         // 4-bit integer part allows to present any 16-bit sample in the log-space
00038         // Obviously, the log value doesn't contain the sign of the resulting sample
00039         Bit16u logValue;
00040         enum {
00041                 POSITIVE,
00042                 NEGATIVE
00043         } sign;
00044 };
00045 
00046 class LA32Utilites {
00047 public:
00048         static Bit16u interpolateExp(const Bit16u fract);
00049         static Bit16s unlog(const LogSample &logSample);
00050         static void addLogSamples(LogSample &logSample1, const LogSample &logSample2);
00051 };
00052 
00061 class LA32WaveGenerator {
00062         //***************************************************************************
00063         //  The local copy of partial parameters below
00064         //***************************************************************************
00065 
00066         bool active;
00067 
00068         // True means the resulting square wave is to be multiplied by the synchronous cosine
00069         bool sawtoothWaveform;
00070 
00071         // Logarithmic amp of the wave generator
00072         Bit32u amp;
00073 
00074         // Logarithmic frequency of the resulting wave
00075         Bit16u pitch;
00076 
00077         // Values in range [1..31]
00078         // Value 1 correspong to the minimum resonance
00079         Bit8u resonance;
00080 
00081         // Processed value in range [0..255]
00082         // Values in range [0..128] have no effect and the resulting wave remains symmetrical
00083         // Value 255 corresponds to the maximum possible asymmetric of the resulting wave
00084         Bit8u pulseWidth;
00085 
00086         // Composed of the base cutoff in range [78..178] left-shifted by 18 bits and the TVF modifier
00087         Bit32u cutoffVal;
00088 
00089         // Logarithmic PCM sample start address
00090         const Bit16s *pcmWaveAddress;
00091 
00092         // Logarithmic PCM sample length
00093         Bit32u pcmWaveLength;
00094 
00095         // true for looped logarithmic PCM samples
00096         bool pcmWaveLooped;
00097 
00098         // false for slave PCM partials in the structures with the ring modulation
00099         bool pcmWaveInterpolated;
00100 
00101         //***************************************************************************
00102         // Internal variables below
00103         //***************************************************************************
00104 
00105         // Relative position within either the synth wave or the PCM sampled wave
00106         // 0 - start of the positive rising sine segment of the square wave or start of the PCM sample
00107         // 1048576 (2^20) - end of the negative rising sine segment of the square wave
00108         // For PCM waves, the address of the currently playing sample equals (wavePosition / 256)
00109         Bit32u wavePosition;
00110 
00111         // Relative position within a square wave phase:
00112         // 0             - start of the phase
00113         // 262144 (2^18) - end of a sine phase in the square wave
00114         Bit32u squareWavePosition;
00115 
00116         // Relative position within the positive or negative wave segment:
00117         // 0 - start of the corresponding positive or negative segment of the square wave
00118         // 262144 (2^18) - corresponds to end of the first sine phase in the square wave
00119         // The same increment sampleStep is used to indicate the current position
00120         // since the length of the resonance wave is always equal to four square wave sine segments.
00121         Bit32u resonanceSinePosition;
00122 
00123         // The amp of the resonance sine wave grows with the resonance value
00124         // As the resonance value cannot change while the partial is active, it is initialised once
00125         Bit32u resonanceAmpSubtraction;
00126 
00127         // The decay speed of resonance sine wave, depends on the resonance value
00128         Bit32u resAmpDecayFactor;
00129 
00130         // Fractional part of the pcmPosition
00131         Bit32u pcmInterpolationFactor;
00132 
00133         // Current phase of the square wave
00134         enum {
00135                 POSITIVE_RISING_SINE_SEGMENT,
00136                 POSITIVE_LINEAR_SEGMENT,
00137                 POSITIVE_FALLING_SINE_SEGMENT,
00138                 NEGATIVE_FALLING_SINE_SEGMENT,
00139                 NEGATIVE_LINEAR_SEGMENT,
00140                 NEGATIVE_RISING_SINE_SEGMENT
00141         } phase;
00142 
00143         // Current phase of the resonance wave
00144         enum {
00145                 POSITIVE_RISING_RESONANCE_SINE_SEGMENT,
00146                 POSITIVE_FALLING_RESONANCE_SINE_SEGMENT,
00147                 NEGATIVE_FALLING_RESONANCE_SINE_SEGMENT,
00148                 NEGATIVE_RISING_RESONANCE_SINE_SEGMENT
00149         } resonancePhase;
00150 
00151         // Resulting log-space samples of the square and resonance waves
00152         LogSample squareLogSample;
00153         LogSample resonanceLogSample;
00154 
00155         // Processed neighbour log-space samples of the PCM wave
00156         LogSample firstPCMLogSample;
00157         LogSample secondPCMLogSample;
00158 
00159         //***************************************************************************
00160         // Internal methods below
00161         //***************************************************************************
00162 
00163         Bit32u getSampleStep();
00164         Bit32u getResonanceWaveLengthFactor(Bit32u effectiveCutoffValue);
00165         Bit32u getHighLinearLength(Bit32u effectiveCutoffValue);
00166 
00167         void computePositions(Bit32u highLinearLength, Bit32u lowLinearLength, Bit32u resonanceWaveLengthFactor);
00168         void advancePosition();
00169 
00170         void generateNextSquareWaveLogSample();
00171         void generateNextResonanceWaveLogSample();
00172         void generateNextSawtoothCosineLogSample(LogSample &logSample) const;
00173 
00174         void pcmSampleToLogSample(LogSample &logSample, const Bit16s pcmSample) const;
00175         void generateNextPCMWaveLogSamples();
00176 
00177 public:
00178         // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters
00179         void initSynth(const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance);
00180 
00181         // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters
00182         void initPCM(const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped, const bool pcmWaveInterpolated);
00183 
00184         // Update parameters with respect to TVP, TVA and TVF, and generate next sample
00185         void generateNextSample(const Bit32u amp, const Bit16u pitch, const Bit32u cutoff);
00186 
00187         // WG output in the log-space consists of two components which are to be added (or ring modulated) in the linear-space afterwards
00188         LogSample getOutputLogSample(const bool first) const;
00189 
00190         // Deactivate the WG engine
00191         void deactivate();
00192 
00193         // Return active state of the WG engine
00194         bool isActive() const;
00195 
00196         // Return true if the WG engine generates PCM wave samples
00197         bool isPCMWave() const;
00198 
00199         // Return current PCM interpolation factor
00200         Bit32u getPCMInterpolationFactor() const;
00201 };
00202 
00203 // LA32PartialPair contains a structure of two partials being mixed / ring modulated
00204 class LA32PartialPair {
00205         LA32WaveGenerator master;
00206         LA32WaveGenerator slave;
00207         bool ringModulated;
00208         bool mixed;
00209 
00210         static Bit16s unlogAndMixWGOutput(const LA32WaveGenerator &wg, const LogSample * const ringModulatingLogSample);
00211 
00212 public:
00213         enum PairType {
00214                 MASTER,
00215                 SLAVE
00216         };
00217 
00218         // ringModulated should be set to false for the structures with mixing or stereo output
00219         // ringModulated should be set to true for the structures with ring modulation
00220         // mixed is used for the structures with ring modulation and indicates whether the master partial output is mixed to the ring modulator output
00221         void init(const bool ringModulated, const bool mixed);
00222 
00223         // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters
00224         void initSynth(const PairType master, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance);
00225 
00226         // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters
00227         void initPCM(const PairType master, const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped);
00228 
00229         // Update parameters with respect to TVP, TVA and TVF, and generate next sample
00230         void generateNextSample(const PairType master, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff);
00231 
00232         // Perform mixing / ring modulation and return the result
00233         Bit16s nextOutSample();
00234 
00235         // Deactivate the WG engine
00236         void deactivate(const PairType master);
00237 
00238         // Return active state of the WG engine
00239         bool isActive(const PairType master) const;
00240 };
00241 
00242 } // namespace MT32Emu
00243 
00244 #endif // #ifndef MT32EMU_LA32_WAVE_GENERATOR_H
00245 
00246 #endif // #if MT32EMU_ACCURATE_WG == 0