4 * Copyright (C) 2001-2007 Krzysztof Foltman
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.
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.
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., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
21 #ifndef __CALF_PRIMITIVES_H
22 #define __CALF_PRIMITIVES_H
33 /// Set a float to zero
34 inline void zero(float &v
) {
38 /// Set a double to zero
39 inline void zero(double &v
) {
43 /// Set 64-bit unsigned integer value to zero
44 inline void zero(uint64_t &v
) { v
= 0; };
45 /// Set 32-bit unsigned integer value to zero
46 inline void zero(uint32_t &v
) { v
= 0; };
47 /// Set 16-bit unsigned integer value to zero
48 inline void zero(uint16_t &v
) { v
= 0; };
49 /// Set 8-bit unsigned integer value to zero
50 inline void zero(uint8_t &v
) { v
= 0; };
51 /// Set 64-bit signed integer value to zero
52 inline void zero(int64_t &v
) { v
= 0; };
53 /// Set 32-bit signed integer value to zero
54 inline void zero(int32_t &v
) { v
= 0; };
55 /// Set 16-bit signed integer value to zero
56 inline void zero(int16_t &v
) { v
= 0; };
57 /// Set 8-bit signed integer value to zero
58 inline void zero(int8_t &v
) { v
= 0; };
60 /// Set array (buffer or anything similar) to vector of zeroes
62 void zero(T
*data
, unsigned int size
) {
65 for (unsigned int i
=0; i
<size
; i
++)
69 template<class T
= float>struct stereo_sample
{
72 /// default constructor - preserves T's semantics (ie. no implicit initialization to 0)
73 inline stereo_sample() {
75 inline stereo_sample(T _left
, T _right
) {
79 inline stereo_sample(T _both
) {
83 inline stereo_sample(const stereo_sample
<U
> &value
) {
87 inline stereo_sample
& operator=(const T
&value
) {
92 inline stereo_sample
& operator=(const stereo_sample
<U
> &value
) {
98 inline operator T() const {
99 return (left+right)/2;
102 inline stereo_sample
& operator*=(const T
&multiplier
) {
107 inline stereo_sample
& operator+=(const stereo_sample
<T
> &value
) {
109 right
+= value
.right
;
112 inline stereo_sample
& operator-=(const stereo_sample
<T
> &value
) {
114 right
-= value
.right
;
117 template<typename U
> inline stereo_sample
<U
> operator*(const U
&value
) const {
118 return stereo_sample
<U
>(left
*value
, right
*value
);
120 /*inline stereo_sample<float> operator*(float value) const {
121 return stereo_sample<float>(left*value, right*value);
123 inline stereo_sample<double> operator*(double value) const {
124 return stereo_sample<double>(left*value, right*value);
126 inline stereo_sample
<T
> operator+(const stereo_sample
<T
> &value
) {
127 return stereo_sample(left
+value
.left
, right
+value
.right
);
129 inline stereo_sample
<T
> operator-(const stereo_sample
<T
> &value
) {
130 return stereo_sample(left
-value
.left
, right
-value
.right
);
132 inline stereo_sample
<T
> operator+(const T
&value
) {
133 return stereo_sample(left
+value
, right
+value
);
135 inline stereo_sample
<T
> operator-(const T
&value
) {
136 return stereo_sample(left
-value
, right
-value
);
138 inline stereo_sample
<float> operator+(float value
) {
139 return stereo_sample
<float>(left
+value
, right
+value
);
141 inline stereo_sample
<float> operator-(float value
) {
142 return stereo_sample
<float>(left
-value
, right
-value
);
144 inline stereo_sample
<double> operator+(double value
) {
145 return stereo_sample
<double>(left
+value
, right
+value
);
147 inline stereo_sample
<double> operator-(double value
) {
148 return stereo_sample
<double>(left
-value
, right
-value
);
152 /// Multiply constant by stereo_value
154 inline stereo_sample
<T
> operator*(const T
&value
, const stereo_sample
<T
> &value2
) {
155 return stereo_sample
<T
>(value2
.left
*value
, value2
.right
*value
);
158 /// Add constant to stereo_value
160 inline stereo_sample
<T
> operator+(const T
&value
, const stereo_sample
<T
> &value2
) {
161 return stereo_sample
<T
>(value2
.left
+value
, value2
.right
+value
);
164 /// Subtract stereo_value from constant (yields stereo_value of course)
166 inline stereo_sample
<T
> operator-(const T
&value
, const stereo_sample
<T
> &value2
) {
167 return stereo_sample
<T
>(value
-value2
.left
, value
-value2
.right
);
170 /// Shift value right by 'bits' bits (multiply by 2^-bits)
172 inline stereo_sample
<T
> shr(stereo_sample
<T
> v
, int bits
= 1) {
173 v
.left
= shr(v
.left
, bits
);
174 v
.right
= shr(v
.right
, bits
);
178 /// Set a stereo_sample<T> value to zero
180 inline void zero(stereo_sample
<T
> &v
) {
185 /// 'Small value' for integer and other types
187 inline T
small_value() {
191 /// '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 inline float small_value
<float>() {
194 return (1.0/16777216.0); // allows for 2^-24, should be enough for 24-bit DACs at least :)
197 /// 'Small value' for doubles (2^-24) - used for primitive underrun prevention. The value is pretty much arbitrary.
199 inline double small_value
<double>() {
200 return (1.0/16777216.0);
203 /// Convert a single value to single value = do nothing :) (but it's a generic with specialisation for stereo_sample)
205 inline float mono(T v
) {
209 /// Convert a stereo_sample to single value by averaging two channels
211 inline T
mono(stereo_sample
<T
> v
) {
212 return shr(v
.left
+v
.right
);
215 /// Clip a value to [min, max]
217 inline T
clip(T value
, T min
, T max
) {
218 if (value
< min
) return min
;
219 if (value
> max
) return max
;
223 /// Clip a double to [-1.0, +1.0]
224 inline double clip11(double value
) {
225 double a
= fabs(value
);
226 if (a
<=1) return value
;
227 return (a
<0) ? -1.0 : 1.0;
230 /// Clip a float to [-1.0f, +1.0f]
231 inline float clip11(float value
) {
232 float a
= fabsf(value
);
233 if (a
<=1) return value
;
234 return (a
<0) ? -1.0f
: 1.0f
;
237 /// Clip a double to [0.0, +1.0]
238 inline double clip01(double value
) {
239 double a
= fabs(value
-0.5);
240 if (a
<=0.5) return value
;
241 return (a
<0) ? -0.0 : 1.0;
244 /// Clip a float to [0.0f, +1.0f]
245 inline float clip01(float value
) {
246 float a
= fabsf(value
-0.5f
);
247 if (a
<=0.5f
) return value
;
248 return (a
<0) ? -0.0f
: 1.0f
;
251 // Linear interpolation (mix-way between v1 and v2).
252 template<typename T
, typename U
>
253 inline T
lerp(T v1
, T v2
, U mix
) {
254 return v1
+(v2
-v1
)*mix
;
257 // Linear interpolation for stereo values (mix-way between v1 and v2).
259 inline stereo_sample
<T
> lerp(stereo_sample
<T
> &v1
, stereo_sample
<T
> &v2
, float mix
) {
260 return stereo_sample
<T
>(v1
.left
+(v2
.left
-v1
.left
)*mix
, v1
.right
+(v2
.right
-v1
.right
)*mix
);
264 * decay-only envelope (linear or exponential); deactivates itself when it goes below a set point (epsilon)
268 double value
, initial
;
269 unsigned int age
, mask
;
275 initial
= value
= 0.0;
277 inline bool get_active() {
280 inline double get() {
281 return active
? value
: 0.0;
283 inline void set(double v
) {
288 /// reinitialise envelope (must be called if shape changes from linear to exponential or vice versa in the middle of envelope)
294 inline void add(double v
) {
303 static inline double calc_exp_constant(double times
, double cycles
)
307 return pow(times
, 1.0 / cycles
);
309 inline void age_exp(double constant
, double epsilon
) {
312 value
= initial
* pow(constant
, (double)age
);
320 inline void age_lin(double constant
, double epsilon
) {
323 value
= initial
- constant
* age
;
331 inline void deactivate() {
341 virtual void execute(scheduler
*s
)=0;
342 virtual void dispose() { delete this; }
346 /// this scheduler is based on std::multimap, so it isn't very fast, I guess
347 /// maybe some day it should be rewritten to use heapsort or something
348 /// work in progress, don't use!
350 std::multimap
<unsigned int, task
*> timeline
;
351 unsigned int time
, next_task
;
353 class end_buf_task
: public task
{
356 end_buf_task(scheduler
*_p
) : p(_p
) {}
357 virtual void execute(scheduler
*s
) { p
->eob
= true; }
358 virtual void dispose() { }
364 , next_task((unsigned)-1)
369 next_task
= (unsigned)-1;
372 inline bool is_next_tick() {
373 if (time
< next_task
)
377 inline void next_tick() {
380 void set(int pos
, task
*t
) {
381 timeline
.insert(std::pair
<unsigned int, task
*>(time
+pos
, t
));
382 next_task
= timeline
.begin()->first
;
385 std::multimap
<unsigned int, task
*>::iterator i
= timeline
.begin();
386 while(i
!= timeline
.end() && i
->first
== time
) {
387 i
->second
->execute(this);
388 i
->second
->dispose();
395 void set_buffer_size(int count
) {
401 * Force "small enough" float value to zero
403 inline void sanitize(float &value
)
405 if (std::abs(value
) < small_value
<float>())
410 * Force "small enough" double value to zero
412 inline void sanitize(double &value
)
414 if (std::abs(value
) < small_value
<double>())
419 * Force "small enough" stereo value to zero
422 inline void sanitize(stereo_sample
<T
> &value
)
424 sanitize(value
.left
);
425 sanitize(value
.right
);
428 inline float fract16(unsigned int value
)
430 return (value
& 0xFFFF) * (1.0 / 65536.0);
434 * typical precalculated sine table
436 template<class T
, int N
, int Multiplier
>
440 static bool initialized
;
446 for (int i
=0; i
<N
+1; i
++)
447 data
[i
] = (T
)(Multiplier
*sin(i
*2*M_PI
*(1.0/N
)));
451 template<class T
, int N
, int Multiplier
>
452 bool sine_table
<T
,N
,Multiplier
>::initialized
= false;
454 template<class T
, int N
, int Multiplier
>
455 T sine_table
<T
,N
,Multiplier
>::data
[N
+1];
457 /// fast float to int conversion using default rounding mode
458 inline int fastf2i_drm(float f
)
461 __asm ( "flds %1; fistpl %0" : "=m"(v
) : "m"(f
));
465 /// Convert MIDI note to frequency in Hz.
466 inline float note_to_hz(double note
)
468 return 440 * pow(2.0, (note
- 69) / 12.0);
471 /// Hermite interpolation between two points and slopes in normalized range (written after Wikipedia article)
472 /// @arg t normalized x coordinate (0-1 over the interval in question)
473 /// @arg p0 first point
474 /// @arg p1 second point
475 /// @arg m0 first slope (multiply by interval width when using over non-1-wide interval)
476 /// @arg m1 second slope (multiply by interval width when using over non-1-wide interval)
477 inline float normalized_hermite(float t
, float p0
, float p1
, float m0
, float m1
)
481 return (2*t3
- 3*t2
+ 1) * p0
+ (t3
- 2*t2
+ t
) * m0
+ (-2*t3
+ 3*t2
) * p1
+ (t3
-t2
) * m1
;
484 /// Hermite interpolation between two points and slopes
485 /// @arg x point within interval (x0 <= x <= x1)
486 /// @arg x0 interval start
487 /// @arg x1 interval end
488 /// @arg p0 value at x0
489 /// @arg p1 value at x1
490 /// @arg m0 slope (steepness, tangent) at x0
491 /// @arg m1 slope at x1
492 inline float hermite_interpolation(float x
, float x0
, float x1
, float p0
, float p1
, float m0
, float m1
)
494 float width
= x1
- x0
;
495 float t
= (x
- x0
) / width
;
503 float ct2
= -3 * p0
- 2 * m0
+ 3 * p1
- m1
;
504 float ct3
= 2 * p0
+ m0
- 2 * p1
+ m1
;
506 return ct3
* t3
+ ct2
* t2
+ ct1
* t
+ ct0
;
507 //return (2*t3 - 3*t2 + 1) * p0 + (t3 - 2*t2 + t) * m0 + (-2*t3 + 3*t2) * p1 + (t3-t2) * m1;