1 /*-
2  * Copyright (c) 2010-2021 Hans Petter Selasky. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include "midipp_decode.h"
27 
28 #include "midipp_buttonmap.h"
29 #include "midipp_chords.h"
30 #include "midipp_mainwindow.h"
31 #include "midipp_scores.h"
32 #include "midipp_button.h"
33 #include "midipp_element.h"
34 #include "midipp_groupbox.h"
35 #include "midipp_instrument.h"
36 
37 Q_DECL_EXPORT const QString
MppKeyStr(int key)38 MppKeyStr(int key)
39 {
40 	int rem = MPP_BAND_REM(key, MPP_MAX_BANDS);
41 	int off;
42 	int sub;
43 	int oct;
44 
45 	off = rem / MPP_BAND_STEP_12;
46 	sub = rem % MPP_BAND_STEP_12;
47 	oct = (key - rem) / MPP_MAX_BANDS;
48 
49 	if (sub != 0) {
50 		const char *off_map[12] = {
51 			"C%1.%2", "D%1B.%2", "D%1.%2", "E%1B.%2",
52 			"E%1.%2", "F%1.%2", "G%1B.%2", "G%1.%2",
53 			"A%1B.%2", "A%1.%2", "H%1B.%2", "H%1.%2"
54 		};
55 		sub = MPP_SUBDIV_REM_BITREV(sub);
56 		return (QString(off_map[off]).arg(oct).arg(sub));
57 	} else {
58 	  	const char *off_map[12] = {
59 			"C%1", "D%1B", "D%1", "E%1B",
60 			"E%1", "F%1", "G%1B", "G%1",
61 			"A%1B", "A%1", "H%1B", "H%1"
62 		};
63 		return (QString(off_map[off]).arg(oct));
64 	}
65 }
66 
67 Q_DECL_EXPORT const QString
MppKeyStrNoOctave(int key)68 MppKeyStrNoOctave(int key)
69 {
70 	int rem = MPP_BAND_REM(key, MPP_MAX_BANDS);
71 	int off;
72 	int sub;
73 
74 	off = rem / MPP_BAND_STEP_12;
75 	sub = rem % MPP_BAND_STEP_12;
76 
77 	if (sub != 0) {
78 		const char *off_map[12] = {
79 			"C.%1", "Db.%1", "D.%1", "Eb.%1",
80 			"E.%1", "F.%1", "Gb.%1", "G.%1",
81 			"Ab.%1", "A.%1", "Hb.%1", "H.%1"
82 		};
83 		sub = MPP_SUBDIV_REM_BITREV(sub);
84 		return (QString(off_map[off]).arg(sub));
85 	} else {
86 	  	const char *off_map[12] = {
87 			"C", "Db", "D", "Eb",
88 			"E", "F", "Gb", "G",
89 			"Ab", "A", "Hb", "H"
90 		};
91 		return (QString(off_map[off]));
92 	}
93 }
94 
95 Q_DECL_EXPORT const QString
MppBitsToString(const MppChord_t & mask,int off)96 MppBitsToString(const MppChord_t &mask, int off)
97 {
98 	QString temp;
99 	int x;
100 
101 	for (x = 0; x != MPP_MAX_CHORD_BANDS; x++) {
102 		if (mask.test(x) == 0)
103 			continue;
104 		temp += MppKeyStrNoOctave((x * MPP_BAND_STEP_CHORD) + off);
105 		temp += " ";
106 	}
107 	return (temp);
108 }
109 
110 void
MppScoreVariantInit(void)111 MppScoreVariantInit(void)
112 {
113 	const int rk = 0;
114 	MppChord_t mask;
115 	QString str;
116 	uint32_t x;
117 	uint32_t y;
118 	uint32_t z;
119 
120 	Mpp.VariantList += QString("\n/* Unique chords having two keys */\n\n");
121 
122 	for (z = 0, x = MPP_BAND_STEP_12; x != MPP_MAX_BANDS; x += MPP_BAND_STEP_12) {
123 		mask.zero();
124 		mask.set(0);
125 		mask.set(x / MPP_BAND_STEP_CHORD);
126 
127 		if (MppFindChordRoot(mask) != mask)
128 			continue;
129 
130 		MppChordToStringGeneric(mask, rk, rk, 0, MPP_BAND_STEP_12, str);
131 		if (str.isEmpty())
132 			str = "  ";
133 		else
134 			z++;
135 
136 		Mpp.VariantList += str;
137 		Mpp.VariantList += " = ";
138 		Mpp.VariantList += MppBitsToString(mask, rk);
139 		Mpp.VariantList += "\n";
140 	}
141 
142 	Mpp.VariantList += QString("\n/* Total number of variants is %1 */\n\n").arg(z);
143 	Mpp.VariantList += QString("/* Unique chords having three keys */\n\n");
144 
145 	for (z = 0, x = MPP_BAND_STEP_12; x != MPP_MAX_BANDS; x += MPP_BAND_STEP_12) {
146 		for (y = x + MPP_BAND_STEP_12; y != MPP_MAX_BANDS; y += MPP_BAND_STEP_12) {
147 			mask.zero();
148 			mask.set(0);
149 			mask.set(x / MPP_BAND_STEP_CHORD);
150 			mask.set(y / MPP_BAND_STEP_CHORD);
151 
152 			if (MppFindChordRoot(mask) != mask)
153 				continue;
154 
155 			MppChordToStringGeneric(mask, rk, rk, 0, MPP_BAND_STEP_12, str);
156 			if (str.isEmpty())
157 				str = "   ";
158 			else
159 				z++;
160 			Mpp.VariantList += str;
161 			Mpp.VariantList += " = ";
162 			Mpp.VariantList += MppBitsToString(mask, rk);
163 			Mpp.VariantList += "\n";
164 		}
165 	}
166 
167 	Mpp.VariantList += QString("\n/* Total number of variants is %1 */\n\n").arg(z);
168 
169 	Mpp.VariantList += QString("/* List of supported keys */\n\n");
170 
171 	for (x = 0; x != MPP_MAX_CHORD_BANDS; x++) {
172 		Mpp.VariantList += MppKeyStr(x * MPP_BAND_STEP_CHORD);
173 		Mpp.VariantList += QString(" /* %1 of %2 */\n").arg(x + 1)
174 		    .arg(MPP_MAX_CHORD_BANDS);
175 	}
176 
177 	/* Key adjustment table for K5.1 effect */
178 	Mpp.KeyAdjust[4] = round((MPP_MAX_BANDS * log(1.0 + 1.0 / 4.0) / log(2.0)) - (MPP_BAND_STEP_12 * 4));
179 	Mpp.KeyAdjust[5] = round((MPP_MAX_BANDS * log(1.0 + 1.0 / 3.0) / log(2.0)) - (MPP_BAND_STEP_12 * 5));
180 	Mpp.KeyAdjust[7] = round((MPP_MAX_BANDS * log(1.0 + 1.0 / 2.0) / log(2.0)) - (MPP_BAND_STEP_12 * 7));
181 
182 	Mpp.KeyAdjust[1] = Mpp.KeyAdjust[5] - Mpp.KeyAdjust[4];
183 	Mpp.KeyAdjust[2] = Mpp.KeyAdjust[7] - Mpp.KeyAdjust[5];
184 	Mpp.KeyAdjust[3] = Mpp.KeyAdjust[7] - Mpp.KeyAdjust[4];
185 
186 	Mpp.KeyAdjust[6] = Mpp.KeyAdjust[7] - Mpp.KeyAdjust[1];
187 
188 	Mpp.KeyAdjust[8] = -Mpp.KeyAdjust[4];
189 	Mpp.KeyAdjust[9] = -Mpp.KeyAdjust[3];
190 	Mpp.KeyAdjust[10] = -Mpp.KeyAdjust[2];
191 	Mpp.KeyAdjust[11] = -Mpp.KeyAdjust[1];
192 }
193 
194 static void
MppInitArray(const uint16_t * src,MppChord_t * dst,uint8_t n)195 MppInitArray(const uint16_t *src, MppChord_t *dst, uint8_t n)
196 {
197 	while (n--) {
198 		dst[n].zero();
199 		for (uint8_t x = 0; x != 12; x++) {
200 			if ((src[n] >> x) & 1)
201 				dst[n].set((MPP_BAND_STEP_12 / MPP_BAND_STEP_CHORD) * x);
202 		}
203 	}
204 }
205 
206 static int
MppCommonKeys(const MppChord_t & pa,const MppChord_t & pb,int a_key,int b_key)207 MppCommonKeys(const MppChord_t & pa, const MppChord_t & pb, int a_key, int b_key)
208 {
209 	MppChord_t temp = pb;
210 	int key = ((12 + a_key - b_key) % 12) *
211 	    (MPP_BAND_STEP_12 / MPP_BAND_STEP_CHORD);
212 
213 	while (key--) {
214 		if (temp.test(0)) {
215 			temp.tog(0);
216 			temp.tog(MPP_MAX_CHORD_BANDS);
217 		}
218 		temp.shr();
219 	}
220 
221 	temp &= pa;
222 	return (temp.order());
223 }
224 
MppDecodeCircle(MppDecodeTab * _ptab)225 MppDecodeCircle :: MppDecodeCircle(MppDecodeTab *_ptab)
226 {
227 	static const uint16_t circle[NMAX] = { 0x91, 0x89, 0x249 };
228 	ptab = _ptab;
229 
230 	MppInitArray(circle, mask, NMAX);
231 
232 	memset(r_press, 0, sizeof(r_press));
233 	memset(r_key, 0, sizeof(r_key));
234 	memset(r_mask, 0, sizeof(r_mask));
235 
236 	setMinimumSize(128,128);
237 }
238 
~MppDecodeCircle()239 MppDecodeCircle :: ~MppDecodeCircle()
240 {
241 }
242 
243 void
mousePressEvent(QMouseEvent * event)244 MppDecodeCircle :: mousePressEvent(QMouseEvent *event)
245 {
246 	QPoint p = event->pos();
247 
248 	for (uint8_t x = 0; x != NMAX; x++) {
249 		for (uint8_t y = 0; y != 12; y++) {
250 			if (r_press[x][y].contains(p) == 0)
251 				continue;
252 			ptab->chord_key -= ptab->chord_key % MPP_MAX_BANDS;
253 			ptab->chord_key += MPP_BAND_STEP_12 * r_key[x][y];
254 			ptab->chord_bass = ptab->chord_key % MPP_MAX_BANDS;
255 			ptab->chord_mask = r_mask[x][y];
256 			ptab->chord_step = MPP_BAND_STEP_12;
257 			ptab->handle_refresh();
258 			ptab->handle_play_press();
259 			return;
260 		}
261 	}
262 }
263 
264 void
mouseReleaseEvent(QMouseEvent * event)265 MppDecodeCircle :: mouseReleaseEvent(QMouseEvent *event)
266 {
267 	QPoint p = event->pos();
268 
269 	for (uint8_t x = 0; x != NMAX; x++) {
270 		for (uint8_t y = 0; y != 12; y++) {
271 			if (r_press[x][y].contains(p) == 0)
272 				continue;
273 			ptab->handle_play_release();
274 		}
275 	}
276 }
277 
278 void
paintEvent(QPaintEvent * event)279 MppDecodeCircle :: paintEvent(QPaintEvent *event)
280 {
281 	QPainter paint(this);
282 	int w = width();
283 	int h = height();
284 	int r;
285 	qreal step;
286 	uint8_t x;
287 	uint8_t y;
288 	uint8_t z;
289 	int found_key;
290 	uint32_t rols;
291 	MppChord_t footprint;
292 
293 	paint.fillRect(QRectF(0,0,w,h), Mpp.ColorWhite);
294 	paint.setRenderHints(QPainter::Antialiasing, 1);
295 
296 	memset(r_press, 0, sizeof(r_press));
297 	memset(r_key, 0, sizeof(r_key));
298 	memset(r_mask, 0, sizeof(r_mask));
299 
300 	footprint = MppFindChordRoot(ptab->chord_mask, &rols);
301 	found_key = (ptab->chord_key +
302 	    (rols * MPP_BAND_STEP_CHORD)) % MPP_MAX_BANDS;
303 	found_key /= MPP_BAND_STEP_12;
304 
305 	r = (w > h) ? h : w;
306 	step = r / (2 * (NMAX + 2));
307 
308 	QFont fnt[NMAX];
309 
310 	fnt[0].setPixelSize(step / 1.5);
311 	fnt[1].setPixelSize(step / 2.5);
312 	fnt[2].setPixelSize(step / 3.5);
313 
314 	for (x = 0; x != NMAX; x++) {
315 		const qreal radius = (NMAX + 2 - x) * step - step / 2.0;
316 
317 		paint.setPen(QPen(Mpp.ColorBlack, 2));
318 		paint.setBrush(QBrush());
319 
320 		paint.drawEllipse(QRectF(w / 2.0 - radius,
321 					 h / 2.0 - radius,
322 					 2.0*radius, 2.0*radius));
323 
324 		for (y = z = 0; y != 12; y++) {
325 			const double phase = 2.0 * M_PI * (double)y / 12.0;
326 			const qreal xp = radius * cos(phase) + w / 2.0;
327 			const qreal yp = radius * sin(phase) + h / 2.0;
328 
329 			r_press[x][y] = QRect(xp - step / 2.0,
330 					      yp - step / 2.0,
331 					      step, step);
332 			switch (x) {
333 			case 1:
334 				r_key[x][y] = (z + 9) % 12;
335 				break;
336 			default:
337 				r_key[x][y] = z;
338 				break;
339 			}
340 			r_mask[x][y] = mask[x];
341 
342 			z += 7;
343 			z %= 12;
344 		}
345 	}
346 
347 	for (x = 0; x != NMAX; x++) {
348 		paint.setFont(fnt[x]);
349 
350 		for (y = 0; y != 12; y++) {
351 			QColor bg;
352 			QColor fg;
353 
354 			switch (MppCommonKeys(r_mask[x][y], footprint,
355 					      r_key[x][y], found_key)) {
356 			case 4:
357 			case 3:
358 				bg = Mpp.ColorWhite;
359 				fg = Mpp.ColorBlack;
360 				break;
361 			case 2:
362 				bg = Mpp.ColorLight;
363 				fg = Mpp.ColorWhite;
364 				break;
365 			case 1:
366 				bg = Mpp.ColorGrey;
367 				fg = Mpp.ColorWhite;
368 				break;
369 			default:
370 				bg = Mpp.ColorBlack;
371 				fg = Mpp.ColorWhite;
372 				break;
373 			}
374 			paint.setPen(QPen(bg, 0));
375 			paint.setBrush(bg);
376 
377 			paint.drawEllipse(r_press[x][y]);
378 
379 			paint.setPen(QPen(fg, 0));
380 			paint.setBrush(fg);
381 
382 			QString suffix;
383 
384 			switch (x) {
385 			case 1:
386 				suffix = "m";
387 				break;
388 			case 2:
389 				suffix = "°7";
390 				break;
391 			default:
392 				break;
393 			}
394 
395 			paint.drawText(r_press[x][y],
396 			    Qt::AlignCenter | Qt::TextSingleLine,
397 			    MppKeyStrNoOctave(r_key[x][y] * MPP_BAND_STEP_12) + suffix);
398 		}
399 	}
400 }
401 
402 uint8_t
parseScoreChord(MppChordElement * pinfo)403 MppDecodeTab :: parseScoreChord(MppChordElement *pinfo)
404 {
405 	QString out;
406 	uint32_t is_sharp;
407 	uint32_t any = 0;
408 	uint32_t key = 0;
409 	uint32_t bass;
410 	MppChord_t footprint;
411 
412 	if (pinfo->chord != 0)
413 		is_sharp = (pinfo->chord->txt.indexOf('#') > -1);
414 	else
415 		is_sharp = 0;
416 
417 	footprint.zero();
418 
419 	for (int x = 0; x != MPP_MAX_CHORD_BANDS; x++) {
420 		if (pinfo->stats[x] == 0)
421 			continue;
422 		footprint.set(x);
423 		any = 1;
424 	}
425 	if (!any)
426 		return (1);	/* not found */
427 
428 	while (footprint.test(0) == 0) {
429 		footprint.shr();
430 		key += MPP_BAND_STEP_CHORD;
431 	}
432 
433 	bass = MPP_BAND_REM(pinfo->key_base, MPP_MAX_BANDS);
434 
435 	MppChordToStringGeneric(footprint, key, bass, is_sharp, MPP_BAND_STEP_CHORD, out);
436 
437 	if (out.isEmpty())
438 		return (1);	/* not found */
439 
440 	chord_key = key;
441 	chord_bass = bass;
442 	chord_sharp = is_sharp;
443 	chord_mask = footprint;
444 
445 	MPP_BLOCKED(lin_edit,setText(out));
446 
447 	handle_align(pinfo->key_max + 1);
448 	handle_refresh();
449 
450 	return (0);
451 }
452 
MppDecodeTab(MppMainWindow * _mw)453 MppDecodeTab :: MppDecodeTab(MppMainWindow *_mw)
454   : QWidget()
455 {
456 
457 	chord_key = 5 * 12 * MPP_BAND_STEP_12; /* C5 */
458 	chord_bass = 0;	/* C */
459 	chord_sharp = 0;
460 	chord_step = MPP_BAND_STEP_12;
461 	chord_mask.zero();
462 	chord_mask.set(0);
463 	chord_mask.set((MPP_BAND_STEP_12 / MPP_BAND_STEP_CHORD) * 4);
464 	chord_mask.set((MPP_BAND_STEP_12 / MPP_BAND_STEP_CHORD) * 7);
465 	delta_v = 0;
466 
467 	mw = _mw;
468 
469 	gl = new QGridLayout(this);
470 
471 	gb = new MppGroupBox(tr("Chord Selector"));
472 
473 	gl->setRowStretch(1,1);
474 	gl->setColumnStretch(0,1);
475 
476 	lin_edit = new QLineEdit(QString("C"));
477 	lin_edit->setMaxLength(256);
478 
479 	lin_out = new QLineEdit();
480 	lin_out->setMaxLength(256);
481 
482 	but_map_volume = new MppButtonMap("Key volume\0"
483 					  "MAX\0"
484 					  "63\0"
485 					  "31\0"
486 					  "15\0"
487 					  "7\0", 5, 5);
488 	but_map_volume->setSelection(4);
489 
490 	but_map_view = new MppButtonMap("View selection\0"
491 					"View-A\0"
492 					"View-B\0", 2, 2);
493 
494 #if MPP_MAX_VIEWS != 2
495 #error "Please update code above"
496 #endif
497 	but_insert = new QPushButton(tr("&Insert"));
498 	but_rol_up = new QPushButton(tr("Rotate\n&up"));
499 	but_rol_down = new QPushButton(tr("Rotate\nd&own"));
500 	but_mod_up = new QPushButton(tr("&Next\nvariant"));
501 	but_mod_down = new QPushButton(tr("Pre&vious\nvariant"));
502 	but_step_up_half = new QPushButton(tr("Step up\n12 scale"));
503 	but_step_down_half = new QPushButton(tr("Step down\n12 scale"));
504 	but_step_up_one = new QPushButton(tr("Step up\n192 scale"));
505 	but_step_down_one = new QPushButton(tr("Step down\n192 scale"));
506 	but_round_12 = new QPushButton(tr("Round to 12 scale"));
507 	but_play = new QPushButton(tr("&Play"));
508 
509 	connect(but_play, SIGNAL(pressed()), this, SLOT(handle_play_press()));
510 	connect(but_play, SIGNAL(released()), this, SLOT(handle_play_release()));
511 
512 	connect(but_insert, SIGNAL(released()), this, SLOT(handle_insert()));
513 
514 	connect(but_rol_up, SIGNAL(pressed()), this, SLOT(handle_rol_up()));
515 	connect(but_rol_up, SIGNAL(released()), this, SLOT(handle_play_release()));
516 	connect(but_rol_down, SIGNAL(pressed()), this, SLOT(handle_rol_down()));
517 	connect(but_rol_down, SIGNAL(released()), this, SLOT(handle_play_release()));
518 
519 	connect(but_mod_up, SIGNAL(pressed()), this, SLOT(handle_mod_up()));
520 	connect(but_mod_up, SIGNAL(released()), this, SLOT(handle_play_release()));
521 	connect(but_mod_down, SIGNAL(pressed()), this, SLOT(handle_mod_down()));
522 	connect(but_mod_down, SIGNAL(released()), this, SLOT(handle_play_release()));
523 
524 	connect(but_step_up_half, SIGNAL(pressed()), this, SLOT(handle_step_up_half()));
525 	connect(but_step_up_half, SIGNAL(released()), this, SLOT(handle_play_release()));
526 	connect(but_step_down_half, SIGNAL(pressed()), this, SLOT(handle_step_down_half()));
527 	connect(but_step_down_half, SIGNAL(released()), this, SLOT(handle_play_release()));
528 
529 	connect(but_step_up_one, SIGNAL(pressed()), this, SLOT(handle_step_up_one()));
530 	connect(but_step_up_one, SIGNAL(released()), this, SLOT(handle_play_release()));
531 	connect(but_step_down_one, SIGNAL(pressed()), this, SLOT(handle_step_down_one()));
532 	connect(but_step_down_one, SIGNAL(released()), this, SLOT(handle_play_release()));
533 
534 	connect(but_round_12, SIGNAL(pressed()), this, SLOT(handle_round_12()));
535 	connect(but_round_12, SIGNAL(released()), this, SLOT(handle_play_release()));
536 
537 	connect(lin_edit, SIGNAL(textChanged(const QString &)), this, SLOT(handle_parse()));
538 
539 	gb->addWidget(
540 	    new QLabel(tr("[CDEFGABH][#b][...][/CDEFGABH[#b]]")),
541 	    0,0,1,4, Qt::AlignHCenter|Qt::AlignVCenter);
542 
543 	gb->addWidget(but_rol_down, 2,0,1,1);
544 	gb->addWidget(but_rol_up, 2,1,1,1);
545 
546 	gb->addWidget(but_mod_down, 2,2,1,1);
547 	gb->addWidget(but_mod_up, 2,3,1,1);
548 
549 	gb->addWidget(but_step_down_half, 3,0,1,1);
550 	gb->addWidget(but_step_up_half, 3,1,1,1);
551 	gb->addWidget(but_step_down_one, 3,2,1,1);
552 	gb->addWidget(but_step_up_one, 3,3,1,1);
553 
554 	gb->addWidget(but_round_12, 4,0,1,2);
555 
556 	gb->addWidget(lin_edit, 5,0,1,4);
557 	gb->addWidget(lin_out, 6,0,1,4);
558 
559 	gb->addWidget(but_map_volume, 7,0,1,4);
560 	gb->addWidget(but_map_view, 8,0,1,4);
561 
562 	gb->addWidget(but_insert, 9, 2, 1, 2);
563 	gb->addWidget(but_play, 9, 0, 1, 2);
564 
565 	gb_gen = new MppGroupBox(tr("Chord Scratch Area"));
566 	gl->addWidget(gb_gen, 1,0,1,1);
567 
568 	editor = new MppDecodeEditor(_mw);
569 	editor->setTabChangesFocus(true);
570 
571 	gb_gen->addWidget(editor, 0,0,1,1);
572 
573 	gb_dc = new MppGroupBox(tr("Circle of fifths"));
574 	wi_dc = new MppDecodeCircle(this);
575 	gb_dc->addWidget(wi_dc, 0,0,1,1);
576 
577 	split = new QSplitter();
578 #if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR)
579 	split->setHandleWidth(32);
580 #else
581 	split->setHandleWidth(16);
582 #endif
583 	split->addWidget(gb);
584 	split->addWidget(gb_dc);
585 
586 	gl->addWidget(split, 0,0,1,1);
587 
588 	handle_parse();
589 
590 	but_insert->setFocus();
591 
592 	reset_state();
593 
594 	connect(this, SIGNAL(key_pressed(int)),
595 		this, SLOT(handle_key_pressed(int)));
596 	connect(this, SIGNAL(key_released(int)),
597 		this, SLOT(handle_key_released(int)));
598 	connect(this, SIGNAL(sustain_pedal(int)),
599 		this, SLOT(handle_sustain_pedal(int)));
600 }
601 
602 void
handle_play_press()603 MppDecodeTab :: handle_play_press()
604 {
605 	MppScoreMain *sm = mw->scores_main[but_map_view->currSelection];
606 	uint8_t vel = (127 >> but_map_volume->currSelection);
607 	int key_bass;
608 
609 	mw->atomic_lock();
610 	key_bass = chord_key - MPP_BAND_REM(chord_key, MPP_MAX_BANDS) + chord_bass;
611 	if (key_bass >= chord_key)
612 		key_bass -= 2 * MPP_MAX_BANDS;
613 	else
614 		key_bass -= 1 * MPP_MAX_BANDS;
615 
616 	mw->output_key(MPP_DEFAULT_TRACK(sm->unit), sm->synthChannel, key_bass, vel, 0, 0);
617 	mw->output_key(MPP_DEFAULT_TRACK(sm->unit), sm->synthChannel, key_bass + MPP_MAX_BANDS, vel, 0, 0);
618 
619 	for (int x = 0; x != MPP_MAX_CHORD_BANDS; x++) {
620 		if (chord_mask.test(x)) {
621 			mw->output_key(MPP_DEFAULT_TRACK(sm->unit),
622 			sm->synthChannel, chord_key + (x * MPP_BAND_STEP_CHORD), vel, 0, 0);
623 		}
624 	}
625 	mw->atomic_unlock();
626 }
627 
628 void
handle_play_release()629 MppDecodeTab :: handle_play_release()
630 {
631   	MppScoreMain *sm = mw->scores_main[but_map_view->currSelection];
632 	int key_bass;
633 
634 	mw->atomic_lock();
635 	key_bass = chord_key - MPP_BAND_REM(chord_key, MPP_MAX_BANDS) + chord_bass;
636 	if (key_bass >= chord_key)
637 		key_bass -= 2 * MPP_MAX_BANDS;
638 	else
639 		key_bass -= 1 * MPP_MAX_BANDS;
640 
641 	mw->output_key(MPP_DEFAULT_TRACK(sm->unit), sm->synthChannel, key_bass, 0, 0, 0);
642 	mw->output_key(MPP_DEFAULT_TRACK(sm->unit), sm->synthChannel, key_bass + MPP_MAX_BANDS, 0, 0, 0);
643 
644 	for (int x = 0; x != MPP_MAX_CHORD_BANDS; x++) {
645 		if (chord_mask.test(x)) {
646 			mw->output_key(MPP_DEFAULT_TRACK(sm->unit),
647 			    sm->synthChannel, chord_key + (x * MPP_BAND_STEP_CHORD), 0, 0, 0);
648 		}
649 	}
650 	mw->atomic_unlock();
651 }
652 
653 void
handle_insert()654 MppDecodeTab :: handle_insert()
655 {
656 	QPlainTextEdit *qedit = mw->currEditor();
657 	if (qedit == 0)
658 		return;
659 
660 	QTextCursor cursor(qedit->textCursor());
661 	MppChordElement info;
662 	MppElement *ptr;
663 	MppHead temp;
664 	int row;
665 
666 	temp += qedit->toPlainText();
667 	temp.flush();
668 
669 	row = cursor.blockNumber();
670 
671 	cursor.beginEditBlock();
672 
673 	/* check if the chord is valid */
674 	if (temp.getChord(row, &info) != 0) {
675 		if (info.chord != 0) {
676 			info.chord->txt = QChar('(') + lin_edit->text().trimmed() + QChar(')');
677 
678 			cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor, 1);
679 			cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, info.chord->line);
680 			cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::MoveAnchor, 1);
681 			cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor, 1);
682 			cursor.removeSelectedText();
683 			cursor.insertText(temp.toPlain(info.chord->line).replace("\n", ""));
684 		}
685 		if (info.start != 0) {
686 			for (ptr = info.start; ptr != info.stop;
687 			    ptr = TAILQ_NEXT(ptr, entry)) {
688 				ptr->type = MPP_T_UNKNOWN;
689 				ptr->txt = "";
690 			}
691 
692 			info.start->txt = getText();
693 
694 			cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor, 1);
695 			cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, row);
696 			cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::MoveAnchor, 1);
697 			cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor, 1);
698 			cursor.removeSelectedText();
699 			cursor.insertText(temp.toPlain(info.start->line).replace("\n", ""));
700 		}
701 	} else {
702 		cursor.removeSelectedText();
703 		cursor.insertText(getText() + QChar('\n'));
704 	}
705 	cursor.endEditBlock();
706 
707 	mw->handle_compile();
708 }
709 
710 void
handle_align(int key)711 MppDecodeTab :: handle_align(int key)
712 {
713 	if (key < (2 * MPP_MAX_BANDS) ||
714 	    key > (128 * MPP_BAND_STEP_12 - MPP_MAX_BANDS))
715 		return;
716 
717 	chord_key = key - MPP_BAND_REM(key, MPP_MAX_BANDS) +
718 	    MPP_MAX_BANDS + MPP_BAND_REM(chord_key, MPP_MAX_BANDS);
719 
720 	for (int x = MPP_MAX_CHORD_BANDS; x--; ) {
721 		if (chord_mask.test(x) == 0)
722 			continue;
723 		if ((chord_key + (x * MPP_BAND_STEP_CHORD)) < key)
724 			break;
725 		int rols = 0;
726 		MppRolUpChord(chord_mask, rols);
727 		chord_key -= rols * MPP_BAND_STEP_CHORD;
728 		x = MPP_MAX_CHORD_BANDS;
729 	}
730 }
731 
732 void
handle_rol_up()733 MppDecodeTab :: handle_rol_up()
734 {
735 	int rols;
736 
737 	if (chord_key > (128 * MPP_BAND_STEP_12 - MPP_MAX_BANDS))
738 		return;
739 	handle_play_release();
740 	rols = 0;
741 	MppRolDownChord(chord_mask, rols);
742 	chord_key += rols * MPP_BAND_STEP_CHORD;
743 	handle_refresh();
744 	handle_play_press();
745 }
746 
747 void
handle_rol_down()748 MppDecodeTab :: handle_rol_down()
749 {
750 	int rols;
751 
752 	if (chord_key < 2 * MPP_MAX_BANDS)
753 		return;
754 	handle_play_release();
755 	rols = 0;
756 	MppRolUpChord(chord_mask, rols);
757 	chord_key -= rols * MPP_BAND_STEP_CHORD;
758 	handle_refresh();
759 	handle_play_press();
760 }
761 
762 void
handle_mod_up()763 MppDecodeTab :: handle_mod_up()
764 {
765 	uint32_t rols;
766 	handle_play_release();
767 	chord_mask = MppFindChordRoot(chord_mask, &rols);
768 	chord_key += rols * MPP_BAND_STEP_CHORD;
769 	MppNextChordRoot(chord_mask,
770 	    chord_step / MPP_BAND_STEP_CHORD);
771 	handle_refresh();
772 	handle_play_press();
773 }
774 
775 void
handle_mod_down()776 MppDecodeTab :: handle_mod_down()
777 {
778   	uint32_t rols;
779 	handle_play_release();
780 	chord_mask = MppFindChordRoot(chord_mask, &rols);
781 	chord_key += rols * MPP_BAND_STEP_CHORD;
782 	MppPrevChordRoot(chord_mask,
783 	    chord_step / MPP_BAND_STEP_CHORD);
784 	handle_refresh();
785 	handle_play_press();
786 }
787 
788 void
handle_step_up_half()789 MppDecodeTab :: handle_step_up_half()
790 {
791 	handle_play_release();
792 	if (chord_key < (128 * MPP_BAND_STEP_12)) {
793 		chord_key += MPP_BAND_STEP_12;
794 		chord_bass += MPP_BAND_STEP_12;
795 		chord_bass %= MPP_MAX_BANDS;
796 		handle_refresh();
797 	}
798 	handle_play_press();
799 }
800 
801 void
handle_step_down_half()802 MppDecodeTab :: handle_step_down_half()
803 {
804 	handle_play_release();
805 	if (chord_key >= (25 * MPP_BAND_STEP_12)) {
806 		chord_key -= MPP_BAND_STEP_12;
807 		chord_bass += 11 * MPP_BAND_STEP_12;
808 		chord_bass %= MPP_MAX_BANDS;
809 		handle_refresh();
810 	}
811 	handle_play_press();
812 }
813 
814 void
handle_step_up_one()815 MppDecodeTab :: handle_step_up_one()
816 {
817 	handle_play_release();
818 	if (chord_key < (128 * MPP_BAND_STEP_12)) {
819 		chord_key += MPP_BAND_STEP_CHORD;
820 		chord_bass += MPP_BAND_STEP_CHORD;
821 		chord_bass %= MPP_MAX_BANDS;
822 		handle_refresh();
823 	}
824 	handle_play_press();
825 }
826 
827 void
handle_step_down_one()828 MppDecodeTab :: handle_step_down_one()
829 {
830 	handle_play_release();
831 	if (chord_key >= (24 * MPP_BAND_STEP_12 + 1)) {
832 		chord_key -= MPP_BAND_STEP_CHORD;
833 		chord_bass += MPP_MAX_BANDS - MPP_BAND_STEP_CHORD;
834 		chord_bass %= MPP_MAX_BANDS;
835 		handle_refresh();
836 	}
837 	handle_play_press();
838 }
839 
840 void
handle_round_12()841 MppDecodeTab :: handle_round_12()
842 {
843 	handle_play_release();
844 	round(MPP_BAND_STEP_12);
845 	handle_play_press();
846 }
847 
848 void
round(int value)849 MppDecodeTab :: round(int value)
850 {
851 	int x,y,mod;
852 
853 	if (value < 1)
854 		return;
855 
856 	mod = (value / MPP_BAND_STEP_CHORD);
857 
858 	chord_step = value;
859 
860 	chord_key += value / 2;
861 	chord_key -= chord_key % value;
862 
863 	chord_bass += value / 2;
864 	chord_bass -= chord_bass % value;
865 	chord_bass %= MPP_MAX_BANDS;
866 
867 	if (mod > 0) {
868 		for (x = 0; x != MPP_MAX_CHORD_BANDS; x++) {
869 			if (chord_mask.test(x) == 0 || (x % mod) == 0)
870 				continue;
871 
872 			y = x + (mod / 2);
873 			y -= (y % mod);
874 			y %= MPP_MAX_CHORD_BANDS;
875 
876 			chord_mask.clr(x);
877 			chord_mask.set(y);
878 		}
879 	}
880 	handle_refresh();
881 }
882 
883 void
handle_refresh()884 MppDecodeTab :: handle_refresh()
885 {
886 	QString out_key;
887 	QString str;
888 	int key_bass;
889 
890 	key_bass = chord_key -
891 	    MPP_BAND_REM(chord_key, MPP_MAX_BANDS) +
892 	    chord_bass;
893 
894 	if (key_bass >= chord_key)
895 		key_bass -= 2 * MPP_MAX_BANDS;
896 	else
897 		key_bass -= 1 * MPP_MAX_BANDS;
898 
899 	MppChordToStringGeneric(chord_mask, chord_key, key_bass,
900 	    chord_sharp, MPP_BAND_STEP_CHORD, str);
901 
902 	out_key += MppKeyStr(key_bass);
903 	out_key += " ";
904 	out_key += MppKeyStr(key_bass + MPP_MAX_BANDS);
905 	out_key += " ";
906 
907 	for (int x = 0; x != MPP_MAX_CHORD_BANDS; x++) {
908 		if (chord_mask.test(x) == 0)
909 			continue;
910 		out_key += MppKeyStr((x * MPP_BAND_STEP_CHORD) + chord_key);
911 		out_key += " ";
912 	}
913 
914 	if (str.isEmpty() == 0) {
915 		out_key += "/* ";
916 		out_key += str;
917 		out_key += " */";
918 	}
919 
920 	MPP_BLOCKED(lin_edit,setText(str));
921 	MPP_BLOCKED(lin_out,setText(out_key));
922 
923 	wi_dc->update();
924 }
925 
926 void
handle_parse()927 MppDecodeTab :: handle_parse()
928 {
929 	QString out_key;
930 	MppChord_t mask;
931 	int key_bass;
932 	uint32_t rem;
933 	uint32_t bass;
934 
935 	QString chord = lin_edit->text().trimmed();
936 	if (chord.isEmpty())
937 		goto error;
938 
939 	MppStringToChordGeneric(mask, rem, bass, MPP_BAND_STEP_CHORD, chord);
940 	chord_sharp = (chord.indexOf('#') > -1);
941 
942 	if (mask.test(0) == 0)
943 		goto error;
944 
945 	chord_bass = MPP_BAND_REM(bass, MPP_MAX_BANDS);
946 	chord_key = chord_key -
947 	    MPP_BAND_REM(chord_key, MPP_MAX_BANDS) +
948 	    rem;
949 	chord_mask = mask;
950 
951 	key_bass = chord_key -
952 	    MPP_BAND_REM(chord_key, MPP_MAX_BANDS) +
953 	    chord_bass;
954 
955 	if (key_bass >= chord_key)
956 		key_bass -= 2 * MPP_MAX_BANDS;
957 	else
958 		key_bass -= 1 * MPP_MAX_BANDS;
959 
960 	out_key += MppKeyStr(key_bass);
961 	out_key += " ";
962 	out_key += MppKeyStr(key_bass + MPP_MAX_BANDS);
963 	out_key += " ";
964 
965 	for (int x = 0; x != MPP_MAX_CHORD_BANDS; x++) {
966 		if (chord_mask.test(x) == 0)
967 			continue;
968 		out_key += MppKeyStr((x * MPP_BAND_STEP_CHORD) + chord_key);
969 		out_key += " ";
970 	}
971 
972 	out_key += "/* ";
973 	out_key += chord;
974 	out_key += " */";
975 
976 	lin_out->setText(out_key);
977 
978 	goto done;
979 error:
980 	chord_mask.zero();
981 	chord_mask.set(0);
982 	lin_out->setText("/* ERROR */");
983 done:
984 	wi_dc->update();
985 }
986 
987 QString
getText()988 MppDecodeTab :: getText()
989 {
990 	return (lin_out->text());
991 }
992 
993 void
setText(QString str)994 MppDecodeTab :: setText(QString str)
995 {
996 	MPP_BLOCKED(lin_edit,setText(str));
997 	handle_parse();
998 }
999 
1000 void
keyPressEvent(QKeyEvent * event)1001 MppDecodeTab :: keyPressEvent(QKeyEvent *event)
1002 {
1003 	switch (event->key()) {
1004 	case Qt::Key_Up:
1005 		handle_mod_up();
1006 		break;
1007 	case Qt::Key_Down:
1008 		handle_mod_down();
1009 		break;
1010 	default:
1011 		break;
1012 	}
1013 }
1014 
1015 void
keyReleaseEvent(QKeyEvent * event)1016 MppDecodeTab :: keyReleaseEvent(QKeyEvent *event)
1017 {
1018 	switch (event->key()) {
1019 	case Qt::Key_Up:
1020 		handle_play_release();
1021 		break;
1022 	case Qt::Key_Down:
1023 		handle_play_release();
1024 		break;
1025 	default:
1026 		break;
1027 	}
1028 }
1029 
1030 void
reset_state()1031 MppDecodeTab :: reset_state()
1032 {
1033 	memset(key_bitmap, 0, sizeof(key_bitmap));
1034 	sustain = 0;
1035 	stable = 0;
1036 }
1037 
1038 void
watchdog()1039 MppDecodeTab :: watchdog()
1040 {
1041 	constexpr unsigned stride = MPP_BAND_STEP_12 / MPP_BAND_STEP_CHORD;
1042 	MppChordElement info = {};
1043 	unsigned int x;
1044 	int key;
1045 	bool any_new = false;
1046 	bool pressed = false;
1047 
1048 	for (x = 0; x != 128; x++) {
1049 		if (!(key_bitmap[x] & BIT_PRESSED)) {
1050 			if (key_bitmap[x] & BIT_CACHED)
1051 				any_new = true;
1052 			key_bitmap[x] &= ~BIT_CACHED;
1053 			continue;
1054 		}
1055 		if (!(key_bitmap[x] & BIT_CACHED)) {
1056 			key_bitmap[x] |= BIT_CACHED;
1057 			any_new = true;
1058 		}
1059 		key = x * MPP_BAND_STEP_12;
1060 		if (pressed == false)
1061 			info.key_base = key;
1062 		if (info.key_max < key)
1063 			info.key_max = key;
1064 		pressed = true;
1065 		info.stats[(x * stride) % MPP_MAX_CHORD_BANDS]++;
1066 	}
1067 
1068 	if (any_new || !pressed) {
1069 		stable = 0;
1070 		return;
1071 	} else {
1072 		switch (stable) {
1073 		case 0:
1074 			stable = 1;
1075 			return;
1076 		case 1:
1077 			stable = 2;
1078 			break;
1079 		default:
1080 			return;
1081 		}
1082 	}
1083 
1084 	if (parseScoreChord(&info) != 0)
1085 		return;
1086 
1087 	if (mw->scoreRecordOn == 2)
1088 		mw->mbm_score_record->setSelection(0);
1089 
1090 	QPlainTextEdit *ped = mw->currEditor();
1091 	if (ped == 0)
1092 		return;
1093 
1094 	QTextCursor cursor;
1095 
1096 	cursor = QTextCursor(ped->textCursor());
1097 	cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor, 1);
1098 	cursor.beginEditBlock();
1099 	cursor.insertText(getText() + QChar('\n'));
1100 	cursor.endEditBlock();
1101 
1102 	ped->setTextCursor(cursor);
1103 }
1104 
1105 void
handle_key_pressed(int key)1106 MppDecodeTab :: handle_key_pressed(int key)
1107 {
1108 	key /= MPP_BAND_STEP_12;
1109 	if (key < 0 || key > 127)
1110 		return;
1111 	key_bitmap[key] |= BIT_PRESSED;
1112 	key_bitmap[key] &= ~BIT_RELEASED;
1113 }
1114 
1115 void
handle_key_released(int key)1116 MppDecodeTab :: handle_key_released(int key)
1117 {
1118 	key /= MPP_BAND_STEP_12;
1119 	if (key < 0 || key > 127)
1120 		return;
1121 	key_bitmap[key] |= BIT_RELEASED;
1122 	if (sustain == 0)
1123 		key_bitmap[key] &= ~BIT_PRESSED;
1124 }
1125 
1126 void
handle_sustain_pedal(int level)1127 MppDecodeTab :: handle_sustain_pedal(int level)
1128 {
1129 	if (sustain == (level >= 64))
1130 		return;
1131 	sustain = (level >= 64);
1132 	if (sustain != 0)
1133 		return;
1134 	for (unsigned x = 0; x != 128; x++) {
1135 		if (key_bitmap[x] & BIT_RELEASED)
1136 			key_bitmap[x] &= ~BIT_PRESSED;
1137 	}
1138 }
1139 
1140 void
mouseDoubleClickEvent(QMouseEvent * e)1141 MppDecodeEditor :: mouseDoubleClickEvent(QMouseEvent *e)
1142 {
1143 	MppHead temp;
1144 	MppChordElement info;
1145 	QTextCursor cursor(textCursor());
1146 	int row;
1147 
1148 	cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::MoveAnchor, 1);
1149 	cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor, 1);
1150 
1151 	/* check if the line is empty */
1152 	if (cursor.selectedText().simplified().size() == 0)
1153 		return;
1154 
1155 	row = cursor.blockNumber();
1156 
1157 	temp += toPlainText();
1158 	temp.flush();
1159 
1160 	/* check if the chord is valid */
1161 	if (temp.getChord(row, &info) != 0)
1162 		mw->tab_chord_gl->parseScoreChord(&info);
1163 
1164 	setTextCursor(cursor);
1165 }
1166