Etterna 0.74.4
Loading...
Searching...
No Matches
WideRangeRoll.h
1#pragma once
2#include "../IntervalHandInfo.h"
3
9{
10 const CalcPatternMod _pmod = WideRangeRoll;
11 const std::string name = "WideRangeRollMod";
12
13#pragma region params
14
15 float window_param = 5.F;
16
17 float min_mod = 0.25F;
18 float max_mod = 1.F;
19 float base = 0.15F;
20 float scaler = 0.9F;
21
22 float cv_reset = 1.F;
23 float cv_threshold = 0.35F;
24 float other_cv_threshold = 0.3F;
25
26 const std::vector<std::pair<std::string, float*>> _params{
27 { "window_param", &window_param },
28
29 { "min_mod", &min_mod },
30 { "max_mod", &max_mod },
31 { "base", &base },
32 { "scaler", &scaler },
33
34 { "cv_reset", &cv_reset },
35 { "cv_threshold", &cv_threshold },
36 { "other_cv_threshold", &other_cv_threshold },
37 };
38#pragma endregion params and param map
39
40 int window = 0;
41
42 // moving window of longest roll sequences seen in the interval
44
45 // we want to keep custom adjusted ms values here
46 CalcMovingWindow<float> _mw_adj_ms;
47
48 bool last_passed_check = false;
49 int nah_this_file_aint_for_real = 0;
50 int max_thingy = 0;
51 float hi_im_a_float = 0.F;
52
53 // WE CAN JUST MOVE THE TIMING CHECK FUNCTIONS INTO CALCWINDOW LUL
54 std::vector<float> idk_ms = { 0.F, 0.F, 0.F, 0.F };
55 std::vector<float> seq_ms = { 0.F, 0.F, 0.F };
56
57 float moving_cv = cv_reset;
58 float pmod = min_mod;
59
60#pragma region generic functions
61
62 void full_reset()
63 {
64 _mw_max.zero();
65 _mw_adj_ms.zero();
66
67 last_passed_check = false;
68 nah_this_file_aint_for_real = 0;
69 max_thingy = 0;
70 hi_im_a_float = 0.F;
71
72 for (auto& v : seq_ms) {
73 v = 0.F;
74 }
75 for (auto& v : idk_ms) {
76 v = 0.F;
77 }
78
79 moving_cv = cv_reset;
80 pmod = neutral;
81 }
82
83 void setup()
84 {
85 window =
86 std::clamp(static_cast<int>(window_param), 1, max_moving_window_size);
87 }
88
89#pragma endregion
90
91 void zoop_the_woop(const int& pos,
92 const float& div,
93 const float& scaler = 1.F)
94 {
95 seq_ms[pos] /= div;
96 last_passed_check = do_timing_thing(scaler);
97 seq_ms[pos] *= div;
98 }
99
100 void woop_the_zoop(const int& pos,
101 const float& mult,
102 const float& scaler = 1.F)
103 {
104 seq_ms[pos] *= mult;
105 last_passed_check = do_timing_thing(scaler);
106 seq_ms[pos] /= mult;
107 }
108
109 auto do_timing_thing(const float& scaler) -> bool
110 {
111 _mw_adj_ms(seq_ms[1]);
112
113 if (_mw_adj_ms.get_cv_of_window(window) > other_cv_threshold) {
114 return false;
115 }
116
117 hi_im_a_float = cv(seq_ms);
118
119 // ok we're pretty sure it's a roll don't bother with the test
120 if (hi_im_a_float < 0.12F) {
121 moving_cv = (hi_im_a_float + moving_cv + hi_im_a_float) / 3.F;
122 return true;
123 }
124 {
125 moving_cv = (hi_im_a_float + moving_cv) / 2.F;
126 }
127
128 return moving_cv < cv_threshold / scaler;
129 }
130
131 auto do_other_timing_thing(const float& scaler) -> bool
132 {
133 _mw_adj_ms(idk_ms[1]);
134 _mw_adj_ms(idk_ms[2]);
135
136 if (_mw_adj_ms.get_cv_of_window(window) > other_cv_threshold) {
137 return false;
138 }
139
140 hi_im_a_float = cv(idk_ms);
141
142 // ok we're pretty sure it's a roll don't bother with the test
143 if (hi_im_a_float < 0.12F) {
144 moving_cv = (hi_im_a_float + moving_cv + hi_im_a_float) / 3.F;
145 return true;
146 }
147 {
148 moving_cv = (hi_im_a_float + moving_cv) / 2.F;
149 }
150
151 return moving_cv < cv_threshold / scaler;
152 }
153
154 void handle_ccacc_timing_check() { zoop_the_woop(1, 2.5F, 1.25F); }
155
156 void handle_roll_timing_check()
157 {
158 if (any_ms_is_greater(seq_ms[1], seq_ms[0])) {
159 zoop_the_woop(1, 2.5F);
160 } else {
161 seq_ms[0] /= 2.5F;
162 seq_ms[2] /= 2.5F;
163 last_passed_check = do_timing_thing(1.F);
164 seq_ms[0] *= 2.5F;
165 seq_ms[2] *= 2.5F;
166 }
167 }
168
169 void handle_ccsjjscc_timing_check(const float& now)
170 {
171 // translate over the values
172 idk_ms[2] = seq_ms[0];
173 idk_ms[1] = seq_ms[1];
174 idk_ms[0] = seq_ms[2];
175
176 // add the new value
177 idk_ms[3] = now;
178
179 // run 2 tests so we can keep a stricter cutoff
180 // need to put cv in array thingy mcboop
181 // check 1
182 idk_ms[1] /= 2.5F;
183 idk_ms[2] /= 2.5F;
184
185 do_other_timing_thing(1.25F);
186
187 idk_ms[1] *= 2.5F;
188 idk_ms[2] *= 2.5F;
189
190 if (last_passed_check) {
191 return;
192 }
193
194 // test again
195 idk_ms[1] /= 3.F;
196 idk_ms[2] /= 3.F;
197
198 do_other_timing_thing(1.25F);
199
200 idk_ms[1] *= 3.F;
201 idk_ms[2] *= 3.F;
202 }
203
204 void complete_seq()
205 {
206 if (nah_this_file_aint_for_real > 0) {
207 max_thingy = nah_this_file_aint_for_real > max_thingy
208 ? nah_this_file_aint_for_real
209 : max_thingy;
210 }
211 nah_this_file_aint_for_real = 0;
212 }
213
214 void bibblybop(const meta_type& _last_mt)
215 {
216 // see below
217 if (_last_mt == meta_enigma) {
218 moving_cv = (moving_cv + hi_im_a_float) / 2.F;
219 } else if (_last_mt == meta_meta_enigma) {
220 moving_cv = (moving_cv + hi_im_a_float + hi_im_a_float) / 3.F;
221 }
222
223 if (!last_passed_check) {
224 complete_seq();
225 return;
226 }
227
228 ++nah_this_file_aint_for_real;
229
230 // if we are here and mt.last == meta enigma, we skipped 1 note
231 // before we identified a jumptrillable roll continuation, if meta
232 // meta enigma, 2
233
234 // borp it
235 if (_last_mt == meta_enigma) {
236 ++nah_this_file_aint_for_real;
237 }
238
239 // same but even more-er
240 if (_last_mt == meta_meta_enigma) {
241 nah_this_file_aint_for_real += 2;
242 }
243 }
244
245 void advance_sequencing(const base_type& bt,
246 const meta_type& mt,
247 const meta_type& _last_mt,
248 const float& any_ms,
249 const float& tc_ms)
250 {
251 // we will let ohjumps through here
252
253 update_seq_ms(bt, any_ms, tc_ms);
254 if (bt == base_single_jump || bt == base_jump_single) {
255 return;
256 }
257
258 if (bt == base_jump_jump) {
259 // its an actual jumpjack/jumptrill, don't bother with timing checks
260 // disable for now
261 if (nah_this_file_aint_for_real > 0) {
262 bibblybop(_last_mt);
263 }
264 return;
265 }
266
267 // look for stuff thats jumptrillyable.. if that stuff... then leads
268 // into more stuff.. that is jumptrillyable... then .... badonk it
269 switch (mt) {
270 case meta_acca:
271 // unlike wrjt we want to complete and reset on these
272 complete_seq();
273 break;
274 case meta_cccccc:
275 handle_roll_timing_check();
276 bibblybop(_last_mt);
277 break;
278 case meta_ccacc:
279 handle_ccacc_timing_check();
280 bibblybop(_last_mt);
281 break;
282 case meta_ccsjjscc:
283 case meta_ccsjjscc_inverted:
284 handle_ccsjjscc_timing_check(any_ms);
285 bibblybop(_last_mt);
286 break;
287 case meta_type_init:
288 case meta_enigma:
289 // this could yet be something we are interested in, but we
290 // don't know yet, so just wait and see
291 break;
292 case meta_meta_enigma:
293 case meta_unknowable_enigma:
294 // it's been too long... your vision becomes blurry.. your
295 // memory fades... why are we here again? what are we trying
296 // to do? who are we....
297 complete_seq();
298 break;
299 default:
300 assert(0);
301 break;
302 }
303 }
304
305 void update_seq_ms(const base_type& bt,
306 const float& any_ms,
307 const float& tc_ms)
308 {
309 seq_ms[0] = seq_ms[1]; // last_last
310 seq_ms[1] = seq_ms[2]; // last
311
312 // update now
313 // for anchors, track tc_ms
314 if (bt == base_single_single) {
315 seq_ms[2] = tc_ms;
316 // for base_left_right or base_right_left, track cc_ms
317 } else {
318 seq_ms[2] = any_ms;
319 }
320 }
321
322 void set_pmod(const ItvHandInfo& itvhi)
323 {
324 // check taps for _this_ interval, if there's none, and there was a
325 // powerful roll mod before, the roll mod will extend into the empty
326 // interval at minimum value due to 0/n, and then the smoother will push
327 // that push that into the adjecant intervals
328 // then check for the window values, perhaps we should also neutral set
329 // if a large sequence has just ended on this interval, but that may
330 // change too much and the tuning is already looking good anyway
331 if (itvhi.get_taps_nowi() == 0 || itvhi.get_taps_windowi(window) == 0 ||
332 _mw_max.get_total_for_window(window) == 0) {
333 pmod = neutral;
334 return;
335 }
336
337 // really uncertain about the using the total of _mw_max here, but
338 // that's what it was, so i'll keep it for now
339 const float zomg = itvhi.get_taps_windowf(window) /
340 _mw_max.get_total_for_windowf(window);
341
342 pmod *= zomg;
343 pmod = std::clamp(base + fastsqrt(pmod), min_mod, max_mod);
344 }
345
346 auto operator()(const ItvHandInfo& itvhi) -> float
347 {
348 max_thingy = nah_this_file_aint_for_real > max_thingy
349 ? nah_this_file_aint_for_real
350 : max_thingy;
351
352 _mw_max(max_thingy);
353
354 set_pmod(itvhi);
355
356 interval_end();
357 return pmod;
358 }
359
360 void interval_end() { max_thingy = 0; }
361};
Definition CalcWindow.h:15
void zero()
set everything to zero
Definition CalcWindow.h:210
auto get_total_for_windowf(const int &window) const -> float
Definition CalcWindow.h:100
auto get_total_for_window(const int &window) const -> T
get the sum for the moving window up to a given size
Definition CalcWindow.h:46
auto get_cv_of_window(const int &window) const -> float
get the coefficient of variance of the moving window up to a given size
Definition CalcWindow.h:113
accumulates hand specific info across an interval as it's processed by row
Definition IntervalHandInfo.h:6
auto get_taps_nowi() const -> int
access functions for hand tap counts
Definition IntervalHandInfo.h:135
auto get_taps_windowf(const int &window) const -> float
cast to float for divisioning and clean screen
Definition IntervalHandInfo.h:153
Definition WideRangeRoll.h:9