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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3561 - (hide annotations) (download) (as text)
Fri Aug 23 11:44:00 2019 UTC (4 years, 8 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 8877 byte(s)
NKSP: Added standard units support for numbers and final "!" operator:

* NKSP strictness: Variable names, function names and preprocessor condition
  names must start with a regular character (a-z or A-Z); starting them with
  a digit or underscore is no longer allowed.

* NKSP parser fix: equal comparison operator "=" and not equal comparison
  operator "#" must only accept integer operands.

* NKSP language: Implemented support for standard units like Hertz, seconds,
  Bel including support for metric unit prefixes; so one can now e.g.
  conveniently use numbers in scripts like "5us" meaning "5 microseconds",
  or e.g. "12kHz" meaning "12 kilo Hertz", or e.g. "-14mdB" meaning
  "minus 14 Millidecibel", or e.g. "28c" meaning "28 cents" (for tuning).

* NKSP language: Introduced "final" operator "!" which is specifically
  intended for synthesis parameter values to denote that the synthesis
  parameter value is intended to be the "final" value for that synthesis
  parameter that should explicitly be used by the engine and thus causing
  the sampler engine to ignore all other modulation sources for the same
  synthesis parameter (like e.g. LFO, EG); by simply prefixing a value,
  variable or formula with this new "!" operator the expression is marked as
  being "final".

* Bumped version (2.1.1.svn4).

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_LFOTRIANGLEINTMATH_H__
22     #define __LS_LFOTRIANGLEINTMATH_H__
23    
24     #include "LFOBase.h"
25    
26     namespace LinuxSampler {
27    
28     /** @brief Triangle LFO (int math implementation)
29     *
30     * This is a triangle Low Frequency Oscillator which uses pure integer
31     * math (without branches) to synthesize the triangular wave.
32     */
33     template<range_type_t RANGE>
34     class LFOTriangleIntMath : public LFOBase<RANGE> {
35     public:
36    
37     /**
38     * Constructor
39     *
40     * @param Max - maximum value of the output levels
41     */
42     LFOTriangleIntMath(float Max) : LFOBase<RANGE>::LFOBase(Max) {
43     }
44    
45     /**
46     * Calculates exactly one sample point of the LFO wave.
47     *
48     * @returns next LFO level
49     */
50     inline float render() {
51     const int signshifts = (sizeof(int) * 8) - 1;
52     iLevel += c;
53     const int iSign = (iLevel >> signshifts) | 1;
54     if (RANGE == range_unsigned)
55     return normalizer * (float) (iSign * iLevel);
56     else /* signed range */
57     return normalizer * (float) (iSign * iLevel) + offset;
58     }
59    
60     /**
61     * Update LFO depth with a new external controller value.
62     *
63     * @param ExtControlValue - new external controller value
64     */
65 schoenebeck 3118 inline void updateByMIDICtrlValue(const uint16_t& ExtControlValue) {
66     this->ExtControlValue = ExtControlValue;
67    
68 schoenebeck 717 const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
69 schoenebeck 3118 const float max = (this->InternalDepth + ExtControlValue * this->ExtControlDepthCoeff) * this->ScriptDepthFactor;
70 schoenebeck 717 if (RANGE == range_unsigned) {
71 schoenebeck 718 normalizer = max / (float) intLimit;
72 schoenebeck 717 } else { // signed range
73 schoenebeck 718 normalizer = max / (float) intLimit * 4.0f;
74 schoenebeck 717 offset = -max;
75     }
76     }
77    
78     /**
79     * Will be called by the voice when the key / voice was triggered.
80     *
81     * @param Frequency - frequency of the oscillator in Hz
82     * @param StartLevel - on which level the wave should start
83     * @param InternalDepth - firm, internal oscillator amplitude
84     * @param ExtControlDepth - defines how strong the external MIDI
85     * controller has influence on the
86     * oscillator amplitude
87 schoenebeck 718 * @param FlipPhase - inverts the oscillator wave against
88     * a horizontal axis
89 schoenebeck 717 * @param SampleRate - current sample rate of the engines
90     * audio output signal
91     */
92     void trigger(float Frequency, start_level_t StartLevel, uint16_t InternalDepth, uint16_t ExtControlDepth, bool FlipPhase, unsigned int SampleRate) {
93 schoenebeck 3118 this->Frequency = Frequency;
94 senkov 719 this->InternalDepth = (InternalDepth / 1200.0f) * this->Max;
95     this->ExtControlDepthCoeff = (((float) ExtControlDepth / 1200.0f) / 127.0f) * this->Max;
96 schoenebeck 3118 this->ScriptFrequencyFactor = this->ScriptDepthFactor = 1.f; // reset for new voice
97 schoenebeck 718 if (RANGE == range_unsigned) {
98     this->InternalDepth *= 2.0f;
99     this->ExtControlDepthCoeff *= 2.0f;
100     }
101 schoenebeck 3561 this->pFinalDepth = NULL;
102     this->pFinalFrequency = NULL;
103 schoenebeck 717
104     const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
105 schoenebeck 3118 const float freq = Frequency * this->ScriptFrequencyFactor;
106     const float r = freq / (float) SampleRate; // frequency alteration quotient
107 schoenebeck 717 c = (int) (intLimit * r);
108    
109     switch (StartLevel) {
110 schoenebeck 718 case start_level_max:
111     iLevel = (FlipPhase) ? 0 : intLimit >> 1;
112 schoenebeck 717 break;
113 schoenebeck 718 case start_level_mid:
114 schoenebeck 717 if (FlipPhase) c = -c; // wave should go down
115 schoenebeck 718 iLevel = intLimit >> 2;
116 schoenebeck 717 break;
117 schoenebeck 718 case start_level_min:
118     iLevel = (FlipPhase) ? intLimit >> 1 : 0;
119 schoenebeck 717 break;
120     }
121     }
122 iliev 2225
123     /**
124     * Should be invoked after the LFO is triggered.
125     * @param phase From 0 to 360 degrees.
126     */
127     void setPhase(float phase) {
128     if (phase < 0) phase = 0;
129     if (phase > 360) phase = 360;
130     phase /= 360.0f;
131     const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
132     unsigned int uiPhase = intLimit * phase + iLevel;
133     if (uiPhase > intLimit / 2) iLevel = uiPhase - intLimit;
134     else iLevel = uiPhase;
135     }
136 iliev 2227
137     void setFrequency(float Frequency, unsigned int SampleRate) {
138 schoenebeck 3118 this->Frequency = Frequency;
139     const float freq = Frequency * this->ScriptFrequencyFactor;
140 iliev 2227 const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
141 schoenebeck 3118 float r = freq / (float) SampleRate; // frequency alteration quotient
142 iliev 2227 c = (int) (intLimit * r);
143     }
144 schoenebeck 717
145 schoenebeck 3561 void setScriptDepthFactor(float factor, bool isFinal) {
146 schoenebeck 3118 this->ScriptDepthFactor = factor;
147 schoenebeck 3561 // set or reset this script depth parameter to be the sole
148     // source for the LFO depth
149     if (isFinal && !this->pFinalDepth)
150     this->pFinalDepth = &this->ScriptDepthFactor;
151     else if (!isFinal && this->pFinalDepth == &this->ScriptDepthFactor)
152     this->pFinalDepth = NULL;
153     // recalculate upon new depth
154 schoenebeck 3118 updateByMIDICtrlValue(this->ExtControlValue);
155     }
156    
157     void setScriptFrequencyFactor(float factor, unsigned int SampleRate) {
158     this->ScriptFrequencyFactor = factor;
159 schoenebeck 3561 // in case script frequency was set as "final" value before,
160     // reset it so that all sources are processed from now on
161     if (this->pFinalFrequency == &this->ScriptFrequencyFactor)
162     this->pFinalFrequency = NULL;
163     // recalculate upon new frequency
164 schoenebeck 3118 setFrequency(this->Frequency, SampleRate);
165     }
166    
167 schoenebeck 3561 void setScriptFrequencyFinal(float hz, unsigned int SampleRate) {
168     this->ScriptFrequencyFactor = hz;
169     // assign script's given frequency as sole source for the LFO
170     // frequency, thus ignore all other sources
171     if (!this->pFinalFrequency)
172     this->pFinalFrequency = &this->ScriptFrequencyFactor;
173     // recalculate upon new frequency
174     setFrequency(this->Frequency, SampleRate);
175     }
176    
177 senkov 720 protected:
178 schoenebeck 717 int iLevel;
179     int c;
180     float offset; ///< only needed for signed range
181     float normalizer;
182     };
183    
184     } // namespace LinuxSampler
185    
186     #endif // __LS_LFOTRIANGLEINTMATH_H__

  ViewVC Help
Powered by ViewVC