Mozzi  version v1.1.0
sound synthesis library for Arduino
WaveFolder.h
1 /*
2  * Wavefolder.h
3  *
4  * Copyright 2022 Thomas Combriat
5  *
6  * This file is part of Mozzi.
7  *
8  * Mozzi is licensed under a Creative Commons
9  * Attribution-NonCommercial-ShareAlike 4.0 International License.
10  *
11  */
12 
13 #ifndef WAVEFOLDER_H
14 #define WAVEFOLDER_H
15 
16 
17 #include "IntegerType.h"
18 #include "AudioOutput.h"
19 
20 
21 /*
22  A simple wavefolder which folds the waves once it reachs the up or
23  low limits. The wave can be folded several times. It constrains the wave
24  to be constrain between the LowLimit and the HighLimit.
25  By default, this class is working on data which not overflow the
26  AudioOutputStorage_t type, which is int by default.
27  Feeding samples which, before folding, are overflowing this container
28  will lead to unpredicted behavior.
29  It is possible to use a bigger type with the template formulation
30  if needed.
31 */
32 
33 
34 /** A simple wavefolder
35  */
36 
37 template<typename T=AudioOutputStorage_t>
39 {
40 public:
41  /** Constructor
42  */
44 
45 
46  /** Set the high limit where the wave will start to be folded back the other way.
47  @param highLimit the high limit used by the wavefolder.
48  */
49  void setHighLimit(T highLimit)
50  {
51  hl = highLimit;
52  R = hl-ll;
53  Ri = NUMERATOR / (hl-ll); // calculated here to speed up next()
54  }
55 
56 
57  /** Set the low limit where the wave will start to be folded back the other way.
58  @param lowLimit the low limit used by the wavefolder.
59  */
60  void setLowLimit(T lowLimit)
61  {
62  ll = lowLimit;
63  R = hl-ll;
64  Ri = NUMERATOR / (hl-ll); // calculated here to speed up next()
65  }
66 
67 
68  /** Set the low and the high limits at the same time.
69  @param lowLimit the low limit used by the wavefolder
70  @param highLimit the high limit used by the wavefolder
71  @note highLimit MUST be higher than lowLimit
72  */
73  void setLimits(T lowLimit, T highLimit)
74  {
75  hl = highLimit;
76  ll = lowLimit;
77  R = hl-ll;
78  Ri = NUMERATOR / (hl-ll); // calculated here to speed up next()
79  }
80 
81 
82  /** Return the next folded sample
83  @param in is the signal input.
84  @return the folded output.
85  */
86  T next(T in)
87  {
88  if (in > hl)
89  {
90  typename IntegerType<sizeof(T)>::unsigned_type sub = in-hl;
91  /* Instead of using a division, we multiply by the inverse.
92  As the inverse is necessary smaller than 1, in order to fit in an integer
93  we multiply it by NUMERATOR before computing the inverse.
94  The shift is equivalent to divide by the NUMERATOR:
95  q = sub / R = (sub * (NUMERATOR/R))/NUMERATOR with NUMERATOR/R = Ri
96  */
97  typename IntegerType<sizeof(T)>::unsigned_type q = ((typename IntegerType<sizeof(T)+sizeof(T)>::unsigned_type) sub*Ri) >> SHIFT;
98  typename IntegerType<sizeof(T)>::unsigned_type r = sub - q*R; // remainer
99  if (q&0b1) return ll+r; //odd
100  else return hl-r; // even
101 
102  }
103  else if (in < ll)
104  {
105  typename IntegerType<sizeof(T)>::unsigned_type sub = ll-in;
106  typename IntegerType<sizeof(T)>::unsigned_type q = ((typename IntegerType<sizeof(T)+sizeof(T)>::unsigned_type) sub*Ri) >> SHIFT;
107  typename IntegerType<sizeof(T)>::unsigned_type r = sub - q*R; // remainer
108  if (q&0b1) return hl-r;
109  else return ll+r;
110  }
111  else return in;
112  }
113 
114 private:
115  T hl;
116  T ll;
117  typename IntegerType<sizeof(T)>::unsigned_type R;
118  typename IntegerType<sizeof(T)>::unsigned_type Ri;
119  static const uint8_t SHIFT = (sizeof(T) << 3);
120  static const typename IntegerType<sizeof(T)>::unsigned_type NUMERATOR = ((typename IntegerType<sizeof(T)+sizeof(T)>::unsigned_type) 1<<(SHIFT))-1;
121 
122  // Slower (way slower, around 2.5 times) but more precise, kept in case we want to switch one day.
123  /* typename IntegerType<sizeof(T)+sizeof(T)>::unsigned_type Ri;
124  static const uint8_t SHIFT = 1+(sizeof(T) << 3);
125  static const typename IntegerType<sizeof(T)+sizeof(T)>::unsigned_type NUMERATOR = ((typename IntegerType<sizeof(T)+sizeof(T)>::unsigned_type) 1<<(SHIFT))-1;*/
126 
127 
128 };
129 
130 
131 #endif
void setHighLimit(T highLimit)
Set the high limit where the wave will start to be folded back the other way.
Definition: WaveFolder.h:49
void setLimits(T lowLimit, T highLimit)
Set the low and the high limits at the same time.
Definition: WaveFolder.h:73
void setLowLimit(T lowLimit)
Set the low limit where the wave will start to be folded back the other way.
Definition: WaveFolder.h:60
WaveFolder()
Constructor.
Definition: WaveFolder.h:43
A simple wavefolder.
Definition: WaveFolder.h:38
T next(T in)
Return the next folded sample.
Definition: WaveFolder.h:86
#define AudioOutputStorage_t
The type used to store a single channel of a single frame, internally.
Definition: AudioOutput.h:46