Skip to content

Commit 3927ec1

Browse files
authored
Merge pull request #236 from sensorium/devel/mozziClass_FixMath
Specializations of Mozzi classes for FixMath
2 parents 172da01 + 4f00936 commit 3927ec1

File tree

16 files changed

+824
-298
lines changed

16 files changed

+824
-298
lines changed

AudioOutput.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757

5858
#ifndef AUDIOOUTPUT_H
5959
#define AUDIOOUTPUT_H
60+
#include <FixMath.h>
6061

6162
/** The type used to store a single channel of a single frame, internally. For compatibility with earlier versions of Mozzi this is defined as int.
6263
* If you do not care about keeping old sketches working, you may be able to save some RAM by using int16_t, instead (on boards where int is larger
@@ -134,8 +135,11 @@ struct MonoOutput {
134135
/** Construct an audio frame from a zero-centered value known to be in the 8 bit range. On AVR, if MOZZI_OUTPUT_PWM mode, this is effectively the same as calling the
135136
* constructor, directly (no scaling gets applied). On platforms/configs using more bits, an appropriate left-shift will be performed. */
136137
static inline MonoOutput from8Bit(int16_t l) { return fromNBit(8, l); }
137-
/** Construct an audio frame a zero-centered value known to be in the 16 bit range. This is jsut a shortcut for fromNBit(16, ...) provided for convenience. */
138+
/** Construct an audio frame from a zero-centered value known to be in the 16 bit range. This is jsut a shortcut for fromNBit(16, ...) provided for convenience. */
138139
static inline MonoOutput from16Bit(int16_t l) { return fromNBit(16, l); }
140+
/** Construct an audio frame from a SFix type from FixMath. Mozzi will figure out how many bits are in there and performs appropriate shifting to match the output range. */
141+
template<int8_t NI, int8_t NF, uint64_t RANGE>
142+
static inline MonoOutput fromSFix(SFix<NI,NF,RANGE> l) { return MonoOutput(SCALE_AUDIO(l.asRaw(), (NI+NF+1))) ;}
139143
/** Construct an audio frame a zero-centered value known to be above at almost but not quite the N bit range, e.g. at N=8 bits and a litte. On most platforms, this is
140144
* exactly the same as fromNBit(), shifting up or down to the platforms' available resolution.
141145
*
@@ -179,6 +183,9 @@ template<typename T> static inline StereoOutput fromNBit(uint8_t bits, T l, T r)
179183
static inline StereoOutput from8Bit(int16_t l, int16_t r) { return fromNBit(8, l, r); }
180184
/** See @ref MonoOutput::from16Bit(), stereo variant */
181185
static inline StereoOutput from16Bit(int16_t l, int16_t r) { return fromNBit(16, l, r); }
186+
/** See @ref MonoOutput::fromSFix(), stereo variant. Note that the two channels do not need to have the same number of bits. */
187+
template<int8_t NI, int8_t NF, uint64_t RANGE, int8_t _NI, int8_t _NF, uint64_t _RANGE>
188+
static inline StereoOutput fromSFix(SFix<NI,NF,RANGE> l, SFix<_NI,_NF,_RANGE> r) { return StereoOutput(SCALE_AUDIO(l.asRaw(), (NI+NF+1)), SCALE_AUDIO(r.asRaw(), (_NI+_NF+1))); }
182189
/** See @ref MonoOutput::fromAlmostNBit(), stereo variant */
183190
template<typename A, typename B> static inline StereoOutput fromAlmostNBit(A bits, B l, B r) { return StereoOutput(SCALE_AUDIO_NEAR(l, bits), SCALE_AUDIO_NEAR(r, bits)); }
184191
private:

Line.h

Lines changed: 178 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
#include <Arduino.h>
1717

18+
#include<FixMath.h>
19+
1820
/** For linear changes with a minimum of calculation at each step. For instance,
1921
you can use Line to make an oscillator glide from one frequency to another,
2022
pre-calculating the required phase increments for each end and then letting your
@@ -30,12 +32,15 @@ represent fractional numbers. Google "fixed point arithmetic" if this is new to
3032
you.
3133
*/
3234

