Etterna 0.74.4
Loading...
Searching...
No Matches
MetaIntervalGenericHandInfo.h
1#pragma once
2#include <bit>
3
4enum generic_base_type
5{
6 gbase_hard_trill, // '12' in 6k (ring-middle or pinky-ring)
7 gbase_easy_trill, // '23' in 6k (index-middle or opposite fingers of hand)
8 gbase_single_single, // jack on any column alone
9 gbase_single_chord_jack, // single into a chord forming a jack
10 gbase_single_chord_trill, // single into a chord forming a trill
11 gbase_chord_chord_jack, // 2 chords forming a jack
12 gbase_chord_chord_trill, // 2 chords forming no jack
13 gbase_chord_weird, // 2 chords with a jack and a trill
14 num_gbase_types,
15 gbase_type_init,
16};
17
18// return the mask of notes that would be hard to hit
19// given the notes that were just hit
20inline auto
21hard_trill_mask(const unsigned& last_notes, const unsigned& hand_mask)
22 -> unsigned
23{
24 const auto keycount_on_hand = std::popcount(hand_mask);
25 const auto is_left_hand = (hand_mask & 0b1) > 0u;
26 auto result_mask = 0b0;
27 if (keycount_on_hand <= 2 || keycount_on_hand > 5) {
28 // for 2 columns on this hand, it's always "easy"
29 // and for more than 5... dont care
30 return result_mask;
31 }
32
33 // 3 columns: (6k 212 or 565 is hard)
34 // for 3 columns on left hand (binary is reversed)
35 // 010 returns 001
36 // 001 returns 010 ..
37 // 3 columns on other hand:
38 // 100 returns 010
39 // 010 returns 100
40 if (keycount_on_hand == 3u) {
41 result_mask = is_left_hand ? 0b011 : 0b110;
42 }
43
44 // 4 columns: (8k 232 or 565 is hard)
45 // 0100 returns 0010
46 // 0010 returns 0100
47 else if (keycount_on_hand == 4u) {
48 result_mask = 0b0110;
49 }
50
51 // 5 columns: (10k 232 or 898 is hard)
52 // 01000 returns 00100
53 // 00100 returns 01000
54 // opposite hand
55 // 00010 returns 00100
56 // 00100 returns 00010
57 else {
58 result_mask = is_left_hand ? 0b01100 : 0b00110;
59 }
60
61 if ((result_mask & last_notes) > 0u) {
62 return result_mask & ~last_notes;
63 } else {
64 return 0b0;
65 }
66}
67
68inline auto
69determine_generic_base_pattern_type(const unsigned& notes_now,
70 const unsigned& last_notes,
71 const unsigned& hand_mask)
72 -> generic_base_type
73{
74 if (last_notes == 0u || notes_now == 0u) {
75 return gbase_type_init;
76 }
77
78 const bool now_single = is_only_1_bit(notes_now);
79 const bool last_single = is_only_1_bit(last_notes);
80 const bool has_jack = (notes_now & last_notes) > 0u;
81
82 if (now_single && last_single) {
83 if (has_jack) {
84 return gbase_single_single;
85 }
86 if ((notes_now & hard_trill_mask(last_notes, hand_mask)) > 0u) {
87 return gbase_hard_trill;
88 }
89 return gbase_easy_trill;
90 }
91
92 // only one single
93 if (now_single || last_single) {
94 if (has_jack) {
95 return gbase_single_chord_jack;
96 } else {
97 return gbase_single_chord_trill;
98 }
99 }
100
101 // at this point only consecutive chords are possible
102 if (has_jack) {
103 const bool has_trill = (notes_now ^ last_notes) > 0u;
104 if (has_trill) {
105 // a one handed anchored jack with a trill
106 // [12][13]...
107 return gbase_chord_weird;
108 } else {
109 return gbase_chord_chord_jack;
110 }
111 } else {
112 return gbase_chord_chord_trill;
113 }
114}
115
116inline auto
117is_bracket(const unsigned& notes_row,
118 const unsigned& last_notes,
119 const unsigned& lastlast_notes) -> bool
120{
121 // firstsec and secthird rows must form some trill
122 // firstthird rows must "jack" if put next to each other
123 return (notes_row ^ last_notes) > 0 && (last_notes ^ lastlast_notes) > 0 &&
124 (notes_row & lastlast_notes) > 0;
125}
126
127inline auto
128basetype_stops_bracket(const generic_base_type& bt)
129{
130 switch(bt) {
131 case gbase_single_single:
132 case gbase_chord_chord_jack:
133 case gbase_single_chord_jack:
134 case gbase_easy_trill:
135 case gbase_chord_weird:
136 return true;
137 default:
138 return false;
139 }
140}
141
145{
146 unsigned lastlast_row = 0u;
147 unsigned last_row = 0u;
148 generic_base_type last_type = gbase_type_init;
149
150 int total_taps = 0;
151 int chord_taps = 0;
152
153 // total number of taps involved in a bracket
154 // classically, a bracket is something like [13]2[13]2
155 // a chord trilling into something that splits it
156 int taps_bracketing = 0;
157 bool bracketing = false;
158
161 {
162 _base_types.fill(0);
163 taps_by_size.fill(0);
164 total_taps = 0;
165 chord_taps = 0;
166 taps_bracketing = 0;
167 bracketing = false;
168 last_type = gbase_type_init;
169 }
170
173 void zero()
174 {
175 _base_types.fill(0);
176 taps_by_size.fill(0);
177 total_taps = 0;
178 chord_taps = 0;
179 taps_bracketing = 0;
180 bracketing = false;
181 last_type = gbase_type_init;
182 }
183
184 void handle_row(const unsigned& new_row, const unsigned& hand_mask){
185 auto pattern_type = determine_generic_base_pattern_type(
186 new_row, last_row, hand_mask);
187
188 const auto taps_in_row = std::popcount(new_row);
189 total_taps += taps_in_row;
190 if (taps_in_row > 1) {
191 chord_taps += taps_in_row;
192 }
193
194 if (pattern_type >= num_gbase_types) {
195 lastlast_row = last_row;
196 last_row = new_row;
197 return;
198 }
199
200 // stop the bracketing
201 if (basetype_stops_bracket(pattern_type)) {
202 bracketing = false;
203 }
204
205 // we might be able to start bracketing
206 else if (!basetype_stops_bracket(last_type)) {
207 if (is_bracket(new_row, last_row, lastlast_row)) {
208 if (bracketing) {
209 taps_bracketing += taps_in_row;
210 } else {
211 bracketing = true;
212 taps_bracketing += taps_in_row + std::popcount(last_row) +
213 std::popcount(lastlast_row);
214 }
215 }
216 }
217
218 lastlast_row = last_row;
219 last_row = new_row;
220 last_type = pattern_type;
221 _base_types[pattern_type]++;
222 taps_by_size[taps_in_row - 1] += taps_in_row;
223 }
224
225 int possible_brackets() const
226 {
227 return _base_types[gbase_hard_trill] +
228 _base_types[gbase_single_chord_trill] +
229 _base_types[gbase_chord_chord_trill];
230 }
231
232 std::array<int, num_gbase_types> _base_types = { 0, 0, 0, 0, 0, 0, 0, 0 };
233 std::array<int, num_tap_size> taps_by_size = { 0, 0, 0, 0, 0, 0, 0, 0,
234 0, 0, 0, 0, 0, 0, 0, 0 };
235
236};
237
Definition MetaIntervalGenericHandInfo.h:145
void interval_end()
handle end of interval
Definition MetaIntervalGenericHandInfo.h:160
void zero()
Definition MetaIntervalGenericHandInfo.h:173