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

Annotation of /linuxsampler/trunk/src/engines/common/LFOSawIntMathNew.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, 6 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 7933 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 3612 /*
2     * Copyright (c) 2019 Christian Schoenebeck
3     *
4     * http://www.linuxsampler.org
5     *
6     * This file is part of LinuxSampler and released under the same terms.
7     * See README file for details.
8     */
9    
10 schoenebeck 3614 #ifndef LS_LFOSAWINTMATHNEW_H
11     #define LS_LFOSAWINTMATHNEW_H
12 schoenebeck 3612
13     #include <stdlib.h>
14     #include "LFOBase.h"
15    
16     namespace LinuxSampler {
17    
18     /** @brief Saw LFO (int math implementation)
19     *
20     * This is a Saw Low Frequency Oscillator which uses pure integer
21     * math (without branches) to synthesize the saw wave.
22     */
23     template<LFO::range_type_t RANGE>
24 schoenebeck 3614 class LFOSawIntMathNew : public LFOBase<RANGE> {
25 schoenebeck 3612 public:
26     /**
27     * Constructor
28     *
29     * @param Max - maximum value of the output levels
30     */
31 schoenebeck 3614 LFOSawIntMathNew(float Max) : LFOBase<RANGE>::LFOBase(Max) {
32 schoenebeck 3625 //NOTE: DO NOT add any custom initialization here, since it would break LFOCluster construction !
33 schoenebeck 3612 }
34    
35     /**
36     * Calculates exactly one sample point of the LFO wave.
37     *
38     * @returns next LFO level
39     */
40     inline float render() {
41     this->slope += this->c;
42     if (RANGE == LFO::range_unsigned)
43     return this->denormalizer * float(this->slope);
44     else // signed range
45     return this->denormalizer * float(int(this->slope) + this->offset);
46     }
47    
48     /**
49     * Update LFO depth with a new external controller value.
50     *
51     * @param ExtControlValue - new external controller value
52     */
53     inline void updateByMIDICtrlValue(const uint16_t& ExtControlValue) {
54     this->ExtControlValue = ExtControlValue;
55    
56     const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
57     const float max = (this->InternalDepth + ExtControlValue * this->ExtControlDepthCoeff) * this->ScriptDepthFactor;
58     if (RANGE == LFO::range_unsigned) {
59     denormalizer = max / (float) intLimit / 2.0;
60     } else { // signed range
61     denormalizer = max / (float) intLimit * 2.0;
62     offset = -max;
63     }
64     }
65    
66     /**
67     * Will be called by the voice when the key / voice was triggered.
68     *
69     * @param Frequency - frequency of the oscillator in Hz
70     * @param StartLevel - on which level the wave should start
71     * @param InternalDepth - firm, internal oscillator amplitude
72     * @param ExtControlDepth - defines how strong the external MIDI
73     * controller has influence on the
74     * oscillator amplitude
75     * @param FlipPhase - inverts the oscillator wave against
76     * a horizontal axis
77     * @param SampleRate - current sample rate of the engines
78     * audio output signal
79     */
80     void trigger(float Frequency, LFO::start_level_t StartLevel, uint16_t InternalDepth, uint16_t ExtControlDepth, bool FlipPhase, unsigned int SampleRate) {
81     this->Frequency = Frequency;
82     this->InternalDepth = (InternalDepth / 1200.0f) * this->Max;
83     this->ExtControlDepthCoeff = (((float) ExtControlDepth / 1200.0f) / 127.0f) * this->Max;
84     this->ScriptFrequencyFactor = this->ScriptDepthFactor = 1.f; // reset for new voice
85     if (RANGE == LFO::range_unsigned) {
86     this->InternalDepth *= 2.0f;
87     this->ExtControlDepthCoeff *= 2.0f;
88     }
89     this->pFinalDepth = NULL;
90     this->pFinalFrequency = NULL;
91    
92     this->flipPhaseFactor = FlipPhase ? -1 : 1;
93     const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
94     const float freq = Frequency * this->ScriptFrequencyFactor;
95     const float r = freq / (float) SampleRate; // frequency alteration quotient
96     c = int(intLimit * r * this->flipPhaseFactor);
97    
98     const int slopeAtMid = (RANGE == LFO::range_unsigned) ? intLimit / 2 : intLimit;
99     const int slopeAtMin = (RANGE == LFO::range_unsigned) ? intLimit : intLimit / 2;
100    
101     switch (StartLevel) {
102     case LFO::start_level_mid:
103     //slope = (FlipPhase) ? slopeAtMin : slopeAtMid;
104     slope = slopeAtMid;
105     break;
106    
107     // with saw function, min and max are actually always the same thing
108     // (and no matter if FlipPhase or not)
109     case LFO::start_level_max:
110     case LFO::start_level_min:
111     slope = slopeAtMin;
112     break;
113     }
114     }
115    
116     /**
117     * Should be invoked after the LFO is triggered.
118     * @param phase From 0 to 360 degrees.
119     */
120     void setPhase(float phase) {
121     if (phase < 0) phase = 0;
122     if (phase > 360) phase = 360;
123     phase /= 360.0f;
124     const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
125     slope += intLimit * phase * flipPhaseFactor;
126     }
127    
128     void setFrequency(float Frequency, unsigned int SampleRate) {
129     this->Frequency = Frequency;
130     const float freq = Frequency * this->ScriptFrequencyFactor;
131     const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
132     float r = freq / (float) SampleRate; // frequency alteration quotient
133     c = int(intLimit * r * this->flipPhaseFactor);
134     }
135    
136     void setScriptDepthFactor(float factor, bool isFinal) {
137     this->ScriptDepthFactor = factor;
138     // set or reset this script depth parameter to be the sole
139     // source for the LFO depth
140     if (isFinal && !this->pFinalDepth)
141     this->pFinalDepth = &this->ScriptDepthFactor;
142     else if (!isFinal && this->pFinalDepth == &this->ScriptDepthFactor)
143     this->pFinalDepth = NULL;
144     // recalculate upon new depth
145     updateByMIDICtrlValue(this->ExtControlValue);
146     }
147    
148     void setScriptFrequencyFactor(float factor, unsigned int SampleRate) {
149     this->ScriptFrequencyFactor = factor;
150     // in case script frequency was set as "final" value before,
151     // reset it so that all sources are processed from now on
152     if (this->pFinalFrequency == &this->ScriptFrequencyFactor)
153     this->pFinalFrequency = NULL;
154     // recalculate upon new frequency
155     setFrequency(this->Frequency, SampleRate);
156     }
157    
158     void setScriptFrequencyFinal(float hz, unsigned int SampleRate) {
159     this->ScriptFrequencyFactor = hz;
160     // assign script's given frequency as sole source for the LFO
161     // frequency, thus ignore all other sources
162     if (!this->pFinalFrequency)
163     this->pFinalFrequency = &this->ScriptFrequencyFactor;
164     // recalculate upon new frequency
165     setFrequency(this->Frequency, SampleRate);
166     }
167    
168     protected:
169     unsigned int slope;
170     unsigned int c;
171     float offset; ///< only needed for signed range
172     float denormalizer;
173     float flipPhaseFactor; ///< Factor instead of boolean to avoid branches.
174     };
175    
176     } // namespace LinuxSampler
177    
178 schoenebeck 3614 #endif // LS_LFOSAWINTMATHNEW_H

  ViewVC Help
Powered by ViewVC