1 /*
2  *  tracker/DialogResample.cpp
3  *
4  *  Copyright 2009 Peter Barth
5  *
6  *  This file is part of Milkytracker.
7  *
8  *  Milkytracker is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  Milkytracker is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with Milkytracker.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 /*
24  *  DialogResample.cpp
25  *  MilkyTracker
26  *
27  *  Created by Peter Barth on 25.10.05.
28  *
29  */
30 
31 #include "DialogResample.h"
32 #include "Screen.h"
33 #include "StaticText.h"
34 #include "CheckBox.h"
35 #include "CheckBoxLabel.h"
36 #include "PPUIConfig.h"
37 #include "MessageBoxContainer.h"
38 #include "Font.h"
39 #include "ListBox.h"
40 #include "Seperator.h"
41 #include "XModule.h"
42 #include "ResamplerHelper.h"
43 
getc4spd(mp_sint32 relnote,mp_sint32 finetune)44 float getc4spd(mp_sint32 relnote,mp_sint32 finetune)
45 {
46 	static const mp_sint32	table[] = {65536,69432,73561,77935,82570,87480,92681,98193,104031,110217,116771,123715,
47 						   65536,65565,65595,65624,65654,65684,65713,65743,65773,65802,65832,65862,65891,
48 						   65921,65951,65981,66010,66040,66070,66100,66130,66160,66189,66219,66249,66279,
49 						   66309,66339,66369,66399,66429,66459,66489,66519,66549,66579,66609,66639,66669,
50 						   66699,66729,66759,66789,66820,66850,66880,66910,66940,66971,67001,67031,67061,
51 						   67092,67122,67152,67182,67213,67243,67273,67304,67334,67365,67395,67425,67456,
52 						   67486,67517,67547,67578,67608,67639,67669,67700,67730,67761,67792,67822,67853,
53 						   67883,67914,67945,67975,68006,68037,68067,68098,68129,68160,68190,68221,68252,
54 						   68283,68314,68344,68375,68406,68437,68468,68499,68530,68561,68592,68623,68654,
55 						   68685,68716,68747,68778,68809,68840,68871,68902,68933,68964,68995,69026,69057,
56 						   69089,69120,69151,69182,69213,69245,69276,69307,69339,69370,69401};
57 
58 	mp_sint32 c4spd = 8363;
59 	mp_sbyte xmfine = finetune;
60 
61 	mp_sbyte octave = (relnote+96)/12;
62 	mp_sbyte note = (relnote+96)%12;
63 
64 	mp_sbyte o2 = octave-8;
65 
66 	if (xmfine<0)
67 	{
68 		xmfine+=(mp_sbyte)128;
69 		note--;
70 		if (note<0)
71 		{
72 			note+=12;
73 			o2--;
74 		}
75 	}
76 
77 	if (o2>=0)
78 	{
79 		c4spd<<=o2;
80 	}
81 	else
82 	{
83 		c4spd>>=-o2;
84 	}
85 
86 	float f = table[(mp_ubyte)note]*(1.0f/65536.0f) * c4spd;
87 	return f * (table[(mp_ubyte)xmfine+12]*(1.0f/65536.0f));
88 }
89 
DialogResample(PPScreen * screen,DialogResponder * responder,pp_int32 id)90 DialogResample::DialogResample(PPScreen* screen,
91 							   DialogResponder* responder,
92 							   pp_int32 id) :
93 	PPDialogBase(),
94 	count(0),
95 	resamplerHelper(new ResamplerHelper()),
96 	interpolationType(1),
97 	adjustFtAndRelnote(true)
98 {
99 #ifdef __LOWRES__
100 	initDialog(screen, responder, id, "Resample" PPSTR_PERIODS, 290, 142+15+20+16, 26+15, "Ok", "Cancel");
101 #else
102 	initDialog(screen, responder, id, "Resample" PPSTR_PERIODS, 290, 142+20+16, 26, "Ok", "Cancel");
103 #endif
104 
105 	pp_int32 x = getMessageBoxContainer()->getLocation().x;
106 
107 	pp_int32 width = getMessageBoxContainer()->getSize().width;
108 
109 	pp_int32 x2 = x;
110 	pp_int32 y2 = getMessageBoxContainer()->getControlByID(MESSAGEBOX_STATICTEXT_MAIN_CAPTION)->getLocation().y;
111 
112 	PPButton* button;
113 
114 	y2 +=16;
115 
116 	// enter edit field 1
117 	x2 = x + width / 2 - (10*8+35 + 14*8)/2;
118 
119 	messageBoxContainerGeneric->addControl(new PPStaticText(0, screen, this, PPPoint(x2, y2+2), "Relative note", true));
120 
121 	x2+=17*8;
122 	PPListBox* listBox = new PPListBox(MESSAGEBOX_LISTBOX_VALUE_ONE, screen, this, PPPoint(x2, y2), PPSize(7*8,12), true, true, false);
123 	listBox->showSelection(false);
124 	listBox->setBorderColor(messageBoxContainerGeneric->getColor());
125 	listBox->setMaxEditSize(8);
126 	listBoxes[0] = listBox;
127 	messageBoxContainerGeneric->addControl(listBox);
128 
129 	button = new PPButton(MESSAGEBOX_BUTTON_INCREASE_VALUEONE, screen, this, PPPoint(x2 + listBox->getSize().width + 2, y2), PPSize(16, 11));
130 	button->setText("+");
131 	messageBoxContainerGeneric->addControl(button);
132 
133 	button = new PPButton(MESSAGEBOX_BUTTON_DECREASE_VALUEONE, screen, this, PPPoint(x2 + listBox->getSize().width + 2 + button->getSize().width + 1, y2), PPSize(16, 11));
134 	button->setText("-");
135 	messageBoxContainerGeneric->addControl(button);
136 
137 	y2+=16;
138 
139 	x2 = x + width / 2 - (10*8+35 + 14*8)/2;
140 
141 	messageBoxContainerGeneric->addControl(new PPStaticText(0, screen, this, PPPoint(x2, y2+2), "Fine tune", true));
142 
143 	x2+=17*8;
144 	listBox = new PPListBox(MESSAGEBOX_LISTBOX_VALUE_TWO, screen, this, PPPoint(x2, y2), PPSize(7*8,12), true, true, false);
145 	listBox->showSelection(false);
146 	listBox->setBorderColor(messageBoxContainerGeneric->getColor());
147 	listBox->setMaxEditSize(8);
148 	listBoxes[1] = listBox;
149 	messageBoxContainerGeneric->addControl(listBox);
150 
151 	button = new PPButton(MESSAGEBOX_BUTTON_INCREASE_VALUETWO, screen, this, PPPoint(x2 + listBox->getSize().width + 2, y2), PPSize(16, 11));
152 	button->setText("+");
153 	messageBoxContainerGeneric->addControl(button);
154 
155 	button = new PPButton(MESSAGEBOX_BUTTON_DECREASE_VALUETWO, screen, this, PPPoint(x2 + listBox->getSize().width + 2 + button->getSize().width + 1, y2), PPSize(16, 11));
156 	button->setText("-");
157 	messageBoxContainerGeneric->addControl(button);
158 
159 	y2+=16;
160 
161 	x2 = x + width / 2 - (10*8+35 + 14*8)/2;
162 
163 	messageBoxContainerGeneric->addControl(new PPStaticText(0, screen, this, PPPoint(x2, y2+2), "C4 speed (Hz)", true));
164 
165 	x2+=14*8;
166 	listBox = new PPListBox(MESSAGEBOX_LISTBOX_VALUE_THREE, screen, this, PPPoint(x2, y2), PPSize(10*8,12), true, true, false);
167 	listBox->showSelection(false);
168 	listBox->setBorderColor(messageBoxContainerGeneric->getColor());
169 	listBox->setMaxEditSize(8);
170 	listBoxes[2] = listBox;
171 	messageBoxContainerGeneric->addControl(listBox);
172 
173 	button = new PPButton(MESSAGEBOX_BUTTON_INCREASE_VALUETHREE, screen, this, PPPoint(x2 + listBox->getSize().width + 2, y2), PPSize(16, 11));
174 	button->setText("+");
175 	messageBoxContainerGeneric->addControl(button);
176 
177 	button = new PPButton(MESSAGEBOX_BUTTON_DECREASE_VALUETHREE, screen, this, PPPoint(x2 + listBox->getSize().width + 2 + button->getSize().width + 1, y2), PPSize(16, 11));
178 	button->setText("-");
179 	messageBoxContainerGeneric->addControl(button);
180 
181 	y2+=16;
182 	x2 = x + width / 2 - (10*8+35 + 14*8)/2;
183 	messageBoxContainerGeneric->addControl(new PPStaticText(0, screen, this, PPPoint(x2, y2+2), "New size:", true));
184 	x2+=18*8;
185 	messageBoxContainerGeneric->addControl(new PPStaticText(MESSAGEBOX_STATICTEXT_USER1, screen, this, PPPoint(x2, y2+2), "XXXXXXXX"));
186 
187 	y2+=16;
188 
189 	x2 = x + width / 2 - (10*8+35 + 14*8)/2;
190 	messageBoxContainerGeneric->addControl(new PPStaticText(0, screen, this, PPPoint(x2, y2+2), "Interpolation:", true));
191 
192 	x2+=15*8;
193 	button = new PPButton(MESSAGEBOX_CONTROL_USER1, screen, this, PPPoint(x2, y2), PPSize(button->getLocation().x + button->getSize().width - x2, 11), false);
194 	button->setText(resamplerHelper->getResamplerName(interpolationType, true));
195 	button->setColor(messageBoxContainerGeneric->getColor());
196 	button->setTextColor(PPUIConfig::getInstance()->getColor(PPUIConfig::ColorStaticText));
197 
198 	messageBoxContainerGeneric->addControl(button);
199 
200 	y2+=16;
201 
202 	x2 = x + width / 2 - (10 * 8 + 35 + 14 * 8) / 2 + 21 * 8;
203 	checkBox = new PPCheckBox(MESSAGEBOX_CONTROL_USER2, screen, this, PPPoint(x2, y2 + 1));
204 	checkBox->checkIt(adjustFtAndRelnote);
205 	messageBoxContainerGeneric->addControl(checkBox);
206 
207 	x2 -= 21 * 8;
208 	messageBoxContainerGeneric->addControl(new PPCheckBoxLabel(0, screen, this, PPPoint(x2, y2 + 2), "Adjust Ft/Rel.Note:", checkBox, true));
209 
210 	y2+=16;
211 
212 #ifdef __LOWRES__
213 	pp_int32 height = getMessageBoxContainer()->getSize().height;
214 	pp_int32 y = getMessageBoxContainer()->getLocation().y;
215 
216 	const char buttonTexts[] = {'1','2','3','4','5','6','7','8','9','0','+','-','.','<','>'};
217 
218 	pp_int32 bWidth = (width - 22*2 - 2*3) / sizeof(buttonTexts);
219 	pp_int32 x2_2 = x+4;
220 
221 	pp_int32 y2_2 = y+height - 4 - 13;
222 
223 	messageBoxContainerGeneric->addControl(new PPSeperator(0, screen, PPPoint(x2_2-1, y2_2-3), width-2*3, messageBoxContainerGeneric->getColor(), true));
224 
225 	pp_uint32 i = 0;
226 	for (i = 0; i < sizeof(buttonTexts); i++)
227 	{
228 		button = new PPButton(MESSAGEBOX_BUTTON_KEYS_BASE+i, screen, this, PPPoint(x2_2, y2_2), PPSize(bWidth+1, 13));
229 		button->setText(buttonTexts[i]);
230 		messageBoxContainerGeneric->addControl(button);
231 		x2_2+=bWidth;
232 	}
233 
234 	bWidth = 22;
235 
236 	button = new PPButton(MESSAGEBOX_BUTTON_KEYS_BASE+i, screen, this, PPPoint(x2_2, y2_2), PPSize(bWidth+1-3, 13));
237 	button->setFont(PPFont::getFont(PPFont::FONT_TINY));
238 	button->setText("Del");
239 	messageBoxContainerGeneric->addControl(button);
240 	x2_2+=bWidth-3;
241 	i++;
242 	button = new PPButton(MESSAGEBOX_BUTTON_KEYS_BASE+i, screen, this, PPPoint(x2_2, y2_2), PPSize(bWidth+1, 13));
243 	button->setFont(PPFont::getFont(PPFont::FONT_TINY));
244 	button->setText("Back");
245 	messageBoxContainerGeneric->addControl(button);
246 #endif
247 
248 	currentSelectedListBox = 0;
249 	relnote = finetune = 0;
250 	c4spd = 0.0f;
251 }
252 
~DialogResample()253 DialogResample::~DialogResample()
254 {
255 	delete resamplerHelper;
256 }
257 
show(bool b)258 void DialogResample::show(bool b/* = true*/)
259 {
260 	if (b)
261 	{
262 		currentSelectedListBox = 0;
263 		updateListBoxes();
264 		listBoxEnterEditState(MESSAGEBOX_LISTBOX_VALUE_ONE);
265 
266 		PPButton* button = static_cast<PPButton*>(messageBoxContainerGeneric->getControlByID(MESSAGEBOX_CONTROL_USER1));
267 		button->setText(resamplerHelper->getResamplerName(interpolationType, true));
268 	}
269 	PPDialogBase::show(b);
270 }
271 
handleEvent(PPObject * sender,PPEvent * event)272 pp_int32 DialogResample::handleEvent(PPObject* sender, PPEvent* event)
273 {
274 	if (event->getID() == eKeyDown)
275 	{
276 		pp_uint16 keyCode = *((pp_uint16*)event->getDataPtr());
277 		if (keyCode == VK_TAB)
278 		{
279 			switchListBox();
280 			event->cancel();
281 		}
282 	}
283 	else if (event->getID() == eCommand || event->getID() == eCommandRepeat)
284 	{
285 		switch (reinterpret_cast<PPControl*>(sender)->getID())
286 		{
287 			case PP_MESSAGEBOX_BUTTON_YES:
288 			{
289 				commitChanges();
290 				break;
291 			}
292 
293 			case MESSAGEBOX_BUTTON_INCREASE_VALUEONE:
294 			{
295 				relnote++;
296 				toC4Speed();
297 				calcSize();
298 				updateListBoxes();
299 				parentScreen->paintControl(messageBoxContainerGeneric);
300 				break;
301 			}
302 
303 			case MESSAGEBOX_BUTTON_DECREASE_VALUEONE:
304 			{
305 				relnote--;
306 				toC4Speed();
307 				calcSize();
308 				updateListBoxes();
309 				parentScreen->paintControl(messageBoxContainerGeneric);
310 				break;
311 			}
312 
313 			case MESSAGEBOX_BUTTON_INCREASE_VALUETWO:
314 			{
315 				finetune++;
316 				toC4Speed();
317 				calcSize();
318 				updateListBoxes();
319 				parentScreen->paintControl(messageBoxContainerGeneric);
320 				break;
321 			}
322 
323 			case MESSAGEBOX_BUTTON_DECREASE_VALUETWO:
324 			{
325 				finetune--;
326 				toC4Speed();
327 				calcSize();
328 				updateListBoxes();
329 				parentScreen->paintControl(messageBoxContainerGeneric);
330 				break;
331 			}
332 
333 			case MESSAGEBOX_BUTTON_INCREASE_VALUETHREE:
334 			{
335 				c4spd++;
336 				fromC4Speed();
337 				calcSize();
338 				updateListBoxes();
339 				parentScreen->paintControl(messageBoxContainerGeneric);
340 				break;
341 			}
342 
343 			case MESSAGEBOX_BUTTON_DECREASE_VALUETHREE:
344 			{
345 				c4spd--;
346 				fromC4Speed();
347 				calcSize();
348 				updateListBoxes();
349 				parentScreen->paintControl(messageBoxContainerGeneric);
350 				break;
351 			}
352 
353 			case MESSAGEBOX_CONTROL_USER1:
354 			{
355 				if (event->getID() != eCommand)
356 					break;
357 
358 				interpolationType = (interpolationType + 1) % resamplerHelper->getNumResamplers();
359 
360 				PPButton* button = static_cast<PPButton*>(messageBoxContainerGeneric->getControlByID(MESSAGEBOX_CONTROL_USER1));
361 				button->setText(resamplerHelper->getResamplerName(interpolationType, true));
362 				parentScreen->paintControl(messageBoxContainerGeneric);
363 				break;
364 			}
365 
366 			case MESSAGEBOX_CONTROL_USER2:
367 			{
368 				if (event->getID() != eCommand)
369 					break;
370 
371 				this->adjustFtAndRelnote = reinterpret_cast<PPCheckBox*>(sender)->isChecked();
372 				break;
373 			}
374 
375 		}
376 	}
377 	else if (event->getID() == eValueChanged)
378 	{
379 		switch (reinterpret_cast<PPControl*>(sender)->getID())
380 		{
381 			case MESSAGEBOX_LISTBOX_VALUE_ONE:
382 			{
383 				const PPString* str = *(reinterpret_cast<PPString* const*>(event->getDataPtr()));
384 				setRelNote((pp_int32)atoi(*str));
385 				calcSize();
386 				updateListBoxes();
387 				parentScreen->paintControl(messageBoxContainerGeneric);
388 				break;
389 			}
390 
391 			case MESSAGEBOX_LISTBOX_VALUE_TWO:
392 			{
393 				const PPString* str = *(reinterpret_cast<PPString* const*>(event->getDataPtr()));
394 				setFineTune((pp_int32)atoi(*str));
395 				calcSize();
396 				updateListBoxes();
397 				parentScreen->paintControl(messageBoxContainerGeneric);
398 				break;
399 			}
400 
401 			case MESSAGEBOX_LISTBOX_VALUE_THREE:
402 			{
403 				const PPString* str = *(reinterpret_cast<PPString* const*>(event->getDataPtr()));
404 				setC4Speed((float)atof(*str));
405 				calcSize();
406 				updateListBoxes();
407 				parentScreen->paintControl(messageBoxContainerGeneric);
408 				break;
409 			}
410 		}
411 	}
412 
413 	return PPDialogBase::handleEvent(sender, event);
414 }
415 
updateListBoxes()416 void DialogResample::updateListBoxes()
417 {
418 	updateListBox(MESSAGEBOX_LISTBOX_VALUE_ONE, (float)relnote, 0);
419 	updateListBox(MESSAGEBOX_LISTBOX_VALUE_TWO, (float)finetune, 0);
420 	updateListBox(MESSAGEBOX_LISTBOX_VALUE_THREE, (float)c4spd, 2);
421 
422 	PPStaticText* staticText = static_cast<PPStaticText*>(messageBoxContainerGeneric->getControlByID(MESSAGEBOX_STATICTEXT_USER1));
423 	staticText->setHexValue(finalSize, 8);
424 
425 	checkBox->checkIt(adjustFtAndRelnote);
426 }
427 
updateListBox(pp_int32 id,float val,pp_int32 numDecimals)428 void DialogResample::updateListBox(pp_int32 id, float val, pp_int32 numDecimals)
429 {
430 	char buffer1[100];
431 	char buffer2[100];
432 
433 	sprintf(buffer1, "%%.%if", numDecimals);
434 
435 	PPListBox* listBox = static_cast<PPListBox*>(messageBoxContainerGeneric->getControlByID(id));
436 	if (listBox)
437 	{
438 		sprintf(buffer2, buffer1, val);
439 		listBox->clear();
440 		listBox->addItem(buffer2);
441 	}
442 }
443 
commitChanges()444 void DialogResample::commitChanges()
445 {
446 	PPListBox* listBox = static_cast<PPListBox*>(messageBoxContainerGeneric->getControlByID(MESSAGEBOX_LISTBOX_VALUE_ONE));
447 	if (listBox)
448 		listBox->commitChanges();
449 
450 	listBox = static_cast<PPListBox*>(messageBoxContainerGeneric->getControlByID(MESSAGEBOX_LISTBOX_VALUE_TWO));
451 	if (listBox)
452 		listBox->commitChanges();
453 }
454 
listBoxEnterEditState(pp_int32 id)455 void DialogResample::listBoxEnterEditState(pp_int32 id)
456 {
457 	PPListBox* listBox = static_cast<PPListBox*>(messageBoxContainerGeneric->getControlByID(id));
458 	if (listBox)
459 		listBox->placeCursorAtEnd();
460 }
461 
switchListBox()462 void DialogResample::switchListBox()
463 {
464 	if (listBoxes[currentSelectedListBox]->isEditing())
465 		listBoxes[currentSelectedListBox]->commitChanges();
466 
467 	currentSelectedListBox = (currentSelectedListBox+1) % 3;
468 
469 	listBoxEnterEditState(listBoxes[currentSelectedListBox]->getID());
470 	messageBoxContainerGeneric->setFocus(listBoxes[currentSelectedListBox]);
471 	parentScreen->paintControl(messageBoxContainerGeneric);
472 }
473 
setRelNote(pp_int32 note)474 void DialogResample::setRelNote(pp_int32 note)
475 {
476 	relnote = note;
477 	toC4Speed();
478 
479 	if (count < 2)
480 	{
481 		count++;
482 		if (count == 2)
483 			originalc4spd = c4spd;
484 	}
485 }
486 
setFineTune(pp_int32 ft)487 void DialogResample::setFineTune(pp_int32 ft)
488 {
489 	finetune = ft;
490 	toC4Speed();
491 
492 	if (count < 2)
493 	{
494 		count++;
495 		if (count == 2)
496 			originalc4spd = c4spd;
497 	}
498 }
499 
setC4Speed(float c4spd)500 void DialogResample::setC4Speed(float c4spd)
501 {
502 	this->c4spd = c4spd;
503 	fromC4Speed();
504 }
505 
setSize(pp_uint32 size)506 void DialogResample::setSize(pp_uint32 size)
507 {
508 	this->size = size;
509 
510 	calcSize();
511 }
512 
toC4Speed()513 void DialogResample::toC4Speed()
514 {
515 	validate();
516 	c4spd = getc4spd(relnote, finetune);
517 	validate();
518 }
519 
fromC4Speed()520 void DialogResample::fromC4Speed()
521 {
522 	validate();
523 	mp_sbyte rn, ft;
524 	XModule::convertc4spd((mp_uint32)c4spd, &ft, &rn);
525 	relnote = rn;
526 	finetune = ft;
527 	validate();
528 }
529 
calcSize()530 void DialogResample::calcSize()
531 {
532 	float c4spd = getc4spd(relnote, finetune);
533 	float step = originalc4spd / c4spd;
534 
535 	finalSize = (mp_uint32)(size / step);
536 }
537 
validate()538 void DialogResample::validate()
539 {
540 	if (relnote > 48)
541 		relnote = 48;
542 	if (relnote < -48)
543 		relnote = -48;
544 
545 	if (finetune > 127)
546 		finetune = 127;
547 	if (finetune < -128)
548 		finetune = -128;
549 
550 	if (c4spd < 0)
551 		c4spd = 0;
552 
553 	if (c4spd > 65535*4)
554 		c4spd = 65535*4;
555 }
556