forked from sensorium/Mozzi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
WaveFolder.h
133 lines (107 loc) · 3.84 KB
/
WaveFolder.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
/*
* WaveFolder.h
*
* This file is part of Mozzi.
*
* Copyright 2022-2024 Thomas Combriat and the Mozzi Team
*
* Mozzi is licensed under the GNU Lesser General Public Licence (LGPL) Version 2.1 or later.
*
*/
#ifndef WAVEFOLDER_H
#define WAVEFOLDER_H
#include "IntegerType.h"
#include "AudioOutput.h"
/*
A simple wavefolder which folds the waves once it reachs the up or
low limits. The wave can be folded several times. It constrains the wave
to be constrain between the LowLimit and the HighLimit.
By default, this class is working on data which not overflow the
AudioOutputStorage_t type, which is int by default.
Feeding samples which, before folding, are overflowing this container
will lead to unpredicted behavior.
It is possible to use a bigger type with the template formulation
if needed.
*/
/** A simple wavefolder
*/
template<typename T=AudioOutputStorage_t>
class WaveFolder
{
public:
/** Constructor
*/
WaveFolder(){;}
/** Set the high limit where the wave will start to be folded back the other way.
@param highLimit the high limit used by the wavefolder.
*/
void setHighLimit(T highLimit)
{
hl = highLimit;
R = hl-ll;
Ri = NUMERATOR / (hl-ll); // calculated here to speed up next()
}
/** Set the low limit where the wave will start to be folded back the other way.
@param lowLimit the low limit used by the wavefolder.
*/
void setLowLimit(T lowLimit)
{
ll = lowLimit;
R = hl-ll;
Ri = NUMERATOR / (hl-ll); // calculated here to speed up next()
}
/** Set the low and the high limits at the same time.
@param lowLimit the low limit used by the wavefolder
@param highLimit the high limit used by the wavefolder
@note highLimit MUST be higher than lowLimit
*/
void setLimits(T lowLimit, T highLimit)
{
hl = highLimit;
ll = lowLimit;
R = hl-ll;
Ri = NUMERATOR / (hl-ll); // calculated here to speed up next()
}
/** Return the next folded sample
@param in is the signal input.
@return the folded output.
*/
T next(T in)
{
if (in > hl)
{
typename IntegerType<sizeof(T)>::unsigned_type sub = in-hl;
/* Instead of using a division, we multiply by the inverse.
As the inverse is necessary smaller than 1, in order to fit in an integer
we multiply it by NUMERATOR before computing the inverse.
The shift is equivalent to divide by the NUMERATOR:
q = sub / R = (sub * (NUMERATOR/R))/NUMERATOR with NUMERATOR/R = Ri
*/
typename IntegerType<sizeof(T)>::unsigned_type q = ((typename IntegerType<sizeof(T)+sizeof(T)>::unsigned_type) sub*Ri) >> SHIFT;
typename IntegerType<sizeof(T)>::unsigned_type r = sub - q*R; // remainer
if (q&0b1) return ll+r; //odd
else return hl-r; // even
}
else if (in < ll)
{
typename IntegerType<sizeof(T)>::unsigned_type sub = ll-in;
typename IntegerType<sizeof(T)>::unsigned_type q = ((typename IntegerType<sizeof(T)+sizeof(T)>::unsigned_type) sub*Ri) >> SHIFT;
typename IntegerType<sizeof(T)>::unsigned_type r = sub - q*R; // remainer
if (q&0b1) return hl-r;
else return ll+r;
}
else return in;
}
private:
T hl;
T ll;
typename IntegerType<sizeof(T)>::unsigned_type R;
typename IntegerType<sizeof(T)>::unsigned_type Ri;
static const uint8_t SHIFT = (sizeof(T) << 3);
static const typename IntegerType<sizeof(T)>::unsigned_type NUMERATOR = ((typename IntegerType<sizeof(T)+sizeof(T)>::unsigned_type) 1<<(SHIFT))-1;
// Slower (way slower, around 2.5 times) but more precise, kept in case we want to switch one day.
/* typename IntegerType<sizeof(T)+sizeof(T)>::unsigned_type Ri;
static const uint8_t SHIFT = 1+(sizeof(T) << 3);
static const typename IntegerType<sizeof(T)+sizeof(T)>::unsigned_type NUMERATOR = ((typename IntegerType<sizeof(T)+sizeof(T)>::unsigned_type) 1<<(SHIFT))-1;*/
};
#endif