1 /*
2 * Komposter
3 *
4 * Copyright (c) 2010 Noora Halme et al. (see AUTHORS)
5 *
6 * This code is licensed under the GNU General Public
7 * License version 2. See LICENSE for full text.
8 *
9 * Patch editor page
10 *
11 */
12
13 #include "patch.h"
14
15 // button indexes
16 #define B_PREV 0
17 #define B_NEXT 1
18 #define B_PREVSYN 2
19 #define B_SYNNAME 3
20 #define B_NEXTSYN 4
21 #define B_PATCHNAME 5
22
23 #define B_CUT 6
24 #define B_COPY 7
25 #define B_PASTE 8
26
27 #define B_OCTDN 9
28 #define B_OCTUP 10
29
30 #define B_MOD_ADDPREC 0
31 #define B_MOD_DECPREC 1
32 #define B_MOD_VALUE 2
33
34 #define PIANO_LEFT 8
35 #define PIANO_WIDTH (9*16*7)
36 #define PIANO_RIGHT (PIANO_LEFT+PIANO_WIDTH)
37 #define PIANO_TOP 520
38 #define PIANO_HEIGHT 70
39 #define PIANO_BOTTOM (PIANO_TOP+PIANO_HEIGHT+2)
40
41 #define PATCHES_PER_COLUMN 30
42
43 #define PIANO_OCTAVES 7
44
45 extern int csynth;
46 extern char synthname[MAX_SYNTH][128]; // from synthesizer.c
47 extern synthmodule mod[MAX_SYNTH][MAX_MODULES]; // ditto
48 extern int signalfifo[MAX_SYNTH][MAX_MODULES]; // module execution stack
49
50 // from modules.c
51 extern float pitch[MAX_SYNTH];
52 extern int accent[MAX_SYNTH];
53 extern int gate[MAX_SYNTH];
54
55 // from pattern.c
56 extern int coct;
57
58 // from sequencer.c
59 extern int seqch;
60 extern int bpm;
61
62 // keyboard keys to mimic piano keys
63 char pianokeys[36]={
64 'z', 's', 'x', 'd', 'c', 'v', 'g', 'b', 'h', 'n', 'j', 'm', // octave 1
65 'q', '2', 'w', '3', 'e', 'r', '5', 't', '6', 'y', '7', 'u', // octave 2
66 'i', '9', 'o', '0', 'p', 0, 0, 0, 0, 0, 0, 0}; // partial octave 3, null terminates
67
68
69
70 int patch_ui[11];
71 int modulator_ui[3];
72 int cpkey=-1;
73 int cphover=-1;
74 int cpkeydown=-1;
75 int kpkeydown=-1;
76 int patchkbfocus=0;
77 int modkbfocus=0;
78 char modeditbox[128];
79 int patchcursor=0;
80
81 int cpatch[MAX_SYNTH]; // selected patch for each synth
82 char patchname[MAX_SYNTH][MAX_PATCHES][128];
83 float modvalue[MAX_SYNTH][MAX_PATCHES][MAX_MODULES];
84 int modquantifier[MAX_SYNTH][MAX_PATCHES][MAX_MODULES];
85
86 // "clipboard" for cut/copy/paste patches
87 int patch_clipboard_synth; // which synth the is for (-1 if clipboard is empty)
88 int patch_clipboard_modcount; // how many modulator values were copied
89 float patch_clipboard_modvalue[MAX_MODULES];
90 int patch_clipboard_quantifier[MAX_MODULES];
91
92 float patch_modulator_floatval;
93 int patch_modulator_intval;
94
95
patch_init()96 void patch_init()
97 {
98 int i, j, k;
99
100 cphover=-1; cpkey=-1; cpkeydown=-1;
101 patchkbfocus=0;
102 for(i=0;i<6;i++) patch_ui[i]=0;
103
104 for(i=0;i<MAX_SYNTH;i++) {
105 cpatch[i]=0;
106 for(j=0;j<MAX_PATCHES;j++) {
107 strcpy((char*)(&patchname[i][j]), "Unnamed patch");
108 for(k=0;k<MAX_MODULES;k++) {
109 modvalue[i][j][k]=0.0f;
110 modquantifier[i][j][k]=32;
111 }
112 }
113 }
114
115 patch_clipboard_synth=-1;
116
117 synth_stackify(csynth);
118 }
119
120
patch_mouse_hover(int x,int y)121 void patch_mouse_hover(int x, int y)
122 {
123 int m;
124 int octave, key, xoct;
125 int wk[7]={0,2,4,5,7, 9,11};
126 int bk[7]={1,3,0,6,8,10, 0};
127 int pk[7]={0,1,3,0,6, 8,10};
128
129 // test buttons
130 patch_ui[B_PREV]=hovertest_box(x, y, 310, DS_HEIGHT-14, 16, 16);
131 patch_ui[B_NEXT]=hovertest_box(x, y, 362, DS_HEIGHT-14, 16, 16);
132 patch_ui[B_PREVSYN]=hovertest_box(x, y, 14, DS_HEIGHT-14, 16, 16);
133 patch_ui[B_NEXTSYN]=hovertest_box(x, y, 230, DS_HEIGHT-14, 16, 16);
134
135 patch_ui[B_OCTDN]=hovertest_box(x, y, 17, 520-12, 16, 16);
136 patch_ui[B_OCTUP]=hovertest_box(x, y, DS_WIDTH-17, 520-12, 16, 16);
137
138 // patch_ui[B_CUT]=hovertest_box(x, y, 600, DS_HEIGHT-14, 16, 16);
139 patch_ui[B_COPY]=hovertest_box(x, y, 622, DS_HEIGHT-14, 16, 16);
140 patch_ui[B_PASTE]=hovertest_box(x, y, 644, DS_HEIGHT-14, 16, 16);
141 if (patch_clipboard_synth<0 || patch_clipboard_synth!=csynth) patch_ui[B_PASTE]=0;
142
143 // test patch name box
144 patch_ui[B_PATCHNAME]&=0x06;
145 patch_ui[B_PATCHNAME]|=hovertest_box(x, y, 472, DS_HEIGHT-14, 16, 180);
146
147 // any ui-elements active?
148 for(m=0;m<6;m++) if (patch_ui[m]&1) return;
149
150 // test modulators
151 cphover=-1;
152 if (x>=20 && x<380 && y>=8 && y<(8+PATCHES_PER_COLUMN*16)) {
153 cphover=((y-8)/16);
154 }
155 if (x>=400 && x<780 && y>=8 && y<(8+PATCHES_PER_COLUMN*16)) {
156 cphover=(PATCHES_PER_COLUMN + (y-8)/16);
157 }
158
159 // test piano keyboard
160 cpkey=-1;
161 if (x>=PIANO_LEFT && x<PIANO_RIGHT && y>=PIANO_TOP && y<PIANO_BOTTOM) {
162
163 if (y>(PIANO_TOP + PIANO_HEIGHT/2)) { // white keys only
164 octave=(x-PIANO_LEFT)/(7*16);
165 key=((x-PIANO_LEFT) % (7*16))/16;
166 cpkey=octave*12 + wk[key];
167 } else { // white and black
168 octave=(x-PIANO_LEFT)/(7*16);
169
170 // white key as default
171 xoct=((x-PIANO_LEFT)%(7*16));
172 key=xoct/16;
173 cpkey=octave*12 + wk[key];
174 switch (key) {
175 // black key only to right:
176 case 0:
177 case 3:
178 if ( (xoct-(key*16))>10 ) cpkey=octave*12 + bk[key];
179 break;
180
181 // black to right and left
182 case 1:
183 case 4:
184 case 5:
185 if ( (xoct-(key*16))>10) cpkey=octave*12 + bk[key];
186 if ( (xoct-(key*16))<6 ) cpkey=octave*12 + pk[key];
187 break;
188
189 // black key to left
190 case 2:
191 case 6:
192 if ( (xoct-(key*16))<6 ) cpkey=octave*12 + pk[key];
193 break;
194
195 }
196 }
197 }
198
199 }
200
patch_mouse_drag(int x,int y)201 void patch_mouse_drag(int x, int y)
202 {
203 }
204
patch_mouse_click(int button,int state,int x,int y)205 void patch_mouse_click(int button, int state, int x, int y)
206 {
207 int m,mi,mt,t;
208
209 if (button==GLUT_LEFT_BUTTON) {
210 if (state==GLUT_DOWN) {
211
212 // remove kb focus it it was assigned
213 if (patchkbfocus>=0) { patch_ui[patchkbfocus]&=0x03; patchkbfocus=-1; glutIgnoreKeyRepeat(1); }
214
215 // click on the ui buttons
216 if (patch_ui[B_PREV]) {
217 if (cpatch[csynth]>0) cpatch[csynth]--; return;
218 audio_loadpatch(0, csynth, cpatch[csynth]);
219 }
220 if (patch_ui[B_NEXT]) { if (cpatch[csynth]<MAX_PATCHES) cpatch[csynth]++;
221 audio_loadpatch(0, csynth, cpatch[csynth]);
222 return; }
223 if (patch_ui[B_PREVSYN]) { if (csynth>0) {
224 synth_lockaudio();
225 csynth--;
226 synth_stackify(csynth);
227 kmm_gcollect();
228 synth_releaseaudio();
229 }
230 audio_loadpatch(0, csynth, cpatch[csynth]);
231 return; }
232 if (patch_ui[B_NEXTSYN]) { if (csynth<(MAX_SYNTH-1)) {
233 synth_lockaudio();
234 csynth++;
235 synth_stackify(csynth);
236 kmm_gcollect();
237 synth_releaseaudio();
238 }
239 audio_loadpatch(0, csynth, cpatch[csynth]);
240 return;
241 }
242
243 if (patch_ui[B_OCTDN]) {
244 if (coct>0) { coct--; return; }
245 }
246 if (patch_ui[B_OCTUP]) {
247 if (coct<MAX_OCTAVE) { coct++; return; }
248 }
249
250 if (patch_ui[B_COPY]) {
251 patch_clipboard_synth=csynth;
252 m=0;
253 while(signalfifo[csynth][m]>=0) {
254 mi=signalfifo[csynth][m];
255 memcpy(&patch_clipboard_modvalue[m], &modvalue[csynth][cpatch[csynth]][mi], sizeof(float));
256 patch_clipboard_quantifier[m]=modquantifier[csynth][cpatch[csynth]][mi];
257 m++;
258 }
259 patch_clipboard_modcount=m;
260 console_post("Patch copied to clipboard");
261 }
262
263 if (patch_ui[B_PASTE] && patch_clipboard_synth>=0) {
264 if (patch_clipboard_synth >= 0 && patch_clipboard_synth==csynth) {
265 // paste modulator and quantifier settings
266 m=0;
267 while(signalfifo[csynth][m]>=0) {
268 mi=signalfifo[csynth][m];
269 memcpy(&modvalue[csynth][cpatch[csynth]][mi], &patch_clipboard_modvalue[m], sizeof(float));
270 modquantifier[csynth][cpatch[csynth]][mi]=patch_clipboard_quantifier[m];
271 m++;
272 }
273 console_post("Patch pasted from clipboard");
274 }
275 }
276
277 if (patch_ui[B_PATCHNAME]) {
278 // set keyboard focus
279 patch_ui[B_PATCHNAME]|=4;
280 patchkbfocus=B_PATCHNAME;
281 glutIgnoreKeyRepeat(0);
282 return;
283 }
284
285 // click on piano
286 if (cpkey>=0) { // && kpkeydown<0) {
287 cpkeydown=cpkey;
288 audio_trignote(0, cpkey);
289 }
290
291 if (cphover>=0 && signalfifo[csynth][cphover]>=0) {
292 // clicked a modulator, spring up a settings dialog
293 mi=signalfifo[csynth][cphover];
294 mt=mod[csynth][mi].type;
295 if (modModulatorTypes[mt]>0) {
296 switch(mt) {
297 case MOD_WAVEFORM:
298 t=(int)(modvalue[csynth][cpatch[csynth]][mi]);
299 t++; t%=VCO_WAVEFORMS;
300 modvalue[csynth][cpatch[csynth]][mi]=(float)(t);
301 break;
302 case MOD_LFO:
303 t=(int)(modvalue[csynth][cpatch[csynth]][mi]);
304 // t++; t%=LFO_WAVEFORMS;
305 t= (t==2)?3:2;
306 modvalue[csynth][cpatch[csynth]][mi]=(float)(t);
307 break;
308 case MOD_FILTER:
309 t=(int)(modvalue[csynth][cpatch[csynth]][mi]);
310 t++; t%=VCF_MODES;
311 modvalue[csynth][cpatch[csynth]][mi]=(float)(t);
312 break;
313 case MOD_SUPERSAW:
314 t=(int)(modvalue[csynth][cpatch[csynth]][mi]);
315 t++; t%=4;
316 modvalue[csynth][cpatch[csynth]][mi]=(float)(t);
317 break;
318 case MOD_DELAY:
319 t=(int)(modvalue[csynth][cpatch[csynth]][mi]);
320 t++; t%=DELAY_MODES;
321 modvalue[csynth][cpatch[csynth]][mi]=(float)(t);
322 break;
323 case MOD_SLEW:
324 t=(int)(modvalue[csynth][cpatch[csynth]][mi]);
325 t++; t%=SLEW_MODES;
326 modvalue[csynth][cpatch[csynth]][mi]=(float)(t);
327 break;
328 case MOD_MODULATOR:
329 t=(int)(modvalue[csynth][cpatch[csynth]][mi]);
330 t++; t%=seqch;
331 modvalue[csynth][cpatch[csynth]][mi]=(float)(t);
332 break;
333 default:
334 switch(modModulatorTypes[mod[csynth][mi].type]) {
335 case 1: // float
336 patch_modulator_floatval=knob_float2scale(mod[csynth][mi].scale, modvalue[ csynth ][cpatch[csynth]][ mi ]);
337 sprintf(modeditbox, "%g", patch_modulator_floatval);
338 // knob_float2scale(mod[csynth][mi].scale, modvalue[ csynth ][cpatch[csynth]][ mi ]));
339 break;
340 case 2: // integer
341 patch_modulator_intval=modvalue[ csynth ][cpatch[csynth]][ mi ];
342 break;
343 }
344 dialog_open(&patch_draw_modulator, &patch_modulator_hover, &patch_modulator_click);
345 dialog_bindkeyboard(&patch_modulator_keyboard);
346 dialog_bindspecial(&patch_modulator_special);
347 break;
348 }
349 return;
350 } else {
351 console_post("No settings for this module!");
352 }
353 }
354
355 }
356 if (state==GLUT_UP) {
357 if (cpkeydown>=0) // && kpkeydown<0)
358 { cpkeydown=-1; gate[0]=0; }
359
360 patch_mouse_hover(x, y);
361 }
362 }
363 // todo: rightclicks
364 }
365
366 // keyboard callback
patch_keyboard(unsigned char key,int x,int y)367 void patch_keyboard(unsigned char key, int x, int y)
368 {
369 int i, pkey;
370
371 if (patchkbfocus==B_PATCHNAME) {
372 // edit patch name
373 if (key==13) { patch_ui[B_PATCHNAME]&=0x03; patchkbfocus=-1; glutIgnoreKeyRepeat(1); }
374 textbox_edit(patchname[csynth][cpatch[csynth]], key, 25);
375 return;
376 }
377
378 switch (key) {
379 case '-':
380 case '<':
381 if (coct>0) { coct--; return; }
382 break;
383
384 case '+':
385 case '>':
386 if (coct<MAX_OCTAVE) { coct++; return; }
387 break;
388 }
389
390 // keyjazzing! w00t!
391 for (i=0;i<29;i++) {
392 if (pianokeys[i]==key) {
393 // trig note. use same base octave as pattern editor
394 pkey=coct*12 + i;
395 kpkeydown=pkey;
396 audio_trignote(0, pkey);
397 }
398 }
399 }
400
patch_keyboardup(unsigned char key,int x,int y)401 void patch_keyboardup(unsigned char key, int x, int y)
402 {
403 int i;
404
405 for (i=0;i<29;i++) {
406 if (pianokeys[i]==key) {
407 // if this key is still down, drop gate and trig
408 if (kpkeydown==(i+coct*12)) {
409 gate[0]=0;
410 kpkeydown=-1;
411 }
412 }
413 }
414 }
415
416
patch_specialkey(unsigned char key,int x,int y)417 void patch_specialkey(unsigned char key, int x, int y)
418 {
419 switch(key)
420 {
421 case GLUT_KEY_LEFT:
422 if (cpatch[csynth]>0) cpatch[csynth]--;
423 break;
424
425 case GLUT_KEY_RIGHT:
426 if (cpatch[csynth]<MAX_PATCHES) cpatch[csynth]++;
427 break;
428
429 case GLUT_KEY_UP:
430 if (csynth>0) { csynth--; synth_stackify(csynth); }
431 break;
432
433 case GLUT_KEY_DOWN:
434 if (csynth<(MAX_SYNTH-1)) { csynth++; synth_stackify(csynth); }
435 break;
436 }
437 }
438
439
440
patch_draw(void)441 void patch_draw(void)
442 {
443 int m, mm, mi, mt;
444 char tmps[256], quant[256];
445 int x, yd;
446 int rkdown;
447 float f;
448
449 // run through the synth fifo and print out a list of modulators and their current values
450 m=0; mm=0;
451 x=0; yd=0;
452 while(signalfifo[csynth][m]>=0) {
453 mi=signalfifo[csynth][m];
454 mt=mod[csynth][mi].type;
455
456 if (mm>=PATCHES_PER_COLUMN) { x=400; yd=PATCHES_PER_COLUMN*16; }
457 if (m==cphover) {
458 glColor4f(1.0, 1.0, 1.0, 0.16);
459 glBegin(GL_QUADS);
460 glVertex2f(x+16, 8+m*16-yd);
461 glVertex2f(x+380, 8+m*16-yd);
462 glVertex2f(x+380, 24+m*16-yd);
463 glVertex2f(x+16, 24+m*16-yd);
464 glEnd();
465 }
466
467 sprintf(tmps, "%02d", mi); render_text(tmps, x+20, 20+mm*16-yd, 2, 0xff505050, 0);
468 sprintf(tmps, "%s", modTypeNames[mod[csynth][mi].type]); render_text(tmps, x+44, 20+mm*16-yd, 2, 0xffc0c0c0, 0);
469
470 quant[0]='\0';
471 if (modModulatorTypes[mod[csynth][mi].type]==1)
472 sprintf(quant, "(%d bit)", modquantifier[csynth][ cpatch[csynth] ][ mi ]);
473 sprintf(tmps, "%s %s", modModulatorNames[mod[csynth][mi].type], quant);
474 if (mod[csynth][mi].type==MOD_KNOB ||
475 mod[csynth][mi].type==MOD_ATTENUATOR) sprintf(tmps, "%s %s", mod[csynth][mi].label, quant);
476 render_text(tmps, x+110, 20+mm*16-yd, 2, 0xff808080, 0);
477
478 switch(modModulatorTypes[mod[csynth][mi].type])
479 {
480 case 0: tmps[0]='\0'; break; // no modulator value
481 case 1: // float
482 if (mt==MOD_KNOB || mt==MOD_ATTENUATOR || mt==MOD_ACCENT) {
483 f=knob_float2scale(mod[csynth][mi].scale, modvalue[ csynth ][ cpatch[csynth] ][ mi ]);
484 sprintf(tmps, "%g %s", f, knobScaleUnits[ mod[csynth][mi].scale ]);
485 break;
486 } else { sprintf(tmps, "%g", modvalue[ csynth ][ cpatch[csynth] ][ mi ]); break; }
487 case 2: sprintf(tmps, "0x%08x", (int)(modvalue[ csynth ][ cpatch[csynth] ][ mi ])); break; // hex integer
488 case 3: sprintf(tmps, "%s", modVcoWaveforms[(int)(modvalue[csynth][cpatch[csynth]][mi])]);break; // vco waveform bits
489 case 4: sprintf(tmps, "%s", modLfoWaveforms[(int)(modvalue[csynth][cpatch[csynth]][mi])]);break; // lfo waveform bits
490 case 5: sprintf(tmps, "%s", modVcfModes[(int)(modvalue[csynth][cpatch[csynth]][mi])]);break; // vcf mode
491 case 6: sprintf(tmps, "%s", modDelayModes[(int)(modvalue[csynth][cpatch[csynth]][mi])]);break; // delay mode
492 case 7: sprintf(tmps, "%s", modSlewModes[(int)(modvalue[csynth][cpatch[csynth]][mi])]);break; // slew mode
493 case 8: sprintf(tmps, "ch %02d", 1+(int)(modvalue[csynth][cpatch[csynth]][mi]));break; // modulation source channel
494 }
495 if (mt==MOD_CV) sprintf(tmps, "%f hz", pitch[0]);
496 render_text(tmps, x+250, 20+mm*16-yd, 2, 0xffc0c0c0, 0);
497 m++; mm++;
498 }
499
500 // draw the piano keyboard for jazzing with the patch :)
501 rkdown=-1;
502 if (cpkeydown>=0) rkdown=cpkeydown;
503 if (kpkeydown>=0) rkdown=kpkeydown;
504 for(m=0;m<9;m++) {
505 if ( m >= coct && m < (coct+3)) {
506 draw_kbhoct(PIANO_LEFT+m*16*7, PIANO_TOP, 16, 70, m, cpkey, rkdown, &pianokeys[(m-coct)*12]);
507 } else {
508 draw_kbhoct(PIANO_LEFT+m*16*7, PIANO_TOP, 16, 70, m, cpkey, rkdown, NULL);
509 }
510 }
511
512 // draw the ui elements on the patch page
513 draw_button(17, 520-12, 16, "-", patch_ui[B_OCTDN]);
514 draw_button(DS_WIDTH-17, 520-12, 16, "+", patch_ui[B_OCTUP]);
515
516 draw_textbox(472, DS_HEIGHT-14, 16, 180, patchname[csynth][cpatch[csynth]], patch_ui[B_PATCHNAME]);
517
518 // draw_button(600, DS_HEIGHT-14, 16, "X", patch_ui[B_CUT]);
519 draw_button(622, DS_HEIGHT-14, 16, "C", patch_ui[B_COPY]);
520 draw_button(644, DS_HEIGHT-14, 16, "V", patch_ui[B_PASTE]);
521 if (patch_clipboard_synth<0 || patch_clipboard_synth!=csynth) {
522 glColor4f(0,0,0,0.4f);
523 glBegin(GL_QUADS);
524 glVertex2f(644-8, (DS_HEIGHT-14)-8); glVertex2f(644+8, (DS_HEIGHT-14)-8);
525 glVertex2f(644+8, (DS_HEIGHT-14)+8); glVertex2f(644-8, (DS_HEIGHT-14)+8);
526 glEnd();
527 }
528
529 draw_button(310, DS_HEIGHT-14, 16, "<<", patch_ui[B_PREV]);
530 sprintf(tmps, "%02d", cpatch[csynth]);
531 draw_textbox(336, DS_HEIGHT-14, 16, 24, tmps, 0);
532 draw_button(362, DS_HEIGHT-14, 16, ">>", patch_ui[B_NEXT]);
533
534 draw_button(14, DS_HEIGHT-14, 16, "<<", patch_ui[B_PREVSYN]);
535 sprintf(tmps, "%02d:%s",csynth, synthname[csynth]);
536 draw_textbox(122, DS_HEIGHT-14, 16, 188, tmps, patch_ui[B_SYNNAME]);
537 draw_button(230, DS_HEIGHT-14, 16, ">>", patch_ui[B_NEXTSYN]);
538 }
539
540
541
542
543 //
544 // modulator edit dialog
545 //
patch_draw_modulator(void)546 void patch_draw_modulator(void)
547 {
548 int i,mi,j;
549 char tmps[128], label[128], raws[128];
550 u32 fmask, *fptr;
551 float rf, f;
552
553 mi=signalfifo[ csynth ][ cphover ];
554 sprintf(label, "%s", modModulatorNames[mod[csynth][mi].type]);
555 if (mod[csynth][mi].type==MOD_KNOB) sprintf(label, "%s", mod[csynth][mi].label);
556 sprintf(tmps, "%02d %s %s", mi, modTypeNames[mod[csynth][mi].type], label);
557
558 draw_textbox((DS_WIDTH/2), (DS_HEIGHT/2), 120, 226, "", 0);
559 render_text(tmps, (DS_WIDTH/2)-108, (DS_HEIGHT/2)-46, 0, 0xffb05500, 0);
560 render_text("esc/right click to close", (DS_WIDTH/2)+111, (DS_HEIGHT/2)+72, 2, 0xffc0c0c0, 2);
561
562 render_text((char*)knobScaleNames[mod[csynth][mi].scale], (DS_WIDTH/2)-104, (DS_HEIGHT/2)-18, 2, 0xffc0c0c0, 0);
563 draw_textbox((DS_WIDTH/2)+54, (DS_HEIGHT/2)-20, 16, 100, modeditbox, modulator_ui[B_MOD_VALUE]);
564
565 render_text("precision:", (DS_WIDTH/2)-104, (DS_HEIGHT/2)+4, 2, 0xffc0c0c0, 0);
566 sprintf(tmps, "%d bits", modquantifier[ csynth ][ cpatch[csynth] ][ mi ]);
567 draw_textbox((DS_WIDTH/2)+34, (DS_HEIGHT/2)+2, 16, 100, tmps, 0);
568 draw_button((DS_WIDTH/2)+96, (DS_HEIGHT/2)+2, 16, "+", modulator_ui[B_MOD_ADDPREC]);
569 draw_button((DS_WIDTH/2)-28, (DS_HEIGHT/2)+2, 16, "-", modulator_ui[B_MOD_DECPREC]);
570
571 if (modModulatorTypes[mod[csynth][mi].type]==1) { // float
572 i=sscanf(modeditbox, "%f", &rf);
573 if (i==1) {
574 rf=knob_scale2float(mod[csynth][mi].scale, rf);
575 fptr=(unsigned long*)(&rf);
576 fmask=0xffffffff; j=32;
577 while(j>modquantifier[csynth][cpatch[csynth]][mi]) { fmask<<=1; j--; }
578 *fptr&=fmask;
579 f=knob_float2scale(mod[csynth][mi].scale, rf);
580 sprintf(tmps, "%g", f);
581 sprintf(raws, "%g", rf);
582 } else {
583 sprintf(tmps, "Not a float value");
584 raws[0]='\0';
585 }
586 render_text("output:", (DS_WIDTH/2)-104, (DS_HEIGHT/2)+36, 2, 0xffc0c0c0, 0);
587 render_text(tmps, (DS_WIDTH/2)+34, (DS_HEIGHT/2)+36, 2, 0xfff0f0f0, 1);
588
589 render_text("raw:", (DS_WIDTH/2)-104, (DS_HEIGHT/2)+50, 2, 0xffc0c0c0, 0);
590 render_text(raws, (DS_WIDTH/2)+34, (DS_HEIGHT/2)+50, 2, 0xfff0f0f0, 1);
591 }
592 }
593
patch_modulator_hover(int x,int y)594 void patch_modulator_hover(int x, int y)
595 {
596 modulator_ui[B_MOD_ADDPREC]=hovertest_box(x, y, (DS_WIDTH/2)+96, (DS_HEIGHT/2)+2, 16, 16);
597 modulator_ui[B_MOD_DECPREC]=hovertest_box(x, y, (DS_WIDTH/2)-28, (DS_HEIGHT/2)+2 , 16, 16);
598
599 modulator_ui[B_MOD_VALUE]&=0x06;
600 modulator_ui[B_MOD_VALUE]|=hovertest_box(x, y, (DS_WIDTH/2)+34, (DS_HEIGHT/2)-20, 16, 140);
601 }
602
patch_modulator_click(int button,int state,int x,int y)603 void patch_modulator_click(int button, int state, int x, int y)
604 {
605 int mi,i,j;
606 float f;
607 unsigned long fmask, *fptr;
608
609 if (state==GLUT_DOWN && !hovertest_box(x,y,(DS_WIDTH/2),(DS_HEIGHT/2),120,226 )) {
610 glutIgnoreKeyRepeat(1);
611 dialog_close();
612 return;
613 }
614
615 mi=signalfifo[csynth][cphover];
616 if (button==GLUT_RIGHT_BUTTON && hovertest_box(x,y,(DS_WIDTH/2),(DS_HEIGHT/2),120,226 )) {
617 // read the edit box contents back to the modulator
618 switch(modModulatorTypes[mod[csynth][mi].type]) {
619 case 1: // float
620 i=sscanf(modeditbox, "%f", &f);
621 if (i==1) {
622 f=knob_scale2float(mod[csynth][mi].scale, f);
623 fptr=(unsigned long*)(&f);
624 fmask=0xffffffff; j=32;
625 while(j>modquantifier[csynth][cpatch[csynth]][mi]) { fmask<<=1; j--; }
626 *fptr&=fmask;
627 modvalue[csynth][cpatch[csynth]][mi]=f;
628 }
629 break;
630 case 2: // integer
631 break;
632 }
633
634 glutIgnoreKeyRepeat(1); dialog_close(); return;
635 }
636 if (button==GLUT_LEFT_BUTTON) {
637 if (state==GLUT_DOWN) {
638
639 // remove kb focus it it was assigned
640 if (modkbfocus>=0) { modulator_ui[modkbfocus]&=0x03; modkbfocus=-1; glutIgnoreKeyRepeat(1); }
641
642 if (modulator_ui[B_MOD_ADDPREC]) {
643 if (modquantifier[ csynth ][cpatch[csynth]][ mi ]<32) modquantifier[ csynth ][cpatch[csynth]][ mi ]++; return;
644 }
645 if (modulator_ui[B_MOD_DECPREC])
646 {
647 if (modquantifier[ csynth ][cpatch[csynth]][ mi ]>12) modquantifier[ csynth ][cpatch[csynth]][ mi ]--; return;
648 }
649
650 // click to edit box
651 if (modulator_ui[B_MOD_VALUE]) {
652 modulator_ui[B_MOD_VALUE]|=4;
653 modkbfocus=B_MOD_VALUE;
654 glutIgnoreKeyRepeat(0);
655 return;
656 }
657 }
658 }
659 }
660
661
patch_modulator_special(int key,int x,int y)662 void patch_modulator_special(int key, int x, int y)
663 {
664 int mi;
665 float f, oldf;
666
667 /*
668 left/right = change value by 1% of original value
669 up/down = change value by 10% of original value
670 */
671
672 mi=signalfifo[csynth][cphover];
673 if (modModulatorTypes[mod[csynth][mi].type] == 1) { // float
674 f=knob_float2scale(mod[csynth][mi].scale, modvalue[ csynth ][cpatch[csynth]][ mi ]);
675 oldf=f;
676
677 // adjust float value
678 if (key==GLUT_KEY_RIGHT) f+=0.01f * patch_modulator_floatval;
679 if (key==GLUT_KEY_LEFT) f-=0.01f * patch_modulator_floatval;
680 if (key==GLUT_KEY_UP) f+=0.1f * patch_modulator_floatval;
681 if (key==GLUT_KEY_DOWN) f-=0.1f * patch_modulator_floatval;
682
683 // sanity-check value before applying to the module
684 switch (mod[csynth][mi].scale)
685 {
686 case SCALE_RAW:
687 break;
688
689 case SCALE_RAMP:
690 if (f<=0.0) f=oldf;
691 break;
692
693 case SCALE_FREQUENCY_HZ:
694 case SCALE_FREQUENCY_TEMPO:
695 case SCALE_DURATION:
696 case SCALE_DURATION_TEMPO:
697
698 case SCALE_PERCENTAGE:
699 if (f<0.0f) f=0.0f;
700 break;
701
702 case SCALE_MIDI_NOTE:
703 case SCALE_NOTE_INTERVAL:
704 if (f>127.0) f=127.0f;
705 if (f<0.0) f=0.0f;
706 break;
707
708 default:
709 break;
710 }
711
712 // apply value to module
713 modvalue[ csynth ][cpatch[csynth]][ mi ]=knob_scale2float(mod[csynth][mi].scale, f);
714 sprintf(modeditbox, "%g", f);
715 }
716 }
717
patch_modulator_keyboard(unsigned char key,int x,int y)718 void patch_modulator_keyboard(unsigned char key, int x, int y)
719 {
720 int mi,i,j;
721 float f;
722 unsigned long fmask, *fptr;
723
724 mi=signalfifo[csynth][cphover];
725
726 // already has kb focus?
727 if (modkbfocus==B_MOD_VALUE) {
728
729 if (key==13) { modulator_ui[B_MOD_VALUE]&=0x03; modkbfocus=-1; glutIgnoreKeyRepeat(1); } // enter
730 textbox_edit(modeditbox, key, 16);
731 return;
732 }
733
734 if (key==13) { // enter
735 switch(modModulatorTypes[mod[csynth][mi].type]) {
736 case 1: // float
737 i=sscanf(modeditbox, "%f", &f);
738 if (i==1) {
739 f=knob_scale2float(mod[csynth][mi].scale, f);
740 fptr=(unsigned long*)(&f);
741 fmask=0xffffffff; j=32;
742 while(j>modquantifier[csynth][cpatch[csynth]][mi]) { fmask<<=1; j--; }
743 *fptr&=fmask;
744 modvalue[csynth][cpatch[csynth]][mi]=f;
745 }
746 break;
747 case 2: // integer
748 break;
749 }
750
751 glutIgnoreKeyRepeat(1); dialog_close(); return;
752 }
753 if (key==27) { glutIgnoreKeyRepeat(1); dialog_close(); return; } // esc
754
755 // some other key, focus on textbox and edit
756 modulator_ui[B_MOD_VALUE]|=4;
757 modkbfocus=B_MOD_VALUE; glutIgnoreKeyRepeat(0);
758 textbox_edit(modeditbox, key, 16);
759 }
760
761
762
763
764
knob_scale2float(int scale,float value)765 float knob_scale2float(int scale, float value)
766 {
767 switch(scale) {
768 case SCALE_RAW: return value;
769 case SCALE_FREQUENCY_HZ: return value/OUTPUTFREQ;
770 case SCALE_FREQUENCY_TEMPO: return (value*bpm)/(60*OUTPUTFREQ);
771 case SCALE_DURATION_TEMPO: return (60/(bpm*value))*OUTPUTFREQ;
772 case SCALE_DURATION: return value*OUTPUTFREQ;
773 case SCALE_RAMP: return 1 / (value*OUTPUTFREQ);
774 case SCALE_PERCENTAGE: return (value/100.0);
775 case SCALE_MIDI_NOTE: return 8.1757989156 * pow(1.059463094, value) / OUTPUTFREQ;
776 case SCALE_NOTE_INTERVAL: return pow(1.059463094, value);
777 }
778 return 0.0;
779 }
780
knob_float2scale(int scale,float value)781 float knob_float2scale(int scale, float value)
782 {
783 switch(scale) {
784 case SCALE_RAW: return value;
785 case SCALE_FREQUENCY_HZ: return value*OUTPUTFREQ;
786 case SCALE_FREQUENCY_TEMPO: return (value*60*OUTPUTFREQ)/bpm;
787 case SCALE_DURATION_TEMPO: return (OUTPUTFREQ*60)/(value*bpm);
788 case SCALE_DURATION: return value/OUTPUTFREQ;
789 case SCALE_RAMP: return 1 / (value*OUTPUTFREQ);
790 case SCALE_PERCENTAGE: return (value*100.0);
791 case SCALE_MIDI_NOTE: return 17.31234049667*log(0.12231220586*value*OUTPUTFREQ);
792 case SCALE_NOTE_INTERVAL: return 17.31234049667*log(value);
793 }
794 return 0.0;
795 }
796