2
* hdeq.c -- Hand drawn EQ, crossover, and compressor graph interface for
3
* the JAMin (JACK Audio Mastering interface) program.
5
* Copyright (C) 2003 Jan C. Depner.
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27
#include <sys/times.h>
36
#include "callbacks.h"
38
#include "interface.h"
42
#include "compressor-ui.h"
44
#include "gtkmeterscale.h"
47
#include "transport.h"
51
#define NINT(a) ((a)<0.0 ? (int) ((a) - 0.5) : (int) ((a) + 0.5))
54
#define EQ_INTERP (BINS / 2 - 1)
55
#define EQ_SPECTRUM_RANGE 90.0
56
#define XOVER_HANDLE_SIZE 10
57
#define XOVER_HANDLE_HALF_SIZE (XOVER_HANDLE_SIZE / 2)
58
#define NOTCH_HANDLE_HEIGHT 14
59
#define NOTCH_HANDLE_HALF_HEIGHT (NOTCH_HANDLE_HEIGHT / 2)
60
#define NOTCH_HANDLE_WIDTH 6
61
#define NOTCH_HANDLE_HALF_WIDTH (NOTCH_HANDLE_WIDTH / 2)
63
#define NOTCH_INT ((int) ((EQ_INTERP + 1) / (NOTCHES - 1)))
64
#define MOTION_CLOCK_DIFF ((int) (sysconf (_SC_CLK_TCK) * 0.05))
67
void interpolate (float, int, float, float, int *, float *, float *, float *,
69
static void draw_EQ_curve ();
72
/* vi:set ts=8 sts=4 sw=4: */
74
static GtkHScale *l_low2mid, *l_mid2high;
75
static GtkWidget *l_comp[3];
76
static GtkLabel *l_low2mid_lbl, *l_mid2high_lbl, *l_comp_lbl[3],
77
*l_EQ_curve_lbl, *l_c_curve_lbl[3];
78
static GtkDrawingArea *l_EQ_curve, *l_comp_curve[3];
79
static GdkDrawable *EQ_drawable, *comp_drawable[3];
80
static GdkColormap *colormap = NULL;
81
static GdkColor white, black, comp_color[4], EQ_back_color,
82
EQ_fore_color, EQ_spectrum_color, EQ_grid_color,
84
static GdkGC *EQ_gc, *comp_gc[3];
85
static PangoContext *comp_pc[3], *EQ_pc;
86
static GtkAdjustment *l_low2mid_adj;
87
static float EQ_curve_range_x, EQ_curve_range_y, EQ_curve_width,
88
EQ_curve_height, EQ_xinterp[EQ_INTERP + 1], EQ_start,
89
EQ_end, EQ_interval, EQ_yinterp[EQ_INTERP + 1],
90
*EQ_xinput = NULL, *EQ_yinput = NULL,
91
l_geq_freqs[EQ_BANDS], l_geq_gains[EQ_BANDS],
92
comp_curve_range_x[3], comp_curve_range_y[3],
93
comp_curve_width[3], comp_curve_height[3] ,
94
comp_start_x[3], comp_start_y[3], comp_end_x[3],
95
comp_end_y[3], EQ_freq_xinterp[EQ_INTERP + 1],
96
EQ_freq_yinterp[EQ_INTERP + 1],
97
EQ_notch_gain[NOTCHES] = {0.0, 0.0, 0.0, 0.0, 0.0},
98
EQ_x_notched[EQ_INTERP + 1],
99
EQ_y_notched[EQ_INTERP + 1], EQ_gain_lower = -12.0,
100
EQ_gain_upper = 12.0;
101
static int EQ_mod = 1, EQ_drawing = 0, EQ_input_points = 0,
102
EQ_length = 0, comp_realized[3] = {0, 0, 0},
103
EQ_cleared = 1, EQ_realized = 0, xover_active = 0,
104
xover_handle_fa, xover_handle_fb, EQ_drag_fa = 0,
105
EQ_drag_fb = 0, EQ_partial = 0, part_x[2], part_y[2],
106
EQ_notch_drag[NOTCHES] = {0, 0, 0, 0, 0},
107
EQ_notch_Q_drag[NOTCHES] = {0, 0, 0, 0, 0},
108
EQ_notch_handle[2][3][NOTCHES],
109
EQ_notch_width[NOTCHES] = {0, 5, 5, 5, 0},
110
EQ_notch_index[NOTCHES] = {20, NOTCH_INT, 2 * NOTCH_INT,
111
3 * NOTCH_INT, EQ_INTERP - 20},
112
EQ_notch_flag[NOTCHES] = {0, 0, 0, 0, 0};
113
static guint notebook1_page = 0;
114
static gboolean hdeq_ready = FALSE;
118
/* Clear out the hand drawn EQ curves on exit. */
122
if (EQ_xinput) free (EQ_xinput);
123
if (EQ_yinput) free (EQ_yinput);
129
/* Generic color setting. */
131
static void set_color (GdkColor *color, unsigned short red,
132
unsigned short green, unsigned short blue)
134
if (colormap == NULL) colormap = gdk_colormap_get_system ();
137
color->green = green;
140
gdk_colormap_alloc_color (colormap, color, FALSE, TRUE);
144
/* Setup widget bindings based on names from glade-2. DON'T CHANGE WIDGET
145
NAMES in glade-2 without checking first. */
149
l_low2mid = GTK_HSCALE (lookup_widget (main_window, "low2mid"));
150
l_mid2high = GTK_HSCALE (lookup_widget (main_window, "mid2high"));
151
l_low2mid_lbl = GTK_LABEL (lookup_widget (main_window, "low2mid_lbl"));
152
l_mid2high_lbl = GTK_LABEL (lookup_widget (main_window, "mid2high_lbl"));
154
l_comp[0] = lookup_widget (main_window, "frame_l");
155
l_comp[1] = lookup_widget (main_window, "frame_m");
156
l_comp[2] = lookup_widget (main_window, "frame_h");
158
l_comp_lbl[0] = GTK_LABEL (lookup_widget (main_window, "label_freq_l"));
159
l_comp_lbl[1] = GTK_LABEL (lookup_widget (main_window, "label_freq_m"));
160
l_comp_lbl[2] = GTK_LABEL (lookup_widget (main_window, "label_freq_h"));
162
l_EQ_curve = GTK_DRAWING_AREA (lookup_widget (main_window, "EQ_curve"));
163
l_EQ_curve_lbl = GTK_LABEL (lookup_widget (main_window, "EQ_curve_lbl"));
165
l_comp_curve[0] = GTK_DRAWING_AREA (lookup_widget (main_window,
167
l_comp_curve[1] = GTK_DRAWING_AREA (lookup_widget (main_window,
169
l_comp_curve[2] = GTK_DRAWING_AREA (lookup_widget (main_window,
172
l_c_curve_lbl[0] = GTK_LABEL (lookup_widget (main_window,
174
l_c_curve_lbl[1] = GTK_LABEL (lookup_widget (main_window,
176
l_c_curve_lbl[2] = GTK_LABEL (lookup_widget (main_window,
180
set_color (&white, 65535, 65535, 65535);
181
set_color (&black, 0, 0, 0);
182
set_color (&EQ_notch_color, 65535, 65535, 0);
183
set_color (&comp_color[0], 60000, 0, 0);
184
set_color (&comp_color[1], 0, 50000, 0);
185
set_color (&comp_color[2], 0, 0, 60000);
186
set_color (&comp_color[3], 0, 0, 0);
187
set_color (&EQ_back_color, 0, 21611, 0);
188
set_color (&EQ_fore_color, 65535, 65535, 65535);
189
set_color (&EQ_grid_color, 0, 36611, 0);
190
set_color (&EQ_spectrum_color, 32768, 32768, 32768);
194
/* Setting the low to mid crossover. Called from callbacks.c. */
196
void hdeq_low2mid_set (GtkRange *range)
198
double value, other_value, lvalue, mvalue, hvalue;
202
value = gtk_range_get_value (range);
203
other_value = gtk_range_get_value ((GtkRange *) l_mid2high);
204
s_set_value_ui(S_XOVER_FREQ(0), value);
207
/* Don't let the two sliders cross each other and desensitize the mid
208
band compressor if they are the same value. */
210
if (value >= other_value)
213
gtk_range_set_value ((GtkRange *) l_mid2high, value);
215
gtk_widget_set_sensitive (l_comp[1], FALSE);
219
gtk_widget_set_sensitive (l_comp[1], TRUE);
223
/* If the low slider is at the bottom of it's range, desensitize the low
226
l_low2mid_adj = gtk_range_get_adjustment (range);
228
if (value == l_low2mid_adj->lower)
230
gtk_widget_set_sensitive (l_comp[0], FALSE);
234
gtk_widget_set_sensitive (l_comp[0], TRUE);
238
/* Set the label using log scale. */
240
lvalue = pow (10.0, value);
241
sprintf (label, "%05d", NINT (lvalue));
242
gtk_label_set_label (l_low2mid_lbl, label);
245
/* Write value into DSP code */
250
/* Set the compressor labels. */
252
hvalue = pow (10.0, other_value);
253
sprintf (label, _("Mid : %d - %d"), NINT (lvalue), NINT (hvalue));
254
gtk_label_set_label (l_comp_lbl[1], label);
256
lvalue = pow (10.0, l_low2mid_adj->lower);
257
mvalue = pow (10.0, value);
258
sprintf (label, _("Low : %d - %d"), NINT (lvalue), NINT (mvalue));
259
gtk_label_set_label (l_comp_lbl[0], label);
265
/* Setting the mid to high crossover. Called from callbacks.c. */
267
void hdeq_mid2high_set (GtkRange *range)
269
double value, other_value, lvalue, mvalue, hvalue;
273
value = gtk_range_get_value (range);
274
other_value = gtk_range_get_value ((GtkRange *) l_low2mid);
275
s_set_value_ui(S_XOVER_FREQ(1), value);
278
/* Don't let the two sliders cross each other and desensitize the mid
279
band compressor if they are the same value. */
281
if (value <= other_value)
284
gtk_range_set_value ((GtkRange *) l_low2mid, value);
286
gtk_widget_set_sensitive (l_comp[1], FALSE);
290
gtk_widget_set_sensitive (l_comp[1], TRUE);
294
/* If the slider is at the top of it's range, desensitize the high band
298
if (value == l_low2mid_adj->upper)
300
gtk_widget_set_sensitive (l_comp[2], FALSE);
304
gtk_widget_set_sensitive (l_comp[2], TRUE);
308
/* Set the label using log scale. */
310
mvalue = pow (10.0, value);
311
sprintf (label, "%05d", NINT (mvalue));
312
gtk_label_set_label (l_mid2high_lbl, label);
315
/* Write value into DSP code */
320
/* Set the compressor labels. */
322
lvalue = pow (10.0, other_value);
323
sprintf (label, _("Mid : %d - %d"), NINT (lvalue), NINT (mvalue));
324
gtk_label_set_label (l_comp_lbl[1], label);
326
hvalue = pow (10.0, l_low2mid_adj->upper);
327
sprintf (label, _("High : %d - %d"), NINT (mvalue), NINT (hvalue));
328
gtk_label_set_label (l_comp_lbl[2], label);
334
/* Someone has pressed the low to mid crossover button. Called from
337
void hdeq_low2mid_button (int active)
339
xover_active = active;
343
/* Someone has pressed the mid to high crossover button. Called from
346
void hdeq_mid2high_button (int active)
348
xover_active = active;
352
/* Initialize the low to mid crossover adjustment state. */
354
void hdeq_low2mid_init ()
356
s_set_adjustment(S_XOVER_FREQ(0), gtk_range_get_adjustment(GTK_RANGE(l_low2mid)));
360
/* Initialize the mid to high crossover adjustment state. */
362
void hdeq_mid2high_init ()
364
s_set_adjustment(S_XOVER_FREQ(1), gtk_range_get_adjustment(GTK_RANGE(l_mid2high)));
368
/* Set the low to mid and mid to high crossovers. This is from the
369
window1_show callback so it only gets called once. */
371
void crossover_init ()
373
hdeq_low2mid_set ((GtkRange *) l_low2mid);
374
hdeq_mid2high_set ((GtkRange *) l_mid2high);
378
/* If we've modified the graphic EQ (geq) then we want to build the hand
379
drawn EQ from the geq. This flag will cause that to happen on the next
388
/* Convert log frequency to X pixels in the hdeq. */
391
logfreq2xpix (float log_freq, int *x)
393
*x = NINT (((log_freq - l_low2mid_adj->lower) / EQ_curve_range_x) *
398
/* Convert frequency to X pixels in the hdeq. */
401
freq2xpix (float freq, int *x)
405
log_freq = log10f (freq);
406
logfreq2xpix (log_freq, x);
410
/* Convert gain to Y pixels in the hdeq. */
413
gain2ypix (float gain, int *y)
415
*y = EQ_curve_height - NINT (((gain - EQ_gain_lower) /
416
EQ_curve_range_y) * EQ_curve_height);
420
/* Convert log gain to Y pixels in the hdeq. */
423
loggain2ypix (float log_gain, int *y)
427
gain = log_gain * 20.0;
432
/* Draw the spectrum in the hdeq window. This is called from spectrum update
433
which is called based on the timer set up in main.c. */
435
void draw_EQ_spectrum_curve (float single_levels[])
437
static int x[EQ_INTERP], y[EQ_INTERP];
439
float step, range, freq;
442
/* Don't update if we're drawing an EQ curve. */
444
if (!EQ_drawing && !xover_active)
446
/* Plot the curve. */
448
gdk_gc_set_foreground (EQ_gc, &EQ_spectrum_color);
449
gdk_gc_set_function (EQ_gc, GDK_XOR);
450
gdk_gc_set_line_attributes (EQ_gc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT,
454
/* If we've just cleared (redrawn) the curve, don't erase the previous
457
if (EQ_partial || !EQ_cleared)
459
for (i = 1 ; i < EQ_INTERP ; i++)
461
if (!EQ_partial || x[i] < part_x[0] || x[i] > part_x[1] ||
462
y[i] < part_y[0] || y[i] > part_y[1])
464
gdk_draw_line (EQ_drawable, EQ_gc, x[i - 1], y[i - 1],
472
/* Convert the single levels to db, plot, and save the pixel positions
473
so that we can erase them on the next pass. */
475
range = l_geq_freqs[EQ_BANDS - 1] - l_geq_freqs[0];
476
step = range / (float) EQ_INTERP;
478
for (i = 0 ; i < EQ_INTERP ; i++)
480
freq = l_geq_freqs[0] + (float) i * step;
483
freq2xpix (freq, &x[i]);
486
/* Most of the single_level values will be in the -90.0db to
487
-20.0db range. We're using -90.0db to 0.0db as our range. */
489
y[i] = NINT (-(lin2db(single_levels[i]) / EQ_SPECTRUM_RANGE) *
492
if (i) gdk_draw_line (EQ_drawable, EQ_gc, x[i - 1], y[i - 1],
496
gdk_gc_set_line_attributes (EQ_gc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT,
498
gdk_gc_set_foreground (EQ_gc, &black);
499
gdk_gc_set_function (EQ_gc, GDK_COPY);
506
/* Given the frequency this returns the nearest array index in the X direction
507
in the hand drawn EQ curve. This will be one of 1024 values. */
509
static int nearest_x (float freq)
517
for (i = 0 ; i < EQ_length ; i++)
519
ndist = log10f (freq);
520
if (fabs (ndist - EQ_xinterp[i]) < dist)
522
dist = fabs (ndist - EQ_xinterp[i]);
531
/* Set the graphic EQ (geq) sliders and the full set of EQ coefficients
532
based on the hand drawn EQ curve. */
534
static void set_EQ ()
536
float *x = NULL, *y = NULL, interval;
540
/* Make sure we have enough space. */
542
size = EQ_length * sizeof (float);
543
x = (float *) realloc (x, size);
544
y = (float *) realloc (y, size);
548
perror (_("Allocating y in callbacks.c"));
553
/* Recompute the splined curve in the freq domain for setting
556
for (i = 0 ; i < EQ_length ; i++)
557
x[i] = pow (10.0, (double) EQ_x_notched[i]);
559
interval = ((l_geq_freqs[EQ_BANDS - 1]) - l_geq_freqs[0]) / EQ_INTERP;
561
interpolate (interval, EQ_length, l_geq_freqs[0],
562
l_geq_freqs[EQ_BANDS - 1], &EQ_length, x, EQ_y_notched,
563
EQ_freq_xinterp, EQ_freq_yinterp);
570
/* Set EQ coefficients based on the hand-drawn curve. */
572
geq_set_coefs (EQ_length, EQ_freq_xinterp, EQ_freq_yinterp);
575
/* Set the graphic EQ sliders based on the hand-drawn curve. */
577
geq_set_sliders (EQ_length, EQ_freq_xinterp, EQ_freq_yinterp);
583
/* Place the sliding notch filters in the hand drawn EQ curve. */
585
static void insert_notch ()
587
int i, j, ndx, left, right, length;
591
for (i = 0 ; i < EQ_length ; i++)
593
EQ_x_notched[i] = EQ_xinterp[i];
594
EQ_y_notched[i] = EQ_yinterp[i];
598
for (j = 0 ; j < NOTCHES ; j++)
600
if (EQ_notch_flag[j])
604
ndx = EQ_notch_index[j];
605
for (i = 0 ; i < ndx - 10 ; i++)
606
EQ_y_notched[i] = EQ_notch_gain[j];
608
x[0] = EQ_x_notched[ndx - 10];
609
y[0] = EQ_notch_gain[j];
610
x[1] = EQ_x_notched[ndx - 9];
611
y[1] = EQ_notch_gain[j];
612
x[2] = EQ_x_notched[ndx - 1];
613
y[2] = EQ_y_notched[ndx - 1];
614
x[3] = EQ_x_notched[ndx];
615
y[3] = EQ_y_notched[ndx];
617
interpolate (EQ_interval, 4, x[0], x[3], &length, x,
618
y, &EQ_x_notched[ndx - 10], &EQ_y_notched[ndx - 10]);
620
else if (j == NOTCHES - 1)
622
ndx = EQ_notch_index[j];
623
for (i = ndx + 10 ; i < EQ_length ; i++)
624
EQ_y_notched[i] = EQ_notch_gain[j];
626
x[0] = EQ_x_notched[ndx];
627
y[0] = EQ_y_notched[ndx];
628
x[1] = EQ_x_notched[ndx + 1];
629
y[1] = EQ_y_notched[ndx + 1];
630
x[2] = EQ_x_notched[ndx + 9];
631
y[2] = EQ_notch_gain[j];
632
x[3] = EQ_x_notched[ndx + 10];
633
y[3] = EQ_notch_gain[j];
635
interpolate (EQ_interval, 4, x[0], x[3], &length, x,
636
y, &EQ_x_notched[ndx], &EQ_y_notched[ndx]);
640
left = EQ_notch_index[j] - EQ_notch_width[j];
641
right = EQ_notch_index[j] + EQ_notch_width[j];
643
x[0] = EQ_x_notched[left];
644
y[0] = EQ_y_notched[left];
645
x[1] = EQ_x_notched[left + 1];
646
y[1] = EQ_y_notched[left + 1];
647
x[2] = EQ_x_notched[EQ_notch_index[j]];
648
y[2] = EQ_notch_gain[j];
649
x[3] = EQ_x_notched[right - 1];
650
y[3] = EQ_y_notched[right - 1];
651
x[4] = EQ_x_notched[right];
652
y[4] = EQ_y_notched[right];
654
interpolate (EQ_interval, 5, x[0], x[4], &length, x,
655
y, &EQ_x_notched[left], &EQ_y_notched[left]);
662
/* Draw the EQ curve. This may be from the graphic EQ sliders if they have
663
been modified. Usually from the hand drawn EQ though. */
665
static void draw_EQ_curve ()
667
int i, x0 = 0, y0 = 0, x1, y1, inc;
668
float x[EQ_BANDS], y[EQ_BANDS];
671
/* If we're not visible, go away. */
673
if (!EQ_realized) return;
676
/* Clear the curve drawing area. */
679
gdk_gc_set_foreground (EQ_gc, &EQ_back_color);
680
gdk_draw_rectangle (EQ_drawable, EQ_gc, TRUE, 0, 0, EQ_curve_width + 1,
681
EQ_curve_height + 1);
684
/* Draw the grid lines. */
686
geq_get_freqs_and_gains (l_geq_freqs, l_geq_gains);
689
gdk_gc_set_foreground (EQ_gc, &EQ_grid_color);
692
/* Box around the area. */
694
gdk_gc_set_line_attributes (EQ_gc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT,
696
gdk_draw_line (EQ_drawable, EQ_gc, 1, 1, 1, EQ_curve_height);
697
gdk_draw_line (EQ_drawable, EQ_gc, 1, EQ_curve_height, EQ_curve_width,
699
gdk_draw_line (EQ_drawable, EQ_gc, EQ_curve_width, EQ_curve_height,
701
gdk_draw_line (EQ_drawable, EQ_gc, EQ_curve_width, 1, 1, 1);
704
/* Frequency lines on log scale in X. */
706
gdk_gc_set_line_attributes (EQ_gc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT,
708
i = ((int) (l_geq_freqs[0] + 10.0) / 10) * 10;
710
while (i < l_geq_freqs[EQ_BANDS - 1])
712
for (x0 = i ; x0 <= inc * 10 ; x0 += inc)
714
freq2xpix ((float) x0, &x1);
716
gdk_draw_line (EQ_drawable, EQ_gc, x1, 0, x1, EQ_curve_height);
723
/* Gain lines in Y. */
726
if (EQ_curve_range_y < 10.0) inc = 1;
727
for (i = NINT (EQ_gain_lower) ; i < NINT (EQ_gain_upper) ; i++)
731
gain2ypix ((float) i, &y1);
733
gdk_draw_line (EQ_drawable, EQ_gc, 0, y1, EQ_curve_width, y1);
738
/* Add the crossover bars. */
740
gdk_gc_set_line_attributes (EQ_gc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT,
743
gdk_gc_set_foreground (EQ_gc, &comp_color[0]);
744
freq2xpix (xover_fa, &x1);
745
gdk_draw_line (EQ_drawable, EQ_gc, x1, 0, x1, EQ_curve_height);
746
gdk_draw_rectangle (EQ_drawable, EQ_gc, TRUE, x1 - XOVER_HANDLE_HALF_SIZE,
747
0, XOVER_HANDLE_SIZE, XOVER_HANDLE_SIZE);
748
gdk_draw_rectangle (EQ_drawable, EQ_gc, TRUE, x1 - XOVER_HANDLE_HALF_SIZE,
749
EQ_curve_height - XOVER_HANDLE_SIZE, XOVER_HANDLE_SIZE,
751
gdk_gc_set_foreground (EQ_gc, &black);
752
gdk_draw_rectangle (EQ_drawable, EQ_gc, FALSE, x1 - XOVER_HANDLE_HALF_SIZE,
753
0, XOVER_HANDLE_SIZE, XOVER_HANDLE_SIZE);
754
gdk_draw_rectangle (EQ_drawable, EQ_gc, FALSE, x1 - XOVER_HANDLE_HALF_SIZE,
755
EQ_curve_height - XOVER_HANDLE_SIZE, XOVER_HANDLE_SIZE,
758
xover_handle_fa = x1;
761
gdk_gc_set_foreground (EQ_gc, &comp_color[2]);
762
freq2xpix (xover_fb, &x1);
763
gdk_draw_line (EQ_drawable, EQ_gc, x1, 0, x1, EQ_curve_height);
764
gdk_draw_rectangle (EQ_drawable, EQ_gc, TRUE, x1 - XOVER_HANDLE_HALF_SIZE,
765
0, XOVER_HANDLE_SIZE, XOVER_HANDLE_SIZE);
766
gdk_draw_rectangle (EQ_drawable, EQ_gc, TRUE, x1 - XOVER_HANDLE_HALF_SIZE,
767
EQ_curve_height - XOVER_HANDLE_SIZE, XOVER_HANDLE_SIZE,
769
gdk_gc_set_foreground (EQ_gc, &black);
770
gdk_draw_rectangle (EQ_drawable, EQ_gc, FALSE, x1 - XOVER_HANDLE_HALF_SIZE,
771
0, XOVER_HANDLE_SIZE, XOVER_HANDLE_SIZE);
772
gdk_draw_rectangle (EQ_drawable, EQ_gc, FALSE, x1 - XOVER_HANDLE_HALF_SIZE,
773
EQ_curve_height - XOVER_HANDLE_SIZE, XOVER_HANDLE_SIZE,
776
xover_handle_fb = x1;
779
/* If we've messed with the graphics EQ sliders, recompute the splined
784
for (i = 0 ; i < EQ_BANDS ; i++)
786
x[i] = log10 (l_geq_freqs[i]);
787
y[i] = log10 (l_geq_gains[i]);
791
interpolate (EQ_interval, EQ_BANDS, EQ_start, EQ_end,
792
&EQ_length, x, y, EQ_xinterp, EQ_yinterp);
795
/* Save state of the EQ curve. */
797
s_set_value_block (EQ_yinterp, S_EQ_GAIN(0), EQ_length);
800
/* Reset all of the shelves/notches. */
802
for (i = 0 ; i < NOTCHES ; i++)
804
EQ_notch_flag[i] = 0;
805
EQ_notch_gain[i] = 0.0;
807
if (!i || i == NOTCHES - 1)
809
EQ_notch_width[i] = 0;
813
EQ_notch_width[i] = 5;
816
s_set_description (S_NOTCH_GAIN (i) ,
817
g_strdup_printf("Reset notch %d", i));
818
s_set_value_ns (S_NOTCH_GAIN (i), EQ_notch_gain[i]);
819
s_set_value_ns (S_NOTCH_Q (i), (float) EQ_notch_width[i]);
820
s_set_value_ns (S_NOTCH_FLAG (i), (float) EQ_notch_flag[i]);
827
/* Plot the curve. */
829
gdk_gc_set_foreground (EQ_gc, &EQ_fore_color);
830
for (i = 0 ; i < EQ_length ; i++)
832
logfreq2xpix (EQ_x_notched[i], &x1);
833
loggain2ypix (EQ_y_notched[i], &y1);
835
if (i) gdk_draw_line (EQ_drawable, EQ_gc, x0, y0, x1, y1);
842
/* Add the notch handles. */
844
for (i = 0 ; i < NOTCHES ; i++)
846
gdk_gc_set_foreground (EQ_gc, &EQ_notch_color);
848
logfreq2xpix (EQ_x_notched[EQ_notch_index[i]], &x1);
851
/* Make the shelf handles follow the shelf. */
853
if (EQ_notch_flag[i] && (!i || i == NOTCHES - 1))
855
loggain2ypix (EQ_notch_gain[i], &y1);
859
loggain2ypix (EQ_y_notched[EQ_notch_index[i]], &y1);
862
gdk_draw_rectangle (EQ_drawable, EQ_gc, TRUE,
863
x1 - NOTCH_HANDLE_HALF_WIDTH, y1 - NOTCH_HANDLE_HALF_HEIGHT,
864
NOTCH_HANDLE_WIDTH, NOTCH_HANDLE_HEIGHT);
865
gdk_gc_set_foreground (EQ_gc, &black);
866
gdk_draw_rectangle (EQ_drawable, EQ_gc, FALSE,
867
x1 - NOTCH_HANDLE_HALF_WIDTH, y1 - NOTCH_HANDLE_HALF_HEIGHT,
868
NOTCH_HANDLE_WIDTH, NOTCH_HANDLE_HEIGHT);
870
EQ_notch_handle[0][0][i] = EQ_notch_handle[0][1][i] =
871
EQ_notch_handle[0][2][i]= x1;
872
EQ_notch_handle[1][1][i] = y1;
876
EQ_notch_handle[0][0][i] = 0;
880
EQ_notch_handle[0][2][i] = EQ_curve_width;
884
/* Notch handles, not shelf. */
886
if (i && i < NOTCHES - 1)
888
gdk_gc_set_foreground (EQ_gc, &EQ_notch_color);
890
x0 = EQ_notch_index[i] - EQ_notch_width[i];
892
logfreq2xpix (EQ_x_notched[x0], &x1);
893
loggain2ypix (EQ_y_notched[x0], &y1);
895
if (EQ_notch_handle[0][1][i] - x1 < NOTCH_HANDLE_HALF_WIDTH)
896
x1 = EQ_notch_handle[0][1][i] - NOTCH_HANDLE_WIDTH;
898
gdk_draw_arc (EQ_drawable, EQ_gc, TRUE,
899
x1 - NOTCH_HANDLE_WIDTH, y1 - NOTCH_HANDLE_HALF_HEIGHT,
900
NOTCH_HANDLE_WIDTH * 2, NOTCH_HANDLE_HEIGHT, 5760, 11520);
901
gdk_gc_set_foreground (EQ_gc, &black);
902
gdk_draw_arc (EQ_drawable, EQ_gc, FALSE,
903
x1 - NOTCH_HANDLE_WIDTH, y1 - NOTCH_HANDLE_HALF_HEIGHT,
904
NOTCH_HANDLE_WIDTH * 2, NOTCH_HANDLE_HEIGHT, 5760, 11520);
906
EQ_notch_handle[0][0][i] = x1;
907
EQ_notch_handle[1][0][i] = y1;
910
gdk_gc_set_foreground (EQ_gc, &EQ_notch_color);
912
x0 = EQ_notch_index[i] + EQ_notch_width[i];
914
logfreq2xpix (EQ_x_notched[x0], &x1);
915
loggain2ypix (EQ_y_notched[x0], &y1);
917
if (x1 - EQ_notch_handle[0][1][i] < NOTCH_HANDLE_HALF_WIDTH)
918
x1 = EQ_notch_handle[0][1][i] + NOTCH_HANDLE_WIDTH;
920
gdk_draw_arc (EQ_drawable, EQ_gc, TRUE,
921
x1 - NOTCH_HANDLE_WIDTH, y1 - NOTCH_HANDLE_HALF_HEIGHT,
922
NOTCH_HANDLE_WIDTH * 2, NOTCH_HANDLE_HEIGHT, 17280, 11520);
923
gdk_gc_set_foreground (EQ_gc, &black);
924
gdk_draw_arc (EQ_drawable, EQ_gc, FALSE,
925
x1 - NOTCH_HANDLE_WIDTH, y1 - NOTCH_HANDLE_HALF_HEIGHT,
926
NOTCH_HANDLE_WIDTH * 2, NOTCH_HANDLE_HEIGHT, 17280, 11520);
928
EQ_notch_handle[0][2][i] = x1;
929
EQ_notch_handle[1][2][i] = y1;
933
gdk_gc_set_line_attributes (EQ_gc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT,
941
/* Whenever the curve is exposed, which will happen on a resize, we need to
942
get the current dimensions and redraw the curve. */
944
void hdeq_curve_exposed (GtkWidget *widget, GdkEventExpose *event)
946
l_low2mid_adj = gtk_range_get_adjustment ((GtkRange *) l_low2mid);
947
EQ_curve_range_x = l_low2mid_adj->upper - l_low2mid_adj->lower;
949
EQ_curve_range_y = EQ_gain_upper - EQ_gain_lower;
952
/* Since allocation width and height are inclusive we need to decrement
955
EQ_curve_width = widget->allocation.width - 1;
956
EQ_curve_height = widget->allocation.height - 1;
959
/* If we only get part of the window exposed we don't want to redraw the
962
if (event->area.height != widget->allocation.height ||
963
event->area.width != widget->allocation.width ||
964
event->area.x != widget->allocation.x ||
965
event->area.y != widget->allocation.y) EQ_partial = 1;
967
part_x[0] = event->area.x;
968
part_y[0] = event->area.y;
969
part_x[1] = part_x[0] + event->area.width;
970
part_y[1] = part_y[0] + event->area.height;
978
/* Initialize the hdeq. This comes from the realize callback for the hdeq
979
drawing area. Called from callbacks.c. */
981
void hdeq_curve_init (GtkWidget *widget)
983
EQ_drawable = widget->window;
985
EQ_gc = widget->style->fg_gc[GTK_WIDGET_STATE (widget)];
987
EQ_pc = gtk_widget_get_pango_context (widget);
989
geq_get_freqs_and_gains (l_geq_freqs, l_geq_gains);
991
EQ_start = log10 (l_geq_freqs[0]);
992
EQ_end = log10 (l_geq_freqs[EQ_BANDS - 1]);
993
EQ_interval = (EQ_end - EQ_start) / EQ_INTERP;
995
s_set_callback(S_NOTCH_GAIN(0), set_EQ_curve_values);
1001
/* Don't let the notches overlap. */
1003
static int check_notch (int notch, int new, int q)
1005
int j, k, left, right, width, ret;
1015
j = EQ_notch_index[notch + 1] - EQ_notch_width[notch + 1];
1016
if (new >= j || new < 10) ret = 0;
1022
else if (notch == NOTCHES - 1)
1024
k = EQ_notch_index[notch - 1] + EQ_notch_width[notch - 1];
1025
if (new <= k || new > EQ_length - 10) ret = 0;
1033
j = EQ_notch_index[notch - 1] + EQ_notch_width[notch - 1];
1034
k = EQ_notch_index[notch + 1] - EQ_notch_width[notch + 1];
1038
width = EQ_notch_index[notch] - left;
1039
right = left + 2 * width;
1041
if (EQ_notch_index[notch] - left < 5) ret = 0;
1046
width = right - EQ_notch_index[notch];
1047
left = right - 2 * width;
1049
if (right - EQ_notch_index[notch] < 5) ret = 0;
1053
left = new - EQ_notch_width[notch];
1054
right = new + EQ_notch_width[notch];
1056
if (left <= j || right >= k) ret = 0;
1063
/* This comes from the hdeq drawing area motion callback (actually the event
1064
box). There are about a million things going on here. This is basically
1065
the engine for the hdeq interface. The rest of it happens in the button
1066
press and release handlers. Take a look at the comments in the function
1067
to see what's actually happening. */
1069
void hdeq_curve_motion (GdkEventMotion *event)
1071
static int prev_x = -1, prev_y = -1, current_cursor = -1;
1072
int i, j, x, y, size, diffx_fa, diffx_fb, diff_notch[2],
1073
cursor, drag, notch_flag = -1, lo, hi, clock_diff;
1074
float freq, gain, s_gain;
1077
static clock_t old_clock = -1;
1081
/* We don't want motion events until the window is ready. */
1083
if (!hdeq_ready) return;
1086
/* Timing delay so we don't get five bazillion calls. */
1088
new_clock = times (&buf);
1089
clock_diff = abs (new_clock - old_clock);
1091
if (clock_diff < MOTION_CLOCK_DIFF) return;
1093
old_clock = new_clock;
1096
x = NINT (event->x);
1097
y = NINT (event->y);
1101
/* We only want to update things if we've actually moved the cursor. */
1103
if (x != prev_x || y != prev_y)
1105
freq = pow (10.0, (l_low2mid_adj->lower + (((double) x /
1106
(double) EQ_curve_width) * EQ_curve_range_x)));
1109
gain = ((((double) EQ_curve_height - (double) y) /
1110
(double) EQ_curve_height) * EQ_curve_range_y) +
1113
s_gain = -(EQ_SPECTRUM_RANGE - (((((double) EQ_curve_height -
1114
(double) y) / (double) EQ_curve_height) * EQ_SPECTRUM_RANGE)));
1116
sprintf (coords, _("%dHz , EQ : %ddb , Spectrum : %ddb"), NINT (freq),
1117
NINT (gain), NINT (s_gain));
1118
gtk_label_set_text (l_EQ_curve_lbl, coords);
1121
/* If we're in the midst of drawing the curve... */
1125
/* Only allow the user to draw in the positive direction. */
1127
if (!EQ_input_points || x > EQ_xinput[EQ_input_points - 1])
1129
gdk_gc_set_foreground (EQ_gc, &EQ_fore_color);
1130
if (EQ_input_points) gdk_draw_line (EQ_drawable, EQ_gc,
1131
NINT (EQ_xinput[EQ_input_points - 1]),
1132
NINT (EQ_yinput[EQ_input_points - 1]), x, y);
1134
size = (EQ_input_points + 1) * sizeof (float);
1135
EQ_xinput = (float *) realloc (EQ_xinput, size);
1136
EQ_yinput = (float *) realloc (EQ_yinput, size);
1138
if (EQ_yinput == NULL)
1140
perror (_("Allocating EQ_yinput in callbacks.c"));
1144
EQ_xinput[EQ_input_points] = (float) x;
1145
EQ_yinput[EQ_input_points] = (float) y;
1149
else if (EQ_drag_fa)
1151
freq = log10f (freq);
1152
gtk_range_set_value ((GtkRange *) l_low2mid, freq);
1154
else if (EQ_drag_fb)
1156
freq = log10f (freq);
1157
gtk_range_set_value ((GtkRange *) l_mid2high, freq);
1164
/* Check for notch drag. */
1166
for (i = 0 ; i < NOTCHES ; i++)
1168
if (EQ_notch_drag[i])
1170
/* If we're shifted we're raising or lowering notch
1173
if (event->state & GDK_SHIFT_MASK)
1175
if (y >= 0 && y <= EQ_curve_height)
1177
EQ_notch_gain[i] = (((((double) EQ_curve_height -
1178
(double) y) / (double) EQ_curve_height) *
1179
EQ_curve_range_y) + EQ_gain_lower) * 0.05;
1183
EQ_notch_flag[i] = 1;
1185
s_set_description (S_NOTCH_GAIN (i) ,
1186
g_strdup_printf("Move notch %d", i));
1187
s_set_value_ns (S_NOTCH_GAIN (i),
1189
s_set_value_ns (S_NOTCH_FLAG (i),
1190
(float) EQ_notch_flag[i]);
1197
if (x >= 0 && x <= EQ_curve_width && y >= 0 &&
1198
y <= EQ_curve_height)
1200
j = nearest_x (freq);
1201
if (check_notch (i, j, 0))
1203
EQ_notch_index[i] = nearest_x (freq);
1206
(((((double) EQ_curve_height -
1207
(double) y) / (double) EQ_curve_height) *
1208
EQ_curve_range_y) + EQ_gain_lower) *
1210
EQ_notch_flag[i] = 1;
1215
s_set_description (S_NOTCH_GAIN (i) ,
1216
g_strdup_printf("Move notch %d", i));
1217
s_set_value_ns (S_NOTCH_GAIN (i),
1219
s_set_value_ns (S_NOTCH_FREQ (i), freq);
1220
s_set_value_ns (S_NOTCH_FLAG (i),
1221
(float) EQ_notch_flag[i]);
1229
/* Dragging the Q/width handles for the notch filters. */
1231
if (EQ_notch_Q_drag[i])
1233
if (x >= 0 && x <= EQ_curve_width)
1235
j = nearest_x (freq);
1236
if (check_notch (i, j, EQ_notch_Q_drag[i]))
1238
/* Left bracket is 1, right bracket is 2. */
1240
if (EQ_notch_Q_drag[i] == 1)
1242
EQ_notch_width[i] = EQ_notch_index[i] - j;
1246
EQ_notch_width[i] = j - EQ_notch_index[i];
1252
s_set_description (S_NOTCH_GAIN (i) ,
1253
g_strdup_printf("Move notch %d", i));
1254
s_set_value_ns (S_NOTCH_GAIN (i),
1256
s_set_value_ns (S_NOTCH_Q (i),
1257
(float) EQ_notch_width[i]);
1265
/* If we're dragging a notch filter... */
1275
/* If we pass over any of the handles we want to change the
1278
cursor = GDK_PENCIL;
1280
if (EQ_drag_fa || EQ_drag_fb) cursor = GDK_SB_H_DOUBLE_ARROW;
1282
diffx_fa = abs (x - xover_handle_fa);
1283
diffx_fb = abs (x - xover_handle_fb);
1285
if ((diffx_fa <= XOVER_HANDLE_HALF_SIZE ||
1286
diffx_fb <= XOVER_HANDLE_HALF_SIZE) &&
1287
(y <= XOVER_HANDLE_SIZE ||
1288
y >= EQ_curve_height - XOVER_HANDLE_SIZE))
1289
cursor = GDK_SB_H_DOUBLE_ARROW;
1292
/* No point in checking all these if we're already passing
1293
over one of the xover bars. */
1295
if (cursor != GDK_SB_H_DOUBLE_ARROW)
1297
for (i = 0 ; i < NOTCHES ; i++)
1300
if (EQ_notch_drag[i] || EQ_notch_Q_drag[i])
1302
if (event->state & GDK_SHIFT_MASK)
1304
cursor = GDK_SB_V_DOUBLE_ARROW;
1308
if (EQ_notch_drag[i])
1314
cursor = GDK_SB_H_DOUBLE_ARROW;
1321
diff_notch[0] = abs (x - EQ_notch_handle[0][1][i]);
1322
diff_notch[1] = abs (y - EQ_notch_handle[1][1][i]);
1324
if (diff_notch[0] <= NOTCH_HANDLE_HALF_WIDTH &&
1325
diff_notch[1] <= NOTCH_HANDLE_HALF_HEIGHT)
1327
if (event->state & GDK_SHIFT_MASK)
1329
cursor = GDK_SB_V_DOUBLE_ARROW;
1339
if (i && i < NOTCHES - 1)
1341
diff_notch[0] = abs (x - EQ_notch_handle[0][0][i]);
1342
diff_notch[1] = abs (y - EQ_notch_handle[1][0][i]);
1344
if (diff_notch[0] <= NOTCH_HANDLE_HALF_WIDTH &&
1345
diff_notch[1] <= NOTCH_HANDLE_HALF_HEIGHT)
1347
cursor = GDK_SB_H_DOUBLE_ARROW;
1353
diff_notch[0] = abs (x - EQ_notch_handle[0][2][i]);
1354
diff_notch[1] = abs (y - EQ_notch_handle[1][2][i]);
1356
if (diff_notch[0] <= NOTCH_HANDLE_HALF_WIDTH &&
1357
diff_notch[1] <= NOTCH_HANDLE_HALF_HEIGHT)
1359
cursor = GDK_SB_H_DOUBLE_ARROW;
1368
if (current_cursor != cursor)
1370
current_cursor = cursor;
1371
gdk_window_set_cursor (EQ_drawable,
1372
gdk_cursor_new (cursor));
1377
if (notch_flag != -1)
1379
i = EQ_notch_index[notch_flag] - EQ_notch_width[notch_flag];
1380
if (i < 0 || notch_flag == 0) i = 0;
1381
j = EQ_notch_index[notch_flag] + EQ_notch_width[notch_flag];
1382
if (j >= EQ_length || notch_flag == NOTCHES - 1)
1384
lo = NINT (pow (10.0, EQ_xinterp[i]));
1385
hi = NINT (pow (10.0, EQ_xinterp[j]));
1387
sprintf (coords, _("%ddb , %dHz - %dHz"), NINT (gain), lo,
1389
gtk_label_set_text (l_EQ_curve_lbl, coords);
1401
/* This comes from the hdeq drawing area button press callback (actually the
1402
event box). Again, many things happening here depending on the location
1403
of the cursor when the button is pressed. Take a look at the comments in
1404
the function to see what's actually happening. */
1406
void hdeq_curve_button_press (GdkEventButton *event)
1408
float *x = NULL, *y = NULL;
1409
int diffx_fa, diffx_fb, diff_notch[2], i, j, i_start = 0,
1410
i_end = 0, size, ex, ey;
1411
static int interp_pad = 5;
1417
switch (event->button)
1420
/* Button 1 - start drawing or end drawing unless we're over a notch
1421
or xover handle in which case we will be grabbing and sliding the
1422
handle in the X direction. <Shift> button 1 is for grabbing and
1423
sliding in the Y direction (notch/shelf filters only - look at the
1424
motion callback). <Ctrl> button 1 will reset shelf and notch
1429
/* Start drawing. */
1433
/* Checking for position over xover bar or notch handles. */
1435
diffx_fa = abs (ex - xover_handle_fa);
1436
diffx_fb = abs (ex - xover_handle_fb);
1437
if (diffx_fa <= XOVER_HANDLE_HALF_SIZE &&
1438
(ey <= XOVER_HANDLE_SIZE ||
1439
ey >= EQ_curve_height - XOVER_HANDLE_SIZE))
1444
else if (diffx_fb <= XOVER_HANDLE_HALF_SIZE &&
1445
(ey <= XOVER_HANDLE_SIZE ||
1446
ey >= EQ_curve_height - XOVER_HANDLE_SIZE))
1453
for (i = 0 ; i < NOTCHES ; i++)
1455
diff_notch[0] = abs (ex - EQ_notch_handle[0][1][i]);
1456
diff_notch[1] = abs (ey - EQ_notch_handle[1][1][i]);
1458
if (diff_notch[0] <= NOTCH_HANDLE_HALF_WIDTH &&
1459
diff_notch[1] <= NOTCH_HANDLE_HALF_HEIGHT)
1461
/* Reset if <Ctrl> is pressed. */
1464
if (event->state & GDK_CONTROL_MASK)
1466
EQ_notch_flag[i] = 0;
1467
EQ_notch_gain[i] = 0.0;
1469
if (!i || i == NOTCHES - 1)
1471
EQ_notch_width[i] = 0;
1475
EQ_notch_width[i] = 5;
1478
s_set_description (S_NOTCH_GAIN (i) ,
1479
g_strdup_printf("Reset notch %d", i));
1480
s_set_value_ns (S_NOTCH_GAIN (i),
1482
s_set_value_ns (S_NOTCH_Q (i),
1483
(float) EQ_notch_width[i]);
1484
s_set_value_ns (S_NOTCH_FLAG (i),
1485
(float) EQ_notch_flag[i]);
1493
EQ_notch_drag[i] = 1;
1499
if (i && i < NOTCHES - 1)
1501
diff_notch[0] = abs (ex - EQ_notch_handle[0][0][i]);
1502
diff_notch[1] = abs (ey - EQ_notch_handle[1][0][i]);
1504
if (diff_notch[0] <= NOTCH_HANDLE_HALF_WIDTH &&
1505
diff_notch[1] <= NOTCH_HANDLE_HALF_HEIGHT)
1507
/* Left bracket is a 1. */
1509
EQ_notch_Q_drag[i] = 1;
1516
diff_notch[0] = abs (ex - EQ_notch_handle[0][2][i]);
1517
diff_notch[1] = abs (ey - EQ_notch_handle[1][2][i]);
1519
if (diff_notch[0] <= NOTCH_HANDLE_HALF_WIDTH &&
1520
diff_notch[1] <= NOTCH_HANDLE_HALF_HEIGHT)
1522
/* Right bracket is a 2. */
1524
EQ_notch_Q_drag[i] = 2;
1533
/* If we aren't over a handle we must be starting to draw
1534
the curve so mark the starting point. */
1538
/* Save the first point so we can do real narrow EQ
1541
size = (EQ_input_points + 1) * sizeof (float);
1542
EQ_xinput = (float *) realloc (EQ_xinput, size);
1543
EQ_yinput = (float *) realloc (EQ_yinput, size);
1545
if (EQ_yinput == NULL)
1547
perror (_("Allocating EQ_yinput in callbacks.c"));
1551
EQ_xinput[EQ_input_points] = (float) ex;
1552
EQ_yinput[EQ_input_points] = (float) ey;
1561
/* End drawing - combine the drawn data with any parts of the
1562
previous that haven't been superceded by what was drawn. Use
1563
an "interp_pad" cushion on either side of the drawn section
1564
so it will merge nicely with the old data. */
1568
/* Convert the x and y input positions to "real" values. */
1570
for (i = 0 ; i < EQ_input_points ; i++)
1572
EQ_xinput[i] = l_low2mid_adj->lower + (((double) EQ_xinput[i] /
1573
(double) EQ_curve_width) * EQ_curve_range_x);
1576
EQ_yinput[i] = (((((double) EQ_curve_height -
1577
(double) EQ_yinput[i]) / (double) EQ_curve_height) *
1578
EQ_curve_range_y) + EQ_gain_lower) * 0.05;
1582
/* Merge the drawn section with the old curve. */
1584
for (i = 0 ; i < EQ_length ; i++)
1586
if (EQ_xinterp[i] >= EQ_xinput[0])
1588
i_start = i - interp_pad;
1593
for (i = EQ_length - 1 ; i >= 0 ; i--)
1595
if (EQ_xinterp[i] <= EQ_xinput[EQ_input_points - 1])
1597
i_end = i + interp_pad;
1604
for (i = 0 ; i < i_start ; i++)
1606
size = (j + 1) * sizeof (float);
1607
x = (float *) realloc (x, size);
1608
y = (float *) realloc (y, size);
1612
perror (_("Allocating y in callbacks.c"));
1616
x[j] = EQ_xinterp[i];
1617
y[j] = EQ_yinterp[i];
1621
for (i = 0 ; i < EQ_input_points ; i++)
1623
size = (j + 1) * sizeof (float);
1624
x = (float *) realloc (x, size);
1625
y = (float *) realloc (y, size);
1629
perror (_("Allocating y in callbacks.c"));
1633
x[j] = EQ_xinput[i];
1634
y[j] = EQ_yinput[i];
1638
for (i = i_end ; i < EQ_length ; i++)
1640
size = (j + 1) * sizeof (float);
1641
x = (float *) realloc (x, size);
1642
y = (float *) realloc (y, size);
1644
x[j] = EQ_xinterp[i];
1645
y[j] = EQ_yinterp[i];
1650
/* Recompute the splined curve in the log(freq) domain for
1653
interpolate (EQ_interval, j, EQ_start, EQ_end, &EQ_length, x,
1654
y, EQ_xinterp, EQ_yinterp);
1661
/* Save state of the EQ curve. */
1663
s_set_value_block (EQ_yinterp, S_EQ_GAIN(0), EQ_length);
1666
EQ_input_points = 0;
1669
/* Replace shelf and notch areas. */
1674
/* Set the GEQ faders and the EQ coefs. */
1682
/* Redraw the curve. */
1695
/* This comes from the hdeq drawing area button release callback (actually
1696
the event box). Not as much going on here. Mostly just resetting
1697
whatever was done in the motion and button press functions. */
1699
void hdeq_curve_button_release (GdkEventButton *event)
1704
switch (event->button)
1707
if (EQ_drawing == 1)
1711
else if (EQ_drawing == 2)
1717
/* Set the graphic EQ sliders based on the hand-drawn curve. */
1719
geq_set_sliders (EQ_length, EQ_freq_xinterp, EQ_freq_yinterp);
1726
/* Button 2 or 3 - discard the drawn curve. */
1732
EQ_input_points = 0;
1743
for (i = 0 ; i < NOTCHES ; i++)
1745
EQ_notch_drag[i] = 0;
1746
EQ_notch_Q_drag[i] = 0;
1750
set_scene_warning_button ();
1754
/* Set the label in the hdeq. */
1756
void hdeq_curve_set_label (char *string)
1758
gtk_label_set_text (l_EQ_curve_lbl, string);
1762
/* Gets the gain values from the state functions and sets up everything. */
1764
void set_EQ_curve_values (int id, float value)
1769
for (i = 0 ; i < EQ_INTERP ; i++)
1771
EQ_yinterp[i] = s_get_value (S_EQ_GAIN (0) + i);
1775
for (i = 0 ; i < NOTCHES ; i++)
1777
EQ_notch_flag[i] = NINT (s_get_value (S_NOTCH_FLAG (i)));
1778
if (EQ_notch_flag[i])
1780
EQ_notch_width[i] = NINT (s_get_value (S_NOTCH_Q (i)));
1781
EQ_notch_index[i] = nearest_x (s_get_value (S_NOTCH_FREQ (i)));
1782
EQ_notch_gain[i] = s_get_value (S_NOTCH_GAIN (i));
1787
/* Replace shelf and notch areas. */
1792
/* Set the GEQ coefs and faders. */
1800
/* Redraw the curve. */
1806
/* Reset the crossovers. */
1808
void hdeq_set_xover ()
1810
xover_fa = pow (10.0, s_get_value (S_XOVER_FREQ(0)));
1811
xover_fb = pow (10.0, s_get_value (S_XOVER_FREQ(1)));
1813
hdeq_low2mid_init ();
1814
hdeq_mid2high_init ();
1818
/* Set the lower gain limit for the hdeq and the geq. */
1820
void hdeq_set_lower_gain (float gain)
1822
EQ_gain_lower = gain;
1824
set_scene_warning_button ();
1828
/* Set the upper gain limit for the hdeq and the geq. */
1830
void hdeq_set_upper_gain (float gain)
1832
EQ_gain_upper = gain;
1834
set_scene_warning_button ();
1838
/* Write the annotation for the compressor curves when you move the cursor in
1841
static void comp_write_annotation (int i, char *string)
1844
PangoRectangle ink_rect;
1847
/* Clear the annotation area. */
1849
pl = pango_layout_new (comp_pc[i]);
1850
pango_layout_set_text (pl, "-99 , -99", -1);
1851
pango_layout_get_pixel_extents (pl, &ink_rect, NULL);
1853
gdk_window_clear_area (comp_drawable[i], 3, 3, ink_rect.width + 5,
1854
ink_rect.height + 5);
1855
gdk_gc_set_foreground (comp_gc[i], &black);
1857
pl = pango_layout_new (comp_pc[i]);
1858
pango_layout_set_text (pl, string, -1);
1861
gdk_draw_layout (comp_drawable[i], comp_gc[i], 5, 5, pl);
1865
/* Draw the compressor curve (0-2). */
1867
void draw_comp_curve (int i)
1869
int j, x0, y0 = 0.0, x1 = 0.0, y1 = 0.0;
1874
if (!comp_realized[i]) return;
1877
/* Clear the curve drawing area. */
1879
gdk_window_clear_area (comp_drawable[i], 0, 0, comp_curve_width[i],
1880
comp_curve_height[i]);
1881
gdk_gc_set_line_attributes (comp_gc[i], 1, GDK_LINE_SOLID, GDK_CAP_BUTT,
1885
/* Plot the grid lines. */
1887
for (j = NINT (comp_start_x[i]) ; j <= NINT (comp_end_x[i]) ; j++)
1891
x1 = NINT (((float) (j - comp_start_x[i]) /
1892
comp_curve_range_x[i]) * comp_curve_width[i]);
1894
gdk_draw_line (comp_drawable[i], comp_gc[i], x1, 0, x1,
1895
comp_curve_height[i]);
1899
for (j = NINT (comp_start_y[i]) ; j <= NINT (comp_end_y[i]) ; j++)
1905
gdk_gc_set_line_attributes (comp_gc[i], 2, GDK_LINE_SOLID,
1906
GDK_CAP_BUTT, GDK_JOIN_MITER);
1910
gdk_gc_set_line_attributes (comp_gc[i], 1, GDK_LINE_SOLID,
1911
GDK_CAP_BUTT, GDK_JOIN_MITER);
1914
y1 = comp_curve_height[i] - NINT (((float) (j - comp_start_y[i]) /
1915
comp_curve_range_y[i]) * comp_curve_height[i]);
1917
gdk_draw_line (comp_drawable[i], comp_gc[i], 0, y1,
1918
comp_curve_width[i], y1);
1923
/* Plot the curves. */
1925
gdk_gc_set_line_attributes (comp_gc[i], 2, GDK_LINE_SOLID, GDK_CAP_BUTT,
1927
gdk_gc_set_foreground (comp_gc[i], &comp_color[i]);
1930
comp = comp_get_settings (i);
1933
for (x = comp_start_x[i] ; x <= comp_end_x[i] ; x += 0.5f)
1935
x1 = NINT (((x - comp_start_x[i]) / comp_curve_range_x[i]) *
1936
comp_curve_width[i]);
1938
y = eval_comp (comp.threshold, comp.ratio, comp.knee, x) +
1941
y1 = comp_curve_height[i] - NINT (((y - comp_start_y[i]) /
1942
comp_curve_range_y[i]) * comp_curve_height[i]);
1945
gdk_draw_line (comp_drawable[i], comp_gc[i], x0, y0, x1, y1);
1950
gdk_gc_set_line_attributes (comp_gc[i], 1, GDK_LINE_SOLID, GDK_CAP_BUTT,
1952
gdk_gc_set_foreground (comp_gc[i], &black);
1956
/* The compressor curve expose/resize callback (0-2). */
1958
void comp_curve_expose (GtkWidget *widget, int i)
1960
/* Since we're doing inclusive plots on the compressor curves we'll
1961
not decrement the width and height. */
1963
comp_curve_width[i] = widget->allocation.width;
1964
comp_curve_height[i] = widget->allocation.height;
1966
draw_comp_curve (i);
1970
/* The compressor curve realize callback (0-2). */
1972
void comp_curve_realize (GtkWidget *widget, int i)
1974
comp_drawable[i] = widget->window;
1976
comp_start_x[i] = -60.0;
1977
comp_end_x[i] = 0.0;
1978
comp_start_y[i] = -60.0;
1979
comp_end_y[i] = 30.0;
1981
comp_curve_range_x[i] = comp_end_x[i] - comp_start_x[i];
1982
comp_curve_range_y[i] = comp_end_y[i] - comp_start_y[i];
1984
comp_gc[i] = widget->style->fg_gc[GTK_WIDGET_STATE (widget)];
1987
comp_pc[i] = gtk_widget_get_pango_context (widget);
1990
comp_realized[i] = 1;
1994
/* The compressor curve drawing area motion callback (0-2). */
1996
void comp_curve_box_motion (int i, GdkEventMotion *event)
2002
x = comp_start_x[i] + (((float) event->x /
2003
(float) comp_curve_width[i]) * comp_curve_range_x[i]);
2006
y = comp_start_y[i] + ((((float) comp_curve_height[i] - (float) event->y) /
2007
(float) comp_curve_height[i]) * comp_curve_range_y[i]);
2010
sprintf (coords, "%d , %d ", NINT (x), NINT (y));
2011
comp_write_annotation (i, coords);
2015
/* Leaving the box/curve, turn off highlights in the labels of the box and
2018
void comp_box_leave (int i)
2020
gtk_widget_modify_fg ((GtkWidget *) l_comp_lbl[i], GTK_STATE_NORMAL,
2022
gtk_widget_modify_fg ((GtkWidget *) l_c_curve_lbl[i], GTK_STATE_NORMAL,
2027
/* Entering the box/curve, turn on highlights in the labels of the box and
2030
void comp_box_enter (int i)
2032
gtk_widget_modify_fg ((GtkWidget *) l_comp_lbl[i], GTK_STATE_NORMAL,
2034
gtk_widget_modify_fg ((GtkWidget *) l_c_curve_lbl[i], GTK_STATE_NORMAL,
2039
/* Saving the current notebook page on a switch, see callbacks.c. This saves
2040
us querying the GUI 10 times per second from spectrum_update. */
2042
void hdeq_notebook1_set_page (guint page_num)
2044
notebook1_page = page_num;
2048
/* Return the current notebook page - 0 = hdeq, 1 = geq, 2 = spectrum,
2051
int get_current_notebook1_page ()
2053
return (notebook1_page);