Etterna 0.75.1
Loading...
Searching...
No Matches
HandSwitch.h
1#pragma once
2#include "../MetaIntervalGenericHandInfo.h"
3
4// The grand comment of what HSM should do.
5/*
6 * Should be able to take advantage of hand bias to evauluate a handswitch.
7 * Should be able to consider a longjack a handswitching pattern.
8 * Should be able to consider a trill with the middle lane involved a handswitch.
9 * Should be able to consider bracket and chordstreams a handswitch depending on middle lane usage.
10 */
11
13{
14 const CalcPatternMod _pmod = HandSwitch;
15 const std::string name = "HandSwitchMod";
16
17 #pragma region params
18 float min_mod = 0.5F;
19 float max_mod = 1.5F;
20 float mod_base = 0.6F;
21
22 float decay = 1.0F;
23
24 float prop_buffer = 0.0F;
25 float prop_scaler = 0.67F;
26
27 float influence_center = 0.5F;
28 float influence_external = 0.45F;
29 float influence_length = 0.25F;
30
31 float length_cap = 1.0F;
32
33 const std::vector<std::pair<std::string, float*>> _params {
34 { "min_mod", &min_mod },
35 { "max_mod", &max_mod },
36 { "mod_base", &mod_base },
37
38 { "decay", &decay },
39
40 { "prop_buffer", &prop_buffer },
41 { "prop_scaler", &prop_scaler },
42
43 { "influence_center", &influence_center },
44 { "influence_external", &influence_external },
45 { "influence_length", &influence_length },
46
47 { "length_cap", &length_cap },
48 };
49
50 #pragma endregion params and param map
51 float pmod = min_mod;
52 float last_mod = min_mod;
53
54 float _value = 0.F;
55 int _encountered = 0;
56 int _length = 0;
57
58 int _eml = 0;
59
60 int _nm = 0;
61 int _om = 0;
62
63 int _last = 0;
64
65 // basically do the same thing other pmods do
66 void reset_and_decay()
67 {
68 pmod = std::clamp(last_mod - decay, min_mod, max_mod);
69 last_mod = pmod;
70
71 _length = 0;
72 _nm = 0;
73 _om = 0;
74 }
75
76 void advance_sequencing(const float& ms_now, const unsigned& notes)
77 {
78 _eml--;
79
80 // prevents patterning like this, as it's a different field of tech.
81 // 11011
82 // 00100
83
84 if ((notes & 0b11) >= 0b11 && (notes & 0b11000) >= 0b11000)
85 {
86 _eml = 0;
87 return;
88 }
89 if (notes == _last && notes != 0b00100)
90 {
91 _eml = 0;
92 return;
93 }
94 if (notes & 0b00100)
95 {
96 // chord that has both hands and middle lane involved should not be counted as handswitch.
97 if ((notes & 0b11) && (notes & 0b11000))
98 {
99 _eml = 0;
100 return;
101 }
102
103 _eml = 2;
104 _om++;
105
106 if (_length == 0) _length++;
107 }
108 if (_eml > 0)
109 {
110 if (notes & 0b11011) _nm++;
111 }
112
113 if (_eml > 0 && _length > 0)
114 {
115 _length++;
116 }
117 _last = notes;
118 }
119
120 void full_reset()
121 {
122 last_mod = min_mod;
123
124 _value = 0;
125 _encountered = 0;
126
127 _length = 0;
128
129 _eml = 0;
130
131 _om = 0;
132 _nm = 0;
133
134 _last = 0;
135 }
136
137 auto operator()(const metaItvGenericHandInfo& mitvghi)
138 {
139 if (mitvghi.total_taps == 0)
140 {
141 return neutral;
142 }
143
144 if (_eml <= 0)
145 {
146 reset_and_decay();
147 return pmod;
148 }
149
150 float c = _om * influence_center;
151 float x = _nm * influence_external;
152 float m = (1 + std::clamp(influence_length * _length, 0.F, length_cap)) * (c + x) / std::max(_length, 1);
153
154 _value = prop_scaler * m + prop_buffer;
155 _value = std::max(_value, .0F);
156
157 pmod = std::clamp(mod_base + _value, min_mod, max_mod);
158 last_mod = pmod;
159
160 return pmod;
161 }
162};
Definition HandSwitch.h:13
Definition MetaIntervalGenericHandInfo.h:145