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.

183 lines
4.7KB

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