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