summaryrefslogblamecommitdiffstats
path: root/src/synth_gui.c
blob: 85a5be28632d3891e3f7566c0c54f21274de8d9d (plain) (tree)
1
2
3
4
5
6
7




                             
    
                                        


















                                                                              
    
                                       
 


















                                       
 







                                                                                       
 












                                                         


    
                                           
 





                                                                                                                                                                                                               








                                                                                                     









                                                                          

                                

     
 

                                 
                                                                    
                                                                      
                                                           

     

                                                                       
                  



                                                   















                                           


                                         















                                           


                                         















                                           


                                         

     

 
                                                                         









































                                                                                         
 


                                









                         


    
                                                              
 











                                                                               
 







                                                                                                                                        
 
           
 














                                                                                                 
   









                                                                                                    

                                                 
 
                                                                                               
    
                                                                                                                      
 
                              
 
                                   
    











                                                                                 
     


                                          
 



                                                   
 

























                                                                                                                                    
 
                     




                                                              

                                                 


                                   

   







                                                  
                           










                                                                                     
 


                                                         
   






                                                                                       

 
    

                                                                     
              
 






                                                                                                              
                                          

                                                
                            
                                                





                                   
                             




                                                      
                             




                                                      
                             




                                                      
                             




































                                                                                                    











































                                                                                                                                               
                                                             
   




                                                                                                                                      
 
                    
 
    
                                                                
                                                   


















                                                                                     













                                                                                                            































































































                                                                                                                         

    
                       


                          

               
                                             

                                                                                
                                   
                                
 


                                                                                        
                           
 



                                                         
 
 

                 



                                                                                                                        
    

                                          
 



                                                                                   
                                                                                                             
 
                                                                                                                  


                                                                                                  
                                                                                                     

                                                                                                                    
                                                                                                                             
 

                                                    
                                                        
 
                                                                                   


                                                                                         



                                                                                        
                                                   





                                                             
#include "synth_gui.h"
#define RAYGUI_IMPLEMENTATION
#include "raygui.h"
//#include "raylib.h"

void
draw_text(synth_t * synth, int x, int y)
{
  char buf[64];
  int count = 0;
  float text_size = 10;
  int offset = 12;

  snprintf(buf, sizeof buf, "lfo freq       %.4f", synth->cc_lfo_freq.value);
  DrawText(buf, x, y + offset * count++, text_size, GRAY);
  snprintf(buf, sizeof buf, "lfo amp        %.4f", synth->cc_lfo_amp.value);
  DrawText(buf, x, y + offset * count++, text_size, GRAY);
  snprintf(buf, sizeof buf, "filter reso    %.4f", synth->cc_resonance.value);
  DrawText(buf, x, y + offset * count++, text_size, GRAY);
  snprintf(buf, sizeof buf, "filter cutoff  %.1f", synth->cc_cutoff.value);
  DrawText(buf, x, y + offset * count++, text_size, GRAY);
  snprintf(buf, sizeof buf, "extra pitch    %.4f", synth->cc_pitch.value);
  DrawText(buf, x, y + offset * count++, text_size, GRAY);

  DrawRectangleLines(x - 6, y - 3, 120, 3 + (count * offset) + 3, GRAY);
}
void
mouse(synth_t *synth, PaStream *stream)
{
  float m =  GetMouseWheelMove();
  int x = 0;
  if (m < 0) x = -1;
  else if (m > 0) x = 1;
  int y = GetMouseY();

  if (x) {
    if (y > 20 && y <= 32) {
      cc_step(&synth->cc_lfo_freq, x);
    } else if (y > 32 && y <= 44) {
      cc_step(&synth->cc_lfo_amp, x);
    } else if (y > 44 && y <= 56) {
      cc_step(&synth->cc_resonance, x);
    } else if (y > 56 && y <= 68) {
      cc_step(&synth->cc_cutoff, x);
    } else if (y > 68 && y <= 80) {
      cc_step(&synth->cc_pitch, x);
    }
  }

  /* if (CheckCollisionPointRec(GetMousePosition(), (Rectangle){30, 250, 30, 30})) { */
  /*   SetMouseCursor(6); */
  /*   if (IsMouseButtonPressed(0)) { */
  /*     flag = 1; */
  /*   } */
  /* } else { */
  /*   SetMouseCursor(0); */
  /* } */

  /* if (IsMouseButtonDown(0) && flag) { */
  /*   SetMouseCursor(6); */
  /*   Vector2 dx = GetMouseDelta(); */
  /*   int x = 1; */
  /*   if (IsKeyDown(KEY_LEFT_SHIFT)) { */
  /*     x = 3; */
  /*   } */
  /*   if (dx.y < 0) cc_step(&synth->cc_adsr_s, 1*x); */
  /*   if (dx.y > 0) cc_step(&synth->cc_adsr_s, -1*x); */
  /* }  */
  /* if (IsMouseButtonReleased(0)) { */
  /*   flag = 0; */
  /* } */
}

