From 492c3488971a7d1ff2c41c9d84eb7c078296f99e Mon Sep 17 00:00:00 2001 From: "Geoffrey D. Bennett" Date: Wed, 17 Jan 2024 16:03:56 +1030 Subject: [PATCH] Add configurable taper to GtkDial The taper was previously set to a log function which matched the Clarett volume knob. Add linear option to match the Scarlett 4th Gen input gain knobs and hardware level meters. --- src/gtkdial.c | 44 +++++++++++++++++++++++++++++++++++++++++++- src/gtkdial.h | 9 +++++++++ src/iface-mixer.c | 8 ++++---- src/widget-gain.c | 16 +++++++++++++++- src/widget-gain.h | 11 ++++++++++- src/window-levels.c | 1 + src/window-mixer.c | 2 +- 7 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/gtkdial.c b/src/gtkdial.c index 24904ff..30f7945 100644 --- a/src/gtkdial.c +++ b/src/gtkdial.c @@ -84,6 +84,7 @@ enum { PROP_ADJUSTMENT, PROP_ROUND_DIGITS, PROP_ZERO_DB, + PROP_TAPER, LAST_PROP }; @@ -117,6 +118,7 @@ struct _GtkDial { int round_digits; double zero_db; + int taper; }; G_DEFINE_TYPE(GtkDial, gtk_dial, GTK_TYPE_WIDGET) @@ -166,6 +168,18 @@ static double taper_log(double val) { return (val - 0.1) / 0.9; } +static double calc_taper(GtkDial *dial, double val) { + if (dial->taper == GTK_DIAL_TAPER_LINEAR) + return val; + + if (dial->taper == GTK_DIAL_TAPER_LOG) + return taper_log(val); + + g_warning("Invalid taper value: %d", dial->taper); + + return val; +} + static double calc_val(double valp, double mn, double mx) { return (mx - mn) * valp + mn; } @@ -201,7 +215,7 @@ static void get_dial_properties( double mn = dial->adj ? gtk_adjustment_get_lower(dial->adj) : 0; double mx = dial->adj ? gtk_adjustment_get_upper(dial->adj) : 1; double value = dial->adj ? gtk_adjustment_get_value(dial->adj) : 0.25; - props->valp = taper_log(calc_valp(value, mn, mx)); + props->valp = calc_taper(dial, calc_valp(value, mn, mx)); props->angle = calc_val(props->valp, ANGLE_START, ANGLE_END); double radius = props->radius - props->thickness / 2; @@ -287,6 +301,20 @@ static void gtk_dial_class_init(GtkDialClass *klass) { G_PARAM_READWRITE | G_PARAM_CONSTRUCT ); + /** + * GtkDial:taper: (attributes org.gtk.Method.get=gtk_dial_get_taper org.gtk.Method.set=gtk_dial_set_taper) + * + * The taper of the dial. + */ + properties[PROP_TAPER] = g_param_spec_int( + "taper", + "Taper", + "The taper of the dial", + GTK_DIAL_TAPER_LINEAR, GTK_DIAL_TAPER_LOG, + GTK_DIAL_TAPER_LINEAR, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT + ); + g_object_class_install_properties(g_class, LAST_PROP, properties); /** @@ -525,6 +553,9 @@ static void gtk_dial_set_property( case PROP_ZERO_DB: gtk_dial_set_zero_db(dial, g_value_get_double(value)); break; + case PROP_TAPER: + gtk_dial_set_taper(dial, g_value_get_int(value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -549,6 +580,9 @@ static void gtk_dial_get_property( case PROP_ZERO_DB: g_value_set_double(value, dial->zero_db); break; + case PROP_TAPER: + g_value_set_int(value, dial->taper); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -581,6 +615,14 @@ double gtk_dial_get_zero_db(GtkDial *dial) { return dial->zero_db; } +void gtk_dial_set_taper(GtkDial *dial, int taper) { + dial->taper = taper; +} + +int gtk_dial_get_taper(GtkDial *dial) { + return dial->taper; +} + gboolean gtk_dial_set_style( GtkDial *dial, const char *trough_border, diff --git a/src/gtkdial.h b/src/gtkdial.h index 418f4aa..3ab09ae 100644 --- a/src/gtkdial.h +++ b/src/gtkdial.h @@ -65,6 +65,15 @@ int gtk_dial_get_round_digits(GtkDial *dial); void gtk_dial_set_zero_db(GtkDial *dial, double zero_db); double gtk_dial_get_zero_db(GtkDial *dial); +// taper functions +enum { + GTK_DIAL_TAPER_LINEAR, + GTK_DIAL_TAPER_LOG +}; + +void gtk_dial_set_taper(GtkDial *dial, int taper); +int gtk_dial_get_taper(GtkDial *dial); + /** * @brief Set the colors which this dial uses. String codes can be one of the following: * A standard name (Taken from the X11 rgb.txt file) diff --git a/src/iface-mixer.c b/src/iface-mixer.c index 77f9d22..7ca54d6 100644 --- a/src/iface-mixer.c +++ b/src/iface-mixer.c @@ -174,7 +174,7 @@ static void create_input_gain_control( int current_row, int line_num ) { - GtkWidget *w = make_gain_alsa_elem(elem, 0); + GtkWidget *w = make_gain_alsa_elem(elem, 0, WIDGET_GAIN_TAPER_LINEAR); gtk_grid_attach(GTK_GRID(grid), w, line_num, current_row, 1, 1); } @@ -466,7 +466,7 @@ static void create_output_controls( // output controls if (strncmp(elem->name, "Line", 4) == 0) { if (strstr(elem->name, "Playback Volume")) { - w = make_gain_alsa_elem(elem, 1); + w = make_gain_alsa_elem(elem, 1, WIDGET_GAIN_TAPER_LOG); gtk_grid_attach( GTK_GRID(output_grid), w, line_num - 1 + line_1_col, 1, 1, 1 ); @@ -503,7 +503,7 @@ static void create_output_controls( GtkWidget *l = gtk_label_new(gen4 ? "Line 1–2" : "HW"); gtk_grid_attach(GTK_GRID(output_grid), l, 0, 0, 1, 1); - w = make_gain_alsa_elem(elem, 1); + w = make_gain_alsa_elem(elem, 1, WIDGET_GAIN_TAPER_LOG); gtk_widget_set_tooltip_text( w, gen4 @@ -522,7 +522,7 @@ static void create_output_controls( "This control shows the setting of the headphone volume knob." ); gtk_grid_attach(GTK_GRID(output_grid), l, 1, 0, 1, 1); - w = make_gain_alsa_elem(elem, 1); + w = make_gain_alsa_elem(elem, 1, WIDGET_GAIN_TAPER_LOG); gtk_grid_attach(GTK_GRID(output_grid), w, 1, 1, 1, 1); } else if (strcmp(elem->name, "Mute Playback Switch") == 0) { w = make_boolean_alsa_elem( diff --git a/src/widget-gain.c b/src/widget-gain.c index 40f40b6..f167156 100644 --- a/src/widget-gain.c +++ b/src/widget-gain.c @@ -57,7 +57,11 @@ static void gain_updated( } //GList *make_gain_alsa_elem(struct alsa_elem *elem) { -GtkWidget *make_gain_alsa_elem(struct alsa_elem *elem, int zero_is_off) { +GtkWidget *make_gain_alsa_elem( + struct alsa_elem *elem, + int zero_is_off, + int widget_taper +) { struct gain *data = g_malloc(sizeof(struct gain)); data->elem = elem; data->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); @@ -78,6 +82,16 @@ GtkWidget *make_gain_alsa_elem(struct alsa_elem *elem, int zero_is_off) { gtk_dial_set_zero_db(GTK_DIAL(data->dial), zero_db_value); + // convert from widget_taper to gtk_dial_taper + int gtk_dial_taper; + if (widget_taper == WIDGET_GAIN_TAPER_LINEAR) + gtk_dial_taper = GTK_DIAL_TAPER_LINEAR; + else if (widget_taper == WIDGET_GAIN_TAPER_LOG) + gtk_dial_taper = GTK_DIAL_TAPER_LOG; + else + gtk_dial_taper = GTK_DIAL_TAPER_LINEAR; + gtk_dial_set_taper(GTK_DIAL(data->dial), gtk_dial_taper); + data->label = gtk_label_new(NULL); gtk_widget_set_vexpand(data->dial, TRUE); diff --git a/src/widget-gain.h b/src/widget-gain.h index 4d06afe..63c2f0a 100644 --- a/src/widget-gain.h +++ b/src/widget-gain.h @@ -7,4 +7,13 @@ #include "alsa.h" -GtkWidget *make_gain_alsa_elem(struct alsa_elem *alsa_elem, int zero_is_off); +enum { + WIDGET_GAIN_TAPER_LINEAR, + WIDGET_GAIN_TAPER_LOG +}; + +GtkWidget *make_gain_alsa_elem( + struct alsa_elem *elem, + int zero_is_off, + int taper_type +); diff --git a/src/window-levels.c b/src/window-levels.c index 5062015..156bf58 100644 --- a/src/window-levels.c +++ b/src/window-levels.c @@ -96,6 +96,7 @@ GtkWidget *create_levels_controls(struct alsa_card *card) { // create the meter widget and attach to the grid GtkWidget *meter = gtk_dial_new_with_range(-80, 0, 0, 0); + gtk_dial_set_taper(GTK_DIAL(meter), GTK_DIAL_TAPER_LINEAR); gtk_widget_set_sensitive(meter, FALSE); card->meters[meter_num++] = meter; gtk_grid_attach(GTK_GRID(grid), meter, j + 1, i + 1, 1, 1); diff --git a/src/window-mixer.c b/src/window-mixer.c index df088e2..2eb6c75 100644 --- a/src/window-mixer.c +++ b/src/window-mixer.c @@ -76,7 +76,7 @@ GtkWidget *create_mixer_controls(struct alsa_card *card) { } // create the gain control and attach to the grid - GtkWidget *w = make_gain_alsa_elem(elem, 1); + GtkWidget *w = make_gain_alsa_elem(elem, 1, WIDGET_GAIN_TAPER_LOG); gtk_grid_attach(GTK_GRID(mixer_top), w, input_num + 1, mix_num + 2, 1, 1); // look up the r_snk entry for the mixer input number