Etterna 0.74.4
Loading...
Searching...
No Matches
TrillSequencing.h
1#pragma once
2
3#include "../../Dependent/HD_BasicSequencing.h"
4#include "../../CalcWindow.h"
5#include <cassert>
6
8{
9 // trill scenarios
10 enum trillnario
11 {
12 the_lack_thereof, // empty state
13 need_opposite,
14 };
15
16 // for the trill to continue, the next note must be on the opposite hand
17 hands current_hand = left_hand;
18 // for the trill to continue, the left hand notes must be on this column
19 // allow for ohj
20 col_type left_hand_state = col_init;
21 // for the trill to continue, the right hand notes must be on this column
22 // allow for ohj
23 col_type right_hand_state = col_init;
24
25 trillnario current_scenario = the_lack_thereof;
26
28 int cur_length = 0;
29 int jump_count = 0;
30
32 int trills_in_interval = 0;
33 int total_taps = 0;
34
35 // trill ms cv greater than this is rejected
36 float cv_threshold = 0.5F;
37
38 unsigned last_notes = 0b0000;
39 unsigned last_last_notes = 0b0000;
40
41 // true if is a hand or two hand jump
42 bool two_hand_jump(const unsigned& notes) {
43 return ((notes & 0b1100) != 0U) && ((notes & 0b0011) != 0U);
44 }
45
46 // drive the sequencer
47 void process(const float& ms_now, const unsigned& notes) {
48
49 hands notes_hand;
50 col_type notes_coltype;
51 const unsigned prev_notes = last_notes;
52 const unsigned prev_prev_notes = last_last_notes;
53 last_last_notes = last_notes;
54 last_notes = notes;
55
56 if (two_hand_jump(notes)) {
57 if (two_hand_jump(prev_notes)) {
58 // absolutely not
59 dead_trill();
60 return;
61 }
62 if (two_hand_jump(prev_prev_notes)) {
63 // basically not a two hand trill
64 dead_trill();
65 return;
66 }
67
68 if ((notes & 0b1111) == 0b1111) {
69 // quad
70 dead_trill();
71 return;
72 } else if ((notes & 0b1100) == 0b1100) {
73 // jump on left
74 //notes_coltype = determine_col_type(notes, 0b0011);
75 notes_hand = left_hand;
76 notes_coltype = col_ohjump;
77 } else if ((notes & 0b0011) == 0b0011) {
78 // jump on right
79 //notes_coltype = determine_col_type(notes, 0b1100);
80 notes_hand = right_hand;
81 notes_coltype = col_ohjump;
82 } else {
83 // actual two hand jump
84 if (((notes & prev_prev_notes) != 0U) && ((notes & prev_notes) == 0U)) {
85 // a jack separated by a note
86 // current row doesnt form a jack with previous row
87 // (23[24])
88 // find the jack column and hand
89 const unsigned ppn = notes & prev_prev_notes;
90 if ((ppn & 0b1100) != 0U) {
91 notes_hand = left_hand;
92 notes_coltype = determine_col_type(notes, 0b1100);
93 } else if ((ppn & 0b0011) != 0U) {
94 notes_hand = right_hand;
95 notes_coltype = determine_col_type(notes, 0b0011);
96 } else {
97 // preposterous
98 dead_trill();
99 return;
100 }
101 } else {
102 // what (232[24])
103 dead_trill();
104 return;
105 }
106 }
107
108 } else if ((notes & 0b1100) != 0) {
109 notes_hand = left_hand;
110 notes_coltype = determine_col_type(notes, 0b1100);
111 } else if ((notes & 0b0011) != 0) {
112 notes_hand = right_hand;
113 notes_coltype = determine_col_type(notes, 0b0011);
114 } else {
115 // there is a lack of taps.
116 // this typically doesnt happen
117 reset();
118 return;
119 }
120
121 switch (current_scenario) {
122 case the_lack_thereof: {
123 // begin a trill anywhere
124 current_hand = notes_hand;
125 set_hand_states(notes_coltype);
126 current_scenario = need_opposite;
127 break;
128 }
129 case need_opposite: {
130 if (current_hand == notes_hand) {
131 // trill broken
132 dead_trill();
133 } else {
134 if (notes_coltype == col_ohjump) {
135 jump_count++;
136 }
137 if (current_hand == left_hand) {
138 if (right_hand_state == col_init ||
139 right_hand_state == notes_coltype) {
140 right_hand_state = notes_coltype;
141 calc_trill(ms_now);
142 cur_length++;
143 total_taps++;
144 } else {
145 // trill broken
146 dead_trill();
147 right_hand_state = notes_coltype;
148 current_scenario = need_opposite;
149 }
150 } else {
151 if (left_hand_state == col_init ||
152 left_hand_state == notes_coltype) {
153 left_hand_state = notes_coltype;
154 calc_trill(ms_now);
155 cur_length++;
156 total_taps++;
157 } else {
158 // trill broken
159 dead_trill();
160 left_hand_state = notes_coltype;
161 current_scenario = need_opposite;
162 }
163 }
164 }
165 break;
166 }
167 default:
168 assert(0);
169 }
170 }
171
172 void set_hand_states(col_type coltype)
173 {
174 if (current_hand == left_hand) {
175 left_hand_state = coltype;
176 } else {
177 right_hand_state = coltype;
178 }
179 }
180
181 bool calc_trill(const float& ms_now)
182 {
183 const int window = std::min(cur_length, max_moving_window_size);
184 trill_ms(ms_now);
185 // float cv = trill_ms.get_cv_of_window(window);
186 // for high cv, this may be a flam
187 return true;
188 //return cv < cv_threshold;
189 }
190
191 void reset() {
192 trills_in_interval = 0;
193 total_taps = 0;
194 cur_length = 0;
195 trill_ms.zero();
196 current_scenario = the_lack_thereof;
197 left_hand_state = col_init;
198 right_hand_state = col_init;
199 last_notes = 0b0000;
200 last_last_notes = 0b0000;
201 }
202
203 void dead_trill() {
204 cur_length = 0;
205 trill_ms.zero();
206 current_scenario = the_lack_thereof;
207 left_hand_state = col_init;
208 right_hand_state = col_init;
209 last_notes = 0b0000;
210 last_last_notes = 0b0000;
211 }
212};
213
214
217{
218 twohandtrill trill;
219
220 const int _tap_size = 1;
221 const int _jump_size = 2;
222
223 float trill_buffer = 0.F;
224 float trill_scaler = 1.F;
225 float jump_buffer = 0.F;
226 float jump_scaler = 1.F;
227 float jump_weight = 0.5F;
228
229 float min_val = 0.F;
230 float max_val = 1.5F;
231
232 void set_params(const float& cv,
233 const float& tbuffer,
234 const float& tscaler,
235 const float& jbuffer,
236 const float& jscaler,
237 const float& jweight,
238 const float& min,
239 const float& max)
240 {
241 trill.cv_threshold = cv;
242 trill_buffer = tbuffer;
243 trill_scaler = tscaler;
244 jump_buffer = jbuffer;
245 jump_scaler = jscaler;
246 jump_weight = jweight;
247 min_val = min;
248 max_val = max;
249 }
250
251 // advance sequencing
252 void operator()(const float& ms_now, const unsigned& notes)
253 {
254 trill.process(ms_now, notes);
255 }
256
257 void reset() {
258 trill.reset();
259 }
260
262 float get(const metaItvInfo& mitvi) {
263 const float trill_taps = static_cast<float>(trill.total_taps);
264 const float trill_jumps = static_cast<float>(trill.jump_count);
265 const auto& itvi = mitvi._itvi;
266 const float taps = static_cast<float>(itvi.total_taps);
267
268 if (taps == 0.F) {
269 return 0.F;
270 }
271
272 const float jumps = static_cast<float>(itvi.taps_by_size.at(_jump_size));
273
274 float trill_proportion = (trill_taps + trill_buffer) /
275 std::max(taps - trill_buffer, 1.F) *
276 trill_scaler;
277
278 float jump_proportion = (jumps - trill_jumps + jump_buffer) /
279 std::max(taps - jump_buffer, 1.F) * jump_scaler;
280
281 // jump_weight = 0 will make it all jump_proportion
282 float prop = weighted_average(trill_proportion,
283 jump_proportion,
284 std::clamp(1 - jump_weight, 0.F, 1.F),
285 1.F);
286
287 return std::clamp(prop, min_val, max_val);
288 }
289};
Definition CalcWindow.h:15
void zero()
set everything to zero
Definition CalcWindow.h:210
Two Hand Trill Sequencing.
Definition TrillSequencing.h:217
float get(const metaItvInfo &mitvi)
numerical output (kind of like a proportion. 1 is "all trills")
Definition TrillSequencing.h:262
Definition MetaIntervalInfo.h:20
Definition TrillSequencing.h:8
int cur_length
a trill length 1 is 2 notes long and has "completed"
Definition TrillSequencing.h:28