void
keyboard(synth_t * synth, PaStream *stream)
{
  int keys[] = {KEY_Q, KEY_TWO, KEY_W, KEY_THREE, KEY_E, KEY_R, KEY_FIVE, KEY_T, KEY_SIX, KEY_Y, KEY_SEVEN, KEY_U, KEY_I, KEY_NINE, KEY_O, KEY_ZERO, KEY_P, KEY_LEFT_BRACKET, KEY_EQUAL, KEY_RIGHT_BRACKET, 0};

  float note;

  for (int i = 0; keys[i]; i++) {
    if (IsKeyPressed(keys[i])) {
      //printf("Note On : %s[%d] %fHz\n", int_to_note(i % 12), (synth->octave + (i / 12)) % 8, note);
      synth->midi_note[i].freq = 16.35160 * pow(2, (synth->octave + i / 12.0));
      //synth->midi_note[i].freq = notes[i % 12][(synth->octave + (i / 12)) % 8];
      synth->midi_note[i].channel = -1;
      synth->midi_note[i].noteOn = Pa_GetStreamTime(synth->stream);
      synth->midi_note[i].noteOff = 0;
      synth->midi_note[i].velocity = 1.0;
      synth->midi_note[i].elapsed = 0;
      synth->midi_note[i].active = 1;
      int flag = 1;
      for (int j = 0; j < synth->midi_active_n; j++) {
        if (synth->midi_active[j] == &synth->midi_note[i]) {
          flag = 0;
        }
      }
      if (flag) {
        synth->midi_active[synth->midi_active_n++] = &synth->midi_note[i];
      }

      //synth->adsr.elapsed = 0;
      synth->active = 1;
    }
  }

  for (int i = 0; keys[i]; i++) {
    if (IsKeyReleased(keys[i])) {
      synth->midi_note[i].noteOff = Pa_GetStreamTime(synth->stream);
      synth->midi_note[i].noteOffSample = synth->midi_note[i].elapsed;
      note = notes[i % 12][(synth->octave + (i / 12)) % 8];
    }
  }
  
  int patates[] = {KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, 0};
  synth->modi = 0;
  for (int i = 0; patates[i]; i++) {
    if (IsKeyDown(patates[i])) {
      synth->modifiers[synth->modi++] = patates[i];
    }
  }
  
  if (IsKeyDown(265)) { // up
    for (int i = 0; i < synth->modi; i++) {
      if (synth->modifiers[i] == KEY_Z) {
        cc_step(&synth->cc_cutoff, 1);
      }
      if (synth->modifiers[i] == KEY_X) {
        cc_step(&synth->cc_resonance, 1);
      }
      if (synth->modifiers[i] == KEY_C) {
        cc_step(&synth->cc_pitch, 1);
      }
      if (synth->modifiers[i] == KEY_V) {
        cc_step(&synth->cc_lfo_freq, 1);
      }
      if (synth->modifiers[i] == KEY_B) {
        cc_step(&synth->cc_lfo_amp, 1);
      }
    }
  }
  if (IsKeyDown(264)) { // down
    for (int i = 0; i < synth->modi; i++) {
      if (synth->modifiers[i] == KEY_Z) {
        cc_step(&synth->cc_cutoff, -1);
      }
      if (synth->modifiers[i] == KEY_X) {
        cc_step(&synth->cc_resonance, -1);
      }
      if (synth->modifiers[i] == KEY_C) {
        cc_step(&synth->cc_pitch, -1);
      }
      if (synth->modifiers[i] == KEY_V) {
        cc_step(&synth->cc_lfo_freq, -1);
      }
      if (synth->modifiers[i] == KEY_B) {
        cc_step(&synth->cc_lfo_amp, -1);
      }
    }
  }
  if (IsKeyDown(KEY_ENTER)) { // down
    for (int i = 0; i < synth->modi; i++) {
      if (synth->modifiers[i] == KEY_Z) {
        cc_reset(&synth->cc_cutoff);
      }
      if (synth->modifiers[i] == KEY_X) {
        cc_reset(&synth->cc_resonance);
      }
      if (synth->modifiers[i] == KEY_C) {
        cc_reset(&synth->cc_pitch);
      }
      if (synth->modifiers[i] == KEY_V) {
        cc_reset(&synth->cc_lfo_freq);
      }
      if (synth->modifiers[i] == KEY_B) {
        cc_reset(&synth->cc_lfo_amp);
      }
    }
  }
}

