1 
2 /*
3  *  Diverse Bristol audio routines.
4  *  Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5  *
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 3 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 /*
22  * This will be a linear drawbar. Takes a bitmap and locates it according to
23  * input from the mouse/keyboard. Previous positions need to be unmapped, since
24  * there is total repositioning of the image bitmap.
25  */
26 
27 #include "brightoninternals.h"
28 
29 int
destroyHammond(brightonDevice * dev)30 destroyHammond(brightonDevice *dev)
31 {
32 	printf("destroyHammond()\n");
33 
34 	if (dev->image)
35 		brightonFreeBitmap(dev->bwin, dev->image);
36 	dev->image = NULL;
37 
38 	return(0);
39 }
40 
41 static int
displayhammond(brightonDevice * dev)42 displayhammond(brightonDevice *dev)
43 {
44 	brightonIResource *panel;
45 	float displayvalue;
46 
47 	if (dev->bwin->app->resources[dev->panel].flags & BRIGHTON_WITHDRAWN)
48 		return(0);
49 
50 	if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
51 		& BRIGHTON_WITHDRAWN)
52 		return(0);
53 
54 	panel = &dev->bwin->app->resources[dev->panel];
55 
56 	/*
57 	 * Build up a smooth position for the bar. We may need to adjust this based
58 	 * on the to/from values.
59 	 */
60 
61 	if (dev->value == dev->lastvalue)
62 		return(0);
63 
64 	displayvalue = dev->value;
65 
66 /*
67 	brightonFinalRender(dev->bwin,
68 		dev->x + dev->bwin->app->resources[dev->panel].sx,
69 		dev->y + dev->lastposition + dev->bwin->app->resources[dev->panel].sy,
70 		dev->width, dev->height / 4);
71 */
72 
73 	/*
74 	 * This seems odd, the vertical flag refers to the scrolled item, not the
75 	 * direction of movement. Perhaps that should change as the direction of
76 	 * movement is counterintuitive
77 	 */
78 	if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
79 		& BRIGHTON_VERTICAL)
80 	{
81 		if (dev->lastposition >= 0)
82 		{
83 			brightonDevUndraw(dev->bwin, dev->bwin->dlayer,
84 				dev->x + ((int) dev->lastposition)
85 					+ dev->bwin->app->resources[dev->panel].sx,
86 				dev->y + dev->bwin->app->resources[dev->panel].sy,
87 				dev->width / 8, dev->height);
88 			brightonRenderShadow(dev, 1);
89 		}
90 
91 		dev->position = displayvalue * (dev->width - dev->width / 4);
92 
93 		/*
94 		 * Only draw fixed number of steps. Panned. Just draw it.....
95 		 */
96 		brightonStretch(dev->bwin, dev->image,
97 			dev->bwin->dlayer,
98 			(int)(dev->x + dev->position
99 				+ dev->bwin->app->resources[dev->panel].sx),
100 			dev->y + dev->bwin->app->resources[dev->panel].sy,
101 			dev->width / 8, dev->height, 1);
102 
103 		brightonRenderShadow(dev, 0);
104 
105 		/*
106 		 * And request the panel to put this onto the respective image.
107 		 */
108 		if (dev->position > dev->lastposition)
109 		{
110 			brightonFinalRender(dev->bwin,
111 				dev->x + dev->lastposition
112 					+ dev->bwin->app->resources[dev->panel].sx,
113 				dev->y + dev->bwin->app->resources[dev->panel].sy,
114 				dev->width * 2,
115 				dev->position - dev->lastposition + (dev->width >> 2)
116 					+ (dev->height >> 1));
117 		} else {
118 			brightonFinalRender(dev->bwin,
119 				dev->x + dev->position
120 					+ dev->bwin->app->resources[dev->panel].sx,
121 				dev->y + dev->bwin->app->resources[dev->panel].sy,
122 				dev->width * 2 + 1,
123 				dev->lastposition - dev->position + (dev->width >> 2)
124 					+ (dev->height >> 1));
125 		}
126 	} else {
127 		if (dev->lastposition >= 0)
128 		{
129 			brightonDevUndraw(dev->bwin, dev->bwin->dlayer,
130 				dev->x + dev->bwin->app->resources[dev->panel].sx,
131 				dev->y + ((int) dev->lastposition)
132 					+ dev->bwin->app->resources[dev->panel].sy,
133 				dev->width, dev->height / 4);
134 			brightonRenderShadow(dev, 1);
135 		}
136 
137 		dev->position = displayvalue * (dev->height - dev->height / 4);
138 
139 		/*
140 		 * Drawbars are only ever rendered vertically.
141 		 */
142 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
143 			& BRIGHTON_HSCALE)
144 		{
145 			brightonBitmap image2;
146 
147 			brightonDevUndraw(dev->bwin, dev->bwin->dlayer,
148 				dev->x + dev->bwin->app->resources[dev->panel].sx,
149 				dev->y + dev->bwin->app->resources[dev->panel].sy,
150 				dev->width, dev->height);
151 
152 			/*
153 			 * For the Hammond scale we need a different transform. The bitmap
154 			 * wants to be stretched onto the destination, but only part of it
155 			 * depending on the current value.
156 			 *
157 			 * We have to dynamically rebuild the bitmap as well so that we
158 			 * get it to move rather than just be placed.
159 			 */
160 			image2.flags = dev->image2->flags;
161 			image2.width = dev->image2->width;
162 			image2.ncolors = dev->image2->ncolors;
163 			image2.ctabsize = dev->image2->ctabsize;
164 			image2.istatic = dev->image2->istatic;
165 			image2.ostatic = dev->image2->ostatic;
166 			image2.colormap = dev->image2->colormap;
167 			image2.name = dev->image2->name;
168 
169 			image2.height = (((float) dev->image2->height) * displayvalue);
170 			image2.pixels = &dev->image2->pixels[
171 				dev->image2->height * image2.width
172 				- image2.height * image2.width];
173 
174 			if (image2.height != 0)
175 				brightonStretch(dev->bwin, &image2,
176 					dev->bwin->dlayer,
177 					(int) (dev->x + dev->bwin->app->resources[dev->panel].sx),
178 					(int) (dev->y + dev->bwin->app->resources[dev->panel].sy),
179 					dev->width, (int) dev->position, 0);
180 
181 			brightonFinalRender(dev->bwin,
182 				dev->x + dev->bwin->app->resources[dev->panel].sx,
183 				dev->y + dev->bwin->app->resources[dev->panel].sy,
184 				dev->width, (int) dev->height);
185 		}
186 
187 		/*
188 		 * Only draw fixed number of steps. Panned. Just draw it.....
189 		 */
190 		brightonStretch(dev->bwin, dev->image,
191 			dev->bwin->dlayer,
192 			dev->x + dev->bwin->app->resources[dev->panel].sx,
193 			(int)(dev->y + dev->position
194 				+ dev->bwin->app->resources[dev->panel].sy),
195 			dev->width, dev->height / 4, 0);
196 
197 		brightonRenderShadow(dev, 0);
198 
199 		/*
200 		 * And request the panel to put this onto the respective image.
201 		 */
202 		if (dev->position > dev->lastposition)
203 		{
204 			brightonFinalRender(dev->bwin,
205 				dev->x + dev->bwin->app->resources[dev->panel].sx,
206 				dev->y + dev->lastposition
207 					+ dev->bwin->app->resources[dev->panel].sy,
208 				dev->width * 2,
209 				dev->position - dev->lastposition + (dev->height >> 2)
210 					+ (dev->width >> 1));
211 		} else {
212 			brightonFinalRender(dev->bwin,
213 				dev->x + dev->bwin->app->resources[dev->panel].sx,
214 				dev->y + dev->position
215 					+ dev->bwin->app->resources[dev->panel].sy,
216 				dev->width * 2,
217 				dev->lastposition - dev->position + (dev->height >> 2) + 1
218 					+ (dev->width >> 1));
219 		}
220 	}
221 
222 	dev->lastvalue = dev->value;
223 	dev->lastposition = dev->position;
224 
225 	return(0);
226 }
227 
228 static int
considercallback(brightonDevice * dev)229 considercallback(brightonDevice *dev)
230 {
231 	brightonIResource *panel = &dev->bwin->app->resources[dev->panel];
232 	float callvalue;
233 
234 	if (dev->bwin->flags & BRIGHTON_NO_DRAW)
235 		return(0);
236 
237 	if (dev->value > 1.0)
238 		dev->value = 1.0;
239 	else if (dev->value < 0)
240 		dev->value = 0.0;
241 
242 	/*
243 	 * Due to the co-ordinate system, if we do NOT have the reverse flags
244 	 * then we need to reverse the value.
245 	 */
246 	if ((dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
247 		& BRIGHTON_REVERSE) == 0)
248 		callvalue = 1.0 - dev->value;
249 	else
250 		callvalue = dev->value;
251 
252 	if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].to != 1.0)
253 	{
254 		callvalue =
255 			(callvalue
256 			* dev->bwin->app->resources[dev->panel].devlocn[dev->index].to);
257 
258 		if ((callvalue - ((int) callvalue)) > 0.5)
259 			callvalue = ((float) ((int) callvalue) + 1);
260 		else
261 			callvalue = ((float) ((int) callvalue));
262 	}
263 
264 	if (dev->lastvalue != dev->value)
265 	{
266 		if (panel->devlocn[dev->index].callback)
267 		{
268 			panel->devlocn[dev->index].callback(dev->bwin, dev->panel,
269 				dev->index, callvalue);
270 		} else {
271 			if (panel->callback)
272 				panel->callback(dev->bwin, dev->panel, dev->index, callvalue);
273 		}
274 	}
275 	return(0);
276 }
277 
278 static int cx, cy;
279 static float sval;
280 
281 static int
configure(brightonDevice * dev,brightonEvent * event)282 configure(brightonDevice *dev, brightonEvent *event)
283 {
284 /*	printf("configureHammond(%i, %f)\n", event->command, event->value); */
285 
286 	if (event->command == -1)
287 		return(-1);
288 
289 	if (event->command == BRIGHTON_RESIZE)
290 	{
291 		dev->originx = event->x;
292 		dev->originy = event->y;
293 
294 		dev->x = event->x;
295 		dev->y = event->y;
296 		dev->width = event->w;
297 		dev->height = event->h;
298 
299 		/*
300 		 * We should now rework our parent understanding of our window, since
301 		 * it will have altered. NOT NECESSARY FOR SCALE.
302 		brightonPanelLocation(dev->bwin,
303 			dev->panel, dev->index, dev->x, dev->y, dev->width, dev->height);
304 
305 		considercallback(dev);
306 		 */
307 
308 		/*
309 		 * Highlights need to be rendered dynamically in displayhammond().
310 		 */
311 
312 		dev->lastvalue = -1;
313 		displayhammond(dev);
314 
315 		return(0);
316 	}
317 
318 	if (event->command == BRIGHTON_KEYRELEASE)
319 	{
320 		/*
321 		 * This is a little bit 'happens they work'. We should fix these key
322 		 * mappings for keycodes.
323 		 */
324 		switch(event->key) {
325 			default:
326 				break;
327 			case 37:
328 			case 109:
329 			case 65508:
330 			case 65507:
331 				dev->flags &= ~BRIGHTON_CONTROLKEY;
332 				cx = cy = sval = -1;
333 				break;
334 			case 50:
335 			case 62:
336 			case 65505:
337 				dev->flags &= ~BRIGHTON_SHIFTKEY;
338 				break;
339 		}
340 	}
341 
342 	if (event->command == BRIGHTON_BUTTONPRESS)
343 	{
344 		/*
345 		 * This is hard coded, it calls back to the GUI. This is incorrect as
346 		 * the callback dispatcher should be requested by the GUI.
347 		 *
348 		 * Perhaps the MIDI code should actually be in the same library? Why
349 		 * does the GUI need to know about this?
350 		 */
351 		if (event->key == BRIGHTON_BUTTON2)
352 			brightonRegisterController(dev);
353 
354 		return(0);
355 	}
356 
357 	if (event->command == BRIGHTON_BUTTONRELEASE)
358 	{
359 		cx = cy = sval = -1;
360 		dev->flags &= ~BRIGHTON_CONTROLKEY;
361 
362 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
363 			& BRIGHTON_CENTER)
364 		{
365 			dev->value = 0.5;
366 
367 			considercallback(dev);
368 
369 			displayhammond(dev);
370 		}
371 
372 		return(0);
373 	}
374 
375 	if (event->command == BRIGHTON_KEYPRESS)
376 	{
377 		switch(event->key) {
378 			default:
379 				break;
380 			case 37:
381 			case 109:
382 			case 65508:
383 			case 65507:
384 				cx = event->x;
385 				cy = event->y;
386 				sval = dev->value;
387 				dev->flags |= BRIGHTON_CONTROLKEY;
388 				break;
389 			case 50:
390 			case 62:
391 			case 65505:
392 				dev->flags |= BRIGHTON_SHIFTKEY;
393 				break;
394 			case 0x6a:
395 			case 0xff54:
396 				if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_VERTICAL)
397 				{
398 					if (dev->flags & BRIGHTON_SHIFTKEY)
399 						dev->value -= ((float) 256) / 16384;
400 					else
401 						dev->value -= ((float) 1) / 16384;
402 				} else {
403 					if (dev->flags & BRIGHTON_SHIFTKEY)
404 						dev->value += ((float) 256) / 16384;
405 					else
406 						dev->value += ((float) 1) / 16384;
407 				}
408 				break;
409 			case 0x6b:
410 			case 0xff52:
411 				/*if (dev->flags & BRIGHTON_VERTICAL) */
412 				if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_VERTICAL)
413 				{
414 					if (dev->flags & BRIGHTON_SHIFTKEY)
415 						dev->value += ((float) 256) / 16384;
416 					else
417 						dev->value += ((float) 1) / 16384;
418 				} else {
419 					if (dev->flags & BRIGHTON_SHIFTKEY)
420 						dev->value -= ((float) 256) / 16384;
421 					else
422 						dev->value -= ((float) 1) / 16384;
423 				}
424 				break;
425 		}
426 
427 		considercallback(dev);
428 
429 		displayhammond(dev);
430 	}
431 
432 	if (event->command == BRIGHTON_MOTION)
433 	{
434 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
435 			& BRIGHTON_VERTICAL)
436 	 	{
437 			/*
438 			 * Need to add in an optional central dead spot. This should be a
439 			 * small fraction of either side of the bar. It will be where
440 			 * position deviates from mouse location.
441 			if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
442 				& BRIGHTON_NOTCH)
443 			{
444 			} else
445 			 */
446 			if (dev->flags & BRIGHTON_CONTROLKEY)
447 			{
448 				float deltax;
449 
450 				if (cx == -1)
451 				{
452 					sval = dev->value;
453 					cx = event->x;
454 					cy = event->y;
455 				}
456 
457 				deltax = ((float) (event->x - cx)) / 16383.0f;
458 
459 				dev->value = sval + deltax;
460 			} else if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_NOTCH)
461 			{
462 				/*
463 				 * When we are passing zero we should hold for a bit.
464 				 */
465 				dev->value = (((float) (event->x + 5 - dev->x - (dev->width / 8)))
466 					/ (dev->width - dev->width / 4));
467 
468 				if (dev->value > 0.6)
469 					dev->value -= 0.1;
470 				else if (dev->value < 0.4)
471 					dev->value += 0.1;
472 				else
473 					dev->value = 0.5;
474 			} else
475 				dev->value = (((float) (event->x + 5 - dev->x - (dev->width / 8)))
476 					/ (dev->width - dev->width / 4));
477 		} else {
478 			if (dev->flags & BRIGHTON_CONTROLKEY)
479 			{
480 				float deltax;
481 
482 				if (cx == -1)
483 				{
484 					sval = dev->value;
485 					cx = event->x;
486 					cy = event->y;
487 				}
488 
489 				deltax = ((float) (event->y - cy)) / 16383.0f;
490 
491 				dev->value = sval + deltax;
492 			} else if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags & BRIGHTON_NOTCH)
493 			{
494 				dev->value = (((float) (event->y - dev->y - (dev->height / 8)))
495 					/ (dev->height - dev->height / 4));
496 
497 				if (dev->value > 0.6)
498 					dev->value -= 0.1;
499 				else if (dev->value < 0.4)
500 					dev->value += 0.1;
501 				else
502 					dev->value = 0.5;
503 			} else
504 				dev->value = (((float) (event->y - dev->y - (dev->height / 8)))
505 					/ (dev->height - dev->height / 4));
506 		}
507 
508 /*printf("hammond motion %i %i, %i %i, %i %i: %f\n", */
509 /*event->x, event->y, dev->x, dev->y, dev->width, dev->height, dev->value); */
510 
511 		/*
512 		 * We now need to consider rounding this to the resolution of this
513 		 * device. If the max value is not 1.0 then we need to put fixed steps
514 		 * into our new device value.
515 		 */
516 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].to != 1.0)
517 		{
518 			dev->value = (float) ((int)
519 				(dev->value
520 				* dev->bwin->app->resources[dev->panel].devlocn[dev->index].to))
521 				/ dev->bwin->app->resources[dev->panel].devlocn[dev->index].to;
522 		}
523 
524 		considercallback(dev);
525 
526 		displayhammond(dev);
527 
528 		return(0);
529 	}
530 
531 	if (event->command == BRIGHTON_PARAMCHANGE)
532 	{
533 		if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].flags
534 			& BRIGHTON_REVERSE)
535 			dev->value = event->value
536 				/ dev->bwin->app->resources[dev->panel].devlocn[dev->index].to;
537 		else {
538 			if (dev->bwin->app->resources[dev->panel].devlocn[dev->index].to
539 				!= 1.0)
540 			{
541 				dev->value =
542 					(dev->bwin->app->resources[dev->panel].devlocn[dev->index].to - event->value)
543 				/ dev->bwin->app->resources[dev->panel].devlocn[dev->index].to;
544 			} else {
545 				dev->value = (1.0 - event->value) /
546 					dev->bwin->app->resources[dev->panel].devlocn[dev->index].to;
547 			}
548 		}
549 
550 		considercallback(dev);
551 
552 		displayhammond(dev);
553 
554 		return(0);
555 	}
556 	return(0);
557 }
558 
559 int *
createHammond(brightonWindow * bwin,brightonDevice * dev,int index,char * bitmap)560 createHammond(brightonWindow *bwin, brightonDevice *dev, int index, char *bitmap)
561 {
562 /*	printf("createHammond(%s)\n", bitmap); */
563 
564 	dev->destroy = destroyHammond;
565 	dev->configure = configure;
566 	dev->index = index;
567 
568 	dev->bwin = bwin;
569 
570 	if (bitmap == 0)
571 	{
572 		if (dev->image)
573 			brightonFreeBitmap(bwin, dev->image);
574 		/*
575 		 * Open the default bitmap
576 		 */
577 		if (bwin->app->resources[dev->panel].devlocn[dev->index].image != 0)
578 			dev->image =
579 				bwin->app->resources[dev->panel].devlocn[dev->index].image;
580 		else
581 			dev->image = brightonReadImage(bwin, "bitmaps/knobs/slider1.xpm");
582 	} else {
583 		if (dev->image)
584 			brightonFreeBitmap(bwin, dev->image);
585 		dev->image = brightonReadImage(bwin, bitmap);
586 	}
587 
588 	if (bwin->app->resources[dev->panel].devlocn[dev->index].flags &
589 		BRIGHTON_HSCALE)
590 	{
591 		if (dev->image2)
592 			brightonFreeBitmap(bwin, dev->image2);
593 		dev->image2 = brightonReadImage(bwin, "bitmaps/knobs/hammondbar.xpm");
594 	}
595 
596 	/*
597 	 * These will force an update when we first display ourselves.
598 	 */
599 	if (bwin->app->resources[dev->panel].devlocn[dev->index].flags
600 		& BRIGHTON_CENTER)
601 		dev->value = 0.5;
602 	else
603 		dev->value = 0;
604 
605 	dev->value = 0.500001;
606 
607 	dev->lastvalue = -1;
608 	dev->lastposition = 0;
609 
610 	return(0);
611 }
612 
613