diff --git a/envy24control/levelmeters.c b/envy24control/levelmeters.c index fa44979..a07913d 100644 --- a/envy24control/levelmeters.c +++ b/envy24control/levelmeters.c @@ -1,6 +1,8 @@ /***************************************************************************** levelmeters.c - Stereo level meters Copyright (C) 2000 by Jaroslav Kysela + Missing peak-level meter feature implented by NPM: + Copyright (C) 2010 by Niels Mayer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -19,6 +21,7 @@ #include "envy24control.h" +static GdkGC *penWhiteLight[21] = { NULL, }; /* NPM */ static GdkGC *penGreenShadow[21] = { NULL, }; static GdkGC *penGreenLight[21] = { NULL, }; static GdkGC *penOrangeShadow[21] = { NULL, }; @@ -38,15 +41,40 @@ static void update_peak_switch(void) g_print("Unable to read peaks: %s\n", snd_strerror(err)); } +/* + * Niels Mayer (NPM) Jul-11-10: Fixing https://bugzilla.redhat.com/show_bug.cgi?id=602903 + * by implementing peak-level meters. The http://alsa.cybermirror.org/manuals/icensemble/envy24.pdf + * soundchip provides hardware level meters and these are returned via ALSA as such: + * >> amixer -c M66 cget iface=PCM,name='Multi Track Peak',numid=45 + * ; type=INTEGER,access=r-------,values=22,min=0,max=255,step=0 + * : values=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,198,255,198 + * These globals store the peak levels of the meters across callbacks. + */ +#define MULTI_TRACK_PEAK_CHANNELS 22 +static int peak_levels[MULTI_TRACK_PEAK_CHANNELS] = {0,}; +// special case for stereo mix track at "index 0" which is actually "(peaks, 20)" and "(peaks, 21)" cases below +static int peak_lmix = 0; +static int peak_rmix = 0; + +/* NPM: changed for https://bugzilla.redhat.com/show_bug.cgi?id=602903 */ static void get_levels(int idx, int *l1, int *l2) { *l1 = *l2 = 0; if (idx == 0) { - *l1 = snd_ctl_elem_value_get_integer(peaks, 20); - *l2 = snd_ctl_elem_value_get_integer(peaks, 21); + if ((*l1 = snd_ctl_elem_value_get_integer(peaks, 20)) > peak_lmix) { + peak_lmix = (*l1); +// g_print("set peak_lmix: %d\n", peak_lmix); + } + if ((*l2 = snd_ctl_elem_value_get_integer(peaks, 21)) > peak_rmix) { + peak_rmix = (*l2); +// g_print("set peak_rmix: %d\n", peak_rmix); + } } else { - *l1 = *l2 = snd_ctl_elem_value_get_integer(peaks, idx - 1); + if ((*l1 = *l2 = snd_ctl_elem_value_get_integer(peaks, idx - 1)) > peak_levels[idx - 1]) { + peak_levels[idx - 1] = (*l1); +// g_print("set peak_levels[%d]: %d\n", idx - 1, peak_levels[idx - 1]); + } } } @@ -146,6 +174,58 @@ static void redraw_meters(int idx, int width, int height, int level1, int level2 segs_on1--; segs_on2--; } + + /* + * NPM: Fixing https://bugzilla.redhat.com/show_bug.cgi?id=602903 + * The code below was "transformed" from the above (which isn't how + * I'd do things in the first place) and could be further + * simplified to eliminate the for loop. The purpose was to + * reuse the "geometries" implicit in the algorithm above, by + * drawing a line directly above the highest lit segment; + * to represent the "waterline" for the peak audio level. + */ + + int pklevel1, pklevel2; + int drawn1, drawn2; + + if (idx== 0) { + pklevel1 = peak_lmix; + pklevel2 = peak_rmix; + } + else { + pklevel1 = pklevel2 = peak_levels[idx - 1]; + } + segs_on1 = ((segments * pklevel1) + 128) / 255; + segs_on2 = ((segments * pklevel2) + 128) / 255; + drawn1 = drawn2 = FALSE; + for (seg = 0; seg < segments; seg++) { + if ((segs_on1 > 0) ^ (segs_on1 > 1)) { + gdk_draw_line(pixmap[idx], + penWhiteLight[idx], + 6, + 3 + ((segments - seg - 1) * 4), + segment_width + 5, + 3 + ((segments - seg - 1) * 4)); + drawn1 = TRUE; + if ((idx != 0) || drawn2) + break; + } + if (idx == 0) + if ((segs_on2 > 0) ^ (segs_on2 > 1)) { + gdk_draw_line(pixmap[idx], + penWhiteLight[idx], + 2 + (width / 2), + 3 + ((segments - seg - 1) * 4), + segment_width + 1 + (width / 2), + 3 + ((segments - seg - 1) * 4)); + drawn2 = TRUE; + if (drawn1) + break; + } + + segs_on1--; + segs_on2--; + } } gint level_meters_configure_event(GtkWidget *widget, GdkEventConfigure *event) @@ -158,6 +238,7 @@ gint level_meters_configure_event(GtkWidget *widget, GdkEventConfigure *event) widget->allocation.width, widget->allocation.height, -1); + penWhiteLight[idx] = get_pen(idx, 0xffff, 0xffff, 0xffff); penGreenShadow[idx] = get_pen(idx, 0, 0x77ff, 0); penGreenLight[idx] = get_pen(idx, 0, 0xffff, 0); penOrangeShadow[idx] = get_pen(idx, 0xddff, 0x55ff, 0); @@ -255,8 +336,15 @@ gint level_meters_timeout_callback(gpointer data) return TRUE; } +/* NPM fixed lack of implementation ( https://bugzilla.redhat.com/show_bug.cgi?id=602903 )*/ void level_meters_reset_peaks(GtkButton *button, gpointer data) { + int i; + for (i = 0; i < MULTI_TRACK_PEAK_CHANNELS ; i++) { + peak_levels[i] = 0; + } + peak_lmix = 0; + peak_rmix = 0; } void level_meters_init(void)