void frequencyToColor(float frequency, int *red, int *green, int *blue) {
  // Assuming frequency ranges from 20 to 20000 Hz
  float minFrequency = 20.0;
  float maxFrequency = 20000.0;

  // Map the frequency to a value between 0 and 1
  float normalizedFrequency = (frequency - minFrequency) / (maxFrequency - minFrequency);

  // Define colors for the rainbow spectrum
  float hue = normalizedFrequency * 360.0;

  // Convert HSV to RGB
  float c = 1.0;
  float x = c * (1.0 - fabs(fmod(hue / 60.0, 2.0) - 1.0));
  float m = 0.0;

  float r, g, b;

  if (hue >= 0 && hue < 60) {
    r = c;
    g = x;
    b = 0;
  } else if (hue >= 60 && hue < 120) {
    r = x;
    g = c;
    b = 0;
  } else if (hue >= 120 && hue < 180) {
    r = 0;
    g = c;
    b = x;
  } else if (hue >= 180 && hue < 240) {
    r = 0;
    g = x;
    b = c;
  } else if (hue >= 240 && hue < 300) {
    r = x;
    g = 0;
    b = c;
  } else {
    r = c;
    g = 0;
    b = x;
  }

  *red = (int)((r + m) * 255);
  *green = (int)((g + m) * 255);
  *blue = (int)((b + m) * 255);
}

#include "fftw3.h"

float
amp(float re, float im) {
  float a = fabsf(re);
  float b = fabsf(im);
  if (a < b) return b;
  return a;
}

void
draw_adsr(synth_t *synth, int x, int y, int width, int height)
{
  int x_prev = x;
  for (int i = 0; i < synth->midi_active_n; i++) {
    int rec_y = y + height - 1 +
                4.5 * floor( (WIDTH / 24) *
                             - fix_adsr(&synth->adsr,
                                        synth->midi_active[i]->noteOn,
                                        synth->midi_active[i]->noteOff,
                                        synth->midi_active[i]->elapsed,
                                        synth->midi_active[i]->noteOffSample));

    int rec_width = (WIDTH - x - x) / synth->midi_active_n;
    int rec_height = HEIGHT - rec_y;

    int red, green, blue;
    frequencyToColor(synth->midi_active[i]->freq * 25, &red, &green, &blue);
    DrawRectangleGradientV(x_prev, rec_y - 10, rec_width, rec_height, ColorAlpha(BLUE, .2) ,ColorAlpha((Color) {red, green, blue}, .2));
    //DrawRectangleGradientV(x_prev, rec_y - 10, rec_width, rec_height, ColorAlpha(GREEN, .2) ,ColorAlpha(RED, .2));
    //DrawRectangleLines(x_prev, rec_y - 10, rec_width, rec_height, GRAY);
    x_prev += rec_width;
  }
}

int freeze;

