+ Monosynth: add inertia for pitch wheel
[calf.git] / src / calf / fixed_point.h
bloba8f4a0b3eb4de69dfac1775ce2b851140ca9cae3
1 /* Calf DSP Library
2 * DSP primitives.
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_FIXED_POINT_H
22 #define __CALF_FIXED_POINT_H
24 namespace dsp {
26 inline uint32_t shr(uint32_t v, int bits = 1) { return v>>bits; };
27 inline int32_t shr(int32_t v, int bits = 1) { return v>>bits; };
28 inline uint64_t shr(uint64_t v, int bits = 1) { return v>>bits; };
29 inline int64_t shr(int64_t v, int bits = 1) { return v>>bits; };
30 inline float shr(float v, int bits = 1) { return v*(1.0/(1<<bits)); };
31 inline double shr(double v, int bits = 1) { return v*(1.0/(1<<bits)); };
32 template<class T, int FracBits>
33 inline T shr(T v, int bits = 1) {
34 v.set(v >> bits);
35 return v;
38 template<class T, int FracBits> class fixed_point {
39 T value;
40 enum { IntBits = (sizeof(T)/8) - FracBits };
42 public:
43 /// default constructor, does not initialize the value, just like - say - float doesn't
44 inline fixed_point() {
47 /// copy constructor from any other fixed_point value
48 template<class U, int FracBits2> inline fixed_point(const fixed_point<U, FracBits2> &v) {
49 if (FracBits == FracBits2) value = v.get();
50 else if (FracBits > FracBits2) value = v.get() << abs(FracBits - FracBits2);
51 else value = v.get() >> abs(FracBits - FracBits2);
54 /* this would be way too confusing, it wouldn't be obvious if it expects a whole fixed point or an integer part
55 explicit inline fixed_point(T v) {
56 this->value = v;
59 explicit inline fixed_point(double v) {
60 value = (T)(v*one());
63 /// Makes an instance from a representation value (ie. same type of value as is used for internal storage and get/set)
64 static inline fixed_point from_base(const T &v)
66 fixed_point result;
67 result.value = v;
68 return result;
71 inline static T one() {
72 return (T)(1) << FracBits;
75 inline void set(T value) {
76 this->value = value;
79 inline T get() const {
80 return value;
83 inline operator double() const {
84 return value * (1.0/one());
87 inline fixed_point &operator=(double v) {
88 value = (T)(v*one());
89 return *this;
92 template<class U, int FracBits2> static inline T rebase(const fixed_point<U, FracBits2> &v) {
93 if (FracBits == FracBits2)
94 return v.get();
95 if (FracBits > FracBits2)
96 return v.get() << abs(FracBits - FracBits2);
97 return v.get() >> abs(FracBits2 - FracBits);
100 template<class U, int FracBits2> inline fixed_point &operator=(const fixed_point<U, FracBits2> &v) {
101 value = rebase<U, FracBits2>(v);
102 return *this;
105 template<class U, int FracBits2> inline fixed_point &operator+=(const fixed_point<U, FracBits2> &v) {
106 value += rebase<U, FracBits2>(v);
107 return *this;
110 template<class U, int FracBits2> inline fixed_point &operator-=(const fixed_point<U, FracBits2> &v) {
111 value -= rebase<U, FracBits2>(v);
112 return *this;
115 template<class U, int FracBits2> inline fixed_point operator+(const fixed_point<U, FracBits2> &v) const {
116 fixed_point fpv;
117 fpv.set(value + rebase<U, FracBits2>(v));
118 return fpv;
121 template<class U, int FracBits2> inline fixed_point operator-(const fixed_point<U, FracBits2> &v) const {
122 fixed_point fpv;
123 fpv.set(value - rebase<U, FracBits2>(v));
124 return fpv;
127 /// multiply two fixed point values, using long long int to store the temporary multiplication result
128 template<class U, int FracBits2> inline fixed_point operator*(const fixed_point<U, FracBits2> &v) const {
129 fixed_point tmp;
130 tmp.set(((int64_t)value) * v.get() >> FracBits2);
131 return tmp;
134 /// multiply two fixed point values, using BigType (usually 64-bit int) to store the temporary multiplication result
135 template<class U, int FracBits2, class BigType> inline fixed_point& operator*=(const fixed_point<U, FracBits2> &v) {
136 value = (T)(((BigType)value) * v.get() >> FracBits2);
137 return *this;
140 inline fixed_point operator+(int v) const {
141 fixed_point tmp;
142 tmp.set(value + (v << FracBits));
143 return tmp;
146 inline fixed_point operator-(int v) const {
147 fixed_point tmp;
148 tmp.set(value - (v << FracBits));
149 return tmp;
152 inline fixed_point operator*(int v) const {
153 fixed_point tmp;
154 tmp.value = value*v;
155 return tmp;
158 inline fixed_point& operator+=(int v) {
159 value += (v << FracBits);
160 return *this;
163 inline fixed_point& operator-=(int v) {
164 value -= (v << FracBits);
165 return *this;
168 inline fixed_point& operator*=(int v) {
169 value *= v;
170 return *this;
173 /// return integer part
174 inline T ipart() const {
175 return value >> FracBits;
178 /// return integer part as unsigned int
179 inline unsigned int uipart() const {
180 return ((unsigned)value) >> FracBits;
183 /// return integer part as unsigned int
184 inline unsigned int ui64part() const {
185 return ((uint64_t)value) >> FracBits;
188 /// return fractional part as 0..(2^FracBits-1)
189 inline T fpart() const {
190 return value & ((1 << FracBits)-1);
193 /// return fractional part as 0..(2^Bits-1)
194 template<int Bits>
195 inline T fpart() const {
196 int fbits = value & ((1 << FracBits)-1);
197 if (Bits == FracBits) return fbits;
198 int shift = abs(Bits-FracBits);
199 return (Bits < FracBits) ? (fbits >> shift) : (fbits << shift);
202 /// return fractional part as 0..1
203 inline double fpart_as_double() const {
204 return (value & ((1 << FracBits)-1)) * (1.0 / (1 << FracBits));
207 /// use fractional part (either whole or given number of most significant bits) for interpolating between two values
208 /// note that it uses integer arithmetic only, and isn't suitable for floating point or fixed point U!
209 /// @param UseBits can be used when there's a risk of exceeding range of U because max(fpart)*max(v1 or v2) > range of U
210 template<class U, int UseBits, class MulType>
211 inline U lerp_by_fract_int(U v1, U v2) const {
212 int fp = fpart<UseBits>();
213 assert ( fp >=0 && fp <= (1<<UseBits));
214 // printf("diff =
215 return v1 + shr(((MulType)(v2-v1) * fp), UseBits);
218 template<class U, int UseBits>
219 inline U lerp_table_lookup_int(U data[(1<<IntBits)+1]) const {
220 unsigned int pos = uipart();
221 return lerp_by_fract_int<U, UseBits>(data[pos], data[pos+1]);
224 /// Untested... I've started it to get a sin/cos readout for rotaryorgan, but decided to use table-less solution instead
225 /// Do not assume it works, because it most probably doesn't
226 template<class U, int UseBits>
227 inline U lerp_table_lookup_int_shift(U data[(1<<IntBits)+1], unsigned int shift) {
228 unsigned int pos = (uipart() + shift) & ((1 << IntBits) - 1);
229 return lerp_by_fract_int<U, UseBits>(data[pos], data[pos+1]);
232 template<class U>
233 inline U lerp_table_lookup_float(U data[(1<<IntBits)+1]) const {
234 unsigned int pos = uipart();
235 return data[pos] + (data[pos+1]-data[pos]) * fpart_as_double();
238 template<class U>
239 inline U lerp_table_lookup_float_mask(U data[(1<<IntBits)+1], unsigned int mask) const {
240 unsigned int pos = ui64part() & mask;
241 // printf("full = %lld pos = %d + %f\n", value, pos, fpart_as_double());
242 return data[pos] + (data[pos+1]-data[pos]) * fpart_as_double();
245 template<class U, int UseBits, class MulType>
246 inline U lerp_ptr_lookup_int(U *data) const {
247 unsigned int pos = ui64part();
248 return lerp_by_fract_int<U, UseBits, MulType>(data[pos], data[pos+1]);
251 template<class U>
252 inline U lerp_ptr_lookup_float(U *data) const {
253 unsigned int pos = ui64part();
254 return data[pos] + (data[pos+1]-data[pos]) * fpart_as_double();
258 template<class T, int FractBits>
259 inline fixed_point<T, FractBits> operator*(int v, fixed_point<T, FractBits> v2) {
260 v2 *= v;
261 return v2;
264 /// wave position (unsigned 64-bit int including 24-bit fractional part)
265 typedef fixed_point<unsigned long long int, 24> wpos;
269 #endif