1 /*
2  *  tracker/PianoControl.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 #include "PianoControl.h"
24 #include "Screen.h"
25 #include "GraphicsAbstract.h"
26 #include "Font.h"
27 #include "ScrollBar.h"
28 #include "Piano.h"
29 #include "Tools.h"
30 #include "PatternTools.h"
31 #include "TrackerConfig.h"
32 
33 #define SCROLLBARWIDTH SCROLLBUTTONSIZE
34 
35 static const bool blackKeys[] =
36 {
37 	false,
38 	true,
39 	false,
40 	true,
41 	false,
42 	false,
43 	true,
44 	false,
45 	true,
46 	false,
47 	true,
48 	false
49 };
50 
51 static const PPPoint positions[] =
52 {
53 	PPPoint(1,17),
54 	PPPoint(5,6),
55 	PPPoint(9,17),
56 	PPPoint(13,6),
57 	PPPoint(17, 17),
58 	PPPoint(25, 17),
59 	PPPoint(29,6),
60 	PPPoint(33, 17),
61 	PPPoint(37,6),
62 	PPPoint(41, 17),
63 	PPPoint(45,6),
64 	PPPoint(49, 17)
65 };
66 
67 static const PPColor colors[] =
68 {
69 	PPColor(0,0,0),
70 	PPColor(255,255,255),
71 	PPColor(0,0,0),
72 	PPColor(255,255,255),
73 	PPColor(0,0,0),
74 	PPColor(0,0,0),
75 	PPColor(255,255,255),
76 	PPColor(0,0,0),
77 	PPColor(255,255,255),
78 	PPColor(0,0,0),
79 	PPColor(255,255,255),
80 	PPColor(0,0,0)
81 };
82 
XMAX()83 pp_int32 PianoControl::XMAX()
84 {
85 	return pianoBitmap->getBitmapWidth();
86 }
87 
YMAX()88 pp_int32 PianoControl::YMAX()
89 {
90 	return pianoBitmap->getBitmapHeight();
91 }
92 
KEYWIDTH()93 pp_int32 PianoControl::KEYWIDTH()
94 {
95 	return XMAX()/pianoBitmap->getBitmapLUTWidth();
96 }
97 
PianoControl(pp_int32 id,PPScreen * parentScreen,EventListenerInterface * eventListener,const PPPoint & location,const PPSize & size,pp_uint8 numNotes,bool border)98 PianoControl::PianoControl(pp_int32 id,
99 						   PPScreen* parentScreen,
100 						   EventListenerInterface* eventListener,
101 						   const PPPoint& location,
102 						   const PPSize& size,
103 						   pp_uint8 numNotes,
104 						   bool border/*= true*/) :
105 	PPControl(id, parentScreen, eventListener, location, size),
106 	border(border),
107 	NUMNOTES(numNotes),
108 	borderColor(&ourOwnBorderColor),
109 	mode(ModeEdit)
110 {
111 	// default color
112 	ourOwnBorderColor.set(192, 192, 192);
113 
114 	hScrollbar = new PPScrollbar(0, parentScreen, this, PPPoint(location.x, location.y + size.height - SCROLLBARWIDTH - 1), size.width - 1, true);
115 
116 #ifndef __LOWRES__
117 	xscale = 1;
118 	yscale = 1;
119 	pianoBitmap = PianoBitmapLarge::getInstance();
120 #else
121 	xscale = 2;
122 	yscale = 1;
123 	pianoBitmap = PianoBitmapSmall::getInstance();
124 #endif
125 
126 	xMax = XMAX()*xscale;
127 	yMax = YMAX()*yscale;
128 
129 	visibleWidth = size.width - 2;
130 	visibleHeight = size.height - SCROLLBARWIDTH - 2;
131 
132 	adjustScrollbars();
133 
134 	startPos = 0;
135 
136 	caughtControl = NULL;
137 	controlCaughtByLMouseButton = controlCaughtByRMouseButton = false;
138 
139 	nbu = new pp_uint8[NUMNOTES];
140 	memset(nbu, 0, NUMNOTES);
141 
142 	keyState = new KeyState[NUMNOTES];
143 
144 	sampleIndex = 0;
145 }
146 
~PianoControl()147 PianoControl::~PianoControl()
148 {
149 	delete hScrollbar;
150 
151 	delete[] nbu;
152 
153 	delete[] keyState;
154 }
155 
paint(PPGraphicsAbstract * g)156 void PianoControl::paint(PPGraphicsAbstract* g)
157 {
158 	if (!isVisible())
159 		return;
160 
161 	pp_int32 xOffset = 2;
162 
163 	pp_int32 yOffset = 2;
164 
165 	g->setRect(location.x, location.y, location.x + size.width, location.y + size.height);
166 
167 	if (border)
168 	{
169 		drawBorder(g, *borderColor);
170 	}
171 
172 	g->setRect(location.x + 1, location.y + 1, location.x + size.width - 2, location.y + size.height - 2);
173 
174 	pp_int32 width = visibleWidth;
175 
176 	pp_int32 adder = 65536/xscale;
177 
178 	pp_int32 oy = location.y + 1;
179 
180 	// for black piano keys
181 	PPColor colCorrect(TrackerConfig::colorThemeMain);
182 	colCorrect.r<<=1; colCorrect.g<<=1; colCorrect.b<<=1;
183 	// for white piano keys
184 	PPColor colCorrect2(TrackerConfig::colorThemeMain);
185 	colCorrect2.scale(1.5f, 1.5f, 1.6f);
186 	pp_int32 avg = (colCorrect2.b+colCorrect2.g+colCorrect2.r) / 3;
187 	PPColor colCorrect4(avg, avg, avg);
188 
189 	pp_int32 PIANO_LUT_WIDTH = pianoBitmap->getBitmapLUTWidth();
190 	const pp_uint8* PIANO_LUT = pianoBitmap->getBitmapLUT();
191 	const pp_uint8* PIANO = pianoBitmap->getBitmap();
192 
193 	const pp_int32* DIVLUT = pianoBitmap->getDIVLUT();
194 	const pp_int32* MODLUT = pianoBitmap->getMODLUT();
195 
196 	const pp_int32 XMAX = this->XMAX();
197 
198 	for (pp_int32 y = 0; y < visibleHeight; y++)
199 	{
200 		pp_int32 ry = y/yscale;
201 
202 		pp_int32 offset = (ry*XMAX+(startPos/xscale));
203 		pp_int32 ofs = 0;
204 
205 		const pp_uint8* src = PIANO_LUT + (ry*PIANO_LUT_WIDTH*3);
206 
207 		const pp_int32* divLutPtr = DIVLUT-ry*XMAX;
208 		const pp_int32* modLutPtr = MODLUT-ry*XMAX;
209 
210 		pp_int32 ox = location.x + 1;
211 		for (pp_int32 x = 0; x < width; x++)
212 		{
213 			pp_int32 sx = offset+(ofs>>16);
214 			pp_int32 px = modLutPtr[sx];
215 
216 			pp_int32 c = src[px];
217 			pp_int32 gr = src[px+1];
218 			pp_int32 b = src[px+2];
219 
220 			if (c == 255 && gr == 0 && b == 0)
221 			{
222 				g->setColor(PIANO[sx], PIANO[sx], PIANO[sx]);
223 			}
224 			else
225 			{
226 				// color values equal/above 240
227 				if (c >= 240) c-=240;
228 
229 				pp_int32 note = divLutPtr[sx] + c;
230 
231 				if (keyState[note].pressed)
232 				{
233 					if (keyState[note].muted)
234 					{
235 						if (colors[c].r)
236 							g->setSafeColor((PIANO[sx]+(colCorrect4.r>>2)), (PIANO[sx]+(colCorrect4.g>>2)), (PIANO[sx]+(colCorrect4.b>>2)));
237 						else
238 							g->setSafeColor((PIANO[sx]*colCorrect4.r)>>8, (PIANO[sx]*colCorrect4.g)>>8, (PIANO[sx]*colCorrect4.b)>>8);
239 					}
240 					else
241 					{
242 						if (colors[c].r)
243 							g->setSafeColor((PIANO[sx]+(colCorrect.r>>1)), (PIANO[sx]+(colCorrect.g>>1)), (PIANO[sx]+(colCorrect.b>>1)));
244 						else
245 							g->setSafeColor((PIANO[sx]*colCorrect2.r)>>8, (PIANO[sx]*colCorrect2.g)>>8, (PIANO[sx]*colCorrect2.b)>>8);
246 					}
247 				}
248 				else
249 					g->setColor(PIANO[sx], PIANO[sx], PIANO[sx]);
250 			}
251 			g->setPixel(ox, oy);
252 			ofs+=adder;
253 			ox++;
254 		}
255 		oy++;
256 	}
257 
258 	float newXScale = pianoBitmap->getBitmapWidth() / PianoBitmapSmall::getInstance()->getBitmapWidth();
259 	float newYScale = pianoBitmap->getBitmapHeight() / PianoBitmapSmall::getInstance()->getBitmapHeight();
260 
261 	if (mode == ModeEdit)
262 	{
263 		PPFont* font;
264 
265 		font = (xscale == 1 && pianoBitmap == PianoBitmapSmall::getInstance()) ?
266 			PPFont::getFont(PPFont::FONT_TINY) : PPFont::getFont(PPFont::FONT_SYSTEM);
267 
268 		g->setFont(font);
269 
270 		xOffset = 0;
271 		yOffset = -1;
272 		if (xscale > 1)
273 		{
274 			xOffset = 2;
275 		}
276 		else if (pianoBitmap == PianoBitmapLarge::getInstance())
277 		{
278 			xOffset = 1;
279 		}
280 
281 		if (yscale > 1)
282 		{
283 			yOffset = -2;
284 		}
285 		else if (pianoBitmap == PianoBitmapLarge::getInstance())
286 		{
287 			yOffset = 0;
288 		}
289 
290 		for (pp_int32 i = 0; i < NUMNOTES; i++)
291 		{
292 			pp_int32 posx = location.x + 1 + (i/12)*(PIANO_LUT_WIDTH*xscale) - startPos;
293 
294 			//if (blackKeys[i%12] && pianoBitmap == PianoBitmapLarge::getInstance())
295 			//	posx;
296 
297 			g->setColor(colors[i%12]);
298 
299 			char str[3] = "-";
300 
301 			if (nbu[i] != 255)
302 				PPTools::convertToHex(str, nbu[i], 1);
303 
304 			g->drawChar(str[0],
305 						(pp_int32)(posx + (positions[i%12].x*xscale + xOffset)*newXScale),
306 						(pp_int32)(location.y + 1 + (positions[i%12].y*yscale + yOffset)*newYScale));
307 		}
308 
309 	}
310 	else if (mode == ModePlay && (xscale >= 2 || pianoBitmap == PianoBitmapLarge::getInstance()))
311 	{
312 		PPFont* font = PPFont::getFont(PPFont::FONT_TINY);
313 
314 		g->setFont(font);
315 
316 		if (pianoBitmap == PianoBitmapLarge::getInstance())
317 		{
318 			xOffset = 1;
319 			yOffset = 0;
320 		}
321 		else
322 		{
323 			xOffset = 1;
324 			yOffset = -1;
325 		}
326 
327 		for (pp_int32 i = 0; i < NUMNOTES; i++)
328 		{
329 			pp_int32 posx = location.x + 1 + (i/12)*(PIANO_LUT_WIDTH*xscale) - startPos;
330 
331 			if (blackKeys[i%12] && pianoBitmap == PianoBitmapLarge::getInstance())
332 				posx--;
333 
334 			g->setColor(colors[i%12]);
335 
336 			char str[4]/* = "C#"*/;
337 			PatternTools::getNoteName(str, i+1);
338 			if (str[1] == '-')
339 			{
340 				str[1] = str[2];
341 				str[2] = '\0';
342 				xOffset = 0;
343 			}
344 			else
345 			{
346 				str[2] = '\0';
347 				xOffset = 1;
348 			}
349 
350 			pp_int32 correctx = (KEYWIDTH()*xscale) / 2 - font->getStrWidth(str) / 2 - 3;
351 			if (correctx < 0)
352 				correctx = 0;
353 
354 			xOffset += correctx;
355 
356 			g->drawString(str,
357 						  (pp_int32)(posx + (positions[i%12].x*xscale + xOffset)*newXScale),
358 						  (pp_int32)(location.y + 1 + (positions[i%12].y*yscale + yOffset)*newYScale));
359 		}
360 	}
361 
362 	hScrollbar->paint(g);
363 
364 }
365 
dispatchEvent(PPEvent * event)366 pp_int32 PianoControl::dispatchEvent(PPEvent* event)
367 {
368 	if (eventListener == NULL)
369 		return -1;
370 
371 	//if (!visible)
372 	//	return 0;
373 
374 	switch (event->getID())
375 	{
376 		case eRMouseDown:
377 		{
378 			PPPoint* p = (PPPoint*)event->getDataPtr();
379 
380 			if (hScrollbar->hit(*p))
381 			{
382 				if (controlCaughtByLMouseButton)
383 					break;
384 				controlCaughtByRMouseButton = true;
385 				caughtControl = hScrollbar;
386 				caughtControl->dispatchEvent(event);
387 			}
388 			break;
389 		}
390 
391 		case eLMouseDown:
392 		{
393 			PPPoint* p = (PPPoint*)event->getDataPtr();
394 
395 			// Clicked on horizontal scrollbar -> route event to scrollbar and catch scrollbar control
396 			if (hScrollbar->hit(*p))
397 			{
398 				if (controlCaughtByRMouseButton)
399 					break;
400 				controlCaughtByLMouseButton = true;
401 				caughtControl = hScrollbar;
402 				caughtControl->dispatchEvent(event);
403 			}
404 			// Clicked in client area
405 			else
406 			{
407 
408 				pp_int32 note = positionToNote(*p);
409 
410 				if (note != -1)
411 				{
412 
413 					switch (mode)
414 					{
415 						case ModeEdit:
416 						{
417 							nbu[note] = (pp_uint8)sampleIndex & 0xf;
418 							PPEvent e(eValueChanged, &nbu, sizeof(pp_uint8*));
419 							eventListener->handleEvent(reinterpret_cast<PPObject*>(this), &e);
420 							break;
421 						}
422 
423 						case ModePlay:
424 						{
425 							currentSelectedNote = note;
426 							PPEvent e(eSelection, &note, sizeof(note));
427 							eventListener->handleEvent(reinterpret_cast<PPObject*>(this), &e);
428 							break;
429 						}
430 					}
431 
432 					parentScreen->paintControl(this);
433 				}
434 			}
435 
436 			break;
437 		}
438 
439 		case eRMouseUp:
440 		{
441 			controlCaughtByRMouseButton = false;
442 			if (caughtControl && !controlCaughtByLMouseButton && !controlCaughtByRMouseButton)
443 			{
444 				caughtControl->dispatchEvent(event);
445 				caughtControl = NULL;
446 				break;
447 			}
448 			break;
449 		}
450 
451 		case eLMouseUp:
452 			if (caughtControl == NULL)
453 			{
454 				pp_int32 note = currentSelectedNote;
455 
456 				if (note != -1)
457 				{
458 
459 					switch (mode)
460 					{
461 						case ModePlay:
462 						{
463 							pp_int32 v = (1 << 16) + currentSelectedNote;
464 							PPEvent e(eSelection, &v, sizeof(v));
465 							eventListener->handleEvent(reinterpret_cast<PPObject*>(this), &e);
466 							break;
467 						}
468 						case ModeEdit:
469 							break;
470 					}
471 
472 					parentScreen->paintControl(this);
473 				}
474 				break;
475 			}
476 
477 			controlCaughtByLMouseButton = false;
478 			if (!controlCaughtByLMouseButton && !controlCaughtByRMouseButton)
479 			{
480 				caughtControl->dispatchEvent(event);
481 				caughtControl = NULL;
482 			}
483 			break;
484 
485 		case eLMouseDrag:
486 		{
487 			if (caughtControl && controlCaughtByLMouseButton)
488 			{
489 				caughtControl->dispatchEvent(event);
490 				break;
491 			}
492 
493 			//positionToNote(*(PPPoint*)event->getDataPtr());
494 
495 			//parentScreen->paintControl(this);
496 
497 			pp_int32 note = positionToNote(*(PPPoint*)event->getDataPtr());
498 
499 			if (note != -1)
500 			{
501 
502 				switch (mode)
503 				{
504 					case ModeEdit:
505 					{
506 						nbu[note] = (pp_uint8)sampleIndex & 0xf;
507 
508 						PPEvent e(eValueChanged, &nbu, sizeof(pp_uint8*));
509 
510 						eventListener->handleEvent(reinterpret_cast<PPObject*>(this), &e);
511 						break;
512 					}
513 
514 					case ModePlay:
515 					{
516 						if (note == currentSelectedNote)
517 							break;
518 
519 						pp_int32 v = (1 << 16) + currentSelectedNote;
520 						PPEvent e(eSelection, &v, sizeof(v));
521 						eventListener->handleEvent(reinterpret_cast<PPObject*>(this), &e);
522 
523 						currentSelectedNote = note;
524 						PPEvent e2(eSelection, &note, sizeof(note));
525 						eventListener->handleEvent(reinterpret_cast<PPObject*>(this), &e2);
526 						break;
527 					}
528 				}
529 
530 				parentScreen->paintControl(this);
531 			}
532 
533 			break;
534 		}
535 
536 		case eRMouseDrag:
537 		{
538 			if (caughtControl && controlCaughtByRMouseButton)
539 				caughtControl->dispatchEvent(event);
540 			break;
541 		}
542 
543 		case eRMouseRepeat:
544 		{
545 			if (caughtControl && controlCaughtByRMouseButton)
546 				caughtControl->dispatchEvent(event);
547 			break;
548 		}
549 
550 		case eMouseWheelMoved:
551 		{
552 			TMouseWheelEventParams* params = (TMouseWheelEventParams*)event->getDataPtr();
553 
554 			if ((params->deltaX > 0 || params->deltaY < 0) && hScrollbar)
555 			{
556 				PPEvent e(eBarScrollDown);
557 				handleEvent(reinterpret_cast<PPObject*>(hScrollbar), &e);
558 			}
559 			else if ((params->deltaX < 0 || params->deltaY > 0) && hScrollbar)
560 			{
561 				PPEvent e(eBarScrollUp);
562 				handleEvent(reinterpret_cast<PPObject*>(hScrollbar), &e);
563 			}
564 
565 			event->cancel();
566 
567 			break;
568 		}
569 
570 		default:
571 			if (caughtControl == NULL)
572 				break;
573 
574 			caughtControl->dispatchEvent(event);
575 			break;
576 
577 	}
578 
579 	return 0;
580 }
581 
handleEvent(PPObject * sender,PPEvent * event)582 pp_int32 PianoControl::handleEvent(PPObject* sender, PPEvent* event)
583 {
584 	// Horizontal scrollbar, scroll up (=left)
585 	if (sender == reinterpret_cast<PPObject*>(hScrollbar) &&
586 			 event->getID() == eBarScrollUp)
587 	{
588 		startPos-=KEYWIDTH()*xscale;
589 		if (startPos < 0)
590 			startPos = 0;
591 
592 		pp_int32 visibleItems = visibleWidth;
593 
594 		float v = (float)(getMaxWidth() - visibleItems);
595 
596 		hScrollbar->setBarPosition((pp_int32)(startPos*(65536.0f/v)));
597 	}
598 	// Horizontal scrollbar, scroll down (=right)
599 	else if (sender == reinterpret_cast<PPObject*>(hScrollbar) &&
600 			 event->getID() == eBarScrollDown)
601 	{
602 		pp_int32 visibleItems = visibleWidth;
603 
604 		startPos+=KEYWIDTH()*xscale;
605 		if (startPos + visibleItems >= (signed)getMaxWidth())
606 			startPos = getMaxWidth() - visibleItems;
607 
608 		float v = (float)(getMaxWidth() - visibleItems);
609 
610 		hScrollbar->setBarPosition((pp_int32)(startPos*(65536.0f/v)));
611 	}
612 	// Horizontal scrollbar, position changed
613 	else if (sender == reinterpret_cast<PPObject*>(hScrollbar) &&
614 			 event->getID() == eBarPosChanged)
615 	{
616 
617 		float pos = hScrollbar->getBarPosition()/65536.0f;
618 
619 		pp_int32 visibleItems = visibleWidth;
620 
621 		float v = (float)(getMaxWidth() - visibleItems);
622 
623 		startPos = (pp_uint32)(v*pos);
624 	}
625 
626 	parentScreen->paintControl(this);
627 
628 	return 0;
629 }
630 
getMaxWidth()631 pp_int32 PianoControl::getMaxWidth()
632 {
633 	return XMAX()*xscale;
634 }
635 
adjustScrollbars()636 void PianoControl::adjustScrollbars()
637 {
638 	float s = (float)visibleWidth / (float)getMaxWidth();
639 
640 	float olds = hScrollbar->getBarSize() / 65536.0f;
641 
642 	hScrollbar->setBarSize((pp_int32)(s*65536.0f), false);
643 
644 	s = hScrollbar->getBarSize() / 65536.0f;
645 
646 	float scale = s / olds;
647 
648 	float pos = hScrollbar->getBarPosition()/65536.0f;
649 	hScrollbar->setBarPosition((pp_int32)(pos*scale*65536.0f));
650 
651 	pos = hScrollbar->getBarPosition()/65536.0f;
652 
653 	pp_int32 visibleItems = visibleWidth;
654 
655 	float v = (float)(getMaxWidth() - visibleItems);
656 
657 	startPos = (pp_uint32)(v*pos);
658 
659 	if (startPos < 0)
660 	{
661 		startPos = 0;
662 	}
663 
664 		//pp_int32 entireSize = (horizontal?this->size.width:this->size.height) - SCROLLBUTTONSIZE*2;
665 }
666 
setxScale(pp_int32 scale)667 void PianoControl::setxScale(pp_int32 scale)
668 {
669 	xscale = scale;
670 	adjustScrollbars();
671 	assureNoteVisible(4*12);
672 }
673 
setyScale(pp_int32 scale)674 void PianoControl::setyScale(pp_int32 scale)
675 {
676 	yscale = scale;
677 }
678 
setLocation(const PPPoint & location)679 void PianoControl::setLocation(const PPPoint& location)
680 {
681 	PPControl::setLocation(location);
682 
683 	pp_int32 p = hScrollbar->getBarPosition();
684 	pp_int32 s = hScrollbar->getBarSize();
685 	delete hScrollbar;
686 	hScrollbar = new PPScrollbar(0, parentScreen, this, PPPoint(location.x, location.y + size.height - SCROLLBARWIDTH - 1), size.width - 1, true);
687 	hScrollbar->setBarSize(s);
688 	hScrollbar->setBarPosition(p);
689 }
690 
setSize(const PPSize & size)691 void PianoControl::setSize(const PPSize& size)
692 {
693 	PPControl::setSize(size);
694 	delete hScrollbar;
695 
696 	hScrollbar = new PPScrollbar(0, parentScreen, this, PPPoint(location.x, location.y + size.height - SCROLLBARWIDTH - 1), size.width - 1, true);
697 
698 	visibleWidth = size.width - 2;
699 	visibleHeight = size.height - SCROLLBARWIDTH - 2;
700 
701 	adjustScrollbars();
702 	assureNoteVisible(4*12);
703 }
704 
setSampleTable(const pp_uint8 * nbu)705 void PianoControl::setSampleTable(const pp_uint8* nbu)
706 {
707 	if (nbu == NULL)
708 	{
709 		memset(this->nbu, 0, NUMNOTES);
710 		return;
711 	}
712 
713 	memcpy(this->nbu, nbu, NUMNOTES);
714 }
715 
pressNote(pp_int32 note,bool pressed,bool muted)716 void PianoControl::pressNote(pp_int32 note, bool pressed, bool muted/* = false*/)
717 {
718 	if (note >= 0 && note < NUMNOTES)
719 	{
720 		keyState[note].pressed = pressed;
721 		keyState[note].muted = muted;
722 	}
723 }
724 
getNoteState(pp_int32 note) const725 bool PianoControl::getNoteState(pp_int32 note) const
726 {
727 	if (note >= 0 && note < NUMNOTES)
728 		return keyState[note].pressed;
729 	return false;
730 }
731 
assureNoteVisible(pp_int32 note)732 void PianoControl::assureNoteVisible(pp_int32 note)
733 {
734 	pp_int32 PIANO_LUT_WIDTH = pianoBitmap->getBitmapLUTWidth();
735 
736 	pp_int32 startPos = (PIANO_LUT_WIDTH*(note/12)+positions[note%12].x)*xscale;
737 	float v = (float)(getMaxWidth() - visibleWidth);
738 	hScrollbar->setBarPosition((pp_int32)(startPos*(65536.0f/v)));
739 	float pos = hScrollbar->getBarPosition()/65536.0f;
740 	startPos = (pp_uint32)(v*pos);
741 	this->startPos = startPos;
742 }
743 
positionToNote(PPPoint cp)744 pp_int32 PianoControl::positionToNote(PPPoint cp)
745 {
746 
747 	if (sampleIndex < 0)
748 		return -1;
749 
750 	cp.x -= location.x + 1;
751 	cp.y -= location.y + 1;
752 
753 	if (cp.x < 0 || cp.x >= visibleWidth || cp.y < 0 || cp.y >= visibleHeight)
754 		return -1;
755 
756 	pp_int32 PIANO_LUT_WIDTH = pianoBitmap->getBitmapLUTWidth();
757 	const pp_uint8* PIANO_LUT = pianoBitmap->getBitmapLUT();
758 
759 	cp.x/=xscale;
760 	cp.y/=yscale;
761 
762 	cp.x+=startPos/xscale;
763 
764 	pp_int32 octave = cp.x / PIANO_LUT_WIDTH;
765 	pp_int32 ox = cp.x % PIANO_LUT_WIDTH;
766 
767 	pp_int32 c = PIANO_LUT[(cp.y * PIANO_LUT_WIDTH + ox)*3];
768 	pp_int32 g = PIANO_LUT[(cp.y * PIANO_LUT_WIDTH + ox)*3+1];
769 	pp_int32 b = PIANO_LUT[(cp.y * PIANO_LUT_WIDTH + ox)*3+2];
770 
771 	if (c == 255 && g == 0 && b == 0)
772 		return -1;
773 
774 	// color values equal/above 240
775 	if (c >= 240) c-=240;
776 
777 	pp_int32 note = octave*12 + c;
778 
779 	if (note < 0 || note >= NUMNOTES)
780 		return -1;
781 
782 	return note;
783 }
784