void
draw_wave(synth_t *synth, int x, int y, int width, int height)
{
  Color col;
  for (int i = 0; i < width; i++) {
    for (int j = 0; j < synth->viz.rate_divider; j++) {
      int ii =  synth->viz.rate_divider * (i) + j;
      if (synth->viz.wave_viz_buffer[ii] > 1 || synth->viz.wave_viz_buffer[ii] < -1)
        col = RED;
      else if (synth->viz.wave_viz_buffer[ii] >= 0.99 || synth->viz.wave_viz_buffer[ii] <= -0.99)
        col = MAGENTA;
      else
        col = WHITE;
      DrawPixel(i + x , y + height / 2 + floor(50 * synth->viz.wave_viz_buffer[ii + j]), col);
    }
  }
  /* for (int j = 0; j < 100; j++) { */
  /*   DrawPixel(synth->viz.tmp_index / synth->viz.rate_divider + 20,  j + y + height / 2, BLUE); */
  /*   DrawPixel(synth->viz.tmp_index / synth->viz.rate_divider + 20, -j + y + height / 2, BLUE); */
  /* } */
  //EndScissorMode();
}

void
draw_fft(synth_t *synth, int x, int y, int width, int height)
{
  int viz_size = width * synth->viz.rate_divider;
  int fft_output_len = viz_size / 2 + 1;

  fftwf_complex* output = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fft_output_len);
    
  fftwf_plan forward_plan = fftwf_plan_dft_r2c_1d(fft_output_len, synth->viz.fft_input_buffer, output, FFTW_ESTIMATE);

  fftwf_execute(forward_plan);

  fftwf_destroy_plan(forward_plan);
    
  // "Squash" into the Logarithmic Scale
  float step = 1.06;
  float lowf = 1.0f;
  size_t m = 0;
  float max_amp_tso = 1.0f;
  for (float f = lowf; (size_t) f < fft_output_len/2; f = ceilf(f*step)) {
    float f1 = ceilf(f*step);
    float a = 0.0f;
    for (size_t q = (size_t) f; q < fft_output_len/2 && q < (size_t) f1; ++q) {
      // maybe take the log? maybe not
      float b = log(sqrt(output[q][0]*output[q][0] + output[q][1]*output[q][1]));
      if (b > a) a = b;
    }
    if (max_amp_tso < a) max_amp_tso = a;
    synth->viz.fft_output_buffer[m++] = a;
  }

  // Normalize Frequencies to 0..1 range
  for (size_t i = 0; i < m; ++i) {
    synth->viz.fft_output_buffer[i] /= max_amp_tso;
  }

  // Smooth out and smear the values
  for (size_t i = 0; i < m; ++i) {
    float smoothness = 4;
    synth->viz.fft_smooth_buffer[i] += (synth->viz.fft_output_buffer[i] - synth->viz.fft_smooth_buffer[i])*smoothness*((float)1/30);
    /* float smearness = 3; */
    /* ss_smear[i] += (synth->viz.fft_smooth_buffer[i] - ss_smear[i])*smearness*((float)1/30); */
  }
  // Display the Bars
  float cell_width = (float)width/m;
  for (size_t i = 0; i < m; ++i) {
    float t = synth->viz.fft_smooth_buffer[i];
    float saturation = 0.75f;
    float value = 1.0f;
    float hue = (float)i/m;
    Color color = ColorFromHSV(hue*360, saturation, value);
    Vector2 startPos = {
      x + i*cell_width + cell_width/2,
      y + height - height*2/3*t,
    };
    Vector2 endPos = {
      x + i*cell_width + cell_width/2,
      y + height,
    };
    float thick = cell_width/3*sqrtf(t);
    DrawLineEx(startPos, endPos, thick, BLUE);
  }

  fftwf_free(output);
}

