DOSBox-X
|
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 useSawtoothWaveform, const Bit8u usePulseWidth, const Bit8u useResonance); 00180 00181 // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters 00182 void initPCM(const Bit16s * const usePCMWaveAddress, const Bit32u usePCMWaveLength, const bool usePCMWaveLooped, const bool usePCMWaveInterpolated); 00183 00184 // Update parameters with respect to TVP, TVA and TVF, and generate next sample 00185 void generateNextSample(const Bit32u useAmp, const Bit16u usePitch, const Bit32u useCutoffVal); 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 useRingModulated, const bool useMixed); 00222 00223 // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters 00224 void initSynth(const PairType useMaster, 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 useMaster, 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 useMaster); 00237 00238 // Return active state of the WG engine 00239 bool isActive(const PairType useMaster) const; 00240 }; 00241 00242 } // namespace MT32Emu 00243 00244 #endif // #ifndef MT32EMU_LA32_WAVE_GENERATOR_H 00245 00246 #endif // #if MT32EMU_ACCURATE_WG == 0