-
Notifications
You must be signed in to change notification settings - Fork 0
/
VFloatArray.h
190 lines (171 loc) · 5.24 KB
/
VFloatArray.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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#pragma once
#include "VModulator.h"
// Class FloatArray updates an array of smoothly (linearly)
// modulating float parameters. To avoid dynamic allocation,
// make a template for different size arrays. When the destination
// values are reached, set the FloatArray inactive.
//
// This class should look almost exactly like FloatParam.
//
template<int Size, class RcvrType>
class FloatArray : public VModulatorOld<float*, RcvrType>
{
// modulation parameters, like FloatParam, with arrays
private:
float dstVals[Size];
long dstSamp;
float slopes[Size];
VHandler* pparent;
// for returning an array without dynamic allocation
float currVals[Size];
public:
FloatArray();
FloatArray(float* init);
typedef void (RcvrType::*UpdtFn)(float*); //;;;; bielefeld
FloatArray(RcvrType* r, UpdtFn f) :
VModulatorOld<float*, RcvrType>(r, f),
dstSamp(0),
pparent(nullptr)
{
ZeroFloats(dstVals, Size);
ZeroFloats(slopes, Size);
VActor::setTypeName("FloatArray");
VActor::setActive(0);
}
FloatArray(RcvrType*, UpdtFn, float* init);
~FloatArray() {}
// Initiate modulation, or (if modTime==0) set the value instantaneously.
void set(float* newVals, int numVals = Size, float modTime = 0.);
void setIth(int i, float newVal, float modTime);
// "this" is uninitialized with some compilers,
// when used by the initalization list of a handler's constructor.
// So we have to call init() in the constructor, after
// initializing the rest of the object as a line in the
// aforementioned initalization list of a handler's constructor.
void init(VHandler* p) { pparent = p; }
virtual float* currentValue();
};
template<int Size, class RcvrType>
FloatArray<Size, RcvrType>::FloatArray():
VModulatorOld<float*, RcvrType>(),
dstSamp(0),
pparent(nullptr)
{
ZeroFloats(dstVals, Size);
ZeroFloats(slopes, Size);
VActor::setTypeName("FloatArray");
VActor::setActive(0);
}
template<int Size, class RcvrType>
FloatArray<Size, RcvrType>::FloatArray(float* init):
VModulatorOld<float*, RcvrType>(),
dstSamp(0),
pparent(nullptr)
{
FloatCopy(dstVals, init, Size);
ZeroFloats(slopes, Size);
VActor::setTypeName("FloatArray");
}
template<int Size, class RcvrType>
FloatArray<Size, RcvrType>::FloatArray(RcvrType* r, UpdtFn f, float* init):
VModulatorOld<float*, RcvrType>(r, f),
dstSamp(0),
pparent(NULL)
{
FloatCopy(dstVals, init, Size);
ZeroFloats(slopes, Size);
// Send the initial values.
const auto rx = VModulatorOld<float*, RcvrType>::receiver;
if (rx) (rx->*VModulatorOld<float*, RcvrType>::updateFn)(dstVals);
VActor::setTypeName("FloatArray");
VActor::setActive(0);
}
// Compute the current values of the modulation from the
// currentSample number, the destination sample number,
// and the slopes.
template<int Size, class RcvrType>
float* FloatArray<Size, RcvrType>::currentValue()
{
// Update the activity status.
VActor::setActive(dstSamp - SamplesToDate() > 0);
if (!VActor::isActive())
return dstVals;
for (auto i = 0; i < Size; ++i)
currVals[i] = dstVals[i] - ((float)(dstSamp - SamplesToDate()) * slopes[i]);
return currVals;
}
// Start modulating to new values.
template<int Size, class RcvrType>
void FloatArray<Size, RcvrType>::set(float* newVals, int numVals, float modTime)
{
if (numVals < 0)
{
fprintf(stderr, "FloatArray warning: negative # of values\n");
return;
}
if (numVals > Size)
{
fprintf(stderr,
"FloatArray warning: ignoring extra values %d beyond %d\n",
numVals, Size);
numVals = Size;
}
if (modTime <= 0. || (pparent && pparent->getPause()))
{
// set the new values immediately
ZeroFloats(slopes, numVals);
FloatCopy(dstVals, newVals, numVals);
dstSamp = SamplesToDate();
VActor::setActive( false );
const auto rx = VModulatorOld<float*, RcvrType>::receiver;
if (rx) (rx->*VModulatorOld<float *, RcvrType>::updateFn)(dstVals);
}
else
{
// modulate over modTime
const auto modSamps = modTime * globs.SampleRate;
const auto curr = currentValue();
for (int i = 0; i < numVals; i++)
{
slopes[i] = (newVals[i] - curr[i]) / modSamps;
dstVals[i] = newVals[i];
}
dstSamp = SamplesToDate() + modSamps + 0.5;
VActor::setActive( true );
}
}
// Modulate only ONE value.
template<int Size, class RcvrType>
void FloatArray<Size, RcvrType>::setIth(int i, float newVal, float modTime)
{
if (i<0 || i >= Size)
{
fprintf(stderr, "FloatArray error: setting i'th value out of bounds (%d beyond %d)\n", i, Size);
return;
}
if (modTime <= 0. || (pparent && pparent->getPause()))
{
// set the new values immediately
slopes[i] = 0.;
dstVals[i] = newVal;
// Don't do the next two lines: OTHER values may be sloping slowly.
// dstSamp = SamplesToDate();
// setActive( false );
const auto rx = VModulatorOld<float*, RcvrType>::receiver;
if (rx) (rx->*VModulatorOld<float *, RcvrType>::updateFn)(dstVals);
//;; I hope the other dstVals[] are still valid!
}
else
{
// modulate over modTime
const auto modSamps = modTime * globs.SampleRate;
const auto curr = currentValue();
slopes[i] = (newVal - curr[i]) / modSamps;
dstVals[i] = newVal;
// BUG: other values will now slope at the same rate as this one.
// In general, this may cause bugs if you overlap calls to setIth
// for several different values.
dstSamp = SamplesToDate() + modSamps + 0.5;
VActor::setActive( true );
}
}