ScummVM API documentation
LA32WaveGenerator.h
1 /* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
2  * Copyright (C) 2011-2022 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 2.1 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef MT32EMU_LA32_WAVE_GENERATOR_H
19 #define MT32EMU_LA32_WAVE_GENERATOR_H
20 
21 #include "globals.h"
22 #include "internals.h"
23 #include "Types.h"
24 
25 namespace MT32Emu {
26 
37 struct LogSample {
38  // 16-bit fixed point value, includes 12-bit fractional part
39  // 4-bit integer part allows to present any 16-bit sample in the log-space
40  // Obviously, the log value doesn't contain the sign of the resulting sample
41  Bit16u logValue;
42  enum {
43  POSITIVE,
44  NEGATIVE
45  } sign;
46 };
47 
48 class LA32Utilites {
49 public:
50  static Bit16u interpolateExp(const Bit16u fract);
51  static Bit16s unlog(const LogSample &logSample);
52  static void addLogSamples(LogSample &logSample1, const LogSample &logSample2);
53 };
54 
64  //***************************************************************************
65  // The local copy of partial parameters below
66  //***************************************************************************
67 
68  bool active;
69 
70  // True means the resulting square wave is to be multiplied by the synchronous cosine
71  bool sawtoothWaveform;
72 
73  // Logarithmic amp of the wave generator
74  Bit32u amp;
75 
76  // Logarithmic frequency of the resulting wave
77  Bit16u pitch;
78 
79  // Values in range [1..31]
80  // Value 1 correspong to the minimum resonance
81  Bit8u resonance;
82 
83  // Processed value in range [0..255]
84  // Values in range [0..128] have no effect and the resulting wave remains symmetrical
85  // Value 255 corresponds to the maximum possible asymmetric of the resulting wave
86  Bit8u pulseWidth;
87 
88  // Composed of the base cutoff in range [78..178] left-shifted by 18 bits and the TVF modifier
89  Bit32u cutoffVal;
90 
91  // Logarithmic PCM sample start address
92  const Bit16s *pcmWaveAddress;
93 
94  // Logarithmic PCM sample length
95  Bit32u pcmWaveLength;
96 
97  // true for looped logarithmic PCM samples
98  bool pcmWaveLooped;
99 
100  // false for slave PCM partials in the structures with the ring modulation
101  bool pcmWaveInterpolated;
102 
103  //***************************************************************************
104  // Internal variables below
105  //***************************************************************************
106 
107  // Relative position within either the synth wave or the PCM sampled wave
108  // 0 - start of the positive rising sine segment of the square wave or start of the PCM sample
109  // 1048576 (2^20) - end of the negative rising sine segment of the square wave
110  // For PCM waves, the address of the currently playing sample equals (wavePosition / 256)
111  Bit32u wavePosition;
112 
113  // Relative position within a square wave phase:
114  // 0 - start of the phase
115  // 262144 (2^18) - end of a sine phase in the square wave
116  Bit32u squareWavePosition;
117 
118  // Relative position within the positive or negative wave segment:
119  // 0 - start of the corresponding positive or negative segment of the square wave
120  // 262144 (2^18) - corresponds to end of the first sine phase in the square wave
121  // The same increment sampleStep is used to indicate the current position
122  // since the length of the resonance wave is always equal to four square wave sine segments.
123  Bit32u resonanceSinePosition;
124 
125  // The amp of the resonance sine wave grows with the resonance value
126  // As the resonance value cannot change while the partial is active, it is initialised once
127  Bit32u resonanceAmpSubtraction;
128 
129  // The decay speed of resonance sine wave, depends on the resonance value
130  Bit32u resAmpDecayFactor;
131 
132  // Fractional part of the pcmPosition
133  Bit32u pcmInterpolationFactor;
134 
135  // Current phase of the square wave
136  enum {
137  POSITIVE_RISING_SINE_SEGMENT,
138  POSITIVE_LINEAR_SEGMENT,
139  POSITIVE_FALLING_SINE_SEGMENT,
140  NEGATIVE_FALLING_SINE_SEGMENT,
141  NEGATIVE_LINEAR_SEGMENT,
142  NEGATIVE_RISING_SINE_SEGMENT
143  } phase;
144 
145  // Current phase of the resonance wave
146  enum ResonancePhase {
147  POSITIVE_RISING_RESONANCE_SINE_SEGMENT,
148  POSITIVE_FALLING_RESONANCE_SINE_SEGMENT,
149  NEGATIVE_FALLING_RESONANCE_SINE_SEGMENT,
150  NEGATIVE_RISING_RESONANCE_SINE_SEGMENT
151  } resonancePhase;
152 
153  // Resulting log-space samples of the square and resonance waves
154  LogSample squareLogSample;
155  LogSample resonanceLogSample;
156 
157  // Processed neighbour log-space samples of the PCM wave
158  LogSample firstPCMLogSample;
159  LogSample secondPCMLogSample;
160 
161  //***************************************************************************
162  // Internal methods below
163  //***************************************************************************
164 
165  Bit32u getSampleStep();
166  Bit32u getResonanceWaveLengthFactor(Bit32u effectiveCutoffValue);
167  Bit32u getHighLinearLength(Bit32u effectiveCutoffValue);
168 
169  void computePositions(Bit32u highLinearLength, Bit32u lowLinearLength, Bit32u resonanceWaveLengthFactor);
170  void advancePosition();
171 
172  void generateNextSquareWaveLogSample();
173  void generateNextResonanceWaveLogSample();
174  void generateNextSawtoothCosineLogSample(LogSample &logSample) const;
175 
176  void pcmSampleToLogSample(LogSample &logSample, const Bit16s pcmSample) const;
177  void generateNextPCMWaveLogSamples();
178 
179 public:
180  // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters
181  void initSynth(const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance);
182 
183  // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters
184  void initPCM(const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped, const bool pcmWaveInterpolated);
185 
186  // Update parameters with respect to TVP, TVA and TVF, and generate next sample
187  void generateNextSample(const Bit32u amp, const Bit16u pitch, const Bit32u cutoff);
188 
189  // WG output in the log-space consists of two components which are to be added (or ring modulated) in the linear-space afterwards
190  LogSample getOutputLogSample(const bool first) const;
191 
192  // Deactivate the WG engine
193  void deactivate();
194 
195  // Return active state of the WG engine
196  bool isActive() const;
197 
198  // Return true if the WG engine generates PCM wave samples
199  bool isPCMWave() const;
200 
201  // Return current PCM interpolation factor
202  Bit32u getPCMInterpolationFactor() const;
203 }; // class LA32WaveGenerator
204 
205 // LA32PartialPair contains a structure of two partials being mixed / ring modulated
207 public:
208  enum PairType {
209  MASTER,
210  SLAVE
211  };
212 
213  virtual ~LA32PartialPair() {}
214 
215  // ringModulated should be set to false for the structures with mixing or stereo output
216  // ringModulated should be set to true for the structures with ring modulation
217  // mixed is used for the structures with ring modulation and indicates whether the master partial output is mixed to the ring modulator output
218  virtual void init(const bool ringModulated, const bool mixed) = 0;
219 
220  // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters
221  virtual void initSynth(const PairType master, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance) = 0;
222 
223  // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters
224  virtual void initPCM(const PairType master, const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped) = 0;
225 
226  // Deactivate the WG engine
227  virtual void deactivate(const PairType master) = 0;
228 }; // class LA32PartialPair
229 
231  LA32WaveGenerator master;
232  LA32WaveGenerator slave;
233  bool ringModulated;
234  bool mixed;
235 
236  static Bit16s unlogAndMixWGOutput(const LA32WaveGenerator &wg);
237 
238 public:
239  // ringModulated should be set to false for the structures with mixing or stereo output
240  // ringModulated should be set to true for the structures with ring modulation
241  // mixed is used for the structures with ring modulation and indicates whether the master partial output is mixed to the ring modulator output
242  void init(const bool ringModulated, const bool mixed);
243 
244  // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters
245  void initSynth(const PairType master, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance);
246 
247  // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters
248  void initPCM(const PairType master, const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped);
249 
250  // Update parameters with respect to TVP, TVA and TVF, and generate next sample
251  void generateNextSample(const PairType master, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff);
252 
253  // Perform mixing / ring modulation of WG output and return the result
254  // Although, LA32 applies panning itself, we assume it is applied in the mixer, not within a pair
255  Bit16s nextOutSample();
256 
257  // Deactivate the WG engine
258  void deactivate(const PairType master);
259 
260  // Return active state of the WG engine
261  bool isActive(const PairType master) const;
262 }; // class LA32IntPartialPair
263 
264 } // namespace MT32Emu
265 
266 #endif // #ifndef MT32EMU_LA32_WAVE_GENERATOR_H
Definition: LA32WaveGenerator.h:230
Definition: LA32WaveGenerator.h:206
Definition: Analog.h:26
Definition: LA32WaveGenerator.h:48
Definition: LA32WaveGenerator.h:63
Definition: LA32WaveGenerator.h:37