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

Contents of /linuxsampler/trunk/src/engines/common/LFOSquareIntMath.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3612 - (show annotations) (download) (as text)
Mon Sep 30 18:03:43 2019 UTC (4 years, 6 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 7503 byte(s)
Added new LFO implementations:

* Added int math square LFO implementation.

* Added int math saw LFO implementation.

* Added numeric complex nr sine LFO implementation.

* Added public API C++ class "LFO", which is a cluster class
  encapsulating all the sampler's LFO implementations to be used by
  3rd party applications (e.g. by Gigedit).

* Marked class LFOTriangleDiHarmonic as deprecated
  (will be removed in future).

* Added LFOAll.h which includes all LFO implementation's header files.

* Fixed benchmarks/triang.cpp falsely having favoured "int math abs"
  algorithm (since result of 2nd run was not accumulated).

* Added benchmark for saw wave (benchmarks/saw.cpp).

* Added benchmark for sine wave (benchmarks/sine.cpp).

* Added benchmark for square wave (benchmarks/square.cpp).

* Increased amount of benchmarks runs by factor 6 to achieve benchmark
  times which are large enough on modern systems.

* Cleanup of LFO APIs.

* Bumped version (2.1.1.svn18).

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

  ViewVC Help
Powered by ViewVC