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