Etterna 0.74.4
Loading...
Searching...
No Matches
OHT.h
1#pragma once
2#include "../IntervalHandInfo.h"
3
4/* this is complex enough it should probably have its own sequencer, there's
5 * also a fair bit of redundancy between this, wrjt, wrr. Currently this has the
6 * best component construction for the pmod so maybe the other mods should use
7 * this as a template? */
8
9static const int max_trills_per_interval = 4;
10
14{
15 const CalcPatternMod _pmod = OHTrill;
16 const std::string name = "OHTrillMod";
17
18#pragma region params
19
20 float window_param = 3.F;
21
22 float min_mod = 0.9F;
23 float max_mod = 1.F;
24 float base = 1.35F;
25 float suppression = 0.4F;
26
27 float cv_reset = 1.F;
28 float cv_threshhold = 0.5F;
29
30 const std::vector<std::pair<std::string, float*>> _params{
31 { "window_param", &window_param },
32
33 { "min_mod", &min_mod },
34 { "max_mod", &max_mod },
35 { "base", &base },
36 { "suppression", &suppression },
37
38 { "cv_reset", &cv_reset },
39 { "cv_threshhold", &cv_threshhold },
40 };
41#pragma endregion params and param map
42
43 int window = 0;
44 int cc_window = 0;
45
46 bool luca_turilli = false;
47
48 // ok new plan, ohj, wrjt and wrr are relatively well tuned so i'll try this
49 // here, handle merging multiple sequences in a single interval into one
50 // value at interval end and keep a window of that. suppose we have two
51 // intervals of 12 notes with 8 in trill formation, one has an 8 note trill
52 // and the other has two 4 note trills at the start/end, we want to punish
53 // the 8 note trill harder, this means we _will_ be resetting the
54 // consecutive trill counter every interval, but will not be resetting the
55 // trilling flag, this way we don't have to futz around with awkward
56 // proportion math, similar to thing 1 and thing 2
58 CalcMovingWindow<int> _mw_oht_taps;
59
60 std::array<int, max_trills_per_interval> foundyatrills = { 0, 0, 0, 0 };
61
62 int found_oht = 0;
63 int oht_len = 0;
64 int oht_taps = 0;
65
66 float hello_my_name_is_goat = 0.F;
67
68 float moving_cv = cv_reset;
69 float pmod = min_mod;
70
71#pragma region generic functions
72
73 void full_reset()
74 {
75 badjuju.zero();
76 _mw_oht_taps.zero();
77
78 luca_turilli = false;
79 found_oht = 0;
80 oht_len = 0;
81
82 for (auto& v : foundyatrills) {
83 v = 0;
84 }
85
86 moving_cv = cv_reset;
87 pmod = neutral;
88 }
89
90 void setup()
91 {
92 window =
93 std::clamp(static_cast<int>(window_param), 1, max_moving_window_size);
94 cc_window =
95 std::clamp(static_cast<int>(window_param), 1, max_moving_window_size);
96 }
97
98#pragma endregion
99
100 auto make_thing(const float& itv_taps) -> float
101 {
102 hello_my_name_is_goat = 0.F;
103
104 if (found_oht == 0) {
105 return 0.F;
106 }
107
108 for (auto& v : foundyatrills) {
109 if (v == 0) {
110 continue;
111 }
112
113 // water down smaller sequences
114 hello_my_name_is_goat =
115 (static_cast<float>(v) / itv_taps) - suppression;
116 }
117 return std::clamp(hello_my_name_is_goat, 0.1F, 1.F);
118 }
119
120 void complete_seq()
121 {
122 if (!luca_turilli || oht_len == 0) {
123 return;
124 }
125
126 if (found_oht < max_trills_per_interval) {
127 foundyatrills.at(found_oht) = oht_len;
128 }
129
130 luca_turilli = false;
131 oht_len = 0;
132 ++found_oht;
133 moving_cv = (moving_cv + cv_reset) / 2.F;
134 }
135
136 auto oht_timing_check(const CalcMovingWindow<float>& ms_any) -> bool
137 {
138 moving_cv = (moving_cv + ms_any.get_cv_of_window(cc_window)) / 2.F;
139 // the primary difference from wrr, just check cv on the base ms values,
140 // we are looking for values that are all close together without any
141 // manipulation
142 return moving_cv < cv_threshhold;
143 }
144
145 void wifflewaffle()
146 {
147 if (luca_turilli) {
148 ++oht_len;
149 ++oht_taps;
150 } else {
151 luca_turilli = true;
152 oht_len += 3;
153 oht_taps += 3;
154 }
155 }
156
157 void advance_sequencing(const meta_type& mt,
158 const CalcMovingWindow<float>& ms_any)
159 {
160
161 switch (mt) {
162 case meta_cccccc:
163 if (oht_timing_check(ms_any)) {
164 wifflewaffle();
165 } else {
166 complete_seq();
167 }
168 break;
169 case meta_ccacc:
170 // wait to see what happens
171 break;
172 case meta_enigma:
173 case meta_meta_enigma:
174 // also wait to see what happens, but not if last was ccacc,
175 // since we only don't complete there if we don't immediately go
176 // back into ohts
177
178 // this seems to be overkill with how lose the detection is
179 // already anyway
180
181 // if (now.last_cc == meta_ccacc) {
182 // complete_seq();
183 //}
184 // break;
185 default:
186 complete_seq();
187 break;
188 }
189 }
190
191 void set_pmod(const ItvHandInfo& itvhi)
192 {
193
194 // no taps, no trills
195 if (itvhi.get_taps_windowi(window) == 0 ||
196 _mw_oht_taps.get_total_for_window(window) == 0) {
197 pmod = neutral;
198 return;
199 }
200
201 // full oht
202 if (itvhi.get_taps_windowi(window) ==
203 _mw_oht_taps.get_total_for_window(window)) {
204 pmod = min_mod;
205 return;
206 }
207
208 badjuju(make_thing(itvhi.get_taps_nowf()));
209
210 pmod = base - badjuju.get_mean_of_window(window);
211 pmod = std::clamp(pmod, min_mod, max_mod);
212 }
213
214 auto operator()(const ItvHandInfo& itvhi) -> float
215 {
216 if (oht_len > 0 && found_oht < max_trills_per_interval) {
217 foundyatrills.at(found_oht) = oht_len;
218 ++found_oht;
219 }
220
221 _mw_oht_taps(oht_taps);
222
223 set_pmod(itvhi);
224
225 interval_end();
226 return pmod;
227 }
228
229 void interval_end()
230 {
231 foundyatrills.fill(0);
232 found_oht = 0;
233 oht_len = 0;
234 oht_taps = 0;
235 }
236};
Definition CalcWindow.h:15
void zero()
set everything to zero
Definition CalcWindow.h:210
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_mean_of_window(const int &window) const -> float
get the mean for the moving window up to a given size
Definition CalcWindow.h:85
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_nowf() const -> float
cast to float for divisioning and clean screen
Definition IntervalHandInfo.h:141
Definition OHT.h:14