1 /*
2  * Copyright (C) 2020 Hermann Meyer, Andreas Degert
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  * --------------------------------------------------------------------------
18  */
19 
20 /*---------------------------------------------------------------------
21 -----------------------------------------------------------------------
22                 define PortIndex and plugin uri
23 -----------------------------------------------------------------------
24 ----------------------------------------------------------------------*/
25 
26 #include "gx_mbcompressor.h"
27 
28 /*---------------------------------------------------------------------
29 -----------------------------------------------------------------------
30                 define controller numbers
31 -----------------------------------------------------------------------
32 ----------------------------------------------------------------------*/
33 
34 #define CONTROLS 26
35 
36 /*---------------------------------------------------------------------
37 -----------------------------------------------------------------------
38                 include the LV2 interface
39 -----------------------------------------------------------------------
40 ----------------------------------------------------------------------*/
41 
42 #include "lv2_plugin.cc"
43 
44 /*---------------------------------------------------------------------
45 -----------------------------------------------------------------------
46                 define the plugin settings
47 -----------------------------------------------------------------------
48 ----------------------------------------------------------------------*/
49 
50 typedef struct {
51     Widget_t *meter_widget[10];
52     Widget_t *combo_widget[5];
53     Adjustment_t *adj[3];
54     float db_zero;
55 } X11_UI_Private_t;
56 
57 // setup a color theme
set_my_theme(Xputty * main)58 static void set_my_theme(Xputty *main) {
59     main->color_scheme->normal = (Colors) {
60          /* cairo    / r  / g  / b  / a  /  */
61         .fg =       { 0.45, 0.45, 0.45, 1.0},
62         .bg =       { 0.07, 0.05, 0.14, 1.00},
63         .base =     { 0.0, 0.0, 0.0, 1.00},
64         .text =     { 0.45, 0.45, 0.45, 1.0},
65         .shadow =   { 0.28, 0.34, 0.62, 0.43},
66         .frame =    { 0.0, 0.0, 0.0, 1.0},
67         .light =    { 0.1, 0.1, 0.1, 1.0}
68     };
69 
70     main->color_scheme->prelight = (Colors) {
71         .fg =       { 1.0, 1.0, 1.0, 1.0},
72         .bg =       { 0.14, 0.14, 0.22, 1.00},
73         .base =     { 0.0, 0.0, 0.0, 1.00},
74         .text =     { 0.7, 0.7, 0.7, 1.0},
75         .shadow =   { 0.28, 0.34, 0.62, 0.63},
76         .frame =    { 0.3, 0.3, 0.3, 1.0},
77         .light =    { 0.3, 0.3, 0.3, 1.0}
78     };
79 
80     main->color_scheme->selected = (Colors) {
81         .fg =       { 0.9, 0.9, 0.9, 1.0},
82         .bg =       { 0.14, 0.14, 0.22, 1.00},
83         .base =     { 0.0, 0.0, 0.18, 1.00},
84         .text =     { 1.0, 1.0, 1.0, 1.0},
85         .shadow =   { 0.28, 0.34, 0.62, 0.93},
86         .frame =    { 0.18, 0.18, 0.18, 1.0},
87         .light =    { 0.18, 0.18, 0.28, 1.0}
88     };
89 }
90 
91 // draw the slider handle
rounded_rectangle(cairo_t * cr,float x,float y,float w,float h)92 static void rounded_rectangle(cairo_t *cr,float x, float y, float w, float h) {
93     float r = h*0.55;
94 
95     cairo_move_to(cr,x+r,y);
96     cairo_line_to(cr,x+w-r,y);
97     cairo_curve_to(cr,x+w,y,x+w,y,x+w,y+r);
98     cairo_line_to(cr,x+w,y+h-r);
99     cairo_curve_to(cr,x+w,y+h,x+w,y+h,x+w-r,y+h);
100     cairo_line_to(cr,x+r,y+h);
101     cairo_curve_to(cr,x,y+h,x,y+h,x,y+h-r);
102     cairo_line_to(cr,x,y+r);
103     cairo_curve_to(cr,x,y,x,y,x+r,y);
104 }
105 
106 // draw the slider
draw_my_hslider(void * w_,void * user_data)107 static void draw_my_hslider(void *w_, void* user_data) {
108     Widget_t *w = (Widget_t*)w_;
109     X11_UI* ui = (X11_UI*)w->parent_struct;
110     X11_UI_Private_t *ps = (X11_UI_Private_t*)ui->private_ptr;
111 
112     int width = w->width-2;
113     int height = w->height-2;
114     float center = (float)height/2;
115 
116     float sliderstate1 = adj_get_state(w->adj);
117     float sliderstate2 = adj_get_state(ps->adj[0]);
118     float sliderstate3 = adj_get_state(ps->adj[1]);
119     float sliderstate4 = adj_get_state(ps->adj[2]);
120     float sliderstate = 0.0;
121     Color_state s1 = NORMAL_;
122     Color_state s2 = NORMAL_;
123     Color_state s3 = NORMAL_;
124     Color_state s4 = NORMAL_;
125 
126     if (w->state>0.0 && w->state<4.0 && w->adj_x) {
127         if (w->adj_x == w->adj) {
128             sliderstate = sliderstate1;
129             s1 = PRELIGHT_;
130         } else if (w->adj_x == ps->adj[0]) {
131             sliderstate = sliderstate2;
132             s2 = PRELIGHT_;
133         } else if (w->adj_x == ps->adj[1]) {
134             sliderstate = sliderstate3;
135             s3 = PRELIGHT_;
136         } else if (w->adj_x == ps->adj[2]) {
137             sliderstate = sliderstate4;
138             s4 = PRELIGHT_;
139         }
140     }
141     cairo_pattern_t* pat;
142 
143     pat = cairo_pattern_create_linear (0, 0, 0, height);
144     cairo_pattern_add_color_stop_rgba (pat, 1,  0.25, 0.25, 0.25, 1.0);
145     cairo_pattern_add_color_stop_rgba (pat, 0.75,  0.2, 0.2, 0.2, 1.0);
146     cairo_pattern_add_color_stop_rgba (pat, 0.5,  0.15, 0.15, 0.15, 1.0);
147     cairo_pattern_add_color_stop_rgba (pat, 0.25,  0.1, 0.1, 0.1, 1.0);
148     cairo_pattern_add_color_stop_rgba (pat, 0,  0.05, 0.05, 0.05, 1.0);
149 
150 
151     cairo_set_source (w->crb, pat);
152     rounded_rectangle(w->crb, 0.0, 0.0,width,height);
153     cairo_set_line_width(w->crb,2);
154     cairo_stroke(w->crb);
155     cairo_pattern_destroy (pat);
156     pat = NULL;
157 
158     use_text_color_scheme(w, get_color_state(w));
159     cairo_move_to (w->crb, center, center);
160     cairo_line_to(w->crb,width-center,center);
161     cairo_set_line_width(w->crb,center/10);
162     cairo_stroke(w->crb);
163 
164     pat = cairo_pattern_create_linear (0, 0, 0, height);
165     cairo_pattern_add_color_stop_rgba (pat, 0,  0.25, 0.25, 0.25, 1.0);
166     cairo_pattern_add_color_stop_rgba (pat, 0.25,  0.2, 0.2, 0.2, 1.0);
167     cairo_pattern_add_color_stop_rgba (pat, 0.5,  0.15, 0.15, 0.15, 1.0);
168     cairo_pattern_add_color_stop_rgba (pat, 0.75,  0.1, 0.1, 0.1, 1.0);
169     cairo_pattern_add_color_stop_rgba (pat, 1,  0.05, 0.05, 0.05, 1.0);
170 
171     cairo_set_source (w->crb, pat);
172     rounded_rectangle(w->crb, (width-height)*sliderstate1,0,height, height);
173     cairo_fill_preserve (w->crb);
174     cairo_set_source_rgb (w->crb, 0.1, 0.1, 0.1);
175     cairo_set_line_width(w->crb,2);
176     cairo_stroke(w->crb);
177     cairo_new_path (w->crb);
178     cairo_set_source (w->crb, pat);
179     rounded_rectangle(w->crb, (width-height)*sliderstate2,0,height, height);
180     cairo_fill_preserve (w->crb);
181     cairo_set_source_rgb (w->crb, 0.1, 0.1, 0.1);
182     cairo_stroke(w->crb);
183     cairo_new_path (w->crb);
184     cairo_set_source (w->crb, pat);
185     rounded_rectangle(w->crb, (width-height)*sliderstate3,0,height, height);
186     cairo_fill_preserve (w->crb);
187     cairo_set_source_rgb (w->crb, 0.1, 0.1, 0.1);
188     cairo_stroke(w->crb);
189     cairo_new_path (w->crb);
190     cairo_set_source (w->crb, pat);
191     rounded_rectangle(w->crb, (width-height)*sliderstate4,0,height, height);
192     cairo_fill_preserve (w->crb);
193     cairo_set_source_rgb (w->crb, 0.1, 0.1, 0.1);
194     cairo_stroke(w->crb);
195     cairo_new_path (w->crb);
196     cairo_pattern_destroy (pat);
197     pat = NULL;
198 
199     use_text_color_scheme(w, s1);
200     cairo_set_line_width(w->crb,2);
201     cairo_move_to (w->crb,((width-height)*sliderstate1)+center, 2.0);
202     cairo_line_to(w->crb,((width-height)*sliderstate1)+center,height-4.0);
203     cairo_stroke(w->crb);
204     use_text_color_scheme(w, s2);
205     cairo_move_to (w->crb,((width-height)*sliderstate2)+center, 2.0);
206     cairo_line_to(w->crb,((width-height)*sliderstate2)+center,height-4.0);
207     cairo_stroke(w->crb);
208     use_text_color_scheme(w, s3);
209     cairo_move_to (w->crb,((width-height)*sliderstate3)+center, 2.0);
210     cairo_line_to(w->crb,((width-height)*sliderstate3)+center,height-4.0);
211     cairo_stroke(w->crb);
212     use_text_color_scheme(w, s4);
213     cairo_move_to (w->crb,((width-height)*sliderstate4)+center, 2.0);
214     cairo_line_to(w->crb,((width-height)*sliderstate4)+center,height-4.0);
215     cairo_stroke(w->crb);
216 
217     /** show value on the slider**/
218     if (w->state>0.0 && w->state<4.0 && w->adj_x) {
219         use_fg_color_scheme(w, PRELIGHT_);
220         cairo_text_extents_t extents;
221         char s[64];
222         char l[64];
223         snprintf(l,63,"%s ", w->label);
224         const char* format[] = {"%.1f", "%.2f", "%.3f"};
225         snprintf(s, 63, format[2-1], pow(10.0,w->adj_x->value));
226         strcat(l,s);
227         cairo_set_font_size (w->crb, min(11.0,height));
228         cairo_text_extents(w->crb, l, &extents);
229         cairo_move_to (w->crb, min(width-extents.width ,(width-height)*sliderstate), height);
230         cairo_show_text(w->crb, l);
231         cairo_new_path (w->crb);
232     }
233 }
234 
plugin_value_changed(X11_UI * ui,Widget_t * w,PortIndex index)235 void plugin_value_changed(X11_UI *ui, Widget_t *w, PortIndex index) {
236     if (ui->block_event != w->data) {
237         if (index >= MODE1 && index <= MODE5) {
238             float value = adj_get_value(w->adj)+1.0;
239             ui->write_function(ui->controller,w->data,sizeof(float),0,&value);
240             ui->block_event = -1;
241         }
242     }
243 }
244 
245 // check that bands didn't overlap
check_multi_controller(X11_UI * ui,uint32_t port_index,float value)246 static void check_multi_controller(X11_UI* ui, uint32_t port_index, float value) {
247     X11_UI_Private_t *ps = (X11_UI_Private_t*)ui->private_ptr;
248     float v = log10f(value);
249     switch ((PortIndex)port_index)
250         {
251         case CROSSOVER_B1_B2:
252             check_value_changed(ui->widget[25]->adj, &v);
253             adj_set_value(ps->adj[0], max(adj_get_value(ps->adj[0]), v+0.1));
254         break;
255         case CROSSOVER_B2_B3:
256             adj_set_value(ui->widget[25]->adj, min(adj_get_value(ui->widget[25]->adj), v-0.1));
257             check_value_changed(ps->adj[0], &v);
258             adj_set_value(ps->adj[1], max(adj_get_value(ps->adj[1]), v+0.1));
259         break;
260         case CROSSOVER_B3_B4:
261             adj_set_value(ps->adj[0], min(adj_get_value(ps->adj[0]), v-0.1));
262             check_value_changed(ps->adj[1], &v);
263             adj_set_value(ps->adj[2], max(adj_get_value(ps->adj[2]), v+0.1));
264         break;
265         case CROSSOVER_B4_B5:
266             adj_set_value(ps->adj[1], min(adj_get_value(ps->adj[1]), v-0.1));
267             check_value_changed(ps->adj[2], &v);
268         break;
269         default:
270         break;
271     }
272 }
273 
274 // if adjustment value changed send notify to host
slider_value_changed(void * w_,void * user_data)275 static void slider_value_changed(void *w_, void* user_data) {
276     Widget_t *w = (Widget_t*)w_;
277     X11_UI* ui = (X11_UI*)w->parent_struct;
278     X11_UI_Private_t *ps = (X11_UI_Private_t*)ui->private_ptr;
279     uint32_t port_index = 0;
280     float value = 0.0;
281     if (w->adj_x == w->adj) {
282         port_index = CROSSOVER_B1_B2;
283         value = adj_get_value(w->adj);
284     } else if (w->adj_x == ps->adj[0]) {
285         port_index = CROSSOVER_B2_B3;
286         value = adj_get_value(ps->adj[0]);
287     } else if (w->adj_x == ps->adj[1]) {
288         port_index = CROSSOVER_B3_B4;
289         value = adj_get_value(ps->adj[1]);
290     } else if (w->adj_x == ps->adj[2]) {
291         port_index = CROSSOVER_B4_B5;
292         value = adj_get_value(ps->adj[2]);
293     }
294     if (port_index) {
295         float v = pow(10,value);
296         check_multi_controller(ui,port_index, v);
297         if (ui->block_event != (int)port_index)
298             ui->write_function(ui->controller,port_index,sizeof(float),0,&v);
299         ui->block_event = -1;
300     }
301 }
302 
303 // redraw slider when mouse button released
my_slider_released(void * w_,void * button_,void * user_data)304 static void my_slider_released(void *w_, void* button_, void* user_data) {
305     Widget_t *w = (Widget_t*)w_;
306     expose_widget(w);
307 }
308 
309 // set active adjustment based on mouse position
my_slider_pressed(void * w_,void * button_,void * user_data)310 static void my_slider_pressed(void *w_, void* button_, void* user_data) {
311     Widget_t *w = (Widget_t*)w_;
312     X11_UI* ui = (X11_UI*)w->parent_struct;
313     X11_UI_Private_t *ps = (X11_UI_Private_t*)ui->private_ptr;
314     float x = float(w->pos_x)/float(w->width-w->height);
315 
316     float sliderstate1 = adj_get_state(w->adj);
317     float sliderstate2 = adj_get_state(ps->adj[0]);
318     float sliderstate3 = adj_get_state(ps->adj[1]);
319     float sliderstate4 = adj_get_state(ps->adj[2]);
320 
321     if (x < sliderstate1+0.04 && x >sliderstate1) {
322         w->adj_x = w->adj;
323         w->label = "Band 1<|>2 ";
324     }
325     else if (x < sliderstate2+0.04 && x >sliderstate2) {
326         w->adj_x = ps->adj[0];
327         w->label = "Band 2<|>3 ";
328     }
329     else if (x < sliderstate3+0.04 && x >sliderstate3) {
330         w->adj_x = ps->adj[1];
331         w->label = "Band 3<|>4 ";
332     }
333     else if (x < sliderstate4+0.04 && x >sliderstate4) {
334         w->adj_x = ps->adj[2];
335         w->label = "Band 4<|>5 ";
336     } else {
337         w->adj_x = NULL;
338         w->label = " ";
339     }
340     adj_set_start_value(w);
341 
342     expose_widget(w);
343 }
344 
345 // shortcut to create multi adjustment slider with portindex binding
add_my_slider(Widget_t * w,PortIndex index,const char * label,X11_UI * ui,int x,int y,int width,int height)346 Widget_t* add_my_slider(Widget_t *w, PortIndex index, const char * label,
347                                 X11_UI* ui, int x, int y, int width, int height) {
348     X11_UI_Private_t *ps = (X11_UI_Private_t*)ui->private_ptr;
349     w = create_widget(ui->win->app, ui->win, x, y, width, height);
350     w->label = label;
351     w->adj = add_adjustment(w,1.3, 1.3, 1.3, 4.3, 0.001, CL_CONTINUOS);
352     adj_set_scale(w->adj, 2.0);
353     ps->adj[0] = add_adjustment(w,1.3, 1.3, 1.3, 4.3, 0.001, CL_CONTINUOS);
354     adj_set_scale(ps->adj[0], 2.0);
355     ps->adj[1] = add_adjustment(w,1.3, 1.3, 1.3, 4.3, 0.001, CL_CONTINUOS);
356     adj_set_scale(ps->adj[1], 2.0);
357     ps->adj[2] = add_adjustment(w,1.3, 1.3, 1.3, 4.3, 0.001, CL_CONTINUOS);
358     adj_set_scale(ps->adj[2], 2.0);
359     w->scale.gravity = ASPECT;
360     w->func.expose_callback = draw_my_hslider;
361     w->func.enter_callback = transparent_draw;
362     w->func.leave_callback = transparent_draw;
363     w->func.button_press_callback = my_slider_pressed;
364     w->func.button_release_callback = my_slider_released;
365     w->parent_struct = ui;
366     w->data = index;
367     w->func.value_changed_callback = slider_value_changed;
368     return w;
369 }
370 
plugin_set_window_size(int * w,int * h,const char * plugin_uri)371 void plugin_set_window_size(int *w,int *h,const char * plugin_uri) {
372     (*w) = 780; //initial width of main window
373     (*h) = 520; //initial height of main window
374 }
375 
plugin_set_name()376 const char* plugin_set_name() {
377     return "GxMultiBandCompressor"; //plugin name to display on UI
378 }
379 
plugin_create_controller_widgets(X11_UI * ui,const char * plugin_uri)380 void plugin_create_controller_widgets(X11_UI *ui, const char * plugin_uri) {
381     X11_UI_Private_t *ps =(X11_UI_Private_t*)malloc(sizeof(X11_UI_Private_t));;
382     ui->private_ptr = (void*)ps;
383     ps->db_zero = 20.*log10(0.0000003); // -130db
384     set_my_theme(&ui->main);
385 
386     int iw=0;
387     int w_pos = 620;
388     int port = (PortIndex) V1;
389     for (;iw<10;iw++) {
390         ps->meter_widget[iw] = add_vmeter(ui->win, "Meter", false, w_pos, 60, 20, 340);
391         ps->meter_widget[iw]->parent_struct = ui;
392         ps->meter_widget[iw]->scale.gravity = CENTER;
393         ps->meter_widget[iw]->data = port;
394         port +=1;
395         w_pos +=20;
396         if(iw == 4) w_pos = 60;
397     }
398 
399 
400     iw=0;
401     w_pos = 200;
402     port = (PortIndex) MAKEUP1;
403     for (;iw<5;iw++) {
404         ui->widget[iw] = add_my_knob(ui->widget[iw], (PortIndex)port,"Makeup", ui,w_pos, 0, 60, 85);
405         set_adjustment(ui->widget[iw]->adj,13.0, 13.0, -50.0, 50.0, 0.1, CL_CONTINUOS);
406         //adj_set_scale(ui->widget[iw]->adj, 2.0);
407         port +=1;
408         w_pos +=80;
409     }
410 
411     w_pos = 200;
412     port = (PortIndex) MAKEUPTHRESHOLD1;
413     for (;iw<10;iw++) {
414         ui->widget[iw] = add_my_knob(ui->widget[iw], (PortIndex)port,"Threshold", ui,w_pos, 85, 60, 85);
415         set_adjustment(ui->widget[iw]->adj,2.0, 2.0, 0.0, 10.0, 0.01, CL_CONTINUOS);
416         //adj_set_scale(ui->widget[iw]->adj, 2.0);
417         port +=1;
418         w_pos +=80;
419     }
420 
421     w_pos = 200;
422     port = (PortIndex) RATIO1;
423     for (;iw<15;iw++) {
424         ui->widget[iw] = add_my_knob(ui->widget[iw], (PortIndex)port,"Ratio", ui,w_pos, 170, 60, 85);
425         set_adjustment(ui->widget[iw]->adj,4.0, 4.0, 1.0, 100.0, 0.1, CL_CONTINUOS);
426         //adj_set_scale(ui->widget[iw]->adj, 2.0);
427         port +=1;
428         w_pos +=80;
429     }
430 
431     w_pos = 200;
432     port = (PortIndex) ATTACK1;
433     for (;iw<20;iw++) {
434         ui->widget[iw] = add_my_knob(ui->widget[iw], (PortIndex)port,"Attack", ui,w_pos, 255, 60, 85);
435         set_adjustment(ui->widget[iw]->adj,0.012, 0.012, 0.001, 1.0, 0.001, CL_CONTINUOS);
436         //adj_set_scale(ui->widget[iw]->adj, 2.0);
437         port +=1;
438         w_pos +=80;
439     }
440 
441     w_pos = 200;
442     port = (PortIndex) RELEASE1;
443     for (;iw<25;iw++) {
444         ui->widget[iw] = add_my_knob(ui->widget[iw], (PortIndex)port,"Release", ui,w_pos, 340, 60, 85);
445         set_adjustment(ui->widget[iw]->adj,1.25, 1.25, 0.01, 10.0, 0.01, CL_CONTINUOS);
446         //adj_set_scale(ui->widget[iw]->adj, 2.0);
447         port +=1;
448         w_pos +=80;
449     }
450 
451     w_pos = 185;
452     port = (PortIndex) MODE1;
453     const char* model[] = {"Compress","Bypass","Mute"};
454     size_t len = sizeof(model) / sizeof(model[0]);
455     iw=0;
456     for (;iw<5;iw++) {
457         ps->combo_widget[iw] = add_my_combobox(ps->combo_widget[iw], (PortIndex)port,"Mode", model, len, 0, ui, w_pos, 425, 80, 25);
458         //adj_set_scale(ui->widget[iw]->adj, 2.0);
459         port +=1;
460         w_pos +=80;
461     }
462 
463     ui->widget[25] = add_my_slider(ui->widget[25], CROSSOVER_B1_B2,"Crossover ",ui, 160,460, 480, 20);
464 }
465 
466 // map power to db for meter widgets
set_meter_value(X11_UI * ui,Widget_t * w,float value)467 static void set_meter_value(X11_UI* ui, Widget_t*w, float value) {
468     X11_UI_Private_t *ps = (X11_UI_Private_t*)ui->private_ptr;
469     float new_val = power2db(w,20.*log10(max(ps->db_zero,value)));
470     check_value_changed(w->adj,&new_val);
471 }
472 
plugin_cleanup(X11_UI * ui)473 void plugin_cleanup(X11_UI *ui) {
474     X11_UI_Private_t *ps = (X11_UI_Private_t*)ui->private_ptr;
475     int i = 0;
476     for(;i<10;i++)
477         destroy_widget(ps->meter_widget[i],&ui->main);
478     i = 0;
479     for(;i<5;i++)
480         destroy_widget(ps->combo_widget[i],&ui->main);
481     delete_adjustment(ps->adj[0]);
482     delete_adjustment(ps->adj[1]);
483     delete_adjustment(ps->adj[2]);
484     ui->widget[25]->adj_x = NULL;
485     free(ps);
486     ui->private_ptr = NULL;
487 }
488 
plugin_port_event(LV2UI_Handle handle,uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)489 void plugin_port_event(LV2UI_Handle handle, uint32_t port_index,
490                         uint32_t buffer_size, uint32_t format,
491                         const void * buffer) {
492     X11_UI* ui = (X11_UI*)handle;
493     X11_UI_Private_t *ps = (X11_UI_Private_t*)ui->private_ptr;
494     float value = *(float*)buffer;
495     if (port_index == V1) set_meter_value(ui,ps->meter_widget[0],value);
496     else if (port_index == V2) set_meter_value(ui,ps->meter_widget[1],value);
497     else if (port_index == V3) set_meter_value(ui,ps->meter_widget[2],value);
498     else if (port_index == V4) set_meter_value(ui,ps->meter_widget[3],value);
499     else if (port_index == V5) set_meter_value(ui,ps->meter_widget[4],value);
500     else if (port_index == V6) set_meter_value(ui,ps->meter_widget[5],value);
501     else if (port_index == V7) set_meter_value(ui,ps->meter_widget[6],value);
502     else if (port_index == V8) set_meter_value(ui,ps->meter_widget[7],value);
503     else if (port_index == V9) set_meter_value(ui,ps->meter_widget[8],value);
504     else if (port_index == V10) set_meter_value(ui,ps->meter_widget[9],value);
505     if (port_index >= CROSSOVER_B1_B2 && port_index <= CROSSOVER_B4_B5) {
506         check_multi_controller(ui, port_index, value);
507         ui->block_event = (int)port_index;
508     }
509     if (port_index >= MODE1 && port_index <= MODE5) {
510         value -=1.0;
511         check_value_changed(ps->combo_widget[port_index]->adj, &value);
512         ui->block_event = (int)port_index;
513     }
514 }
515