-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TapTempoBox.qml
205 lines (167 loc) · 6.17 KB
/
TapTempoBox.qml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
/**
* Exposed properties:
* - tempo: the tempo value by unitDuration [ReadWrite]
* - unitDuration: the base duration selected (4 for a whole, 1 for a quarter, ...) [ReadWrite]
* - tempoText: a representation with Symbols of the selected tempo [ReadOnly]
* - tempoValue: Quarter-based tempo value [ReadOnly]
* - unitFractionDenum: the denumerator of the fraction to use for durations [ReadOnly]
*
* Versions history
* 1.0.0 Version initiale (tirée de TapTempo et séparation en TapTempoBox et TempoUnitBox)
* 1.0.1 Nouvelle approche du Binding
* 1.0.1 New setBeatBaseFromMarking function
*/
RowLayout {
// id
id: control
// layout
spacing: 5
// control
property var sizeMult: 1.5
property var buttonColor: "#21be2b"
property var buttonDownColor: "#17a81a"
// input properties
property alias tempoMult: lstMult.unitDuration
property var tempo: -1
// returned values
readonly property var tempoText: { {
var settings = lstMult.unitText;
if (settings == undefined || tempo <= 0) {
return null;
}
return lstMult.unitText + ' = ' + tempo;
}
}
readonly property var tempoValue: { {
return tempo * tempoMult;
}
}
onTempoChanged: {
//the tempo property changed from an external property set => we propagate this to the SpinBox
if (!txtTempo._inOnActivated) {
txtTempo.value=tempo;
}
}
// inner data
readonly property int averageOn: 5
property var lastclicks: []
property var tempoElement
property var curSegment
// Components
TempoUnitBox {
id: lstMult
unitDuration: 1
sizeMult: control.sizeMult
implicitHeight: 40*sizeMult
implicitWidth: 90
}
SpinBox {
id: txtTempo
Layout.preferredHeight: 40*sizeMult
from: 0
to: 360
stepSize: 1
editable: true
font.pointSize: 8.6*sizeMult
textFromValue: function (value) {
var text = (value > 0) ? value : "";
//debugO("textFromValue", text);
return text;
}
valueFromText: function (text) {
var val = (text === "") ? -1 : parseInt(text);
if (isNaN(val))
val = -1;
// debugO("valueFromText", val);
return val;
}
property var _inOnActivated: false
onValueChanged: {
_inOnActivated=true;
tempo = value;
_inOnActivated=false;
}
validator: IntValidator {
locale: txtTempo.locale.name
bottom: 0
top: txtTempo.to
}
}
Button {
id: btnTap
text: "Tap!"
font.pointSize: 10*sizeMult
background: Rectangle {
implicitWidth: 40*sizeMult
implicitHeight: 40*sizeMult
color: btnTap.down ? buttonDownColor : buttonColor
radius: 4
}
onClicked: {
if (lastclicks.length == averageOn)
lastclicks.shift(); // removing oldest one
lastclicks.push(new Date());
if (lastclicks.length >= 2) {
var avg = 0;
for (var i = 1; i < lastclicks.length; i++) {
avg += (lastclicks[i] - lastclicks[i - 1]);
}
console.log("total diffs: " + avg);
avg = avg / (lastclicks.length - 1);
console.log("avg diffs: " + avg);
tempo = Math.round(60 * 1000 / avg);
//debugO("--tempo", tempo);
} else {
tempo = -1;
}
}
}
/// Analyses tempo marking text to attempt to discover the base beat being used
/// If a beat is NOT detected, it does nothing
function setBeatBaseFromMarking(tempoMarking) {
// First look for metronome marking symbols
var foundTempoText=tempoMarking.text.replace('<sym>space</sym>', '');
var foundMetronomeSymbols = foundTempoText.match(/(<sym>met.*<\/sym>)+/g);
// strip html tags and split around '='
var data = foundTempoText.replace(/<.*?>/g,'').split('=');
var tempo=parseInt(data[1]);
if (isNaN(tempo)) tempo=0;
if (foundMetronomeSymbols !== null) {
// Locate the index in our dropdown matching the found beatString
for( var i = lstMult.multipliers.rowCount(); --i>=0 ; ) {
if (lstMult.multipliers.get(i).sym == foundMetronomeSymbols[0]) {
// Found this marking in the dropdown at metronomeMarkIndex
return {multiplier: lstMult.multipliers.get(i).mult, tempo: tempo};
}
}
} else {
// Metronome marking symbols are substituted with their character entity if the text was edited
// UTF-16 range [\uECA0 - \uECB6] (double whole - 1024th)
for (var beatString, charidx = 0; charidx < foundTempoText.length; charidx++) {
beatString = foundTempoText[charidx];
if ((beatString >= "\uECA2") && (beatString <= "\uECA9")) {
// Found base tempo - continue looking for augmentation dots
while (++charidx < foundTempoText.length) {
if (foundTempoText[charidx] == "\uECB7") {
beatString += " \uECB7";
} else if (foundTempoText[charidx] != ' ') {
break; // No longer augmentation dots or spaces
}
}
// Locate the index in our dropdown matching the found beatString
for( var i = lstMult.multipliers.rowCount(); --i>=0 ; ) {
if (lstMult.multipliers.get(i).text == beatString) {
// Found this marking in the dropdown at metronomeMarkIndex
return {multiplier: lstMult.multipliers.get(i).mult, tempo: tempo};
}
}
break; // Done processing base tempo
}
}
}
return {multiplier: -1, tempo: tempo};
}
}