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
23 #include <fcntl.h>
24
25 #include "brighton.h"
26 #include "brightonMini.h"
27 #include "brightoninternals.h"
28
29 static int rBassInit();
30 static int rBassConfigure();
31 static int rBassCallback(brightonWindow *, int, int, float);
32 static int rBassMidiCallback(brightonWindow *, int, int, float);
33
34 extern guimain global;
35
36 #include "brightonKeys.h"
37
38 #define OPTS_PANEL 0
39 #define MOD_PANEL 1
40 #define MEM_PANEL 2
41 #define KEY_PANEL 3
42
43 #define FIRST_DEV 0
44
45 #define MOD_COUNT 2
46 #define OPTS_COUNT 8
47 #define MEM_COUNT 17
48
49 #define OPTS_START 0
50 #define MOD_START OPTS_COUNT
51 #define MEM_START (MOD_COUNT + MOD_START)
52
53 #define ACTIVE_DEVS (OPTS_COUNT + MOD_COUNT - 1)
54 #define DEVICE_COUNT (MOD_COUNT + OPTS_COUNT + MEM_COUNT)
55 #define DISPLAY_DEV (MEM_COUNT - 1)
56 #define MEM_MGT ACTIVE_DEVS
57
58 #define MIDI_MGT (MEM_MGT + 12)
59
60 extern int memCallback(brightonWindow * , int, int, float);
61 extern brightonLocations mem[];
62
63 /*
64 * This structure is for device definition. The structure is defined in
65 * include/brighton.h, further definitions in brighton/brightonDevtable.h and
66 * include/brightoninternals.h
67 *
68 * typedef int (*brightonCallback)(int, float);
69 * typedef struct BrightonLocations {
70 * int device; 0=rotary, 1=scale, etc.
71 * float relx, rely; relative position with regards to 1000 by 1000 window
72 * float relw, relh; relative height.
73 * int from, to;
74 * brightonCallback callback; specific to this dev
75 * char *image; bitmap. If zero take a device default.
76 * int flags;
77 * } brightonLocations;
78 *
79 * This example is for a rBassBristol type synth interface.
80 */
81
82 #define R1 0
83
84 #define W1 100
85 #define L1 600
86
87 #define C1 40
88 #define C2 190
89 #define C3 340
90 #define C4 490
91 #define C5 700
92 #define C6 850
93
94 static brightonLocations locations[MOD_COUNT] = {
95 {"Bass", 0, 50, 100, 400, 700, 0, 1, 0, 0, 0, 0},
96 {"Volume", 0, 125, 100, 400, 700, 0, 1, 0, 0, 0, 0},
97 /* {"", 2, 50, 200, 30, 400, 0, 1, 0, */
98 /* "bitmaps/buttons/rockerwhite.xpm", 0, 0}, */
99 };
100
101 #define S1 200
102
103 /* Options should only be a few piano selectors, no programmers. */
104 static brightonLocations options[OPTS_COUNT] = {
105 {"", 2, 100, 500, 50, 200, 0, 1, 0,
106 "bitmaps/buttons/pressoff.xpm", "bitmaps/buttons/presson.xpm", 0},
107 {"", 2, 200, 500, 50, 200, 0, 1, 0,
108 "bitmaps/buttons/pressoff.xpm", "bitmaps/buttons/presson.xpm", 0},
109 {"", 2, 300, 500, 50, 200, 0, 1, 0,
110 "bitmaps/buttons/pressoff.xpm", "bitmaps/buttons/presson.xpm", 0},
111 {"", 2, 400, 500, 50, 200, 0, 1, 0,
112 "bitmaps/buttons/pressoff.xpm", "bitmaps/buttons/presson.xpm", 0},
113 {"", 2, 500, 500, 50, 200, 0, 1, 0,
114 "bitmaps/buttons/pressoff.xpm", "bitmaps/buttons/presson.xpm", 0},
115 {"", 2, 600, 500, 50, 200, 0, 1, 0,
116 "bitmaps/buttons/pressoff.xpm", "bitmaps/buttons/presson.xpm", 0},
117 {"", 2, 700, 500, 50, 200, 0, 1, 0,
118 "bitmaps/buttons/pressoff.xpm", "bitmaps/buttons/presson.xpm", 0},
119 {"", 2, 800, 500, 50, 200, 0, 1, 0,
120 "bitmaps/buttons/pressoff.xpm", "bitmaps/buttons/presson.xpm", 0},
121 };
122
123 /*
124 * This is a set of globals for the main window rendering. Again taken from
125 * include/brighton.h
126 */
127 brightonApp rhodesBassApp = {
128 "rhodesbass",
129 0, /* no blueprint on wood background. */
130 "bitmaps/textures/leather.xpm",
131 0,
132 rBassInit,
133 rBassConfigure, /* 3 callbacks */
134 rBassMidiCallback,
135 0,
136 {32, 0, 2, 2, 5, 520, 0, 1},
137 290, 200, 0, 0,
138 7, /* panel count */
139 {
140 {
141 "Opts",
142 "bitmaps/blueprints/rhodesopts.xpm",
143 "bitmaps/textures/metal5.xpm", /* flags */
144 0x020,
145 0,
146 0,
147 rBassCallback,
148 19, 40, 600, 400,
149 OPTS_COUNT,
150 options
151 },
152 {
153 "Mods",
154 "bitmaps/blueprints/rhodes.xpm",
155 "bitmaps/images/rhodesplate.xpm",
156 BRIGHTON_STRETCH,
157 0,
158 0,
159 rBassCallback,
160 12, 499, 976, 100,
161 MOD_COUNT,
162 locations
163 },
164 {
165 "Mem",
166 "bitmaps/blueprints/genmem.xpm",
167 "bitmaps/textures/metal5.xpm", /* flags */
168 0x020,
169 0,
170 0,
171 memCallback,
172 619, 40, 362, 400,
173 MEM_COUNT,
174 mem
175 },
176 {
177 "Keyboard",
178 0,
179 "bitmaps/newkeys/ekbg.xpm", /* flags */
180 0x020|BRIGHTON_STRETCH,
181 0,
182 0,
183 keyCallback,
184 70, 602, 870, 375,
185 KEY_COUNT_2OCTAVE,
186 keys2octave
187 },
188 {
189 "Rhodes",
190 0,
191 "bitmaps/images/rhodes.xpm",
192 BRIGHTON_STRETCH, /* flags */
193 0,
194 0,
195 0,
196 12, 20, 976, 475,
197 0,
198 0
199 },
200 {
201 "backing",
202 0,
203 "bitmaps/textures/metal6.xpm", /* flags */
204 BRIGHTON_STRETCH,
205 0,
206 0,
207 0,
208 928, 602, 60, 370,
209 0,
210 0
211 },
212 {
213 "backing",
214 0,
215 "bitmaps/textures/metal6.xpm", /* flags */
216 BRIGHTON_STRETCH,
217 0,
218 0,
219 0,
220 12, 602, 60, 370,
221 0,
222 0
223 },
224 }
225 };
226
227 /*static dispatcher dispatch[DEVICE_COUNT]; */
228
229 static int
rBassMidiSendMsg(void * synth,int fd,int chan,int c,int o,int v)230 rBassMidiSendMsg(void *synth, int fd, int chan, int c, int o, int v)
231 {
232 /*printf("rBassMidiSendMsg(%i, %i, %i)\n", c, o, v); */
233 bristolMidiSendMsg(fd, chan, c, o, v);
234 return(0);
235 }
236
237 /*
238 * For the sake of ease of use, links have been placed here to be called
239 * by any of the devices created. They would be better in some other file,
240 * perhaps with this as a dispatch.
241 *
242 * Param refers to the device index in the locations table given below.
243 */
244 static int
rBassCallback(brightonWindow * win,int panel,int index,float value)245 rBassCallback(brightonWindow * win, int panel, int index, float value)
246 {
247 guiSynth *synth = findSynth(global.synths, win);
248 int sendvalue;
249
250 /* printf("rBassCallback(%i, %i, %f): %x\n", panel, index, value, synth); */
251
252 if (synth == 0)
253 return(0);
254
255 if ((index >= DEVICE_COUNT) || ((synth->flags & OPERATIONAL) == 0))
256 return(0);
257
258 if (rhodesBassApp.resources[panel].devlocn[index].to == 1)
259 sendvalue = value * C_RANGE_MIN_1;
260 else
261 sendvalue = value;
262
263 switch (panel) {
264 case OPTS_PANEL:
265 index += OPTS_START;
266 break;
267 case MOD_PANEL:
268 index += MOD_START;
269 break;
270 case MEM_PANEL:
271 index += MEM_START;
272 break;
273 }
274
275 synth->mem.param[index] = value;
276
277 if ((!global.libtest) || (index >= ACTIVE_DEVS))
278 synth->dispatch[index].routine(synth,
279 global.controlfd, synth->sid,
280 synth->dispatch[index].controller,
281 synth->dispatch[index].operator,
282 sendvalue);
283 #ifdef DEBUG
284 else
285 printf("dispatch[%p,%i](%i, %i, %i, %i, %i)\n", synth, index,
286 global.controlfd, synth->sid,
287 synth->dispatch[index].controller,
288 synth->dispatch[index].operator,
289 sendvalue);
290 #endif
291
292 return(0);
293 }
294
295 static void
rBassProgramme(guiSynth * synth,int fd,int chan,int cont,int op,int value)296 rBassProgramme(guiSynth *synth, int fd, int chan, int cont, int op, int value)
297 {
298 brightonEvent event;
299
300 if (synth->dispatch[OPTS_START].other2)
301 {
302 synth->dispatch[OPTS_START].other2 = 0;
303 synth->mem.param[synth->dispatch[OPTS_START].other1] = 0;
304 return;
305 }
306
307 if ((synth->flags & MEM_LOADING) == 0)
308 {
309 if (synth->dispatch[OPTS_START].other1 != -1)
310 {
311 synth->dispatch[OPTS_START].other2 = 1;
312
313 if (synth->dispatch[OPTS_START].other1 != op)
314 event.value = 0;
315 else
316 event.value = 1;
317
318 brightonParamChange(synth->win, OPTS_PANEL,
319 synth->dispatch[OPTS_START].other1, &event);
320 }
321 synth->dispatch[OPTS_START].other1 = op;
322 synth->mem.param[op] = 1;
323 }
324
325 if (synth->flags & SUPPRESS)
326 return;
327
328 if (value != 0)
329 {
330 float *memhold;
331 float mem[256];
332 int optr, ind;
333
334 /* printf("rBassProgramme(%x, %i, %i, %i, %i, %i)\n", */
335 /* synth, fd, chan, cont, op, value); */
336
337 /*
338 * Each of the 8 voices has an associated set of DX parameters. We
339 * need to get hold of these, and send them directly over our config
340 * interface tap - we cannot forward via the normal GUi interface since
341 * we do not have these parameters mapped.
342 *
343 * The memories are mapped as 6 operators, each with 20 parameters,
344 * of which 13 are active, and then we have 4 additional parameters for
345 * algo, pitch, glide and volume.
346 */
347 memhold = &synth->mem.param[0];
348
349 synth->mem.param = &mem[0];
350
351 ind = 1000 + op;
352
353 /*
354 * Load the memory parameters with no callbacks.
355 */
356 if (loadMemory(synth, "rhodes", 0, ind, 148, 0,
357 BRISTOL_FORCE|BRISTOL_NOCALLS) < 0)
358 {
359 printf("NO MEM FOUND, returning\n");
360 synth->mem.param = memhold;
361 synth->dispatch[OPTS_START].other1 = op;
362 return;
363 }
364
365 for (optr = 0; optr < 6; optr++)
366 {
367 /*printf("configuring operator %i\n", optr); */
368 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
369 126, optr * 10, mem[optr * 20] * C_RANGE_MIN_1);
370 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
371 optr, 1, mem[optr * 20 + 1] * C_RANGE_MIN_1);
372 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
373 optr, 0, mem[optr * 20 + 2]);
374 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
375 optr, 6, mem[optr * 20 + 3] * C_RANGE_MIN_1);
376 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
377 126, optr * 10 + 1, mem[optr * 20 + 4] * C_RANGE_MIN_1);
378 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
379 optr, 2, mem[optr * 20 + 5] * C_RANGE_MIN_1);
380 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
381 optr, 3, mem[optr * 20 + 6] * C_RANGE_MIN_1);
382 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
383 optr, 4, mem[optr * 20 + 7] * C_RANGE_MIN_1);
384 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
385 optr, 5, mem[optr * 20 + 8] * C_RANGE_MIN_1);
386 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
387 optr, 7, mem[optr * 20 + 9] * C_RANGE_MIN_1);
388 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
389 126, optr * 10 + 2, mem[optr * 20 + 10] * C_RANGE_MIN_1);
390 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
391 126, optr * 10 + 3, mem[optr * 20 + 11] * C_RANGE_MIN_1);
392 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
393 optr, 9, mem[optr * 20 + 12] * C_RANGE_MIN_1);
394 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
395 optr, 10, mem[optr * 20 + 13] * C_RANGE_MIN_1);
396 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
397 optr, 11, mem[optr * 20 + 14] * C_RANGE_MIN_1);
398 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
399 optr, 12, mem[optr * 20 + 15] * C_RANGE_MIN_1);
400 }
401 /*
402 * These go through all the algorithms, looking for a single nonzero
403 */
404 for (ind = 0; ind < 24; ind++)
405 {
406 if (mem[120 + ind] != 0)
407 {
408 /*printf("configuring algo %i\n", ind); */
409 bristolMidiSendMsg(global.controlfd, synth->sid, 126, 101, ind);
410 }
411 }
412 rBassMidiSendMsg(synth, global.controlfd, synth->sid,
413 126, 102, C_RANGE_MIN_1);
414
415 synth->mem.param = memhold;
416 synth->dispatch[OPTS_START].other1 = op;
417 }
418 }
419
420 static int
rBassMidiCallback(brightonWindow * win,int command,int value,float v)421 rBassMidiCallback(brightonWindow *win, int command, int value, float v)
422 {
423 guiSynth *synth = findSynth(global.synths, win);
424
425 printf("midi callback: %x, %i\n", command, value);
426
427 switch(command)
428 {
429 case MIDI_PROGRAM:
430 printf("midi program: %x, %i\n", command, value);
431 synth->location = value;
432
433 rBassProgramme(synth, global.controlfd, synth->sid,
434 synth->dispatch[OPTS_START].controller,
435 synth->dispatch[OPTS_START].operator, 1.0f);
436
437 break;
438 case MIDI_BANK_SELECT:
439 printf("midi banksel: %x, %i\n", command, value);
440 synth->bank = value;
441 break;
442 }
443 return(0);
444 }
445
446 static void
rBassPanelSwitch(guiSynth * id,int fd,int chan,int cont,int op,int value)447 rBassPanelSwitch(guiSynth *id, int fd, int chan, int cont, int op, int value)
448 {
449 brightonEvent event;
450
451 id->flags |= SUPPRESS;
452 /*printf("rBassPanelSwitch()\n"); */
453 /*
454 * If the sendvalue is zero, then withdraw the opts window, draw the
455 * slider window, and vice versa.
456 */
457 if (value == 0)
458 {
459 event.type = BRIGHTON_EXPOSE;
460 event.intvalue = 0;
461 brightonParamChange(id->win, 0, -1, &event);
462 event.intvalue = 0;
463 brightonParamChange(id->win, 2, -1, &event);
464 event.intvalue = 1;
465 brightonParamChange(id->win, 4, -1, &event);
466 } else {
467 event.type = BRIGHTON_EXPOSE;
468 event.intvalue = 0;
469 brightonParamChange(id->win, 4, -1, &event);
470 event.intvalue = 1;
471 brightonParamChange(id->win, 0, -1, &event);
472 event.intvalue = 1;
473 brightonParamChange(id->win, 2, -1, &event);
474 }
475 id->flags &= ~SUPPRESS;
476 }
477
478 static void
rBassVolume(guiSynth * id,int fd,int chan,int cont,int op,int value)479 rBassVolume(guiSynth *id, int fd, int chan, int cont, int op, int value)
480 {
481 /*printf("rBassVolume(%i)\n", value); */
482 bristolMidiSendMsg(global.controlfd, chan, 126, 102, value);
483 }
484
485 static void
rBassBoost(guiSynth * synth,int fd,int chan,int cont,int op,int value)486 rBassBoost(guiSynth *synth, int fd, int chan, int cont, int op, int value)
487 {
488 /*printf("rBassBoost(%i)\n", value); */
489 bristolMidiControl(global.controlfd, synth->midichannel,
490 0, 1, value >> 7);
491 }
492
493 /*
494 * Any location initialisation required to run the callbacks. For bristol, this
495 * will connect to the engine, and give it some base parameters.
496 * May need to generate some application specific menus.
497 * Will also then make specific requests to some of the devices to alter their
498 * rendering.
499 */
500 static int
rBassInit(brightonWindow * win)501 rBassInit(brightonWindow *win)
502 {
503 guiSynth *synth = findSynth(global.synths, win);
504 dispatcher *dispatch;
505 int i;
506
507 if (synth == 0)
508 {
509 synth = findSynth(global.synths, 0);
510 if (synth == 0)
511 {
512 printf("cannot init\n");
513 return(0);
514 }
515 }
516
517 synth->win = win;
518
519 printf("Initialise the Rhodes Bass link to bristol: %p\n", synth->win);
520
521 synth->mem.param = (float *) brightonmalloc(DEVICE_COUNT * sizeof(float));
522 synth->mem.count = DEVICE_COUNT;
523 synth->mem.active = ACTIVE_DEVS;
524 synth->dispatch = (dispatcher *)
525 brightonmalloc(DEVICE_COUNT * sizeof(dispatcher));
526 dispatch = synth->dispatch;
527
528 /*
529 * The rhodes is actually a DX algorithm
530 */
531 synth->synthtype = 3;
532
533 /*
534 * We really want to have three connection mechanisms. These should be
535 * 1. Unix named sockets.
536 * 2. UDP sockets.
537 * 3. MIDI pipe.
538 */
539 if (!global.libtest)
540 if ((synth->sid = initConnection(&global, synth)) < 0)
541 return(-1);
542
543 for (i = 0; i < DEVICE_COUNT; i++)
544 {
545 synth->dispatch[i].routine = rBassMidiSendMsg;
546 }
547
548 synth->dispatch[MOD_START + 0].routine = (synthRoutine) rBassBoost;
549 synth->dispatch[MOD_START + 1].routine = (synthRoutine) rBassVolume;
550 synth->dispatch[MOD_START + 2].routine = (synthRoutine) rBassPanelSwitch;
551
552 synth->dispatch[OPTS_START + 0].routine
553 = synth->dispatch[OPTS_START + 1].routine
554 = synth->dispatch[OPTS_START + 2].routine
555 = synth->dispatch[OPTS_START + 3].routine
556 = synth->dispatch[OPTS_START + 4].routine
557 = synth->dispatch[OPTS_START + 5].routine
558 = synth->dispatch[OPTS_START + 6].routine
559 = synth->dispatch[OPTS_START + 7].routine
560 = (synthRoutine) rBassProgramme;
561 synth->dispatch[OPTS_START + 0].operator = 0;
562 synth->dispatch[OPTS_START + 1].operator = 1;
563 synth->dispatch[OPTS_START + 2].operator = 2;
564 synth->dispatch[OPTS_START + 3].operator = 3;
565 synth->dispatch[OPTS_START + 4].operator = 4;
566 synth->dispatch[OPTS_START + 5].operator = 5;
567 synth->dispatch[OPTS_START + 6].operator = 6;
568 synth->dispatch[OPTS_START + 7].operator = 7;
569
570 return(0);
571 }
572
573 /*
574 * This will be called to make any routine specific parameters available.
575 */
576 static int
rBassConfigure(brightonWindow * win)577 rBassConfigure(brightonWindow *win)
578 {
579 guiSynth *synth = findSynth(global.synths, win);
580 brightonEvent event;
581
582 if (synth == 0)
583 {
584 printf("problems going operational\n");
585 return(-1);
586 }
587
588 if (synth->flags & OPERATIONAL)
589 return(0);
590
591 printf("going operational\n");
592
593 synth->flags |= OPERATIONAL;
594 synth->keypanel = 3;
595 synth->keypanel2 = -1;
596 synth->transpose = 48;
597 /* loadMemory(synth, "rhodes", 0, synth->location, synth->mem.active, */
598 /* FIRST_DEV, 0); */
599
600 rBassProgramme(synth, global.controlfd, synth->sid,
601 synth->dispatch[OPTS_START].controller,
602 synth->dispatch[OPTS_START].operator, 1.0f);
603
604 displayPanelText(synth, "PRG", synth->location, MEM_PANEL, MEM_COUNT - 1);
605
606 /*
607 * Hm. This is a hack for a few bits of bad rendering of a keyboard. Only
608 * occurs on first paint, so we suppress the first paint, and then request
609 * an expose here.
610 */
611 event.type = BRIGHTON_EXPOSE;
612 event.intvalue = 1;
613 brightonParamChange(synth->win, KEY_PANEL, -1, &event);
614 event.type = BRIGHTON_FLOAT;
615 event.value = 1;
616 brightonParamChange(synth->win, 0, 0, &event);
617 configureGlobals(synth);
618
619 brightonPut(synth->win, "bitmaps/blueprints/rhodesbassshade.xpm",
620 0, 0, synth->win->width, synth->win->height);
621
622 return(0);
623 }
624
625