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