forked from sensorium/Mozzi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mozzi_fixmath.h
413 lines (316 loc) · 17.8 KB
/
mozzi_fixmath.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
/*
* mozzi_fixmath.h
*
* Copyright 2012 Tim Barrass.
*
* This file is part of Mozzi.
*
* Mozzi is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
*
*/
#ifndef FIXEDMATH_H_
#define FIXEDMATH_H_
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
/**@ingroup fixmath
@{
*/
// types
typedef int8_t Q0n7; /**< signed fractional number using 7 fractional bits, represents -0.5 to 0.496*/
typedef int8_t Q7n0; /**< ordinary old signed Q7n0 int8_t with 0 fractional bits, represents -128 to 127*/
typedef uint8_t Q0n8; /**< unsigned fractional number using 8 fractional bits, represents 0.0 to 0.996*/
typedef uint8_t Q8n0; /**< normal uint8_t with 0 fractional bits, represents 0.0 to 255.0*/
typedef uint16_t Q0n16; /**< unsigned fractional number using 16 fractional bits, represents 0.0 to 0.999*/
typedef uint32_t Q0n31; /**< signed number using 0 integer bits and 31 fractional bits, represents -0.2147483648 to 0.2147483647*/
typedef int16_t Q7n8; /**< signed fractional number using 7 integer bits and 8 fractional bits, represents -127.996 to 127.996*/
typedef uint16_t Q3n13; /**< unsigned fractional number using 3 integer bits and 13 fractional bits, represents 0 to 7.999*/
typedef int16_t Q1n14; /**< signed fractional number using 1 integer bit and 14 fractional bits, represents -1.999 to 1.999*/
typedef int16_t Q15n0; /**< signed number using 15 integer bits and 0 fractional bits, represents -2147483648 to 2147483647*/
typedef uint16_t Q8n8; /**< unsigned fractional number using 8 integer bits and 8 fractional bits, represents 0 to 255.996*/
typedef int16_t Q0n15; /**< signed fractional number using 0 integer bits and 15 fractional bits, represents -0.32768 to 0.32767*/
typedef uint16_t Q1n15; /**< unsigned fractional number using 1 integer bit and 15 fractional bits, represents 0 to 1.999*/
typedef uint16_t Q16n0; /**< unsigned number using 16 integer bits and 0 fractional bits, represents 0 to 65536.0*/
typedef int32_t Q23n8; /**< signed fractional number using 23 integer bits and 8 fractional bits, represents -8388607.996 to 8388607.996*/
typedef int32_t Q15n16; /**< signed fractional number using 15 integer bits and 16 fractional bits, represents -32767.999 to 32767.999*/
typedef int32_t Q31n0; /**< signed (normal int32_t int16_t) number using 31 integer bits and 0 fractional bits, represents -2147483648 to 2147483647*/
typedef uint32_t Q32n0; /**< unsigned (normal uint32_t int16_t) number using 32 integer bits and 0 fractional bits, represents 0 to 4294967295*/
typedef uint32_t Q0n32; /**< unsigned fractional number using 0 integer bits and 32 fractional bits, represents 0 to 0.999999999767169*/
typedef uint32_t Q8n24; /**< signed fractional number using 8 integer bits and 24 fractional bits, represents 0 to 255.999*/
typedef uint32_t Q24n8; /**< unsigned fractional number using 24 integer bits and 8 fractional bits, represents 0 to 16777215*/
typedef uint32_t Q16n16; /**< unsigned fractional number using 16 integer bits and 16 fractional bits, represents 0 to 65535.999*/
/** @}*/
/** @ingroup fixmath
@{
*/
// macros to save runtime calculations for representations of 1
#define Q0n7_FIX1 ((Q0n7) 127) /**< 0.992 in Q0n7 format*/
#define Q7n8_FIX1 ((Q7n8) 256) /**< 1 in Q7n8 format*/
#define Q8n8_FIX1 ((Q8n8) 256) /**< 1 in Q8n8 format*/
#define Q23n8_FIX1 ((Q23n8) 256) /**< 1 in Q23n8 format*/
#define Q1n14_FIX1 ((Q1n14) 16384) /**< 1 in Q1n14 format*/
#define Q1n15_FIX1 ((Q1n15) 32768) /**< 1 in Q1n15 format*/
#define Q16n16_FIX1 ((Q16n16) 65536) /**< 1 in Q16n16 format*/
#define Q0n15_FIX1 ((Q0n15) 32767) /**< 0.999 in Q0n15 format*/
#define Q0n16_FIX1 ((Q0n16) 65535) /**< 0.999 in Q0n16 format*/
#define Q15n0_FIX1 ((Q15n0) 16384) /**< 1 in Q15n0 format*/
#define Q15n16_FIX1 ((Q15n16) 65536) /**< 1 in Q15n16 format*/
#define Q8n24_FIX1 ((Q8n24) 16777216) /**< 1 in Q8n24 format*/
#define Q0n32_FIX1 ((Q0n32) 4294967295) /**< 0.999999999767169 in Q0n32 format*/
#define Q16n16_PI ((Q16n16) 205887) /**< PI in Q16n16 format*/
#define Q3n13_2PI ((Q3n13) 411775) /**< 2*PI in Q3n13 format*/
#define Q16n16_2PI ((Q16n16) 411775) /**< 2*PI in Q16n16 format*/
#define low15bits ((Q1n15) 32767) /**< Useful for keeping the lower 15 bits of a Q1n15 number, using &*/
/** @}*/
/*
Type conversions: Float to Q
To convert a number from floating point to Qm.n format:
Multiply the floating point number by 2^n
Round to the nearest integer
Q to float
To convert a number from Qm.n format to floating point:
Convert the number to floating point as if it were an integer
Multiply by 2^-n
*/
/** @ingroup fixmath
@{
*/
inline
Q0n7 float_to_Q0n7(float a) { return static_cast<Q0n7>(a*256); } /**<Convert float to Q0n7 fix. @param a is a float*/
inline
Q0n8 float_to_Q0n8(float a) { return static_cast<Q0n8>(a*256); } /**<Convert float to Q0n8 fix. @param a is a float*/
inline
Q7n8 float_to_Q7n8(float a) { return static_cast<Q7n8>(a*256); } /**<Convert float to Q7n8 fix. @param a is a float*/
inline
Q8n8 float_to_Q8n8(float a) { return static_cast<Q8n8>(a*256); } /**<Convert float to Q8n8 fix. @param a is a float*/
inline
Q1n14 float_to_Q1n14(float a) { return static_cast<Q1n14>(a*16384); } /**<Convert float to Q1n14 fix. @param a is a float*/
inline
Q1n15 float_to_Q1n15(float a) { return static_cast<Q1n15>(a*32768); } /**<Convert float to Q1n15 fix. @param a is a float*/
inline
Q8n24 float_to_Q8n24(float a) { return static_cast<Q8n24>(a*16777216); } /**<Convert float to Q8n24 fix. @param a is a float*/
inline
Q23n8 float_to_Q23n8(float a) { return static_cast<Q23n8>(a*256); } /**<Convert float to Q23n8 fix. @param a is a float*/
inline
Q24n8 float_to_Q24n8(float a) { return static_cast<Q24n8>(a*256); } /**<Convert float to Q24n8 fix. @param a is a float*/
inline
Q16n16 float_to_Q16n16(float a) { return static_cast<Q16n16>(a*65536); } /**<Convert float to Q16n16 fix. @param a is a float*/
inline
Q0n16 float_to_Q0n16(float a) { return static_cast<Q0n16>(a*65536); } /**<Convert float to Q0n16 fix. @param a is a float*/
inline
Q15n16 float_to_Q15n16(float a) { return static_cast<Q15n16>(a*65536); } /**<Convert float to Q15n16 fix. @param a is a float*/
inline
Q1n14 Q0n7_to_Q1n14(Q0n7 a) { return (static_cast<Q1n14>(a))<<7; } /**<Convert Q0n7 int8_t to Q1n14 fix. @param a is a Q0n7 int8_t */
inline
Q15n16 Q0n7_to_Q15n16(Q0n7 a) { return (static_cast<Q15n16>(a))<<8; } /**<Convert Q0n7 signed int8_t to Q15n16 fix. @param a is a Q0n7 signed int8_t */
inline
float Q0n7_to_float(Q0n7 a) { return (static_cast<float>(a))/256; } /**<Convert Q0n7 fix to float. @param a is a Q0n7 int8_t*/
inline
Q1n15 Q0n8_to_Q1n15(Q0n8 a) { return (static_cast<Q1n15>(a))<<7; } /**<Convert Q0n8 uint8_t to Q1n15 fix. @param a is a Q0n8 uint8_t */
inline
Q8n8 Q0n8_to_Q8n8(Q0n8 a) { return (static_cast<Q8n8>(a))<<8; } /**<Convert Q0n8 uint8_t to Q8n8 fix. @param a is a Q0n8 uint8_t */
inline
Q8n24 Q0n8_to_Q8n24(Q0n8 a) { return (static_cast<Q8n24>(a))<<16; } /**<Convert Q0n8 uint8_t to Q8n24 fix. @param a is a Q0n8 uint8_t */
inline
Q24n8 Q0n8_to_Q24n8(Q0n8 a) { return (static_cast<Q24n8>(a))<<8; } /**<Convert Q0n8 uint8_t to Q24n8 fix. @param a is a Q0n8 uint8_t */
inline
Q15n16 Q0n8_to_Q15n16(Q0n8 a) { return (static_cast<Q15n16>(a))<<8; } /**<Convert Q0n8 uint8_t to Q15n16 fix. @param a is a Q0n8 uint8_t */
inline
Q16n16 Q0n8_to_Q16n16(Q0n8 a) { return (static_cast<Q16n16>(a))<<8; } /**<Convert Q0n8 uint8_t to Q16n16 fix. @param a is a Q0n8 uint8_t */
inline
float Q0n8_to_float(Q0n8 a) { return (static_cast<float>(a))/256; } /**<Convert Q0n8 fix to float. @param a is a Q0n8 uint8_t*/
inline
Q7n8 Q7n0_to_Q7n8(Q7n0 a) { return (static_cast<Q7n8>(a))<<8; } /**<Convert Q7n0 int8_t to Q7n8 fix. @param a is a int8_t*/
inline
Q15n16 Q7n0_to_Q15n16(Q7n0 a) { return (static_cast<Q15n16>(a))<<16; } /**<Convert Q7n0 int8_t to Q15n16 fix. @param a is a int8_t*/
inline
Q7n8 Q8n0_to_Q7n8(Q8n0 a) { return (static_cast<Q7n8>(a))<<8; } /**<Convert Q8n0 uint8_t to Q7n8 fix. @param a is a Q8n0 uint8_t*. Beware of overflow. */
inline
Q8n8 Q8n0_to_Q8n8(Q8n0 a) { return (static_cast<Q8n8>(a))<<8; } /**<Convert uint8_t to Q8n8 fix. @param a is a Q8n0 uint8_t*/
inline
Q15n16 Q8n0_to_Q15n16(Q8n0 a) { return (static_cast<Q15n16>(a))<<16; } /**<Convert Q8n0 uint8_t to Q15n16 fix. @param a is a Q8n0 uint8_t */
inline
Q16n16 Q8n0_to_Q16n16(Q8n0 a) { return (static_cast<Q16n16>(a))<<16; } /**<Convert Q8n0 uint8_t to Q16n16 fix. @param a is a Q8n0 uint8_t */
inline
Q7n0 Q7n8_to_Q7n0(Q7n8 a) { return static_cast<Q7n0>((Q7n8)a>>8); } /**<Convert Q7n8 fix to Q7n0. @param a is a Q7n8 int16_t*/
inline
Q15n16 Q7n8_to_Q15n16(Q7n8 a) { return (static_cast<Q15n16>(a))<<8; } /**<Convert Q7n8 fix to Q15n16. @param a is a Q7n8 int16_t*/
inline
float Q7n8_to_float(Q7n8 a) { return (static_cast<float>(a))/256; } /**<Convert Q7n8 fix to float. @param a is a Q7n8 int16_t*/
inline
Q8n0 Q8n8_to_Q8n0(Q8n8 a) { return static_cast<Q8n0>((Q8n8)a>>8); } /**<Convert Q8n8 fix to Q8n0 uint8_t. @param a is a Q8n8 uint16_t*/
inline
Q16n16 Q8n8_to_Q16n16(Q8n8 a) { return (static_cast<Q16n16>(a))<<8; } /**<Convert Q8n8 fix to Q16n16 uint32_t. @param a is a Q8n8 uint16_t*/
inline
float Q8n8_to_float(Q8n8 a) { return (static_cast<float>(a))/256; } /**<Convert Q8n8 fix to float. @param a is a Q8n8 uint16_t*/
inline
Q0n7 Q1n14_to_Q0n7(Q1n14 a) { return static_cast<Q0n7>((Q1n14)a>>7); } /**<Convert Q1n14 fixed to Q0n7 int8_t. @param a is a Q1n14 int16_t*/
inline
float Q1n14_to_float(Q1n14 a) { return (static_cast<float>(a))/16384; } /**<Convert fix to float. @param a is an int16_t*/
inline
Q0n8 Q1n15_to_Q0n8(Q1n15 a) { return static_cast<Q0n8>((Q1n15)a>>7); } /**<Convert Q1n15 fixed to Q0n8 uint8_t. Only for positive values! @param a is a Q1n15 uint16_t*/
inline
float Q1n15_to_float(Q1n15 a) { return (static_cast<float>(a))/32768; } /**<Convert fix to float. @param a is a Q1n15 uint16_t*/
inline
float Q0n16_to_float(Q0n16 a) { return (static_cast<float>(a))/65536; } /**<Convert fix to float. @param a is a Q0n16 uint16_t*/
inline
Q15n16 Q15n0_to_Q15n16(Q15n0 a) { return (static_cast<Q15n16>(a))<<16; } /**<Convert Q15n0 int16_t to Q15n16 fix. @param a is a Q15n0 int16_t */
inline
Q15n16 Q16n0_to_Q15n16(Q16n0 a) { return (static_cast<Q15n16>(a))<<16; } /**<Convert Q16n0 uint16_t to Q15n16 fix. @param a is a Q16n0 uint16_t */
inline
Q23n8 Q16n0_to_Q23n8(Q16n0 a) { return (static_cast<Q23n8>(a))<<8; } /**<Convert Q16n0 uint16_t to Q23n8 fixed point signed int32_t. @param a is a Q16n0 uint16_t*/
inline
Q24n8 Q16n0_to_Q24n8(Q16n0 a) { return (static_cast<Q24n8>(a))<<8; } /**<Convert Q16n0 uint16_t to Q24n8 fixed point uint32_t. @param a is a Q16n0 uint16_t*/
inline
Q16n16 Q16n0_to_Q16n16(Q16n0 a) { return (static_cast<Q16n16>(a))<<16; } /**<Convert Q16n0 uint16_t to Q16n16 fixed point uint32_t. @param a is a Q16n0 uint16_t*/
inline
float Q16n0_to_float(Q16n0 a) { return (static_cast<float>(a)); } /**<Convert Q16n0 uint16_t to float. @param a is a Q16n0 uint16_t*/
inline
Q0n8 Q8n24_to_Q0n8(Q8n24 a) { return static_cast<Q0n8>((Q8n24)a>>16); } /**<Convert Q8n24 fixed to Q0n8 uint8_t. @param a is a Q8n24 uint32_t*/
inline
float Q8n24_to_float(Q8n24 a) { return (static_cast<float>(a))/16777216; } /**<Convert fix to float. @param a is a Q8n24 uint32_t*/
inline
Q31n0 Q23n8_to_Q31n0(Q23n8 a) { return static_cast<Q31n0>((Q23n8)a>>8); } /**<Convert Q23n8 fixed to Q31n0 int32_t. @param a is a Q23n8 int32_t*/
inline
Q16n0 Q23n8_to_Q16n0(Q23n8 a) { return static_cast<Q16n0>((Q23n8)a>>8); } /**<Convert Q23n8 fixed to Q16n0 uint16_t. Positive values only. @param a is a Q23n8 int32_t*/
inline
Q15n0 Q23n8_to_Q15n0(Q23n8 a) { return static_cast<Q15n0>((Q23n8)a>>8); } /**<Convert Q23n8 fixed to Q15n0 signed int16_t. @param a is a Q23n8 int32_t*/
inline
Q7n8 Q23n8_to_Q7n8(Q23n8 a) { return static_cast<Q7n8>(a); } /**<Convert Q23n8 fixed to Q7n8 signed int16_t, losing most significant bits. @param a is a Q23n8 signed int32_t.*/
inline
float Q23n8_to_float(Q23n8 a) { return (static_cast<float>(a))/256; } /**<Convert fix to float. @param a is a Q23n8 signed int32_t*/
inline
Q0n8 Q24n8_to_Q0n8(Q24n8 a) { return static_cast<Q0n8>(a); } /**<Convert Q24n8 fixed to Q0n8 uint8_t. @param a is a Q24n8 uint32_t*/
inline
Q16n16 Q24n8_to_Q16n0(Q24n8 a) { return (static_cast<Q16n0>((Q24n8)a))>>8; } /**<Convert Q24n8 fixed to Q16n0 uint16_t. @param a is a Q24n8 uint32_t*/
inline
Q32n0 Q24n8_to_Q32n0(Q24n8 a) { return static_cast<Q32n0>((Q24n8)a>>8); } /**<Convert Q24n8 fixed to Q32n0 uint32_t. @param a is a Q24n8 uint32_t*/
inline
Q16n16 Q24n8_to_Q16n16(Q24n8 a) { return (static_cast<Q16n16>(a))<<8; } /**<Convert Q24n8 fixed to Q16n16 uint32_t. @param a is a Q24n8 uint32_t*/
inline
float Q24n8_to_float(Q24n8 a) { return (static_cast<float>(a))/256; } /**<Convert fix to float. @param a is a Q24n8 uint32_t*/
inline
Q0n8 Q15n16_to_Q0n8(Q15n16 a) { return static_cast<Q0n8>((Q15n16)a>>8); } /**<Convert Q15n16 fixed to Q0n8 uint8_t. Only for positive values! @param a is a Q15n16 signed int32_t*/
inline
Q8n0 Q15n16_to_Q8n0(Q15n16 a) { return static_cast<Q8n0>((Q15n16)a>>16); } /**<Convert Q15n16 fixed to Q8n0 uint8_t. Only for positive values! @param a is a Q15n16 signed int32_t*/
inline
Q15n0 Q15n16_to_Q15n0(Q15n16 a) { return static_cast<Q15n0>((Q15n16)a>>16); } /**<Convert Q15n16 fixed to Q15n0 signed int16_t. @param a is a Q15n16 signed int32_t*/
inline
Q7n8 Q15n16_to_Q7n8(Q15n16 a) { return static_cast<Q7n8>((Q15n16)a>>8); } /**<Convert Q15n16 fixed to Q7n8 signed int16_t, keeping middle bits only. @param a is a Q15n16 signed int32_t.*/
inline
Q8n8 Q15n16_to_Q8n8(Q15n16 a) { return static_cast<Q8n8>((Q15n16)a>>8); } /**<Convert Q15n16 fixed to Q8n8 signed int16_t, keeping middle bits only. @param a is a Q15n16 signed int32_t.*/
inline
Q23n8 Q15n16_to_Q23n8(Q15n16 a) { return static_cast<Q23n8>((Q15n16)a>>8); } /**<Convert Q15n16 fixed to Q23n8 signed int32_t. @param a is a Q15n16 signed int32_t.*/
inline
float Q15n16_to_float(Q15n16 a) { return (static_cast<float>(a))/65536; } /**<Convert fix to float. @param a is a Q15n16 signed int32_t*/
inline
Q0n8 Q16n16_to_Q0n8(Q16n16 a) { return static_cast<Q0n8>((Q16n16)a>>8); } /**<Convert Q16n16 fixed to Q0n8 uint8_t. @param a is a Q16n16 uint32_t*/
inline
Q8n8 Q16n16_to_Q8n8(Q8n8 a) { return static_cast<Q8n8>((Q16n16)a>>16); } /**<Convert Q16n16 fixed to Q8n8 uint16_t. @param a is a Q16n16 uint32_t*/
inline
Q16n0 Q16n16_to_Q16n0(Q16n16 a) { return static_cast<Q16n0>((Q16n16)a>>16); } /**<Convert Q16n16 fixed to Q16n0 uint16_t. @param a is a Q16n16 uint32_t*/
inline
Q24n8 Q16n16_to_Q24n8(Q16n16 a) { return static_cast<Q24n8>((Q16n16)a>>8); } /**<Convert Q16n16 fixed to Q24n8 uint32_t. @param a is a Q16n16 uint32_t*/
inline
float Q16n16_to_float(Q16n16 a) { return (static_cast<float>(a))/65536; } /**<Convert fix to float. @param a is a Q16n16 uint32_t*/
/** @}*/
/* @ingroup fixmath
Fast (?) fixed point multiply for Q7n8 fractional numbers.
The c version below is 3 times faster, and not subject to the same overflow limitations (+-3.99, or +-2048)
@param a Q7n8 format multiplicand
@param b Q7n8 format multiplier
@return a Q7n8 format product
*/
/*
#define Q7n8_mult(a,b) \
({ \
int16_t prod, val1=a, val2=b ; \
__asm__ __volatile__ ( \
"muls %B1, %B2 \n\t" \
"mov %B0, r0 \n\t" \
"mul %A1, %A2\n\t" \
"mov %A0, r1 \n\t" \
"mulsu %B1, %A2 \n\t" \
"add %A0, r0 \n\t" \
"adc %B0, r1 \n\t" \
"mulsu %B2, %A1 \n\t" \
"add %A0, r0 \n\t" \
"adc %B0, r1 \n\t" \
"clr r1 \n\t" \
: "=&d" (prod) \
: "a" (val1), "a" (val2) \
); \
prod; \
})
*/
/** @ingroup fixmath
Fast fixed point multiply for Q7n8 fractional numbers.
@param a Q7n8 format multiplicand
@param b Q7n8 format multiplier
@return a Q7n8 format product
*/
inline
Q7n8 Q7n8_mult(Q7n8 a, Q7n8 b) {
return ((int16_t)((((int32_t)(a))*(b))>>8));
}
/*
#define FMULS8(v1, v2) \
({ \
uint8_t res; \
uint8_t val1 = v1; \
uint8_t val2 = v2; \
__asm__ __volatile__ \
( \
"fmuls $1, $2" "\n\t" \
"mov $0, r1" "\n\t" \
"clr r1" "\n\t" \
: "=&d" (res) \
: "a" (val1), "a" (val2) \
); \
res; \
}) */
/*
// from octosynth, Joe Marshall 2011:
// multiply 2 16 bit numbers together and shift 8 without precision loss
// requires assembler really
volatile uint8_t zeroReg=0;
volatile uint16_t multipliedCounter=oscillators[c].phaseStep;
asm volatile
(
// high uint8_ts mult together = high uint8_t
"ldi %A[outVal],0" "\n\t"
"mul %B[phaseStep],%B[pitchB}]" "\n\t"
"mov %B[outVal],r0" "\n\t"
// ignore overflow into r1 (should never overflow)
// low uint8_t * high uint8_t -> both uint8_ts
"mul %A[phaseStep],%B[pitchB}]" "\n\t"
"add %A[outVal],r0" "\n\t"
// carry into high uint8_t
"adc %B[outVal],r1" "\n\t"
// high uint8_t* low uint8_t -> both uint8_ts
"mul %B[phaseStep],%A[pitchB}]" "\n\t"
"add %A[outVal],r0" "\n\t"
// carry into high uint8_t
"adc %B[outVal],r1" "\n\t"
// low uint8_t * low uint8_t -> round
"mul %A[phaseStep],%A[pitchB}]" "\n\t"
// the adc below is to round up based on high bit of low*low:
"adc %A[outVal],r1" "\n\t"
"adc %B[outVal],%[ZERO]" "\n\t"
"clr r1" "\n\t"
:[outVal] "=&d" (multipliedCounter)
:[phaseStep] "d" (oscillators[c].phaseStep),[pitchB}] "d"( pitchB}Multiplier),[ZERO] "d" (zeroReg)
:"r1","r0"
);
oscillators[c].phaseStep=multipliedCounter;
*/
int16_t ipow(int16_t base, int16_t exp); /**< dangerous overflow-prone int16_t power function */
Q16n16 Q16n16_pow2(Q8n8 exponent);
uint8_t uint8_tMod(uint8_t n, uint8_t d);
uint8_t uint8_tDiv(uint8_t n, uint8_t d);
uint8_t uint8_tRnd(uint8_t min, uint8_t max);
uint16_t isqrt16(uint16_t n);
uint32_t isqrt32(uint32_t n);
#endif /* FIXEDMATH_H_ */