-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathphasor.h
172 lines (148 loc) · 3.56 KB
/
phasor.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
#pragma once
#define MIN_SAMP 48
class Phasor
{
public:
Phasor() {}
~Phasor() {}
void Init(float sr, size_t len)
{
sr_ = sr;
len_ = end_pos_ = len;
start_pos_ = loop_pos_ = 0;
cur_pos_ = 0;
phase_incr_ = 1;
loop_ = ping_pong_ = false;
play_ = true;
}
// pitch usually in the range of 0.5 to 2.0 (-8va to +8va)
// 1 is no pitch adjustment
void SetPitch(float pitch)
{
phase_incr_ = pitch;
}
// Set a specific frequency in hertz
void SetFreq(float freq)
{
phase_incr_ = sr_ / (freq * len_);
}
// Set a duration in seconds
void SetDur(float dur)
{
phase_incr_ = len_ / (dur * sr_);
}
// All pos are in the range 0 to 1
// They will be multiplied by len_ to get actual size_t sample position
// Don't let start_pos_ go past end_pos_
void SetStartPos(float pos)
{
size_t tmp_pos;
tmp_pos = (pos < 0.0f) ? 0 : ((pos > 1.0f) ? len_ : (size_t)(pos * len_));
start_pos_ = (tmp_pos >= (end_pos_ - MIN_SAMP)) ? (end_pos_ - MIN_SAMP) : tmp_pos;
}
// Set cur_pos_ exactly
// don't need to check for < 0 as size_t is unsigned?
void SetCurPos(size_t pos)
{
cur_pos_ = (pos > len_) ? len_ : pos;
}
// Don't let end_pos_ get in front of start_pos_
// should it be end pos or length?
void SetEndPos(float pos)
{
size_t tmp_pos;
tmp_pos = (pos < 0.0f) ? 0 : ((pos > 1.0f) ? len_ : (size_t)(pos * len_));
end_pos_ = (tmp_pos <= (start_pos_ + MIN_SAMP)) ? (start_pos_ + MIN_SAMP) : tmp_pos;
}
// No checking is done here to ensure loop_pos_ is between start_pos_ and end_pos_
// The logic for this should be done in Process()
void SetLoopPos(float pos)
{
loop_pos_ = (pos < 0.0f) ? 0 : ((pos > 1.0f) ? len_ : (size_t)(pos * len_));
}
void Reset()
{
if (reverse_) {
cur_pos_ = end_pos_;
} else {
cur_pos_ = start_pos_;
}
play_ = true;
}
void SetLoop(bool l)
{
if (l != loop_) {
ToggleLoop();
}
}
void ToggleLoop()
{
loop_ = loop_ ? false : true;
play_ = true;
}
void TogglePingPong()
{
ping_pong_ = ping_pong_ ? false : true;
reverse_ = false;
play_ = true;
}
void SetReverse(bool r)
{
if (r != reverse_) {
ToggleReverse();
}
}
void ToggleReverse()
{
reverse_ = reverse_ ? false : true;
if (reverse_) {
cur_pos_ = end_pos_;
} else {
cur_pos_ = start_pos_;
}
play_ = true;
}
inline float GetPos()
{
return cur_pos_;
}
float Process(bool *eot)
{
*eot = false;
if (play_) {
if (reverse_) {
cur_pos_ -= phase_incr_;
if (cur_pos_ < start_pos_) {
*eot = true;
if (ping_pong_) {
cur_pos_ += phase_incr_;
reverse_ = false;
} else if (loop_) {
cur_pos_ += (end_pos_ - start_pos_);
} else {
play_ = false;
}
}
} else {
cur_pos_ += phase_incr_;
// is it >= or just > ?
if (cur_pos_ >= end_pos_) {
*eot = true;
if (ping_pong_) {
cur_pos_ -= phase_incr_;
reverse_ = true;
} else if (loop_) {
cur_pos_ -= (end_pos_ - start_pos_);
} else {
play_ = false;
}
}
}
}
return cur_pos_;
}
protected:
bool loop_, ping_pong_, reverse_, play_;
size_t start_pos_, end_pos_, loop_pos_, len_;
float sr_, cur_pos_, phase_incr_;
};