35+
36+
37+
3338
template <class T>
3439
class Line
3540
{
3641
private:
37-
volatile T current_value; // volatile because it could be set in control interrupt and updated in audio
38-
volatile T step_size;
42+
T current_value;
43+
T step_size;
3944

4045
public:
4146
/** Constructor. Use the template parameter to set the type of numbers you
@@ -109,7 +114,7 @@ template <>
109114
class Line <unsigned char>
110115
{
111116
private:
112-
volatile unsigned char current_value; // volatile because it could be set in control interrupt and updated in audio
117+
unsigned char current_value;
113118
char step_size;
114119

115120
public:
@@ -178,7 +183,7 @@ template <>
178183
class Line <unsigned int>
179184
{
180185
private:
181-
volatile unsigned int current_value; // volatile because it could be set in control interrupt and updated in audio
186+
unsigned int current_value;
182187
int step_size;
183188

184189
public:
@@ -250,7 +255,7 @@ template <>
250255
class Line <unsigned long>
251256
{
252257
private:
253-
volatile unsigned long current_value; // volatile because it could be set in control interrupt and updated in audio
258+
unsigned long current_value;
254259
long step_size;
255260

256261
public:
@@ -312,6 +317,174 @@ class Line <unsigned long>
312317
}
313318
};
314319

320+
321+
/* UFix specialisation */
322+
template<int8_t NI, int8_t NF>
323+
class Line<UFix<NI, NF>>
324+
{
325+
private:
326+
typedef UFix<NI, NF> internal_type;
327+
internal_type current_value;
328+
SFix<NI,NF> step_size;
329+
330+
public:
331+
/** Constructor. Use the template parameter to set the type of numbers you
332+
want to use. For example, Line \<int\> myline; makes a Line which uses ints.
333+
*/
334+
Line (){;}
335+
336+
/** Increments one step along the line.
337+
@return the next value.
338+
*/
339+
inline
340+
internal_type next()
341+
{
342+
current_value = current_value + step_size;
343+
return current_value;
344+
}
345+
346+
/** Set the current value of the line.
347+
The Line will continue incrementing from this
348+
value using any previously calculated step size.
349+
@param value the number to set the Line's current_value to.
350+
*/
351+
inline
352+
void set(internal_type value)
353+
{
354+
current_value=value;
355+
}
356+
357+
/** Given a target value and the number of steps to take on the way, this calculates the step size needed to get there from the current value.
358+
@param targetvalue the value to move towards.
359+
@param num_steps how many steps to take to reach the target as a UFix<_NI,0>
360+
*/
361+
template<int8_t _NI>
362+
void set(internal_type targetvalue, UFix<_NI,0> num_steps)
363+
{
364+
if(num_steps.asRaw()) {
365+
auto numerator = targetvalue-current_value;
366+
step_size = numerator*num_steps.invAccurate();
367+
} else {
368+
step_size = 0;
369+
current_value = targetvalue;
370+
}
371+
}
372+
373+
374+
/** Given a target value and the number of steps to take on the way, this calculates the step size needed to get there from the current value.
375+
@param targetvalue the value to move towards.
376+
@param num_steps how many steps to take to reach the target.
377+
*/
378+
template<typename T>
379+
void set(internal_type targetvalue, T num_steps)
380+
{
381+
if(num_steps) {
382+
auto numerator = targetvalue-current_value;
383+
step_size = internal_type(numerator.asRaw()/num_steps,true);
384+
} else {
385+
step_size = 0;
386+
current_value = targetvalue;
387+
}
388+
}
389+
390+
/** Given a new starting value, target value and the number of steps to take on the way, this sets the step size needed to get there.
391+
@param startvalue the number to set the Line's current_value to.
392+
@param targetvalue the value to move towards.
393+
@param num_steps how many steps to take to reach the target.
394+
*/
395+
template<typename T>
396+
void set(internal_type startvalue, internal_type targetvalue, T num_steps)
397+
{
398+
set(startvalue);
399+
set(targetvalue, num_steps);
400+
}
401+
};
402+
403+
404+
/* SFix specialisation (if someone has an idea to avoid duplication with UFix) */
405+
template<int8_t NI, int8_t NF>
406+
class Line<SFix<NI, NF>>
407+
{
408+
private:
409+
typedef SFix<NI, NF> internal_type;
410+
internal_type current_value;
411+
SFix<NI+1, NF> step_size;
412+
413+
public:
414+
/** Constructor. Use the template parameter to set the type of numbers you
415+
want to use. For example, Line \<int\> myline; makes a Line which uses ints.
416+
*/
417+
Line (){;}
418+
419+
/** Increments one step along the line.
420+
@return the next value.
421+
*/
422+
inline
423+
internal_type next()
424+
{
425+
current_value = current_value + step_size;
426+
return current_value;
427+
}
428+
429+
/** Set the current value of the line.
430+
The Line will continue incrementing from this
431+
value using any previously calculated step size.
432+
@param value the number to set the Line's current_value to.
433+
*/
434+
inline
435+
void set(internal_type value)
436+
{
437+
current_value=value;
438+
}
439+
440+
/** Given a target value and the number of steps to take on the way, this calculates the step size needed to get there from the current value.
441+
@param targetvalue the value to move towards.
442+
@param num_steps how many steps to take to reach the target as a UFix<_NI,0>
443+
*/
444+
template<int8_t _NI>
445+
void set(internal_type targetvalue, UFix<_NI,0> num_steps)
446+
{
447+
if(num_steps.asRaw()) {
448+
auto numerator = targetvalue-current_value;
449+
step_size = numerator*num_steps.invAccurate();
450+
} else {
451+
step_size = 0;
452+
current_value = targetvalue;
453+
}
454+
}
455+
456+
457+
/** Given a target value and the number of steps to take on the way, this calculates the step size needed to get there from the current value.
458+
@param targetvalue the value to move towards.
459+
@param num_steps how many steps to take to reach the target.
460+
*/
461+
template<typename T>
462+
void set(internal_type targetvalue, T num_steps)
463+
{
464+
if(num_steps) {
465+
auto numerator = targetvalue-current_value;
466+
step_size = internal_type(numerator.asRaw()/num_steps,true);
467+
} else {
468+
step_size = 0;
469+
current_value = targetvalue;
470+
}
471+
}
472+
473+
/** Given a new starting value, target value and the number of steps to take on the way, this sets the step size needed to get there.
474+
@param startvalue the number to set the Line's current_value to.
475+
@param targetvalue the value to move towards.
476+
@param num_steps how many steps to take to reach the target.
477+
*/
478+
template<typename T>
479+
void set(internal_type startvalue, internal_type targetvalue, T num_steps)
480+
{
481+
set(startvalue);
482+
set(targetvalue, num_steps);
483+
}
484+
};
485+
486+
487+
315488
/**
316489
@example 02.Control/Control_Tremelo/Control_Tremelo.ino
317490
This example demonstrates the Line class.

Oscil.h

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,9 @@ class Oscil
159159
each direction. This fixed point math number is interpreted as a SFix<15,16> internally.
160160
@return a sample from the table.
161161
*/
162-
template <byte NI, byte NF>
162+
template <int8_t NI, int8_t NF, uint8_t RANGE>
163163
inline
164-
int8_t phMod(SFix<NI,NF> phmod_proportion)
164+
int8_t phMod(SFix<NI,NF,RANGE> phmod_proportion)
165165
{
166166
return phMod(SFix<15,16>(phmod_proportion).asRaw());
167167
}
@@ -216,11 +216,11 @@ class Oscil
216216
@note This didn't run faster than float last time it was tested, after 2014 code changes. Need to see if 2014 changes improved or worsened performance.
217217
@param frequency in UFix<NI,NF> fixed-point number format.
218218
*/
219-
template <int8_t NI, int8_t NF>
219+
template <int8_t NI, int8_t NF, uint64_t RANGE>
220220
inline
221-
void setFreq(UFix<NI,NF> frequency)
221+
void setFreq(UFix<NI,NF,RANGE> frequency)
222222
{
223-
setFreq_Q16n16(UFix<16,16>(frequency).asRaw());
223+
setFreq_Q16n16(UFix<16,16>(frequency).asRaw());
224224
}
225225

226226

@@ -256,8 +256,9 @@ class Oscil
256256
less than 64 Hz.
257257
@param frequency in UFix<24,8> fixed-point number format.
258258
*/
259+
template <uint64_t RANGE>
259260
inline
260-
void setFreq(UFix<24,8> frequency)
261+
void setFreq(UFix<24,8,RANGE> frequency)
261262
{
262263
setFreq_Q24n8(frequency.asRaw());
263264
}
@@ -295,8 +296,9 @@ class Oscil
295296
@note This didn't run faster than float last time it was tested, after 2014 code changes. Need to see if 2014 changes improved or worsened performance.
296297
@param frequency in UFix<16,16> fixed-point number format.
297298
*/
299+
template <uint64_t RANGE>
298300
inline
299-
void setFreq(UFix<16,16> frequency)
301+
void setFreq(UFix<16,16,RANGE> frequency)
300302
{
301303
setFreq_Q16n16(frequency.asRaw());
302304
}
@@ -309,9 +311,9 @@ class Oscil
309311
@note This didn't run faster than float last time it was tested, after 2014 code changes. Need to see if 2014 changes improved or worsened performance.
310312
@param frequency in SFix<16,16> fixed-point number format.
311313
*/
312-
template <byte NI, byte NF>
314+
template <int8_t NI, int8_t NF, uint64_t RANGE>
313315
inline
314-
void setFreq(SFix<NI,NF> frequency)
316+
void setFreq(SFix<NI,NF,RANGE> frequency)
315317
{
316318
setFreq_Q16n16(UFix<16,16>(frequency).asRaw());
317319
}

0 commit comments

Comments
 (0)