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 #include <fcntl.h>
23 #include <strings.h>
24 #include <sys/time.h>
25 #include <sys/types.h>
26 #include <dirent.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29
30 #include "bristol.h"
31 #include "bristolmidi.h"
32 #include "brightonMixer.h"
33 #include "brightonMixerMemory.h"
34
35 #include "brighton.h"
36 #include "brightonMini.h"
37
38 static mixerMem *new = NULL, *prev = NULL;
39 static char songDir[32] = "default";
40
41 static DIR *memlist = NULL;
42 static struct dirent *entry;
43
44 extern guimain global;
45 extern void displayPanel(guiSynth *, char *, int, int, int);
46
47 /*
48 * Most of this is actually borrowed from brightonroutines.c, but since the
49 * mixer operations are a little central to the whole application have chosen
50 * to make it bespoke
51 */
saveMixerMemory(guiSynth * synth,char * name)52 int saveMixerMemory(guiSynth *synth, char *name)
53 {
54 char path[256];
55 int fd;
56
57 sprintf(path, "%s/memory/%s/%s/%s.mem",
58 getBristolCache("midicontrollermap"), "mixer", songDir, name);
59 sprintf(synth->mem.algo, "mixer");
60 if (name == NULL)
61 sprintf(synth->mem.name, "no name");
62 else
63 sprintf(synth->mem.name, "%s", name);
64
65 if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0)
66 return(-1);
67
68 if (write(fd, &synth->mem, sizeof(struct Memory) - sizeof(float *)) < 0)
69 printf("write failed 1\n");
70 if (write(fd, synth->mem.param, sizeof(mixerMem)) < 0)
71 printf("write failed 1\n");
72
73 close(fd);
74
75 return(0);
76 }
77
78 static int
doLoadMixerMemory(guiSynth * synth)79 doLoadMixerMemory(guiSynth *synth)
80 {
81 brightonEvent event;
82 int channel, param;
83
84 event.type = BRIGHTON_FLOAT;
85
86 /*
87 * Now we have the parameters loaded we need to start sending off events
88 * to the GUI to draw the mixer, that will notify the engine and set the
89 * parameters here again (as an undesirable sideffect);
90 *
91 * Going to start with the steroe bus section as it is (comparatively) easy.
92 */
93 for (channel = 0; channel < 4; channel++)
94 {
95 event.value = new->vbus[channel].clear.vol;
96 brightonParamChange(synth->win, BUS_PANEL,
97 240 + channel * 3, &event);
98
99 event.value = new->vbus[channel].clear.left;
100 brightonParamChange(synth->win, BUS_PANEL,
101 240 + channel * 3 + 1, &event);
102
103 event.value = new->vbus[channel].clear.right;
104 brightonParamChange(synth->win, BUS_PANEL,
105 240 + channel * 3 + 2, &event);
106 }
107
108 /*
109 * Effects bussing section
110 */
111 for (channel = 0; channel < 8; channel++)
112 {
113 /*
114 * Six events for the continuous controllers
115 */
116 for (param = 0; param < 6; param++)
117 {
118 event.value = new->bus[channel].b.opaque[param];
119 brightonParamChange(synth->win, BUS_PANEL,
120 channel * 30 + param, &event);
121 }
122
123 /*
124 * One event for the FX select
125 new->bus[channel].b.clear.algorithm;
126 */
127 event.value = 1.01;
128 if (new->bus[channel].b.clear.algorithm < 0)
129 {
130 brightonParamChange(synth->win, BUS_PANEL,
131 channel * 30 + 6, &event);
132 event.value = 0.0;
133 brightonParamChange(synth->win, BUS_PANEL,
134 channel * 30 + 6, &event);
135 } else {
136 if (new->bus[channel].b.clear.algorithm !=
137 prev->bus[channel].b.clear.algorithm)
138 brightonParamChange(synth->win, BUS_PANEL,
139 channel * 30 + 6 + new->bus[channel].b.clear.algorithm,
140 &event);
141 }
142
143 /*
144 * Sixteen events for the output busses.
145 */
146 for (param = 0; param < 16; param++)
147 {
148 /*
149 if (new->bus[channel].b.clear.outputSelect[param] <= 0)
150 event.value = 0.0;
151 else
152 event.value = 1.01;
153 */
154 event.value = new->bus[channel].b.clear.outputSelect[param];
155 brightonParamChange(synth->win, BUS_PANEL,
156 channel * 30 + 14 + param, &event);
157 }
158 }
159
160 /*
161 * And the channels themselves.
162 */
163 for (channel = 0; channel < new->chancount; channel++)
164 {
165 /*
166 * One event for the input selection. There are several logical states:
167 * 1. New track has selection - call it.
168 * 2. New Track has no selection - clear the previous one.
169 */
170 if (new->chan[channel].inputSelect >= 0)
171 {
172 /*
173 * Only apply if the parameter has changed
174 */
175 if (new->chan[channel].inputSelect
176 != prev->chan[channel].inputSelect)
177 {
178 event.value = 1.0;
179 brightonParamChange(synth->win, channel + 4,
180 new->chan[channel].inputSelect, &event);
181 }
182 } else {
183 event.value = 1.0;
184 brightonParamChange(synth->win, channel + 4, 0, &event);
185 event.value = 0.0;
186 brightonParamChange(synth->win, channel + 4, 0, &event);
187 }
188
189 /*
190 * Presend bus selections
191 */
192 for (param = 0; param < 4; param++)
193 {
194 event.value = new->chan[channel].preSend[param];
195 brightonParamChange(synth->win, channel + 4,
196 16 + param, &event);
197 }
198
199 /*
200 * Dynamics algorithm selection
201 */
202 if (new->chan[channel].dynamics >= 0)
203 {
204 if (new->chan[channel].dynamics != prev->chan[channel].dynamics)
205 {
206 event.value = 1.01;
207 brightonParamChange(synth->win, channel + 4,
208 20 + new->chan[channel].dynamics, &event);
209 }
210 } else {
211 event.value = 1.01;
212 brightonParamChange(synth->win, channel + 4,
213 20, &event);
214 event.value = 0.0;
215 brightonParamChange(synth->win, channel + 4,
216 20, &event);
217 }
218
219 /*
220 * Filter algorithm selection
221 */
222 if (new->chan[channel].filter >= 0)
223 {
224 if (new->chan[channel].filter != prev->chan[channel].filter)
225 {
226 event.value = 1.01;
227 brightonParamChange(synth->win, channel + 4,
228 23 + new->chan[channel].filter, &event);
229 }
230 } else {
231 event.value = 1.01;
232 brightonParamChange(synth->win, channel + 4,
233 23, &event);
234 event.value = 0.0;
235 brightonParamChange(synth->win, channel + 4,
236 23, &event);
237 }
238
239 /*
240 * Postsend bus selections
241 */
242 for (param = 0; param < 4; param++)
243 {
244 event.value = new->chan[channel].postSend[param];
245 brightonParamChange(synth->win, channel + 4,
246 27 + param, &event);
247 }
248
249 /*
250 * FX algorithm selection
251 */
252 if (new->chan[channel].fxAlgo >= 0)
253 {
254 if (new->chan[channel].fxAlgo != prev->chan[channel].fxAlgo)
255 {
256 event.value = 1.01;
257 brightonParamChange(synth->win, channel + 4,
258 31 + new->chan[channel].fxAlgo, &event);
259 }
260 } else {
261 event.value = 1.01;
262 brightonParamChange(synth->win, channel + 4,
263 31, &event);
264 event.value = 0.0;
265 brightonParamChange(synth->win, channel + 4,
266 31, &event);
267 }
268
269 /*
270 * Continuous controllers
271 */
272 for (param = 0; param < 17; param++)
273 {
274 event.value = new->chan[channel].p.opaque[param];
275 brightonParamChange(synth->win, channel + 4,
276 38 + param, &event);
277 }
278
279 event.value = new->chan[channel].mute;
280 brightonParamChange(synth->win, channel + 4, 55, &event);
281 event.value = new->chan[channel].solo;
282 brightonParamChange(synth->win, channel + 4, 56, &event);
283 event.value = new->chan[channel].boost;
284 brightonParamChange(synth->win, channel + 4, 57, &event);
285
286 /*
287 * Output select
288 */
289 for (param = 0; param < 16; param++)
290 {
291 event.value = new->chan[channel].outputSelect[param];
292 brightonParamChange(synth->win, channel + 4,
293 58 + param, &event);
294 }
295
296 /*
297 * vBus selection
298 */
299 if (new->chan[channel].stereoBus >= 0)
300 {
301 if (new->chan[channel].stereoBus != prev->chan[channel].stereoBus)
302 {
303 event.value = 1.01;
304 brightonParamChange(synth->win, channel + 4,
305 74 + new->chan[channel].stereoBus, &event);
306 }
307 } else {
308 event.value = 1.01;
309 brightonParamChange(synth->win, channel + 4,
310 74, &event);
311 event.value = 0.0;
312 brightonParamChange(synth->win, channel + 4,
313 74, &event);
314 }
315
316 event.value = new->chan[channel].p.clear.vol;
317 brightonParamChange(synth->win, channel + 4, 78, &event);
318
319 displayPanel(synth, new->chan[channel].scratch, 0, channel + 4, 79);
320 sprintf(((mixerMem *) synth->mem.param)->chan[channel].scratch, "%s", new->chan[channel].scratch);
321 }
322
323 return(0);
324 }
325
326 /*
327 * Saving the memory is reasonably trivial. Reading it back is a little more
328 * work since we have to call the parameter routines to set the values.
329 */
loadMixerMemory(guiSynth * synth,char * name,int param)330 int loadMixerMemory(guiSynth *synth, char *name, int param)
331 {
332 char path[256];
333 int fd;
334
335 if (param == 1)
336 {
337 sprintf(songDir, "%s", name);
338 return(0);
339 }
340 if (param == 2)
341 {
342 if (strlen(name) != 0)
343 {
344 sprintf(path, "%s/memory/%s/%s", getBristolCache("midicontrollermap"), "mixer", name);
345 mkdir(path, 0755);
346 }
347 return(0);
348 }
349
350 if (strcmp(name, "revert") == 0)
351 {
352 mixerMem *t;
353
354 bcopy(prev, new, sizeof(mixerMem));
355 t = prev;
356 prev = (mixerMem *) synth->mem.param;
357 synth->mem.param = (float *) t;
358
359 doLoadMixerMemory(synth);
360
361 return(0);
362 }
363
364 sprintf(path, "%s/memory/%s/%s/%s.mem",
365 getBristolCache("midicontrollermap"), "mixer", songDir, name);
366
367 if ((fd = open(path, O_RDONLY, 0770)) < 0)
368 {
369 sprintf(path, "%s/memory/%s/%s/%s.mem",
370 global.home, "mixer", songDir, name);
371 if ((fd = open(path, O_RDONLY, 0770)) < 0)
372 return(-1);
373 }
374
375 if (read(fd, &synth->mem.algo[0], 32) < 0)
376 printf("read failed\n");
377 if (read(fd, &synth->mem.name[0], 32) < 0)
378 printf("read failed\n");
379
380 if (read(fd, new, 2 * sizeof(int)) < 0)
381 printf("read failed\n");
382
383 if (read(fd, new, sizeof(mixerMem)) < 0)
384 printf("read failed\n");
385
386 bcopy(synth->mem.param, prev, sizeof(mixerMem));
387
388 doLoadMixerMemory(synth);
389
390 close(fd);
391
392 return(0);
393 }
394
395 /*
396 * Get a memory structure, null it out, put in a few details and give it back
397 */
398 void *
initMixerMemory(int count)399 initMixerMemory(int count)
400 {
401 int i;
402 mixerMem *m;
403
404 if ((m = (mixerMem *) malloc(sizeof(mixerMem))) == NULL)
405 return(0);
406 if ((new = (mixerMem *) malloc(sizeof(mixerMem))) == NULL)
407 return(0);
408 if ((prev = (mixerMem *) malloc(sizeof(mixerMem))) == NULL)
409 return(0);
410
411 bzero(m, sizeof(mixerMem));
412
413 sprintf(&m->name[0], "no name");
414 m->version = MIXER_VERSION;
415 m->chancount = count;
416
417 for (i = 0; i < MAX_CHAN_COUNT; i++)
418 {
419 m->chan[i].inputSelect = -1;
420 m->chan[i].dynamics = -1;
421 m->chan[i].filter = -1;
422 m->chan[i].fxAlgo = -1;
423 m->chan[i].stereoBus = -1;
424 sprintf(&m->chan[i].scratch[0], "Trk: %i", i + 1);
425 }
426 for (i = 0; i < MAX_VBUS_COUNT; i++)
427 m->bus[i].b.clear.algorithm = -1;
428
429 bcopy(m, prev, sizeof(mixerMem));
430
431 return(m);
432 }
433
434 char *
getMixerMemory(mixerMem * m,int op,int param)435 getMixerMemory(mixerMem *m, int op, int param)
436 {
437 char path[256], *dotptr;
438
439 switch(op)
440 {
441 case MM_GETLIST:
442 if (memlist == 0)
443 {
444 /*
445 * See if we want to list songs or memories in a song dir
446 */
447 if (param == 1)
448 sprintf(path, "%s/memory/%s",
449 global.home, "mixer");
450 else
451 sprintf(path, "%s/memory/%s/%s",
452 global.home, "mixer", songDir);
453
454 if ((memlist = opendir(path)) == NULL)
455 return(0);
456 }
457
458 if ((entry = readdir(memlist)) == 0)
459 {
460 closedir(memlist);
461 memlist = NULL;
462 return(0);
463 }
464
465 while (entry->d_name[0] == '.')
466 {
467 if ((entry = readdir(memlist)) == 0)
468 {
469 closedir(memlist);
470 memlist = NULL;
471 return(0);
472 }
473 }
474
475 if ((dotptr = index(entry->d_name, '.')) != NULL)
476 *dotptr = '\0';
477
478 /*
479 * Call a set of routines that will open the directory and then
480 * return its contents until finnished.
481 */
482 return(entry->d_name);
483 default:
484 if (param == 79) {
485 return(&m->chan[op - 4].scratch[0]);
486 }
487 }
488
489 return(0);
490 }
491
492 int
setMixerMemory(mixerMem * m,int op,int param,float * value,char * text)493 setMixerMemory(mixerMem *m, int op, int param, float *value, char *text)
494 {
495 int channel = 0, offset = 0;
496
497 switch(op)
498 {
499 case VBUS_PANEL:
500 /*
501 * We expect parameters from 0 to 12, they will translate to
502 * The bus:v/l/r
503 */
504 channel = param / 3;
505 offset = param % 3;
506
507 m->vbus[channel].opaque[offset] = *value;
508
509 break;
510 case BUS_PANEL:
511 /*
512 * but parameters are opaque but I want to separate them out
513 * here since the functions will be unique in the engine.
514 */
515 channel = param / 30;
516 offset = param % 30;
517
518 if (offset < 6)
519 /*
520 * Continuous controllers
521 */
522 m->bus[channel].b.opaque[offset] = *value;
523 else if (offset < 14) {
524 /*
525 * FX Selector, single value
526 */
527 if (*value == 0)
528 m->bus[channel].b.clear.algorithm = -1;
529 else
530 m->bus[channel].b.clear.algorithm = offset - 6;
531 } else if (offset < 30) {
532 /*
533 * Output channel selection
534 */
535 m->bus[channel].b.clear.outputSelect[offset - 14] = *value;
536 }
537
538 break;
539 default:
540 channel = op - 4;
541 offset = param;
542
543 if (offset < 16) {
544 /*
545 * Input channel selection radio buttons
546 */
547 if (*value == 0) {
548 m->chan[channel].inputSelect = -1;
549 } else {
550 m->chan[channel].inputSelect = offset;
551 }
552 } else if (offset < 20) {
553 /*
554 * Presend bus selection.
555 */
556 m->chan[channel].preSend[offset - 16] = *value;
557 } else if (offset < 23) {
558 /*
559 * Dynamics also radio button selection.
560 */
561 if (*value == 0) {
562 m->chan[channel].dynamics = -1;
563 } else {
564 m->chan[channel].dynamics = offset - 20;
565 }
566 } else if (offset < 27) {
567 /*
568 * Filter algo radio button selection.
569 */
570 if (*value == 0) {
571 m->chan[channel].filter = -1;
572 } else {
573 m->chan[channel].filter = offset - 23;
574 }
575 } else if (offset < 31) {
576 /*
577 * Postsend bus selection.
578 */
579 m->chan[channel].postSend[offset - 27] = *value;
580 } else if (offset < 38) {
581 /*
582 * Effect radio button selection.
583 */
584 if (*value == 0) {
585 m->chan[channel].fxAlgo = -1;
586 } else {
587 m->chan[channel].fxAlgo = offset - 31;
588 }
589 } else if (offset < 55) {
590 /*
591 * The continuous controllers less fader
592 */
593 m->chan[channel].p.opaque[offset - 38] = *value;
594 } else if (offset == 55) {
595 m->chan[channel].mute = *value;
596 } else if (offset == 56) {
597 m->chan[channel].solo = *value;
598 } else if (offset == 57) {
599 m->chan[channel].boost = *value;
600 } else if (offset < 74) {
601 m->chan[channel].outputSelect[offset - 58] = *value;
602 } else if (offset < 78) {
603 /*
604 * vBus radio buttons
605 */
606 if (*value == 0) {
607 m->chan[channel].stereoBus = -1;
608 } else {
609 m->chan[channel].stereoBus = offset - 74;
610 }
611 } else if (offset == 78) {
612 m->chan[channel].p.clear.vol = *value;
613 } else if (offset == 79) {
614 if (text != NULL)
615 sprintf(m->chan[channel].scratch, "%s", text);
616 }
617 break;
618 }
619 return(0);
620 }
621
622
623 /*
624 * loadMemory, saveMemory, initMemory, get/setMemory?
625 */
626 /* wow. the return type of this varies depending on op. no. -DR */
627 int
mixerMemory(guiSynth * synth,int op,int subop,int param,void * value)628 mixerMemory(guiSynth *synth, int op, int subop, int param, void *value)
629 {
630 switch(op) {
631 case MM_SAVE:
632 return(saveMixerMemory(synth, value));
633 case MM_LOAD:
634 return(loadMixerMemory(synth, value, param));
635 case MM_INIT:
636 /*
637 * This was orginally a rather dumb typecast
638 return((int) initMixerMemory(param));
639 * Need to review all of this code as the mixer gets rolled out
640 */
641 return(0);
642 case MM_SET:
643 return(setMixerMemory((mixerMem *) synth->mem.param,
644 subop, param, value, NULL));
645 /*
646 * This will be moved into a separate call.
647 case MM_GET:
648 return(getMixerMemory((mixerMem *) synth->mem.param,
649 subop, param, value));
650 */
651 }
652 return(0);
653 }
654
655