1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
* Copyright (C) 2011, 2012, 2013 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if MT32EMU_ACCURATE_WG == 1
#ifndef MT32EMU_LA32_WAVE_GENERATOR_H
#define MT32EMU_LA32_WAVE_GENERATOR_H
namespace MT32Emu {
/**
* LA32WaveGenerator is aimed to represent the exact model of LA32 wave generator.
* The output square wave is created by adding high / low linear segments in-between
* the rising and falling cosine segments. Basically, it�s very similar to the phase distortion synthesis.
* Behaviour of a true resonance filter is emulated by adding decaying sine wave.
* The beginning and the ending of the resonant sine is multiplied by a cosine window.
* To synthesise sawtooth waves, the resulting square wave is multiplied by synchronous cosine wave.
*/
class LA32WaveGenerator {
//***************************************************************************
// The local copy of partial parameters below
//***************************************************************************
bool active;
// True means the resulting square wave is to be multiplied by the synchronous cosine
bool sawtoothWaveform;
// Logarithmic amp of the wave generator
Bit32u amp;
// Logarithmic frequency of the resulting wave
Bit16u pitch;
// Values in range [1..31]
// Value 1 correspong to the minimum resonance
Bit8u resonance;
// Processed value in range [0..255]
// Values in range [0..128] have no effect and the resulting wave remains symmetrical
// Value 255 corresponds to the maximum possible asymmetric of the resulting wave
Bit8u pulseWidth;
// Composed of the base cutoff in range [78..178] left-shifted by 18 bits and the TVF modifier
Bit32u cutoffVal;
// Logarithmic PCM sample start address
const Bit16s *pcmWaveAddress;
// Logarithmic PCM sample length
Bit32u pcmWaveLength;
// true for looped logarithmic PCM samples
bool pcmWaveLooped;
// false for slave PCM partials in the structures with the ring modulation
bool pcmWaveInterpolated;
//***************************************************************************
// Internal variables below
//***************************************************************************
float wavePos;
float lastFreq;
float pcmPosition;
float getPCMSample(unsigned int position);
public:
// Initialise the WG engine for generation of synth partial samples and set up the invariant parameters
void initSynth(const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance);
// Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters
void initPCM(const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped, const bool pcmWaveInterpolated);
// Update parameters with respect to TVP, TVA and TVF, and generate next sample
float generateNextSample(const Bit32u amp, const Bit16u pitch, const Bit32u cutoff);
// Deactivate the WG engine
void deactivate();
// Return active state of the WG engine
bool isActive() const;
// Return true if the WG engine generates PCM wave samples
bool isPCMWave() const;
};
// LA32PartialPair contains a structure of two partials being mixed / ring modulated
class LA32PartialPair {
LA32WaveGenerator master;
LA32WaveGenerator slave;
bool ringModulated;
bool mixed;
float masterOutputSample;
float slaveOutputSample;
public:
enum PairType {
MASTER,
SLAVE
};
// ringModulated should be set to false for the structures with mixing or stereo output
// ringModulated should be set to true for the structures with ring modulation
// mixed is used for the structures with ring modulation and indicates whether the master partial output is mixed to the ring modulator output
void init(const bool ringModulated, const bool mixed);
// Initialise the WG engine for generation of synth partial samples and set up the invariant parameters
void initSynth(const PairType master, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance);
// Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters
void initPCM(const PairType master, const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped);
// Update parameters with respect to TVP, TVA and TVF, and generate next sample
void generateNextSample(const PairType master, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff);
// Perform mixing / ring modulation and return the result
Bit16s nextOutSample();
// Deactivate the WG engine
void deactivate(const PairType master);
// Return active state of the WG engine
bool isActive(const PairType master) const;
};
} // namespace MT32Emu
#endif // #ifndef MT32EMU_LA32_WAVE_GENERATOR_H
#endif // #if MT32EMU_ACCURATE_WG == 1
|