/[svn]/linuxsampler/trunk/src/engines/common/LFOTriangleDiHarmonic.h
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/common/LFOTriangleDiHarmonic.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3625 - (hide annotations) (download) (as text)
Thu Oct 3 13:37:25 2019 UTC (4 years, 5 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 10091 byte(s)
* gig format extension: Added support for different LFO wave forms
  (currently either sine [default], triangle, saw or square).

* gig format extension: Added support for LFO phase displacement
  (0°..360°).

* gig format extension: Added support for flipping LFO polarity on LFO 3
  (in the original gig format this was only available for LFO 1 and LFO 2).

* Bumped version (2.1.1.svn22).

1 schoenebeck 717 /***************************************************************************
2     * *
3 schoenebeck 3561 * Copyright (C) 2005 - 2019 Christian Schoenebeck *
4 schoenebeck 717 * *
5     * This library is free software; you can redistribute it and/or modify *
6     * it under the terms of the GNU General Public License as published by *
7     * the Free Software Foundation; either version 2 of the License, or *
8     * (at your option) any later version. *
9     * *
10     * This library is distributed in the hope that it will be useful, *
11     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13     * GNU General Public License for more details. *
14     * *
15     * You should have received a copy of the GNU General Public License *
16     * along with this library; if not, write to the Free Software *
17     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
18     * MA 02111-1307 USA *
19     ***************************************************************************/
20    
21     #ifndef __LS_LFOTRIANGLEDIHARMONIC_H__
22     #define __LS_LFOTRIANGLEDIHARMONIC_H__
23    
24     #include "LFOBase.h"
25    
26     // amplitue of 2nd harmonic (to approximate the triangular wave)
27 schoenebeck 1681 #define AMP2 -0.11425509f
28 schoenebeck 717
29     namespace LinuxSampler {
30    
31     /** @brief Triangle LFO (di-harmonic implementation)
32     *
33     * This is a triangle Low Frequency Oscillator implementation which uses
34     * a di-harmonic solution. This means it sums up two harmonics
35     * (sinusoids) to approximate a triangular wave.
36 schoenebeck 3612 *
37     * @deprecated This class will probably be removed in future. Reason: The
38     * resulting wave form is not similar enough to a triangular wave. to
39     * achieve a more appropriate triangular wave form, this class would need
40     * to use more harmonics, but that in turn would make runtime performance of
41     * this class even worse. And since it currently seems to perform worst
42     * already among all triangular wave implementations on all known
43     * architectures, doing that required harmonics change currently does not
44     * make sense. Furthermore the detailed behaviour of the other triangular
45     * LFO implementations had been fixed in the meantime; this one not.
46 schoenebeck 717 */
47 schoenebeck 3612 template<LFO::range_type_t RANGE>
48     class DEPRECATED_API LFOTriangleDiHarmonic : public LFOBase<RANGE> {
49 schoenebeck 717 public:
50    
51     /**
52     * Constructor
53     *
54     * @param Max - maximum value of the output levels
55     */
56     LFOTriangleDiHarmonic(float Max) : LFOBase<RANGE>::LFOBase(Max) {
57 schoenebeck 3625 //NOTE: DO NOT add any custom initialization here, since it would break LFOCluster construction !
58 schoenebeck 717 }
59    
60     /**
61     * Calculates exactly one sample point of the LFO wave.
62     *
63     * @returns next LFO level
64     */
65     inline float render() {
66     real1 -= c1 * imag1;
67     imag1 += c1 * real1;
68     real2 -= c2 * imag2;
69     imag2 += c2 * real2;
70 schoenebeck 3612 if (RANGE == LFO::range_unsigned)
71 schoenebeck 721 return (real1 + real2 * AMP2) * normalizer + offset;
72 schoenebeck 717 else /* signed range */
73     return (real1 + real2 * AMP2) * normalizer;
74     }
75    
76     /**
77     * Update LFO depth with a new external controller value.
78     *
79     * @param ExtControlValue - new external controller value
80     */
81 schoenebeck 3118 inline void updateByMIDICtrlValue(const uint16_t& ExtControlValue) {
82     this->ExtControlValue = ExtControlValue;
83    
84     const float max = (this->InternalDepth + ExtControlValue * this->ExtControlDepthCoeff) * this->ScriptDepthFactor;
85 schoenebeck 3612 if (RANGE == LFO::range_unsigned) {
86 schoenebeck 1681 const float harmonicCompensation = 1.0f + fabsf(AMP2); // to compensate the compensation ;) (see trigger())
87 schoenebeck 717 normalizer = max * 0.5f;
88 schoenebeck 721 offset = normalizer * harmonicCompensation;
89     } else { // signed range
90 schoenebeck 717 normalizer = max;
91 schoenebeck 721 }
92 schoenebeck 717 }
93    
94     /**
95     * Will be called by the voice when the key / voice was triggered.
96     *
97     * @param Frequency - frequency of the oscillator in Hz
98     * @param StartLevel - on which level the wave should start
99     * @param InternalDepth - firm, internal oscillator amplitude
100     * @param ExtControlDepth - defines how strong the external MIDI
101     * controller has influence on the
102     * oscillator amplitude
103 schoenebeck 721 * @param FlipPhase - inverts the oscillator wave against
104     * a horizontal axis
105 schoenebeck 717 * @param SampleRate - current sample rate of the engines
106     * audio output signal
107     */
108 schoenebeck 3612 void trigger(float Frequency, LFO::start_level_t StartLevel, uint16_t InternalDepth, uint16_t ExtControlDepth, bool FlipPhase, unsigned int SampleRate) {
109 schoenebeck 3118 this->Frequency = Frequency;
110     this->ScriptFrequencyFactor = this->ScriptDepthFactor = 1.f; // reset for new voice
111 schoenebeck 1681 const float harmonicCompensation = 1.0f + fabsf(AMP2); // to compensate the 2nd harmonic's amplitude overhead
112     this->InternalDepth = (InternalDepth / 1200.0f) * this->Max / harmonicCompensation;
113 schoenebeck 721 this->ExtControlDepthCoeff = (((float) ExtControlDepth / 1200.0f) / 127.0f) * this->Max / harmonicCompensation;
114 schoenebeck 3561 this->pFinalDepth = NULL;
115     this->pFinalFrequency = NULL;
116 schoenebeck 717
117 schoenebeck 3118 const float freq = Frequency * this->ScriptFrequencyFactor;
118     c1 = 2.0f * M_PI * freq / (float) SampleRate;
119     c2 = 2.0f * M_PI * freq / (float) SampleRate * 3.0f;
120 schoenebeck 717
121 schoenebeck 721 double phi; // phase displacement
122 schoenebeck 717 switch (StartLevel) {
123 schoenebeck 3612 case LFO::start_level_mid:
124 schoenebeck 721 //FIXME: direct jumping to 90� and 270� doesn't work out due to numeric accuracy problems (causes wave deformation)
125     //phi = (FlipPhase) ? 0.5 * M_PI : 1.5 * M_PI; // 90� or 270�
126     //break;
127 schoenebeck 3612 case LFO::start_level_max:
128 schoenebeck 721 phi = (FlipPhase) ? M_PI : 0.0; // 180� or 0�
129 schoenebeck 717 break;
130 schoenebeck 3612 case LFO::start_level_min:
131 schoenebeck 721 phi = (FlipPhase) ? 0.0 : M_PI; // 0� or 180�
132 schoenebeck 717 break;
133     }
134     real1 = real2 = cos(phi);
135     imag1 = imag2 = sin(phi);
136     }
137 iliev 2225
138     /**
139     * Should be invoked after the LFO is triggered with StartLevel
140     * start_level_min.
141     * @param phase From 0 to 360 degrees.
142     */
143     void setPhase(float phase) {
144     if (phase < 0) phase = 0;
145     if (phase > 360) phase = 360;
146     phase /= 360.0f;
147    
148     // FIXME: too heavy?
149     float steps = 1.0f / (c1 / (2.0f * M_PI)); // number of steps for one cycle
150     steps *= phase + 0.25f;
151     for (int i = 0; i < steps; i++) render();
152     }
153 iliev 2227
154     void setFrequency(float Frequency, unsigned int SampleRate) {
155 schoenebeck 3118 this->Frequency = Frequency;
156     const float freq = Frequency * this->ScriptFrequencyFactor;
157     c1 = 2.0f * M_PI * freq / (float) SampleRate;
158     c2 = 2.0f * M_PI * freq / (float) SampleRate * 3.0f;
159 iliev 2227 }
160 schoenebeck 717
161 schoenebeck 3561 void setScriptDepthFactor(float factor, bool isFinal) {
162 schoenebeck 3118 this->ScriptDepthFactor = factor;
163 schoenebeck 3561 // set or reset this script depth parameter to be the sole
164     // source for the LFO depth
165     if (isFinal && !this->pFinalDepth)
166     this->pFinalDepth = &this->ScriptDepthFactor;
167     else if (!isFinal && this->pFinalDepth == &this->ScriptDepthFactor)
168     this->pFinalDepth = NULL;
169     // recalculate upon new depth
170 schoenebeck 3118 updateByMIDICtrlValue(this->ExtControlValue);
171     }
172    
173     void setScriptFrequencyFactor(float factor, unsigned int SampleRate) {
174     this->ScriptFrequencyFactor = factor;
175 schoenebeck 3561 // in case script frequency was set as "final" value before,
176     // reset it so that all sources are processed from now on
177     if (this->pFinalFrequency == &this->ScriptFrequencyFactor)
178     this->pFinalFrequency = NULL;
179     // recalculate upon new frequency
180 schoenebeck 3118 setFrequency(this->Frequency, SampleRate);
181     }
182    
183 schoenebeck 3561 void setScriptFrequencyFinal(float hz, unsigned int SampleRate) {
184     this->ScriptFrequencyFactor = hz;
185     // assign script's given frequency as sole source for the LFO
186     // frequency, thus ignore all other sources
187     if (!this->pFinalFrequency)
188     this->pFinalFrequency = &this->ScriptFrequencyFactor;
189     // recalculate upon new frequency
190     setFrequency(this->Frequency, SampleRate);
191     }
192    
193 schoenebeck 717 private:
194     float c1;
195     float c2;
196     float real1;
197     float imag1;
198     float real2;
199     float imag2;
200     float normalizer;
201 schoenebeck 721 float offset;
202 schoenebeck 717 };
203    
204     } // namespace LinuxSampler
205    
206     #endif // __LS_LFOTRIANGLEDIHARMONIC_H__

  ViewVC Help
Powered by ViewVC