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.

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