void
draw_osc(synth_t * synth, int x, int y, int width, int height)
{
  DrawRectangle(x, y, width, height, BLACK);
  DrawRectangleLines(x, y, width, height, WHITE);
  float osc_wave[width];
  for (int i = 0; i < width; i++) {
    osc_wave[i] = 0;
  }

  for (int i = 0; i < synth->midi_active_n; i++) {
    midi_note_t * note = synth->midi_active[i];
    midi_note_t note_dup;
    note_dup.freq =  note->freq;
    note_dup.channel =  note->channel;
    note_dup.noteOn =  note->noteOn;
    note_dup.noteOff =  note->noteOff;
    note_dup.velocity =  note->velocity;
    note_dup.wvt_index = 0;
    note_dup.lfo_index = note->lfo_index;
    note_dup.elapsed =  note->elapsed;
    note_dup.noteOffSample =  note->noteOffSample;
    note_dup.adsr =  note->adsr;
    note_dup.active = note->active;
    for (int i = 0; i < width; i++) {
      float freq = SAMPLE_RATE/(float)width;
      osc_wave[i] += synth->gen[synth->geni](freq, &note_dup, synth->x, SAMPLE_RATE);
    }
    break;
  }

  float max = 0;
  for (int i = 0; i < width; i++) {
    if (fabs(osc_wave[i]) > max) max = fabs(osc_wave[i]);
  }

  if (synth->midi_active_n) {
    for (int i = 0; i < width; i++) {
      DrawPixel(i + x , y + height / 2 + floor(height/2 * osc_wave[i] / max), RED);    
    }
  }    

}

void
draw_adsr_graph(synth_t * synth, int x, int y, int width, int height)
{
  adsr_t adsr;

  adsr.a = synth->cc_adsr_a.target;
  adsr.peak = synth->cc_adsr_peak.target;
  adsr.d = synth->cc_adsr_d.target;
  adsr.s = synth->cc_adsr_s.target;
  adsr.r = synth->cc_adsr_r.target;

  float total = synth->cc_adsr_a.target + synth->cc_adsr_d.target + synth->cc_adsr_r.target + 0.3; /*sustain*/
  int total_samples = total * SAMPLE_RATE;
  int a = synth->cc_adsr_a.target/total * width;
  int d = synth->cc_adsr_d.target/total * width;
  int s = 0.3/total * width;
  int r = synth->cc_adsr_r.target/total * width;

  float adsr_graph[width];
  for (int i = 0; i < width; i++) {
    float point = 0;

    if (i < a) { //draw atack
      point = fix_adsr(&adsr,
                       1, // note On
                       0, // note Off
                       (float)i/width * total_samples,
                       0);
    } else if (i < a + d) { // draw decay
      point = fix_adsr(&adsr,
                       1, // note On
                       0, // note Off
                       (float)i/width * total_samples,
                       0);
    } else if (i < a + d + s) { // draw sustain
      point = fix_adsr(&adsr,
                       1, // note On
                       0, // note Off
                       (float)i/width * total_samples,
                       0);
    } else if (i < a + d + s + r) { // draw release
      point = fix_adsr(&adsr,
                       0, // note On
                       1, // note Off
                       (float)i/width * total_samples,
                       (float)(a + d + s)/width * total_samples);
    }
    adsr_graph[i] = point * height;
  }
  adsr_graph[0] = adsr_graph[1]; // remove 1st 0

  for (int i = 0; i < width; i++) {
    DrawPixel(i + x , y + height - adsr_graph[i], RED);
  }
  
  int off_idx = a + d + s;
  for (int i = 0; i < synth->midi_active_n; i++) {
    midi_note_t * note = synth->midi_active[i];
    int elapsed_samples = note->elapsed;
    float elapsed_secs = (float)elapsed_samples / SAMPLE_RATE;
    int j = elapsed_secs / total * width;

    if (note->noteOff == 0) {
      if (j < a + d) {
        DrawCircle(j + x , y + height - adsr_graph[j], 5, RED);
      } else if (j < a + d + s - 1) {
        DrawCircle(j + x , y + height - adsr_graph[j], 5, RED);
      } else if (j > a + d + s - 1) {
        DrawCircle(a + d + s + x , y + height - adsr_graph[a + d + s], 5, RED);
      }
    } else { // note off
      int id = a + d + s + (float)(note->elapsed - note->noteOffSample)/SAMPLE_RATE / total * width;
      if (id > 0 && id < width)
        DrawCircle(id + x , y + height - adsr_graph[id], 5, RED);
    }
  }
}

