1 /* Calf DSP Library
2  * DSP primitives.
3  *
4  * Copyright (C) 2001-2007 Krzysztof Foltman
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General
17  * Public License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02111-1307, USA.
20  */
21 #ifndef __CALF_PRIMITIVES_H
22 #define __CALF_PRIMITIVES_H
23 
24 #include <assert.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <cmath>
29 #include <cstdlib>
30 #include <map>
31 
32 namespace dsp {
33 
34 /// Set a float to zero
zero(float & v)35 inline void zero(float &v) {
36     v = 0;
37 };
38 
39 /// Set a double to zero
zero(double & v)40 inline void zero(double &v) {
41     v = 0;
42 };
43 
44 /// Set 64-bit unsigned integer value to zero
zero(uint64_t & v)45 inline void zero(uint64_t &v) { v = 0; };
46 /// Set 32-bit unsigned integer value to zero
zero(uint32_t & v)47 inline void zero(uint32_t &v) { v = 0; };
48 /// Set 16-bit unsigned integer value to zero
zero(uint16_t & v)49 inline void zero(uint16_t &v) { v = 0; };
50 /// Set 8-bit unsigned integer value to zero
zero(uint8_t & v)51 inline void zero(uint8_t &v) { v = 0; };
52 /// Set 64-bit signed integer value to zero
zero(int64_t & v)53 inline void zero(int64_t &v) { v = 0; };
54 /// Set 32-bit signed integer value to zero
zero(int32_t & v)55 inline void zero(int32_t &v) { v = 0; };
56 /// Set 16-bit signed integer value to zero
zero(int16_t & v)57 inline void zero(int16_t &v) { v = 0; };
58 /// Set 8-bit signed integer value to zero
zero(int8_t & v)59 inline void zero(int8_t &v) { v = 0; };
60 
61 /// Set array (buffer or anything similar) to vector of zeroes
62 template<class T>
zero(T * data,unsigned int size)63 void zero(T *data, unsigned int size) {
64     T value;
65     dsp::zero(value);
66     for (unsigned int i=0; i<size; i++)
67         *data++ = value;
68 }
69 
70 template<class T = float>struct stereo_sample {
71     T left;
72     T right;
73     /// default constructor - preserves T's semantics (ie. no implicit initialization to 0)
stereo_samplestereo_sample74     inline stereo_sample() {
75     }
stereo_samplestereo_sample76     inline stereo_sample(T _left, T _right) {
77         left = _left;
78         right = _right;
79     }
stereo_samplestereo_sample80     inline stereo_sample(T _both) {
81         left = right = _both;
82     }
83     template<typename U>
stereo_samplestereo_sample84     inline stereo_sample(const stereo_sample<U> &value) {
85         left = value.left;
86         right = value.right;
87     }
88     inline stereo_sample& operator=(const T &value) {
89         left = right = value;
90         return *this;
91     }
92     template<typename U>
93     inline stereo_sample& operator=(const stereo_sample<U> &value) {
94         left = value.left;
95         right = value.right;
96         return *this;
97     }
98 /*
99     inline operator T() const {
100         return (left+right)/2;
101     }
102 */
103     inline stereo_sample& operator*=(const T &multiplier) {
104         left *= multiplier;
105         right *= multiplier;
106         return *this;
107     }
108     inline stereo_sample& operator+=(const stereo_sample<T> &value) {
109         left += value.left;
110         right += value.right;
111         return *this;
112     }
113     inline stereo_sample& operator-=(const stereo_sample<T> &value) {
114         left -= value.left;
115         right -= value.right;
116         return *this;
117     }
118     template<typename U> inline stereo_sample<U> operator*(const U &value) const {
119         return stereo_sample<U>(left*value, right*value);
120     }
121     /*inline stereo_sample<float> operator*(float value) const {
122         return stereo_sample<float>(left*value, right*value);
123     }
124     inline stereo_sample<double> operator*(double value) const {
125         return stereo_sample<double>(left*value, right*value);
126     }*/
127     inline stereo_sample<T> operator+(const stereo_sample<T> &value) {
128         return stereo_sample(left+value.left, right+value.right);
129     }
130     inline stereo_sample<T> operator-(const stereo_sample<T> &value) {
131         return stereo_sample(left-value.left, right-value.right);
132     }
133     inline stereo_sample<T> operator+(const T &value) {
134         return stereo_sample(left+value, right+value);
135     }
136     inline stereo_sample<T> operator-(const T &value) {
137         return stereo_sample(left-value, right-value);
138     }
139     inline stereo_sample<float> operator+(float value) {
140         return stereo_sample<float>(left+value, right+value);
141     }
142     inline stereo_sample<float> operator-(float value) {
143         return stereo_sample<float>(left-value, right-value);
144     }
145     inline stereo_sample<double> operator+(double value) {
146         return stereo_sample<double>(left+value, right+value);
147     }
148     inline stereo_sample<double> operator-(double value) {
149         return stereo_sample<double>(left-value, right-value);
150     }
151 };
152 
153 /// Multiply constant by stereo_value
154 template<class T>
155 inline stereo_sample<T> operator*(const T &value, const stereo_sample<T> &value2) {
156     return stereo_sample<T>(value2.left*value, value2.right*value);
157 }
158 
159 /// Add constant to stereo_value
160 template<class T>
161 inline stereo_sample<T> operator+(const T &value, const stereo_sample<T> &value2) {
162     return stereo_sample<T>(value2.left+value, value2.right+value);
163 }
164 
165 /// Subtract stereo_value from constant (yields stereo_value of course)
166 template<class T>
167 inline stereo_sample<T> operator-(const T &value, const stereo_sample<T> &value2) {
168     return stereo_sample<T>(value-value2.left, value-value2.right);
169 }
170 
171 /// Shift value right by 'bits' bits (multiply by 2^-bits)
172 template<typename T>
173 inline stereo_sample<T> shr(stereo_sample<T> v, int bits = 1) {
174     v.left = shr(v.left, bits);
175     v.right = shr(v.right, bits);
176     return v;
177 }
178 
179 /// Set a stereo_sample<T> value to zero
180 template<typename T>
zero(stereo_sample<T> & v)181 inline void zero(stereo_sample<T> &v) {
182     dsp::zero(v.left);
183     dsp::zero(v.right);
184 }
185 
186 /// 'Small value' for integer and other types
187 template<typename T>
small_value()188 inline T small_value() {
189     return 0;
190 }
191 
192 /// 'Small value' for floats (2^-24) - used for primitive underrun prevention. The value is pretty much arbitrary (allowing for 24-bit signals normalized to 1.0).
193 template<>
194 inline float small_value<float>() {
195     return (1.0/16777216.0); // allows for 2^-24, should be enough for 24-bit DACs at least :)
196 }
197 
198 /// 'Small value' for doubles (2^-24) - used for primitive underrun prevention. The value is pretty much arbitrary.
199 template<>
200 inline double small_value<double>() {
201     return (1.0/16777216.0);
202 }
203 
204 /// Convert a single value to single value = do nothing :) (but it's a generic with specialisation for stereo_sample)
205 template<typename T>
mono(T v)206 inline float mono(T v) {
207     return v;
208 }
209 
210 /// Convert a stereo_sample to single value by averaging two channels
211 template<typename T>
mono(stereo_sample<T> v)212 inline T mono(stereo_sample<T> v) {
213     return shr(v.left+v.right);
214 }
215 
216 /// Clip a value to [min, max]
217 template<typename T>
clip(T value,T min,T max)218 inline T clip(T value, T min, T max) {
219     if (value < min) return min;
220     if (value > max) return max;
221     return value;
222 }
223 
224 /// Clip a double to [-1.0, +1.0]
clip11(double value)225 inline double clip11(double value) {
226     double a = fabs(value);
227     if (a<=1) return value;
228     return (value<0) ? -1.0 : 1.0;
229 }
230 
231 /// Clip a float to [-1.0f, +1.0f]
clip11(float value)232 inline float clip11(float value) {
233     float a = fabsf(value);
234     if (a<=1) return value;
235     return (value<0) ? -1.0f : 1.0f;
236 }
237 
238 /// Clip a double to [0.0, +1.0]
clip01(double value)239 inline double clip01(double value) {
240     double a = fabs(value-0.5);
241     if (a<=0.5) return value;
242     return (a<0) ? -0.0 : 1.0;
243 }
244 
245 /// Clip a float to [0.0f, +1.0f]
clip01(float value)246 inline float clip01(float value) {
247     float a = fabsf(value-0.5f);
248     if (a<=0.5f) return value;
249     return (value < 0) ? -0.0f : 1.0f;
250 }
251 
252 // Linear interpolation (mix-way between v1 and v2).
253 template<typename T, typename U>
lerp(T v1,T v2,U mix)254 inline T lerp(T v1, T v2, U mix) {
255     return v1+(v2-v1)*mix;
256 }
257 
258 // Linear interpolation for stereo values (mix-way between v1 and v2).
259 template<typename T>
lerp(stereo_sample<T> & v1,stereo_sample<T> & v2,float mix)260 inline stereo_sample<T> lerp(stereo_sample<T> &v1, stereo_sample<T> &v2, float mix) {
261     return stereo_sample<T>(v1.left+(v2.left-v1.left)*mix, v1.right+(v2.right-v1.right)*mix);
262 }
263 
264 /**
265  * decay-only envelope (linear or exponential); deactivates itself when it goes below a set point (epsilon)
266  */
267 class decay
268 {
269     double value, initial;
270     unsigned int age, mask;
271     bool active;
272 public:
decay()273     decay() {
274         active = false;
275         mask = 127;
276         initial = value = 0.0;
277     }
get_active()278     inline bool get_active() {
279         return active;
280     }
get()281     inline double get() {
282         return active ? value : 0.0;
283     }
set(double v)284     inline void set(double v) {
285         initial = value = v;
286         active = true;
287         age = 0;
288     }
289     /// reinitialise envelope (must be called if shape changes from linear to exponential or vice versa in the middle of envelope)
reinit()290     inline void reinit()
291     {
292         initial = value;
293         age = 1;
294     }
add(double v)295     inline void add(double v) {
296         if (active)
297             value += v;
298         else
299             value = v;
300         initial = value;
301         age = 0;
302         active = true;
303     }
calc_exp_constant(double times,double cycles)304     static inline double calc_exp_constant(double times, double cycles)
305     {
306         if (cycles < 1.0)
307             cycles = 1.0;
308         return pow(times, 1.0 / cycles);
309     }
age_exp(double constant,double epsilon)310     inline void age_exp(double constant, double epsilon) {
311         if (active) {
312             if (!(age & mask))
313                 value = initial * pow(constant, (double)age);
314             else
315                 value *= constant;
316             if (value < epsilon)
317                 active = false;
318             age++;
319         }
320     }
age_lin(double constant,double epsilon)321     inline void age_lin(double constant, double epsilon) {
322         if (active) {
323             if (!(age & mask))
324                 value = initial - constant * age;
325             else
326                 value -= constant;
327             if (value < epsilon)
328                 active = false;
329             age++;
330         }
331     }
deactivate()332     inline void deactivate() {
333         active = false;
334         value = 0;
335     }
336 };
337 
338 class scheduler;
339 
340 class task {
341 public:
342     virtual void execute(scheduler *s)=0;
dispose()343     virtual void dispose() { delete this; }
~task()344     virtual ~task() {}
345 };
346 
347 /// this scheduler is based on std::multimap, so it isn't very fast, I guess
348 /// maybe some day it should be rewritten to use heapsort or something
349 /// work in progress, don't use!
350 class scheduler {
351     std::multimap<unsigned int, task *> timeline;
352     unsigned int time, next_task;
353     bool eob;
354     class end_buf_task: public task {
355     public:
356         scheduler *p;
end_buf_task(scheduler * _p)357         end_buf_task(scheduler *_p) : p(_p) {}
execute(scheduler * s)358         virtual void execute(scheduler *s) { p->eob = true; }
dispose()359         virtual void dispose() { }
360     } eobt;
361 public:
362 
scheduler()363     scheduler()
364     : time(0)
365     , next_task((unsigned)-1)
366     , eob(true)
367     , eobt (this)
368     {
369         time = 0;
370         next_task = (unsigned)-1;
371         eob = false;
372     }
is_next_tick()373     inline bool is_next_tick() {
374         if (time < next_task)
375             return true;
376         do_tasks();
377     }
next_tick()378     inline void next_tick() {
379         time++;
380     }
set(int pos,task * t)381     void set(int pos, task *t) {
382         timeline.insert(std::pair<unsigned int, task *>(time+pos, t));
383         next_task = timeline.begin()->first;
384     }
do_tasks()385     void do_tasks() {
386         std::multimap<unsigned int, task *>::iterator i = timeline.begin();
387         while(i != timeline.end() && i->first == time) {
388             i->second->execute(this);
389             i->second->dispose();
390             timeline.erase(i);
391         }
392     }
is_eob()393     bool is_eob() {
394         return eob;
395     }
set_buffer_size(int count)396     void set_buffer_size(int count) {
397         set(count, &eobt);
398     }
399 };
400 
401 /**
402  * Force "small enough" float value to zero
403  */
sanitize(float & value)404 inline void sanitize(float &value)
405 {
406     if (std::abs(value) < small_value<float>())
407         value = 0.f;
408 }
409 
410 /**
411  * Force already-denormal float value to zero
412  */
sanitize_denormal(float & value)413 inline void sanitize_denormal(float& value)
414 {
415     if (((*(unsigned int *) &value) & 0x7f800000) == 0) {
416         value = 0;
417     }
418 }
419 
420 /**
421  * Force "small enough" double value to zero
422  */
sanitize(double & value)423 inline void sanitize(double &value)
424 {
425     if (std::abs(value) < small_value<double>())
426         value = 0.f;
427 }
428 
429 /**
430  * Force "small enough" stereo value to zero
431  */
432 template<class T>
sanitize(stereo_sample<T> & value)433 inline void sanitize(stereo_sample<T> &value)
434 {
435     sanitize(value.left);
436     sanitize(value.right);
437 }
438 
fract16(unsigned int value)439 inline float fract16(unsigned int value)
440 {
441     return (value & 0xFFFF) * (1.0 / 65536.0);
442 }
443 
444 /**
445  * typical precalculated sine table
446  */
447 template<class T, int N, int Multiplier>
448 class sine_table
449 {
450 public:
451     static bool initialized;
452     static T data[N+1];
sine_table()453     sine_table() {
454         if (initialized)
455             return;
456         initialized = true;
457         for (int i=0; i<N+1; i++)
458             data[i] = (T)(Multiplier*sin(i*2*M_PI*(1.0/N)));
459     }
460 };
461 
462 template<class T, int N, int Multiplier>
463 bool sine_table<T,N,Multiplier>::initialized = false;
464 
465 template<class T, int N, int Multiplier>
466 T sine_table<T,N,Multiplier>::data[N+1];
467 
468 /// fast float to int conversion using default rounding mode
fastf2i_drm(float f)469 inline int fastf2i_drm(float f)
470 {
471 #ifdef __X86__
472     volatile int v;
473     __asm ( "flds %1; fistpl %0" : "=m"(v) : "m"(f));
474     return v;
475 #else
476     return (int)nearbyintf(f);
477 #endif
478 }
479 
480 /// Convert MIDI note to frequency in Hz.
481 inline float note_to_hz(double note, double detune_cents = 0.0)
482 {
483     return 440 * pow(2.0, (note - 69 + detune_cents/100.0) / 12.0);
484 }
485 
486 /// Hermite interpolation between two points and slopes in normalized range (written after Wikipedia article)
487 /// @arg t normalized x coordinate (0-1 over the interval in question)
488 /// @arg p0 first point
489 /// @arg p1 second point
490 /// @arg m0 first slope (multiply by interval width when using over non-1-wide interval)
491 /// @arg m1 second slope (multiply by interval width when using over non-1-wide interval)
normalized_hermite(float t,float p0,float p1,float m0,float m1)492 inline float normalized_hermite(float t, float p0, float p1, float m0, float m1)
493 {
494     float t2 = t*t;
495     float t3 = t2*t;
496     return (2*t3 - 3*t2 + 1) * p0 + (t3 - 2*t2 + t) * m0 + (-2*t3 + 3*t2) * p1 + (t3-t2) * m1;
497 }
498 
499 /// Hermite interpolation between two points and slopes
500 /// @arg x point within interval (x0 <= x <= x1)
501 /// @arg x0 interval start
502 /// @arg x1 interval end
503 /// @arg p0 value at x0
504 /// @arg p1 value at x1
505 /// @arg m0 slope (steepness, tangent) at x0
506 /// @arg m1 slope at x1
hermite_interpolation(float x,float x0,float x1,float p0,float p1,float m0,float m1)507 inline float hermite_interpolation(float x, float x0, float x1, float p0, float p1, float m0, float m1)
508 {
509     float width = x1 - x0;
510     float t = (x - x0) / width;
511     m0 *= width;
512     m1 *= width;
513     float t2 = t*t;
514     float t3 = t2*t;
515 
516     float ct0 = p0;
517     float ct1 = m0;
518     float ct2 = -3 * p0 - 2 * m0 + 3 * p1 - m1;
519     float ct3 = 2 * p0 + m0  - 2 * p1 + m1;
520 
521     return ct3 * t3 + ct2 * t2 + ct1 * t + ct0;
522     //return (2*t3 - 3*t2 + 1) * p0 + (t3 - 2*t2 + t) * m0 + (-2*t3 + 3*t2) * p1 + (t3-t2) * m1;
523 }
524 
525 /// convert amplitude value to dB
amp2dB(float amp)526 inline float amp2dB(float amp)
527 {
528     return 6.0 * log(amp) / log(2);
529 }
530 
531 };
532 
533 #endif
534