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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 719 by senkov, Sun Jul 24 16:48:11 2005 UTC revision 3612 by schoenebeck, Mon Sep 30 18:03:43 2019 UTC
# Line 1  Line 1 
1  /***************************************************************************  /***************************************************************************
2   *                                                                         *   *                                                                         *
3   *   Copyright (C) 2005 Christian Schoenebeck                              *   *   Copyright (C) 2005 - 2019 Christian Schoenebeck                       *
4   *                                                                         *   *                                                                         *
5   *   This library is free software; you can redistribute it and/or modify  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 24  Line 24 
24  #include "LFOBase.h"  #include "LFOBase.h"
25    
26  // amplitue of 2nd harmonic (to approximate the triangular wave)  // amplitue of 2nd harmonic (to approximate the triangular wave)
27  // TODO: this was just a quick head calculation, needs to be recalculated exactly (DFT)  #define AMP2    -0.11425509f
 #define AMP2    0.1f  
28    
29  namespace LinuxSampler {  namespace LinuxSampler {
30    
# Line 34  namespace LinuxSampler { Line 33  namespace LinuxSampler {
33       * This is a triangle Low Frequency Oscillator implementation which uses       * This is a triangle Low Frequency Oscillator implementation which uses
34       * a di-harmonic solution. This means it sums up two harmonics       * a di-harmonic solution. This means it sums up two harmonics
35       * (sinusoids) to approximate a triangular wave.       * (sinusoids) to approximate a triangular wave.
36         *
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       */       */
47      template<range_type_t RANGE>      template<LFO::range_type_t RANGE>
48      class LFOTriangleDiHarmonic : public LFOBase<RANGE> {      class DEPRECATED_API LFOTriangleDiHarmonic : public LFOBase<RANGE> {
49          public:          public:
50    
51              /**              /**
# Line 57  namespace LinuxSampler { Line 66  namespace LinuxSampler {
66                  imag1 += c1 * real1;                  imag1 += c1 * real1;
67                  real2 -= c2 * imag2;                  real2 -= c2 * imag2;
68                  imag2 += c2 * real2;                  imag2 += c2 * real2;
69                  if (RANGE == range_unsigned)                  if (RANGE == LFO::range_unsigned)
70                      return (real1 + real2 * AMP2) * normalizer + normalizer;                      return (real1 + real2 * AMP2) * normalizer + offset;
71                  else /* signed range */                  else /* signed range */
72                      return (real1 + real2 * AMP2) * normalizer;                      return (real1 + real2 * AMP2) * normalizer;
73              }              }
# Line 68  namespace LinuxSampler { Line 77  namespace LinuxSampler {
77               *               *
78               * @param ExtControlValue - new external controller value               * @param ExtControlValue - new external controller value
79               */               */
80              inline void update(const uint16_t& ExtControlValue) {              inline void updateByMIDICtrlValue(const uint16_t& ExtControlValue) {
81                  const float max = this->InternalDepth + ExtControlValue * this->ExtControlDepthCoeff;                  this->ExtControlValue = ExtControlValue;
82                  if (RANGE == range_unsigned)  
83                    const float max = (this->InternalDepth + ExtControlValue * this->ExtControlDepthCoeff) * this->ScriptDepthFactor;
84                    if (RANGE == LFO::range_unsigned) {
85                        const float harmonicCompensation = 1.0f + fabsf(AMP2); // to compensate the compensation ;) (see trigger())
86                      normalizer = max * 0.5f;                      normalizer = max * 0.5f;
87                  else /* signed range */                      offset     = normalizer * harmonicCompensation;
88                    } else { // signed range
89                      normalizer = max;                      normalizer = max;
90                    }
91              }              }
92    
93              /**              /**
# Line 85  namespace LinuxSampler { Line 99  namespace LinuxSampler {
99               * @param ExtControlDepth - defines how strong the external MIDI               * @param ExtControlDepth - defines how strong the external MIDI
100               *                          controller has influence on the               *                          controller has influence on the
101               *                          oscillator amplitude               *                          oscillator amplitude
102               * @param FlipPhase       - inverts the oscillator wave               * @param FlipPhase       - inverts the oscillator wave against
103                 *                          a horizontal axis
104               * @param SampleRate      - current sample rate of the engines               * @param SampleRate      - current sample rate of the engines
105               *                          audio output signal               *                          audio output signal
106               */               */
107              void trigger(float Frequency, start_level_t StartLevel, uint16_t InternalDepth, uint16_t ExtControlDepth, bool FlipPhase, unsigned int SampleRate) {              void trigger(float Frequency, LFO::start_level_t StartLevel, uint16_t InternalDepth, uint16_t ExtControlDepth, bool FlipPhase, unsigned int SampleRate) {
108                  this->InternalDepth        = (InternalDepth / 1200.0f) * this->Max;                  this->Frequency = Frequency;
109                  this->ExtControlDepthCoeff = (((float) ExtControlDepth / 1200.0f) / 127.0f) * this->Max;                  this->ScriptFrequencyFactor = this->ScriptDepthFactor = 1.f; // reset for new voice
110                    const float harmonicCompensation = 1.0f + fabsf(AMP2); // to compensate the 2nd harmonic's amplitude overhead
111                    this->InternalDepth        = (InternalDepth / 1200.0f) * this->Max / harmonicCompensation;
112                    this->ExtControlDepthCoeff = (((float) ExtControlDepth / 1200.0f) / 127.0f) * this->Max / harmonicCompensation;
113                    this->pFinalDepth = NULL;
114                    this->pFinalFrequency = NULL;
115    
116                    const float freq = Frequency * this->ScriptFrequencyFactor;
117                    c1 = 2.0f * M_PI * freq / (float) SampleRate;
118                    c2 = 2.0f * M_PI * freq / (float) SampleRate * 3.0f;
119    
120                  c1 = 2.0f * M_PI * Frequency / (float) SampleRate;                  double phi; // phase displacement
                 c2 = 2.0f * M_PI * Frequency / (float) SampleRate * 3.0f;  
   
                 float phi; // phase displacement  
121                  switch (StartLevel) {                  switch (StartLevel) {
122                      case start_level_max:                      case LFO::start_level_mid:
123                          phi = 0.0f; // 0°                          //FIXME: direct jumping to 90° and 270° doesn't work out due to numeric accuracy problems (causes wave deformation)
124                          break;                          //phi = (FlipPhase) ? 0.5 * M_PI : 1.5 * M_PI; // 90° or 270°
125                      case start_level_mid:                          //break;
126                          phi = (FlipPhase) ? 3.0f * M_PI : M_PI; // 270° or 90°                      case LFO::start_level_max:
127                            phi = (FlipPhase) ? M_PI : 0.0; // 180° or 0°
128                          break;                          break;
129                      case start_level_min:                      case LFO::start_level_min:
130                          phi = 2.0f * M_PI; // 180°                          phi = (FlipPhase) ? 0.0 : M_PI; // 0° or 180°
131                          break;                          break;
132                  }                  }
133                  real1 = real2 = cos(phi);                  real1 = real2 = cos(phi);
134                  imag1 = imag2 = sin(phi);                  imag1 = imag2 = sin(phi);
135              }              }
136                
137                /**
138                 * Should be invoked after the LFO is triggered with StartLevel
139                 * start_level_min.
140                 * @param phase From 0 to 360 degrees.
141                 */
142                void setPhase(float phase) {
143                    if (phase < 0) phase = 0;
144                    if (phase > 360) phase = 360;
145                    phase /= 360.0f;
146                    
147                    // FIXME: too heavy?
148                    float steps = 1.0f / (c1 / (2.0f * M_PI)); // number of steps for one cycle
149                    steps *= phase + 0.25f;
150                    for (int i = 0; i < steps; i++) render();
151                }
152                
153                void setFrequency(float Frequency, unsigned int SampleRate) {
154                    this->Frequency = Frequency;
155                    const float freq = Frequency * this->ScriptFrequencyFactor;
156                    c1 = 2.0f * M_PI * freq / (float) SampleRate;
157                    c2 = 2.0f * M_PI * freq / (float) SampleRate * 3.0f;
158                }
159    
160                void setScriptDepthFactor(float factor, bool isFinal) {
161                    this->ScriptDepthFactor = factor;
162                    // set or reset this script depth parameter to be the sole
163                    // source for the LFO depth
164                    if (isFinal && !this->pFinalDepth)
165                        this->pFinalDepth = &this->ScriptDepthFactor;
166                    else if (!isFinal && this->pFinalDepth == &this->ScriptDepthFactor)
167                        this->pFinalDepth = NULL;
168                    // recalculate upon new depth
169                    updateByMIDICtrlValue(this->ExtControlValue);
170                }
171    
172                void setScriptFrequencyFactor(float factor, unsigned int SampleRate) {
173                    this->ScriptFrequencyFactor = factor;
174                    // in case script frequency was set as "final" value before,
175                    // reset it so that all sources are processed from now on
176                    if (this->pFinalFrequency == &this->ScriptFrequencyFactor)
177                        this->pFinalFrequency = NULL;
178                    // recalculate upon new frequency
179                    setFrequency(this->Frequency, SampleRate);
180                }
181    
182                void setScriptFrequencyFinal(float hz, unsigned int SampleRate) {
183                    this->ScriptFrequencyFactor = hz;
184                    // assign script's given frequency as sole source for the LFO
185                    // frequency, thus ignore all other sources
186                    if (!this->pFinalFrequency)
187                        this->pFinalFrequency = &this->ScriptFrequencyFactor;
188                    // recalculate upon new frequency
189                    setFrequency(this->Frequency, SampleRate);
190                }
191    
192          private:          private:
193              float c1;              float c1;
# Line 120  namespace LinuxSampler { Line 197  namespace LinuxSampler {
197              float real2;              float real2;
198              float imag2;              float imag2;
199              float normalizer;              float normalizer;
200                float offset;
201      };      };
202    
203  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.719  
changed lines
  Added in v.3612

  ViewVC Help
Powered by ViewVC