void
draw_signals(synth_t * synth, int x, int y, int width, int height)
{
  DrawRectangleLines(x, y, width, height, WHITE);

  if (synth->viz.wave_enabled || synth->viz.spectrum_enabled)
    synth->viz.rate_divider = GuiSlider((Rectangle){ x + (width / 2) / 2, y - 12, width / 2, 12 }, "", NULL, synth->viz.rate_divider , 1, 150);

  int viz_size = width * synth->viz.rate_divider;
  
  float samples[RING_SIZE];
  int rc = PaUtil_ReadRingBuffer( &synth->viz.wave_buffer, &samples, RING_SIZE);

  synth->viz.freeze = GuiCheckBox((Rectangle){ x + width - 16, y, 16, 16 }, "", synth->viz.freeze);
  if (!synth->viz.freeze) {
    for (int i = 0; i < rc; i++) {
      synth->viz.fft_input_buffer[synth->viz.tmp_index] = samples[i];
      synth->viz.tmp_buffer[synth->viz.tmp_index++] = samples[i];
      if (synth->viz.tmp_index >= viz_size) {
        synth->viz.tmp_index = 0;
      }
    }
    for (int i = synth->viz.tmp_index; i < viz_size + synth->viz.tmp_index; i++) {
      synth->viz.wave_viz_buffer[i - synth->viz.tmp_index] = synth->viz.tmp_buffer[i % (viz_size)];
    }
  } else {
  }

  synth->viz.spectrum_enabled = GuiCheckBox((Rectangle){ x, y, 16, 16 }, "spectrum", synth->viz.spectrum_enabled);
  if (synth->viz.spectrum_enabled) {
    draw_fft(synth, x, y, width, height);
  }

  synth->viz.wave_enabled = GuiCheckBox((Rectangle){ x + 100, y, 16, 16 }, "wave", synth->viz.wave_enabled);
  if (synth->viz.wave_enabled) {
    draw_wave(synth, x, y, width, height);
  }

  synth->viz.adsr_enabled = GuiCheckBox((Rectangle){ x + 170, y, 16, 16 }, "adsr", synth->viz.adsr_enabled);
  if (synth->viz.adsr_enabled) {
    draw_adsr(synth, x, y, width, height);
  }

  synth->viz.osc_enabled = GuiCheckBox((Rectangle){ x + width - 170, y, 16, 16 }, "osc", synth->viz.osc_enabled);
  if (synth->viz.osc_enabled) {
    draw_osc(synth, x + width - 80, y + height - 80, 80, 80);
  }

  synth->viz.adsr_graph_enabled = GuiCheckBox((Rectangle){ x + width - 270, y, 16, 16 }, "adsr graph", synth->viz.adsr_graph_enabled);
  if (synth->viz.adsr_graph_enabled) {
    draw_adsr_graph(synth, x + 20, y + 20, width - 40, height - 40);
  }
}
char * flag = NULL; 

void
draw_cc_circle(cc_t * cc, int x, int y, int width, int height) {
  //DrawRectangleLines(x, y, width, height, WHITE);
  if (CheckCollisionPointRec(GetMousePosition(), (Rectangle){x, y, width, height})) {
    if (IsMouseButtonPressed(0)) {
      flag = cc->name;
    }
  }

  if (IsMouseButtonDown(0) && flag == cc->name) {
    Vector2 dx = GetMouseDelta();
    int x = 1;
    if (IsKeyDown(KEY_LEFT_SHIFT)) {
      x = 3;
    }
    if (dx.y < 0) cc_step(cc, 1*x);
    if (dx.y > 0) cc_step(cc, -1*x);
  } 
  if (IsMouseButtonReleased(0) && flag == cc->name) {
    flag = 0;
  }
  

  int min = 110;
  int max = 110 + (360+70 - 110) * (cc->target) / (cc->max - cc->min);
  DrawRing((Vector2){x + width/2, y + height/2}, width / 2 - 6, width / 2, min, max, 0, Fade(MAROON, 0.7f));
  DrawCircle(x + width/2, y + height/2, width / 2 - 5, BLACK); // Draw circle sector outline

  char buf[32];
  snprintf(buf, sizeof buf, "%0.2f", cc->target);
  DrawText(buf, x + width/2 - MeasureText(buf, 10) / 2, y + height/2 - 10 / 2, 10, GRAY);
  snprintf(buf, sizeof buf, "%s", cc->name);
  DrawText(buf, x + width/2 - MeasureText(buf, 10) / 2, y + height - 10 / 2, 10, GRAY);

}

