Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
5.1KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. Fl_EQGraph.cpp - Equalizer Graphical View
  4. Copyright (C) 2016 Mark McCurry
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. */
  10. #include <FL/Fl.H>
  11. #include <FL/fl_draw.H>
  12. #include "Fl_EQGraph.H"
  13. #include "common.H"
  14. #include "../Effects/EffectMgr.h"
  15. #include "../DSP/FFTwrapper.h"
  16. #include "../globals.h"
  17. #include <rtosc/rtosc.h>
  18. #define MAX_DB 30
  19. Fl_EQGraph::Fl_EQGraph(int x,int y, int w, int h, const char *label)
  20. :Fl_Box(x,y,w,h,label), Fl_Osc_Widget(this), samplerate(48000), gain(0.5f)
  21. {
  22. memset(num, 0, sizeof(num));
  23. memset(dem, 0, sizeof(dem));
  24. num[0] = 1;
  25. dem[0] = 1;
  26. ext = "eq-coeffs";
  27. osc->createLink("/samplerate", this);
  28. osc->requestValue("/samplerate");
  29. oscRegister("eq-coeffs");
  30. oscRegister("parameter0");
  31. }
  32. Fl_EQGraph::~Fl_EQGraph(void)
  33. {}
  34. void Fl_EQGraph::OSC_raw(const char *msg)
  35. {
  36. if(strstr(msg, "samplerate") && !strcmp("f", rtosc_argument_string(msg))) {
  37. samplerate = rtosc_argument(msg, 0).f;
  38. } else if(strstr(msg, "parameter0") && !strcmp("i", rtosc_argument_string(msg))) {
  39. gain = powf(0.005f, (1.0f-rtosc_argument(msg, 0).i/127.0f)) * 10.0f;
  40. } else {
  41. memcpy(dem, rtosc_argument(msg, 0).b.data, sizeof(dem));
  42. memcpy(num, rtosc_argument(msg, 1).b.data, sizeof(num));
  43. redraw();
  44. }
  45. }
  46. void Fl_EQGraph::update(void)
  47. {
  48. oscWrite("eq-coeffs");
  49. }
  50. void Fl_EQGraph::draw_freq_line(float freq, int type)
  51. {
  52. fl_color(FL_GRAY);
  53. float freqx=getfreqpos(freq);
  54. switch(type){
  55. case 0:if (active_r()) fl_color(FL_WHITE);
  56. else fl_color(205,205,205);
  57. fl_line_style(FL_SOLID);
  58. break;
  59. case 1:fl_line_style(FL_DOT);break;
  60. case 2:fl_line_style(FL_DASH);break;
  61. };
  62. if ((freqx>0.0)&&(freqx<1.0))
  63. fl_line(x()+(int) (freqx*w()),y(),
  64. x()+(int) (freqx*w()),y()+h());
  65. }
  66. void Fl_EQGraph::draw(void)
  67. {
  68. int ox=x(),oy=y(),lx=w(),ly=h(),i;
  69. double iy,oiy;
  70. float freqx;
  71. if (active_r()) fl_color(fl_darker(FL_GRAY));
  72. else fl_color(FL_GRAY);
  73. fl_rectf(ox,oy,lx,ly);
  74. //draw the lines
  75. fl_color(fl_lighter(FL_GRAY));
  76. fl_line_style(FL_SOLID);
  77. fl_line(ox+2,oy+ly/2,ox+lx-2,oy+ly/2);
  78. freqx=getfreqpos(1000.0);
  79. if ((freqx>0.0)&&(freqx<1.0))
  80. fl_line(ox+(int) (freqx*lx),oy,
  81. ox+(int) (freqx*lx),oy+ly);
  82. for (i=1;i<10;i++) {
  83. if(i==1) {
  84. draw_freq_line(i*100.0,0);
  85. draw_freq_line(i*1000.0,0);
  86. } else
  87. if (i==5) {
  88. draw_freq_line(i*10.0,2);
  89. draw_freq_line(i*100.0,2);
  90. draw_freq_line(i*1000.0,2);
  91. } else {
  92. draw_freq_line(i*10.0,1);
  93. draw_freq_line(i*100.0,1);
  94. draw_freq_line(i*1000.0,1);
  95. };
  96. };
  97. draw_freq_line(10000.0,0);
  98. draw_freq_line(20000.0,1);
  99. fl_line_style(FL_DOT);
  100. int GY=6;if (ly<GY*3) GY=-1;
  101. for (i=1;i<GY;i++){
  102. int tmp=(int)(ly/(float)GY*i);
  103. fl_line(ox+2,oy+tmp,ox+lx-2,oy+tmp);
  104. };
  105. //draw the frequency response
  106. if (active_r()) fl_color(FL_YELLOW);
  107. else fl_color(200,200,80);
  108. fl_line_style(FL_SOLID,2);
  109. //fl_color( fl_color_add_alpha( fl_color(), 127 ) );
  110. oiy=getresponse(ly,getfreqx(0.0));
  111. fl_begin_line();
  112. for (i=1;i<lx;i++){
  113. float frq=getfreqx(i/(float) lx);
  114. if (frq>samplerate/2) break;
  115. iy=getresponse(ly,frq);
  116. if ((oiy>=0) && (oiy<ly) &&
  117. (iy>=0) && (iy<ly) )
  118. fl_vertex(ox+i,oy+ly-iy);
  119. oiy=iy;
  120. };
  121. fl_end_line();
  122. fl_line_style(FL_SOLID,0);
  123. }
  124. /*
  125. * For those not too familiar with digital filters, what is happening here is an
  126. * evaluation of the filter's frequency response through the evaluation of
  127. * H(z^{-1}) via z^{-1}=e^{j\omega}.
  128. * This will yield a complex result which will indicate the phase and magnitude
  129. * transformation of the input at the set frequency denoted by \omega
  130. */
  131. double Fl_EQGraph::getresponse(int maxy,float freq) const
  132. {
  133. const float angle = 2*PI*freq/samplerate;
  134. float mag = 1;
  135. //std::complex<float> num_res = 0;
  136. //std::complex<float> dem_res = 0;
  137. for(int i = 0; i < MAX_EQ_BANDS*MAX_FILTER_STAGES; ++i) {
  138. if(num[3*i] == 0)
  139. break;
  140. std::complex<float> num_res= 0;
  141. std::complex<float> dem_res= 0;
  142. for(int j=0; j<3; ++j) {
  143. num_res += FFTpolar<float>(num[3*i+j], j*angle);
  144. dem_res += FFTpolar<float>(dem[3*i+j], j*angle);
  145. }
  146. mag *= abs(num_res/dem_res);
  147. }
  148. float dbresp=20*log(mag*gain)/log(10);
  149. //rescale
  150. return (int) ((dbresp/MAX_DB+1.0)*maxy/2.0);
  151. }
  152. float Fl_EQGraph::getfreqx(float x) const
  153. {
  154. if(x>1.0)
  155. x=1.0;
  156. return(20.0*pow((float)1000.0,x));
  157. }
  158. float Fl_EQGraph::getfreqpos(float freq) const
  159. {
  160. if(freq<0.00001)
  161. freq=0.00001;
  162. return(log(freq/20.0)/log(1000.0));
  163. }