Plaquette
 
Loading...
Searching...
No Matches
TimeSliceField.h
1/*
2 * TimeSliceField.h
3 *
4 * (c) 2025 Sofian Audry :: info(@)sofianaudry(.)com
5 * (c) 2018 Thomas O Fredericks :: tof(@)t-o-f(.)info
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20#ifndef TIME_FIELD_H_
21#define TIME_FIELD_H_
22
23#include "AbstractField.h"
24
25namespace pq {
26
31template <size_t COUNT>
33{
34public:
39 TimeSliceField(float period) : _period(period), _full(false), _rolling(false), _changed(false) {
40 reset();
41 }
42 virtual ~TimeSliceField() {}
43
49 virtual float at(float proportion) override {
50 // Special case: proportion == 1 -> return last value.
51 if (proportion >= 1)
52 return _buffer[_trueIndex(LAST_INDEX)];
53
54 // Find index as a floating point value in [0, COUNT-1).
55 float indexFloat = max(proportion, 0) * LAST_INDEX;
56
57 // Find previous index and linear interpolation (lerp) factor.
58 size_t prevIndex = floor(indexFloat); // index in [0, COUNT-1) ie. [0, COUNT-2]
59 float lerpFactor = indexFloat - prevIndex; // remainder
60
61 // Update previous index if rolling.
62 prevIndex = _trueIndex(prevIndex);
63
64 // Find next index.
65 size_t nextIndex = (prevIndex + 1) % COUNT;
66
67 // Interpolate between prev and next value in buffer.
68 return mapFrom01(lerpFactor, _buffer[prevIndex], _buffer[nextIndex]);
69 }
70
72 virtual float get() override { return _lastValue; }
73
79 virtual float put(float value) override {
80
81 // Update value.
82 _nValuesStep++;
83 _currentSumValuesStep += value;
84
85 // Save last value.
86 _lastValue = value;
87
88 return _lastValue;
89 }
90
95 void period(float period) { _period = max(period, 0.0f); }
96
98 float period() const { return _period; }
99
101 float atIndex(size_t index) { return _buffer[_trueIndex(index)]; }
102
104 size_t count() const { return COUNT; }
105
107 bool updated() { return _rolling ? _changed : _full; }
108
110 bool isFull() { return _full; }
111
113 void reset() {
114 _index = 0;
115 _previousIndex = 0;
116 _currentSumValuesStep = 0;
117 _nValuesStep = 0;
118 _full = false;
119 _changed = false;
120 }
121
126 void setRolling(bool rolling) { _rolling = rolling; }
127
129 void rolling() { setRolling(true); }
130
132 void noRolling() { setRolling(false); }
133
135 bool isRolling() const { return _rolling; }
136
138 virtual void onUpdate(EventCallback callback) { onEvent(callback, EVENT_UPDATE); }
139
140protected:
141
142 void _updateBuffer() {
143
144 // Compute value as average.
145 float value = (_nValuesStep ? _currentSumValuesStep / _nValuesStep : _lastValue);
146
147 // Fill missing data.
148 while (_previousIndex != _index) {
149 _buffer[_previousIndex] = value;
150 _previousIndex = (_previousIndex + 1) % COUNT;
151 }
152 _buffer[_index] = value; // last element
153 }
154
155 virtual void step() override {
156 // Reset if full (non-rolling).
157 if (_full && !_rolling)
158 reset();
159
160 // Save previous index.
161 size_t prevIndex = _index;
162
163 // Track if we need to update buffer.
164 bool needsUpdate = false;
165
166 // Update phase time.
167 if (phase32Update(_phase32, _period, sampleRate(), true)) {
168 // Overflow.
169 _index = LAST_INDEX;
170 _full = true;
171 needsUpdate = true;
172 }
173 else {
174 // No overflow: set index as proportion of phase.
175 _index = floor(fixed32ToFloat(_phase32) * COUNT);
176 needsUpdate = (_index < LAST_INDEX);
177 }
178
179 // Record change.
180 _changed = (_index != prevIndex);
181
182 // Upon index change: update buffer.
183 if (needsUpdate && _changed) {
184 // Update buffer.
185 _updateBuffer();
186
187 // Reset.
188 _currentSumValuesStep = 0;
189 _nValuesStep = 0;
190 }
191 }
192
194 virtual bool eventTriggered(EventType eventType) {
195 switch (eventType) {
196 case EVENT_UPDATE: return updated();
197 default: return Unit::eventTriggered(eventType);
198 }
199 }
200
201private:
202 // Internal use: return true index by adjusting it if rolling.
203 size_t _trueIndex(size_t index) {
204 // Started rolling: adjust index.
205 // _index corresponds to end position - used to perform the rolling
206 if (_full && _rolling)
207 index += _index + 1;
208
209 // Return true index (clamped).
210 return index % COUNT;
211 }
212
213protected:
214 // Internal use: precompiled last index.
215 static constexpr size_t LAST_INDEX = COUNT - 1;
216
217 // Buffer containing values.
218 float _buffer[COUNT] = {}; // initialized to zero
219
220 // Current index in buffer.
221 size_t _index;
222
223 // Previous index updated in buffer.
224 size_t _previousIndex;
225
226 // Period in seconds.
227 float _period;
228
229 // Last value recorded by put(float);
230 float _lastValue;
231
232 // Current sum of values between steps + n values (used to compute average).
233 float _currentSumValuesStep;
234 uint16_t _nValuesStep;
235
236 // Phase in [0, 1).
237 q0_32u_t _phase32;
238
239 // Flags.
240 bool _full : 1; // is the buffer full
241 bool _rolling : 1; // rolling mode
242 bool _changed : 1; // did we change index
243 uint8_t _unused : 5; // unused data
244
245};
246
247}
248#endif
Definition AbstractField.h:28
TimeSliceField generic class.
Definition TimeSliceField.h:33
virtual bool eventTriggered(EventType eventType)
Returns true iff an event of a certain type has been triggered.
Definition TimeSliceField.h:194
float period() const
Returns period.
Definition TimeSliceField.h:98
bool updated()
Returns true if the field has been updated and is ready to be used.
Definition TimeSliceField.h:107
size_t count() const
Returns count.
Definition TimeSliceField.h:104
virtual float get() override
Returns value.
Definition TimeSliceField.h:72
float atIndex(size_t index)
Returns value at given index.
Definition TimeSliceField.h:101
bool isFull()
Returns true if the field is full.
Definition TimeSliceField.h:110
virtual float at(float proportion) override
Returns value at given proportion in [0, 1].
Definition TimeSliceField.h:49
void setRolling(bool rolling)
Sets rolling mode.
Definition TimeSliceField.h:126
bool isRolling() const
Returns true if rolling mode is active.
Definition TimeSliceField.h:135
void period(float period)
Sets period over which the time slice occurs.
Definition TimeSliceField.h:95
void noRolling()
Deactivates rolling mode.
Definition TimeSliceField.h:132
TimeSliceField(float period)
Constructor.
Definition TimeSliceField.h:39
void rolling()
Activates rolling mode.
Definition TimeSliceField.h:129
virtual void onUpdate(EventCallback callback)
Registers event callback on update event.
Definition TimeSliceField.h:138
void reset()
Resets the field.
Definition TimeSliceField.h:113
virtual float put(float value) override
Pushes value into the unit.
Definition TimeSliceField.h:79
virtual void onEvent(EventCallback callback, EventType eventType)
Registers event callback.
Definition PqCore.cpp:246
virtual bool eventTriggered(EventType eventType)
Returns true iff an event of a certain type has been triggered.
Definition PqCore.h:371
float sampleRate() const
Returns engine sample rate.
Definition PqCore.h:360