float
map(float value, float start1, float end1, float start2, float end2) {
    return start2 + (end2 - start2) * ((value - start1) / (end1 - start1));
}


void
draw_cc_hbar(cc_t * cc, int x, int y, int width, int height) {
  char buf1[32], buf2[32];

  Vector2 p = GetMousePosition();

  if (CheckCollisionPointRec(p, (Rectangle){x, y, width, height})) {
    if (IsMouseButtonPressed(0)) {
      flag = cc->name;
    }
  }
  if (IsMouseButtonDown(0) && flag == cc->name) {
    if (p.x < x) {
      cc->target = cc->min;
    } else if (p.x >= x + width) {
      cc->target = cc->max;
    } else {
      cc->target = (cc->min + (cc->max - cc->min) * ((((p.x - x) * (float)1/width) - 0) / (1 - 0)));
    }
  } 
  if (IsMouseButtonReleased(0) && flag == cc->name) {
    flag = 0;
  }

  int current = width * (cc->target - cc->min) / (cc->max - cc->min) + cc->min;
  int fill_width = map(cc->target, cc->min, cc->max, 0, width - 2);


  snprintf(buf1, sizeof buf1, "%.2f", cc->target);
  snprintf(buf2, sizeof buf2, "%s", cc->name);

  DrawRectangleLines(x, y, width, height, WHITE);
  DrawRectangle(x+1, y+1, fill_width, height-2, Fade(MAROON, 0.7f));

  DrawText(buf2, x + width/2 - MeasureText(buf2, 10) / 2, y + height - 10 - 2, 10, WHITE);
  DrawText(buf1, x + 3, y + height / 2 - 10 / 2, 10, WHITE);
}

void
draw_cc_vbar(cc_t * cc, int x, int y, int width, int height) {
  char buf1[32], buf2[32];
  int current = height * (cc->target - cc->min) / (cc->max - cc->min) + cc->min - 1;

  Vector2 p = GetMousePosition();

  if (CheckCollisionPointRec(p, (Rectangle){x, y, width, height})) {
    if (IsMouseButtonPressed(0)) {
      flag = cc->name;
    }
  }
  if (IsMouseButtonDown(0) && flag == cc->name) {
    if (p.y < y) {
      cc->target = cc->max;
    } else if (p.y >= y + height) {
      cc->target = cc->min;
    } else {
      cc->target = cc->min + cc->max - (cc->min + (cc->max - cc->min) * ((((p.y - y) * (float)1/height) - 0) / (1 - 0)));
    }
  } 
  if (IsMouseButtonReleased(0) && flag == cc->name) {
    flag = 0;
  }

  snprintf(buf1, sizeof buf1, "%.2f", cc->target);
  snprintf(buf2, sizeof buf2, "%s", cc->name);

  int fill_height = map(cc->target, cc->min, cc->max, 0, height - 2);

  DrawRectangleLines(x, y, width, height, WHITE);
  DrawRectangle(x + 1, y + height - fill_height - 1, width - 2, fill_height, Fade(MAROON, 0.7f));

  DrawText(buf2, x + width/2 - MeasureText(buf2, 10) / 2, y + height + 10, 10, WHITE);
  DrawText(buf1, x + width/2 - MeasureText(buf1, 10) / 2, y - 10, 10, WHITE);
}


void
draw_bars(synth_t * synth, int x, int y, int width, int height, int offset)
{
  int count = 0;
  
  draw_cc_hbar(&synth->cc_adsr_a, x, y + count++ * (height + offset), width, height);
  draw_cc_hbar(&synth->cc_adsr_peak, x, y + count++ * (height + offset), width, height);
  draw_cc_hbar(&synth->cc_adsr_d, x, y + count++ * (height + offset), width, height);
  draw_cc_hbar(&synth->cc_adsr_s, x, y + count++ * (height + offset), width, height);
  draw_cc_hbar(&synth->cc_adsr_r, x, y + count++ * (height + offset), width, height);
  draw_cc_hbar(&synth->cc_gain, x, y + count++ * (height + offset), width, height);
  draw_cc_hbar(&synth->cc_del_feedback, x, y + count++ * (height + offset), width, height);
  draw_cc_hbar(&synth->cc_del_time, x, y + count++ * (height + offset), width, height);
}

void
rayrun(synth_t *synth){
  PaTime current_time = 0;
  PaTime prev_time = 0;

  osc_sound(0);

  InitWindow(WIDTH, HEIGHT, "Raylib synth"); 
  SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
  while (!WindowShouldClose()) {
    keyboard(synth, synth->stream);
    mouse(synth, synth->stream);

    // Draw
    //----------------------------------------------------------------------------------
    BeginDrawing();
    ClearBackground(BLACK);

    draw_cc_circle(&synth->cc_pitch, 30, 250, 30, 30);
    draw_cc_hbar(&synth->cc_cutoff, 30, 300, 256, 24);
    draw_cc_vbar(&synth->cc_resonance, 330, 20, 24, 256);
    //draw_cc_vbar(&synth->cc_adsr_s, 30, 250, 30, 30);


    // GUI
    char buf[64];
    snprintf(buf, sizeof buf, "%d", synth->wvt_pos);
    synth->wvt_pos = GuiSlider((Rectangle){WIDTH / 2 - 108, 150 + 42 + 42, 216, 24 }, "", buf, synth->wvt_pos , 0, 127);
    set_sound_start(synth->wvt_pos*2048);
    set_sound_len(synth->wvt_pos*2048 + 2048);
    
    draw_bars(synth, 20, 20, 200, 16, 3);
    draw_text(synth, WIDTH / 2 - 108, 20);

    if ( GuiButton((Rectangle){ WIDTH / 2 - 108, 150 - 6 - 6 + 42, 216, 6 }, "")) {
      synth->x = 1;
    }
    snprintf(buf, sizeof buf, "%.1f", synth->x);
    synth->x = GuiSlider((Rectangle){ WIDTH / 2 - 108, 150 + 42, 216, 24 }, "x", buf, synth->x , 0.0f, 2.0f);

    synth->filter = GuiToggle((Rectangle){ WIDTH - 100 - 50 - 100 - 50 , 50 , 100, 24 }, "FILTER", synth->filter);

    GuiSpinner((Rectangle){ WIDTH - 100 - 50 , 50, 100, 24 }, "oct: ", &(synth->octave), 0, 7, 0);
    snprintf(buf, sizeof buf, "generator %d  --> ", synth->geni);
    GuiSpinner((Rectangle){ WIDTH - 100 - 50 , 50 + 24 + 6, 100, 24 }, buf, &(synth->geni), 0, 6, 0);

    synth->clamp = GuiToggle((Rectangle){ WIDTH - 100 - 50, 50 + 24 + 6 + 24 + 6, 100, 24 }, "clamp", synth->clamp);
    synth->delay = GuiToggle((Rectangle){ WIDTH - 100 - 50, 50 + 24 + 6 + 24 + 6 + 24 + 6, 100, 24 }, "delay", synth->delay);

    // signals
    draw_signals(synth, 20, 390, WIDTH - 2*20, 200);
    //draw_signals(synth, 300, 390, WIDTH - 2*300, 200);

    //DrawText("THE SYNTH!!!!!!!!!!!!!!!!!!1", WIDTH / 2 - 100, 50, 20, LIGHTGRAY);
    /* DrawText("KEYBOARD: Q .. ]", WIDTH / 2 -300, HEIGHT - 300 - 50, 20, LIGHTGRAY); */
    /* snprintf(buf, sizeof buf, "stream time: %f", Pa_GetStreamTime(synth->stream)); */
    /* DrawText(buf, WIDTH / 2 -300, HEIGHT - 300, 11, LIGHTGRAY); */

    EndDrawing();
    //----------------------------------------------------------------------------------

    current_time = Pa_GetStreamTime(synth->stream);
    //printf("%f :: %ld\n", current_time - prev_time, phase);

    prev_time = current_time;
  }
  CloseWindow();
}