diff --git a/envy24control/AUTHORS b/envy24control/AUTHORS
index 7e8d506..6ee437d 100644
--- a/envy24control/AUTHORS
+++ b/envy24control/AUTHORS
@@ -1 +1,35 @@
 Jaroslav Kysela <perex@perex.cz>
+
+   volume.c:  added by Takashi Iwai <tiwai@suse.de>
+
+   (2003/03/22) Changed to hbox/vbox layout.
+   Copyright (C) 2003 by Søren Wedel Nielsen
+   
+   (16.12.2005)  Re-worked user interface -digital mixer display permanently
+   visible; pcms split to another page; controls re-arranged and all pages
+   scrollable for min window size and greater flexibility; pop-up menu enabled.
+   Changes to levelmeters.c to prevent invalid redraws.
+   New options added: 'w' to set initial window pixel width and 't' for tall equal mixer height style.
+   Copyright (C) 2005 by Alan Horstmann
+
+   (Summer 2010) NPM: (1) Implemented "Peak Hold" functionality in meters;
+   reimplemented meters to do away with inefficient "faux LED" peak-meter
+   display, which causes thousands of rectangles per-second to be drawn,
+   individually, for no good reason other than increasing the load. (2)
+   Significantly reduced the number of timer interrupts generated by this
+   program by slowing down all updates to 10 per second -- previously
+   meters updated 25x/second! (3) All volumes are represented as decibels,
+   including the 0 to -48dB range of the hardware peak-meters, the 0 -to-
+   -48dB&off attenuation for all inputs to the digital mixer, the 0 -to-
+   -63dB attenuation of the analog DAC, and the +18 -to- -63dB
+   attenuation/amplification of the analog ADC. (4) All gtk "scale" widgets
+   have dB legends; the "PageUp" "PageDown" keys allow rapid movement
+   between the marked levels, and "UpArrow" and "DownArrow" allow
+   fine-adjustment.  (5) Added command-line options --no_scale_mark,
+   --channel_group_modulus, --lights_color and --bg_color options; fixed
+   --card and --device to allow valid ALSA card and CTL device names (
+   https://bugzilla.redhat.com/show_bug.cgi?id=602900 ).  (6) Add display
+   of "Delta IEC958 Input Status" under "Hardware Settings."
+
+   Copyright (C) 2010 Niels Mayer ( http://nielsmayer.com )
+   Copyright (C) 2010 Tim E. Real
diff --git a/envy24control/README b/envy24control/README
index 40c4fe6..ea4ba11 100644
--- a/envy24control/README
+++ b/envy24control/README
@@ -5,7 +5,11 @@ Needs:
 
 To build (from unpacked tarball):
 	./configure
-If you use GTK+-1.2, pass --with-gtk2=no
+
+(Note: Envy24control versions > 1.0 (aka "mudita24") expect recent versions
+ of Gtk2 as the GtkScale markers used on the mixer/ADC/DAC sliders have
+ existed only since Gtk version 2.16.  Do not use version 0.6.0's configure
+ option "-with-gtk2=no" and the accompanying file configure.in-gtk1.)
 
 	make
 	su -c 'make install'
@@ -14,3 +18,77 @@ To build (from GIT):
 	./gitcompile
 	su -c 'make install'
 
+--------------------
+
+Notes on the Envy24's hardware Digital Mixer and hardware Metering,
+by Niels Mayer ( http://nielsmayer.com ):
+--------------------
+
+The "Monitor Inputs" and "Monitor PCMs" tabs contain multiple scale widgets
+grouped into L/R pairs and an associated peak-level meter. Each scale
+widget represents the 24 bit attenuation value of each input to the
+ice1712-based soundcard's digital mixer. This mixer is typically used for
+zero-latency monitoring of "live" inputs, alongside backing sounds and
+effects coming from the eight channels of PCM feeding the digital mixer.
+When many inputs are "hot" simultaneously these scale-widgets attenuate the
+inputs going into the digital mixer to prevent the output from clipping.
+For details see http://nielsmayer.com/npm/envy24mixer-architecture.png
+
+(from http://alsa.cybermirror.org/manuals/icensemble/envy24.pdf )
+
+This is what the above manual says about the Envy24's digital mixer:
+> 4.5.5 Multi-Track Digital Monitoring
+> 
+> The Envy24 integrates a 36-bit resolution digital hardware mixer. The
+> width of the data path is strictly to ensure that during processing of
+> all the channels, under any condition, no resolution is lost. The
+> dynamic range of the end user system will be limited by the range of the
+> physical output devices used. In order to maintain identical gain to the
+> input stream (i.e. 0dB), the resulting 24-bit is not msb-aligned to the
+> 36-bit. The overflow bits correspond to the analog distortion due to
+> saturation. The user would need to reduce the overall attenuation of the
+> inputs to avoid clipping. Insertion of the digital mixer adds only a
+> single sample cycle delay with respect to the original data. This
+> extremely low latency all digital mixer provides monitoring
+> functionality and can replace a traditional external analog input
+> mixer. There are 20 independent audio data streams to mix and control
+> the volume.
+
+
+Adjustment of responsivity vs. "zipper noise" from the 1.5dB steps at the
+top-range of the digital mixer attenuators is achieved by the following
+control under "Hardware Settings":
+
+> MT3B: Volume Control Rate Register
+> ...
+> Volume update rate control (sampling rate, PSYNC)
+> This register allows gradual change of the digital mixer volume
+> setting. The value in MT3B specifies the number of samples to elapse (in
+> hex) between each 1.5dB increment/decrement in volume mixer.  This gradual
+> volume update continues until the setting programmed into MT38 is
+> reached. The appropriate value to program may vary, but 00 or 01h are good
+> choices for most cases.
+
+The peak metering data is displayed as 0 to -48dBFS in envy24control's
+meters. This data is derived from the envy24's hardware peak metering:
+
+> MT3F: Peak Meter Data Register
+> [...]
+> Peak data derived from the absolute value of 9 msb.  00h min - FFh max
+> volume. Reading the register resets the meter to 00h.
+
+This resolution of the hardware metering is descibed by Fons Adriaensen in
+a mailing list discussion:
+
+http://lists.linuxaudio.org/pipermail/linux-audio-dev/2010-August/029009.html
+> [...] You have 128 steps between 0 and -6dB...
+> And even at -24dB the next step is 1.3dB lower. Below that
+> it gets worse radipdly. For a meter that is just supposed
+> to keep a check on peak levels it's OK.
+
+Note that hardware metering data is also available from the command-line:
+
+> amixer -c M66 cget iface=PCM,name='Multi Track Peak',numid=45
+> numid=45,iface=PCM,name='Multi Track Peak'
+>   ; type=INTEGER,access=r-------,values=22,min=0,max=255,step=0
+>   : values=63,62,51,49,56,60,63,62,59,54,0,0,0,0,0,0,0,0,0,0,113,112
diff --git a/envy24control/config.c b/envy24control/config.c
index 6933eef..828d8bc 100644
--- a/envy24control/config.c
+++ b/envy24control/config.c
@@ -46,7 +46,7 @@ void config_close()
 
 void config_set_stereo(GtkWidget *but, gpointer data)
 {
-  gint i=(gint)data;
+  gint i=(gint)((long)data); /* NPM: "(gint)((long)data)" suppress "config.c:49: warning: cast from pointer to integer of different size" */
   config_stereo[i]=GTK_TOGGLE_BUTTON(but)->active;
 }
 
diff --git a/envy24control/configure.in b/envy24control/configure.in
index 30dc8a8..85648cd 100644
--- a/envy24control/configure.in
+++ b/envy24control/configure.in
@@ -1,26 +1,14 @@
 AC_INIT(envy24control.c)
-AM_INIT_AUTOMAKE(envy24control, 0.6.0)
+AM_INIT_AUTOMAKE(mudita24, 1.0.3)
 AC_PROG_CC
 AC_PROG_INSTALL
 AC_HEADER_STDC
 
-AC_ARG_WITH(gtk2,
-  [  --with-gtk2=yes,no   Build with GTK+2 (default = yes)],
-  with_gtk2="$withval", with_gtk2="yes")
-
-if test "$with_gtk2" = "yes"; then
-
+## NPM: version > 1.0.1's logarithmic display requires log10() and therefore
+## "-lm". This solution suggested by Guido Scholz on Linux-Audio-Dev ML.
+AC_CHECK_LIB(m, log10,,AC_MSG_ERROR([required library missing]))
+## NPM: version > 1.0.0 requires gtk+2.0 due to use of functionality like
+## gtk_label_set_markup() and the Gtk Scale Markers being introduced in 2.16
 PKG_CHECK_MODULES(ENVY24CONTROL, gtk+-2.0 alsa >= 0.9.0)
 
-else
-
-AM_PATH_GTK(1.0.1)
-AM_PATH_ALSA(1.0.0)
-ENVY24CONTROL_CFLAGS="$CFLAGS $ALSA_CFLAGS $GTK_CFLAGS"
-ENVY24CONTROL_LIBS="$LIBS $ALSA_LIBS $GTK_LIBS"
-AC_SUBST(ENVY24CONTROL_CFLAGS)
-AC_SUBST(ENVY24CONTROL_LIBS)
-
-fi
-
 AC_OUTPUT(Makefile)
diff --git a/envy24control/configure.in-gtk2 b/envy24control/configure.in-gtk2
index d42aee8..7f13a73 100644
--- a/envy24control/configure.in-gtk2
+++ b/envy24control/configure.in-gtk2
@@ -1,5 +1,5 @@
 AC_INIT(envy24control.c)
-AM_INIT_AUTOMAKE(envy24control, 0.6.0)
+AM_INIT_AUTOMAKE(envy24control, 1.0.3)
 AC_PROG_CC
 AC_PROG_INSTALL
 AC_HEADER_STDC
diff --git a/envy24control/envy24control.1 b/envy24control/envy24control.1
index bfa2ad0..dbb181e 100644
--- a/envy24control/envy24control.1
+++ b/envy24control/envy24control.1
@@ -4,86 +4,151 @@ envy24control \- GUI control tool for Envy24 (ice1712) based
 soundcards, under ALSA.
 
 .SH "SYNOPSIS"
-\fBenvy24control\fP [\fI\-c\fP card\-number] [\fI\-D\fP control\-name] [\fI\-o\fP 0\-num DACs max 8] [\fI\-i\fP 0\-num ADCs max 8] [\fI\-p\fP 0\-8] [\fI\-s\fP 0\-2] [\fI\-f\fP <profiles file name>] [\fI\-v\fP] [<profile number>|<profile name>] [\fI\-m\fP midi\-channel] [\fI\-M\fP] [\fI\-w\fP window\-width] [\fI\-t\fP 0\-9]
+\fBenvy24control\fP [\fI\-c\fP card\-number] [\fI\-D\fP control\-name]
+[\fI\-o\fP 0\-num DACs max 8] [\fI\-i\fP 0\-num ADCs max 8] [\fI\-p\fP
+0\-8] [\fI\-s\fP 0\-2] [\fI\-f\fP <profiles file name>] [\fI\-v\fP]
+[<profile number>|<profile name>] [\fI\-m\fP midi\-channel] [\fI\-M\fP]
+[\fI\-w\fP window\-width] [\fI\-t\fP 0\-9] [\fI\-n\fP] [\fI\-g\fP 1\-8]
 
 .SH "DESCRIPTION"
-\fBenvy24control\fP allows control of the digital mixer, channel gains
-and other hardware settings for sound cards based on the ice1712
-chipset (Midiman Delta series, Terratec EWS and EWX series). It also
-displays a level meter for each input and output channel.
-
+\fBenvy24control\fP allows control of the digital mixer, channel gains and
+other hardware settings for sound cards based on the ice1712 chipset (
+http://alsa.cybermirror.org/manuals/icensemble/envy24.pdf ).  It also
+displays a level meter for each input and output channel and maintains peak
+level indicators.  This utility is preferable to \fBalsamixer(1)\fP for
+those with ice1712-based cards: M-Audio Delta 1010, Delta 1010LT, Delta
+DiO 2496, Delta 66, Delta 44, Delta 410 and Audiophile 2496. TerraTec EWS 88MT,
+EWS 88D, EWX 24/96, DMX 6Fire, Phase 88.  Hoontech SoundTrack DSP 24,
+SoundTrack DSP 24 Value, SoundTrack DSP 24 Media 7.1.  Event Electronics
+EZ8.  Digigram VX442.  Lionstracs, Mediastaton.  Terrasoniq TS 88.  Partial
+support for Roland/Edirol DA-2496.
 .SH "INVOKING"
-\fBenvy24control\fP [\fI\-c\fP card\-number] [\fI\-D\fP control\-name] [\fI\-o\fP 0\-num DACs max 8] [\fI\-i\fP 0\-num ADCs max 8] [\fI\-p\fP 0\-8] [\fI\-s\fP 0\-2] [\fI\-f\fP <profiles file name>] [\fI\-v\fP] [<profile number>|<profile name>] [\fI\-m\fP midi\-channel] [\fI\-M\fP] [\fI\-w\fP window\-width] [\fI\-t\fP 0\-9]
+\fBenvy24control\fP [\fI\-c\fP card\-number] [\fI\-D\fP control\-name]
+[\fI\-o\fP 0\-num DACs max 8] [\fI\-i\fP 0\-num ADCs max 8] [\fI\-p\fP
+0\-8] [\fI\-s\fP 0\-2] [\fI\-f\fP <profiles file name>] [\fI\-v\fP]
+[<profile number>|<profile name>] [\fI\-m\fP midi\-channel] [\fI\-M\fP]
+[\fI\-w\fP window\-width] [\fI\-t\fP 0\-9] [\fI\-n\fP] [\fI\-g\fP 1\-8]
 .TP 
 If no control\-name is given, then the first sound card is used.
 
 .SS Options
 .TP 
-\fI\-c\fP card\-number
+\fI\-c\fP, \fI\--card\fP
 Use the card specified by card\-number rather than the first card.
-This is equivalent with \fI\-Dhw:n\fP option where \fIn\fP is the card number.
+This is equivalent with \fI\-Dhw:n\fP option where \fIn\fP is the card
+number. May also use the card name, e.g. \fI\-cM66\fP .
 .TP 
-\fI\-D\fP control\-name
+\fI\-D\fP, \fI\--device\fP
 Use the card specified by control\-name rather than the first card,
 normally this will be of the form hw:\fIn\fP where \fIn\fP is the sound
-card number (zero\-based). This is only needed if you have more than one
-Envy24\-based card or if your Envy24 card is not configured as the first
-card in your ALSA driver setup.
+card number (zero\-based). May also use the card name, e.g. \fI\-Dhw:M66\fP .
+This is only needed if you have more than one Envy24\-based card or 
+if your Envy24 card is not configured as the first card in your ALSA driver setup.
 .TP 
-\fI\-o\fP outputs
+\fI\-o\fP, \fI\--outputs\fP
 Limit number of analog line outputs to display.  Default is the number of
 DACs in the driver specification. Maximum is 8.
 The number of analog output lines can only be reduced from the available
 number of output lines.
 .TP 
-\fI\-i\fP inputs
+\fI\-i\fP, \fI\--inputs\fP
 Limit number of analog line inputs to display.  Default is the number of
 ADCs in the driver specification. Maximum is 8.
 The number of analog input lines can only be reduced from the available
 number of input lines.
 .TP 
-\fI\-p\fP pcm outputs
+\fI\-p\fP, \fI\--pcm_outputs\fP
 Limit number of PCM outputs to display.  Default is 8.
 .TP 
-\fI\-s\fP spdif inputs/outputs
+\fI\-s\fP, \fI\--spdif\fP
 Limit number of SPDIF inputs/outputs to display.  Default is 2.
 .TP 
-\fI\-f\fP name and path of the profiles file name.
-From/to this file will envy24control read/write the alsactl settings.
+\fI\-f\fP, \fI\--profiles_file\fP
+File to read/write the alsactl settings.
 If is not given DEFAULT_PROFILERC or for restore if DEFAULT_PROFILERC
 doesn't exists SYS_PROFILERC will be used.
 .TP 
-\fI\-v\fP view spdif playback channels in the mixer.
+\fI\-v\fP, \fI\--view_spdif_playback\fP
+View spdif playback channels in the mixer.
 It is not possible to manage something (muting, volume levels).
 It is only to view the levelmeters.
 Default is no view of spdif playback channels in the mixer.
 .TP 
-\fI\-m\fP midi\-channel
+\fI\-m\fP, \fI\--midichannel\fP
 Use MIDI controller values to control the Faders in the mixer view.
 The application will react to controllers on channel midi\-channel and
 send controllers on this channel when the user moves the GUI sliders.
 .TP 
-\fI\-M\fP
+\fI\-M\fP, \fI\--midienhanced\fP
 Use an enhanced mapping from midi controller values to db sliders.
 .TP
-\fI\-w\fP window\-width
+\fI\-w\fP, \fI\--window_width\fP
 Specify the initial width of the envy24control window.
 Using window\-width in the range 0\-20 specifies approx number of mixer channels visible.
 Values >20 are interpreted as screen pixels.
 .TP
-\fI\-t\fP tall\-equal mixer heights
-Using \fI\-t\fP 1 enlarges the channel mixers to the same height as the digital mixer.
+\fI\-t\fP, \fI\--tall_equal_mixer_heights\fP
+Using \fI\-t1\fP enlarges the channel mixers to the same height as the digital mixer.
 With values >1 the height of all mixers is increased in stages.
-\fI\-t\fP 0 is the default, set for minimum window height.
+.TP
+\fI\-n\fP, \fI\--no_scale_mark\fP
+Disable scale marks, which may be incorrect on certain cards (?), or whose
+Gtk-detent at the mark position may be annoying.
+.TP
+\fI\-g\fP, \fI\--channel_group_modulus\fP
+Defaults to '2', which causes the application to pair input and output
+channels labeled scale marks to Left/Right sides - this behavior occurs in
+"Monitor Inputs" "Monitor PCMs" and "Analog Volume" panels. Should this
+behavior be inappropriate for 4, 5.1, 7.1, 8.1 and ambisonic setups: Using
+\fI\-g1\fP causes all channels to look the same. Other values up to the
+card's maximum number of input or output channels may produce layouts
+helpful for grouping channels.
+.TP
+\fI\-l\fP, \fI\--lights_color\fP
+Defaults to 'dodgerblue' or '#1e90ff'. Set to a different color to change
+the foreground color of the meters.
+.TP
+\fI\-b\fP, \fI\--bg_color\fP
+Defaults to '#304050'. Set to a different color to change the background
+color of the meters.
 .SH "SEE ALSO"
 \fB
 alsamixer(1),
 amixer(1),
-gamix(1)
+gamix(1),
+kmix(1),
+alsamixergui(1),
+alsamixer-qt4(1)
 \fP
 
 .SH "AUTHOR"
-\fBenvy24control\fP is  by Jaroslav Kysela <perex@perex.cz>
-This document is by James Tappin <james@xena.uklinux.net>.
-Updated by Dirk Kalis <dirk.kalis@t\-online.de>.
-Options\fI\-w\ and \fI\-t\fP added Alan Horstmann <gineera@aspect135.co.uk>
+
+\fBenvy24control\fP is originally by Jaroslav Kysela <perex@perex.cz>.
+with layout changes by Søren Wedel Nielsen, and volume control code by
+Takashi Iwai. 
+
+Options \fI\-w\fP and \fI\-t\fP added Alan Horstmann
+<gineera@aspect135.co.uk>.
+
+(Summer 2010) NPM: (1) Implemented "Peak Hold" functionality in meters;
+reimplemented meters to do away with inefficient "faux LED" peak-meter
+display, which causes thousands of rectangles per-second to be drawn,
+individually, for no good reason other than increasing the load. (2)
+Significantly reduced the number of timer interrupts generated by this
+program by slowing down all updates to 10 per second -- previously meters
+updated 25x/second! (3) All volumes are represented as decibels, including
+the 0 to -48dB range of the hardware peak-meters, the 0 -to- -48dB&off
+attenuation for all inputs to the digital mixer, the 0 -to- -63dB
+attenuation of the analog DAC, and the +18 -to- -63dB
+attenuation/amplification of the analog ADC. (4) All gtk "scale" widgets
+have dB legends; the "PageUp" "PageDown" keys allow rapid movement between
+the marked levels, and "UpArrow" and "DownArrow" allow fine-adjustment.
+(5) Added command-line options \fI\--no_scale_mark\fP,
+\fI\--channel_group_modulus\fP, \fI\--lights_color\fP and \fI\--bg_color
+options\fP; fixed \fI\--card\fP and \fI\--device\fP to allow valid ALSA
+card and CTL device names (
+https://bugzilla.redhat.com/show_bug.cgi?id=602900 ).  (6) Add display of
+"Delta IEC958 Input Status" under "Hardware Settings."
+
+This document is by James Tappin <james@xena.uklinux.net>.  Updated by Dirk
+Kalis <dirk.kalis@t\-online.de>. Further updated by Niels Mayer ( http://nielsmayer.com ).
diff --git a/envy24control/envy24control.c b/envy24control/envy24control.c
index 0b2749e..c358ed0 100644
--- a/envy24control/envy24control.c
+++ b/envy24control/envy24control.c
@@ -1,7 +1,9 @@
 /*****************************************************************************
-   envy24control.c - Env24 chipset (ICE1712) control utility
+   envy24control.c - Envy24 chipset (ICE1712) control utility
    Copyright (C) 2000 by Jaroslav Kysela <perex@perex.cz>
 
+   volume.c:  added by Takashi Iwai <tiwai@suse.de>
+
    (2003/03/22) Changed to hbox/vbox layout.
    Copyright (C) 2003 by Søren Wedel Nielsen
    
@@ -12,6 +14,28 @@
    New options added: 'w' to set initial window pixel width and 't' for tall equal mixer height style.
    Copyright (C) 2005 by Alan Horstmann
 
+   (Summer 2010) (0) After a decade, incremented version to 1.0.  (1)
+   Implemented "Peak Hold" functionality in meters; reimplemented meters to
+   do away with inefficient "faux LED" peak-meter display, which causes
+   thousands of rectangles per-second to be drawn, individually, for no
+   good reason other than increasing the load. (2) Significantly reduced
+   the number of timer interrupts generated by this program by slowing down
+   all updates to 10 per second -- previously meters updated 25x/second!
+   (3) All volumes are represented as decibels, including the 0 to -48dB
+   range of the hardware peak-meters, the 0 -to- -48dB&off attenuation for
+   all inputs to the digital mixer, the 0 -to- -63dB attenuation of the
+   analog DAC, and the +18 -to- -63dB attenuation/amplification of the
+   analog ADC. (4) All gtk "scale" widgets have dB legends; the "PageUp"
+   "PageDown" keys allow rapid movement between the marked levels, and
+   "UpArrow" and "DownArrow" allow fine-adjustment.  (5) Added command-line
+   options --no_scale_mark, --channel_group_modulus, --lights_color and
+   --bg_color options; fixed --card and --device to allow valid ALSA card
+   and CTL device names ( https://bugzilla.redhat.com/show_bug.cgi?id=602900 ).
+   (6) Add display of "Delta IEC958 Input Status" under "Hardware Settings."
+
+   Copyright (C) 2010 Niels Mayer ( http://nielsmayer.com )
+   Copyright (C) 2010 Tim E. Real
+
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
@@ -34,7 +58,10 @@
 #include <getopt.h>
 
 int input_channels, output_channels, pcm_output_channels, spdif_channels, view_spdif_playback, card_number;
-int card_is_dmx6fire = FALSE, tall_equal_mixer_ht = 0;
+int card_is_dmx6fire = FALSE, tall_equal_mixer_ht = FALSE;
+int no_scale_marks = FALSE, channel_group_modulus = 2; /* NPM added options */
+GdkColor *meter_bg = NULL, *meter_fg = NULL; /* NPM added options */
+int card_has_delta_iec958_input_status = FALSE; /* NPM added to support "Delta IEC958 Input Status" */
 char *profiles_file_name, *default_profile;
 
 ice1712_eeprom_t card_eeprom;
@@ -47,6 +74,10 @@ GtkWidget *mixer_clear_peaks_button;
 GtkWidget *mixer_drawing[20];
 GtkObject *mixer_adj[20][2];
 GtkWidget *mixer_vscale[20][2];
+GtkWidget *mixer_label[20][2];			  /* NPM: labels for L/R dB attenuation into digital mixer: see "Monitor Inputs" and "Monitor PCMs" panels */
+GtkWidget *peak_label[MULTI_TRACK_PEAK_CHANNELS]; /* NPM: labels for dBFS peaks for all inputs/outputs of digital mixer: see "Monitor Inputs" and "Monitor PCMs" panels */
+GtkWidget *adc_peak_label[MAX_INPUT_CHANNELS] = {NULL, }; /* NPM: labels for dBFS peak levels of ADC inputs: see "Analog Volume" panel */
+GtkWidget *dac_peak_label[MAX_OUTPUT_CHANNELS] = {NULL, }; /* NPM: labels for dBFS peak levels of DAC outputs: see "Analog Volume" panel */
 GtkWidget *mixer_mute_toggle[20][2];
 GtkWidget *mixer_stereo_toggle[20];
 
@@ -74,6 +105,8 @@ GtkWidget *hw_rate_reset_check;
 GtkObject *hw_volume_change_adj;
 GtkWidget *hw_volume_change_spin;
 
+GtkWidget *hw_iec958_input_status_label; /* NPM */
+
 GtkWidget *hw_spdif_profi_nonaudio_radio;
 GtkWidget *hw_spdif_profi_audio_radio;
 
@@ -118,9 +151,9 @@ GtkWidget *hw_phono_input_off_radio;
 GtkObject *av_dac_volume_adj[10];
 GtkObject *av_adc_volume_adj[10];
 GtkObject *av_ipga_volume_adj[10];
-GtkLabel *av_dac_volume_label[10];
-GtkLabel *av_adc_volume_label[10];
-GtkLabel *av_ipga_volume_label[10];
+GtkWidget *av_dac_volume_label[10];
+GtkWidget *av_adc_volume_label[10];
+GtkWidget *av_ipga_volume_label[10];
 GtkWidget *av_dac_sense_radio[10][4];
 GtkWidget *av_adc_sense_radio[10][4];
 
@@ -132,7 +165,6 @@ struct profile_button {
 GtkWidget *active_button = NULL;
 GtkObject *card_number_adj;
 
-
 static void create_mixer_frame(GtkWidget *box, int stream)
 {
 	GtkWidget *vbox;
@@ -142,7 +174,6 @@ static void create_mixer_frame(GtkWidget *box, int stream)
 	GtkObject *adj;
 	GtkWidget *vscale;
 	GtkWidget *drawing;
-	GtkWidget *label;
 	GtkWidget *toggle;
 	char str[64], drawname[32];
 
@@ -180,17 +211,26 @@ static void create_mixer_frame(GtkWidget *box, int stream)
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
 	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
-	hbox = gtk_hbox_new(FALSE, 2);
+	hbox = gtk_hbox_new(FALSE, 0);
 	gtk_widget_show(hbox);
 	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
 
-	adj = gtk_adjustment_new(96, 0, 96, 1, 16, 0);
+	/*
+	 * NPM: Left-channel scale widgets to adjust 24 bit attenuation of
+	 * each input into ice1712's on-chip digital mixer.
+	 */
+	adj = gtk_adjustment_new(LOW_MIXER_ATTENUATION_VALUE, 0, LOW_MIXER_ATTENUATION_VALUE, 1, MIXER_ATTENUATOR_STEP_SIZE, 0); /* NPM: using step size of 12 gives -12dB step-size */
 	mixer_adj[stream-1][0] = adj;
 	vscale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
+	gtk_scale_set_draw_value(GTK_SCALE(vscale), FALSE); /* NPM: don't draw value since printing dB values via mixer_adjust() */
 	mixer_vscale[stream-1][0] = vscale;
+	/* NPM: above, set step size of 12 ==> -18dB step-size. Place dB-labelled markers at those locations */
+	draw_24bit_attenuator_scale_markings(GTK_SCALE(vscale), GTK_POS_LEFT,
+					     (channel_group_modulus==1)
+					     ? TRUE
+					     : (stream%channel_group_modulus));
         gtk_widget_show(vscale);
 	gtk_box_pack_start(GTK_BOX(hbox), vscale, TRUE, FALSE, 0);
-	gtk_scale_set_value_pos(GTK_SCALE(vscale), GTK_POS_BOTTOM);
 	gtk_scale_set_digits(GTK_SCALE(vscale), 0);
 	gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
 			   GTK_SIGNAL_FUNC(mixer_adjust),
@@ -210,38 +250,52 @@ static void create_mixer_frame(GtkWidget *box, int stream)
 	gtk_signal_connect(GTK_OBJECT(drawing), "configure_event",
 			   GTK_SIGNAL_FUNC(level_meters_configure_event), NULL);
 	gtk_widget_set_events(drawing, GDK_EXPOSURE_MASK);
-	gtk_widget_set_usize(drawing, 36, (60 * tall_equal_mixer_ht + 204));
-	gtk_box_pack_start(GTK_BOX(vbox1), drawing, FALSE, FALSE, 1);
-
-	label = gtk_label_new("");
-	gtk_widget_show(label);
-	gtk_box_pack_start(GTK_BOX(vbox1), label, TRUE, TRUE, 2);
-
-	adj = gtk_adjustment_new(96, 0, 96, 1, 16, 0);
+	gtk_widget_set_usize(drawing, 24, (60 * tall_equal_mixer_ht + 204));
+	gtk_box_pack_end(GTK_BOX(vbox1), drawing, FALSE, FALSE, 0);
+
+	/*
+	 * NPM: Right-channel scale widgets to adjust 24bit attenuation of
+	 * each input into ice1712's on-chip digital mixer.
+	 */
+	adj = gtk_adjustment_new(LOW_MIXER_ATTENUATION_VALUE, 0, LOW_MIXER_ATTENUATION_VALUE, 1, MIXER_ATTENUATOR_STEP_SIZE, 0);
 	mixer_adj[stream-1][1] = adj;
 	vscale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
+	gtk_scale_set_draw_value(GTK_SCALE(vscale), FALSE); /* NPM: don't draw value since printing dB values via mixer_adjust() */
 	mixer_vscale[stream-1][1] = vscale;
-        gtk_widget_show(vscale);
+	draw_24bit_attenuator_scale_markings(GTK_SCALE(vscale), GTK_POS_RIGHT,
+					     (channel_group_modulus==1)
+					     ? FALSE
+					     : ((stream-1)%channel_group_modulus));
+	gtk_widget_show(vscale);
 	gtk_box_pack_start(GTK_BOX(hbox), vscale, TRUE, FALSE, 0);
-	gtk_scale_set_value_pos(GTK_SCALE(vscale), GTK_POS_BOTTOM);
 	gtk_scale_set_digits(GTK_SCALE(vscale), 0);
 	gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
 			   GTK_SIGNAL_FUNC(mixer_adjust),
 			   (gpointer)(long)((stream << 16) + 1));
+
+	/* NPM: Labels to display the retained peak levels gathered from ice1712's hardware metering */
+	peak_label[stream-1] = gtk_label_new("(Off) ");
+	gtk_widget_modify_font(peak_label[stream-1], pango_font_description_from_string ("Monospace"));
+	gtk_widget_show(peak_label[stream-1]);
+	gtk_box_pack_start(GTK_BOX(vbox), peak_label[stream-1], TRUE, FALSE, 0);
 	
 	hbox = gtk_hbox_new(TRUE, 0);
 	gtk_widget_show(hbox);
 	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, FALSE, 0);
 
-	label = gtk_label_new("Left");
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-	gtk_widget_show(label);
-	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
-	
-	label = gtk_label_new("Right");
-	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
-	gtk_widget_show(label);
-	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
+	/* NPM: Labels to display attenuation of Left input into digital mixer: see mixer.c:mixer_adjust() */
+	mixer_label[stream-1][0] = gtk_label_new("(Off) "); /* NPM: note that all but the "(Off)" values get refreshed at startup */
+	gtk_misc_set_alignment(GTK_MISC(mixer_label[stream-1][0]), 0, 0.5);
+	gtk_widget_modify_font(mixer_label[stream-1][0], pango_font_description_from_string ("Monospace"));
+	gtk_widget_show(mixer_label[stream-1][0]);
+	gtk_box_pack_start(GTK_BOX(hbox), mixer_label[stream-1][0], FALSE, TRUE, 0);
+
+	/* NPM: Labels to display attenuation of Right input into digital mixer: see mixer.c:mixer_adjust() */
+	mixer_label[stream-1][1] = gtk_label_new("(Off) "); /* NPM: note that all but the "(Off)" values get refreshed at startup */
+	gtk_misc_set_alignment(GTK_MISC(mixer_label[stream-1][1]), 1, 0.5);
+	gtk_widget_modify_font(mixer_label[stream-1][1], pango_font_description_from_string ("Monospace"));
+	gtk_widget_show(mixer_label[stream-1][1]);
+	gtk_box_pack_start(GTK_BOX(hbox), mixer_label[stream-1][1], FALSE, TRUE, 0);
 
 	toggle = gtk_toggle_button_new_with_label("L/R Gang");
 	mixer_stereo_toggle[stream-1] = toggle;
@@ -249,9 +303,9 @@ static void create_mixer_frame(GtkWidget *box, int stream)
 	gtk_box_pack_end(GTK_BOX(vbox), toggle, FALSE, FALSE, 0);
 	/* gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), TRUE); */
 	gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
-			   GTK_SIGNAL_FUNC(config_set_stereo), (gpointer)stream-1);
+			   GTK_SIGNAL_FUNC(config_set_stereo), (gpointer)(long)(stream - 1)); /* NPM: use (long) to fix "envy24control.c:251: warning: cast to pointer from integer of different size" */
 
-	hbox = gtk_hbox_new(TRUE, 6);
+	hbox = gtk_hbox_new(TRUE, 3);
 	gtk_widget_show(hbox);
 	gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
 
@@ -317,7 +371,7 @@ static void create_inputs_mixer(GtkWidget *main, GtkWidget *notebook, int page)
 
 	for(stream = (MAX_PCM_OUTPUT_CHANNELS + MAX_SPDIF_CHANNELS + 1); \
 		stream <= input_channels + (MAX_PCM_OUTPUT_CHANNELS + MAX_SPDIF_CHANNELS); stream ++) {
-		if (mixer_stream_is_active(stream))
+		if (mixer_stream_is_active(stream)) 
 			create_mixer_frame(hbox, stream);
 	}
 	for(stream = (MAX_PCM_OUTPUT_CHANNELS + MAX_SPDIF_CHANNELS + MAX_INPUT_CHANNELS + 1); \
@@ -439,13 +493,13 @@ static void create_router_frame(GtkWidget *box, int stream, int pos)
 	frame = gtk_frame_new(str);
 	gtk_widget_show(frame);
 	gtk_box_pack_start (GTK_BOX(box), frame, FALSE, FALSE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(frame), 2);
 
 
 	vbox = gtk_vbox_new(TRUE, 0);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 	radiobutton = gtk_radio_button_new_with_label(group, str1);
 	router_radio[stream-1][0] = radiobutton;
@@ -552,13 +606,13 @@ static void create_master_clock(GtkWidget *box)
 
 	frame = gtk_frame_new("Master Clock");
 	gtk_widget_show(frame);
-	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 4);
+	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
 
 
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 
 	radiobutton = gtk_radio_button_new_with_label(group, "Int 22050");
@@ -665,9 +719,9 @@ static void create_rate_state(GtkWidget *box)
 	hbox = gtk_hbox_new(TRUE, 0);
 	gtk_widget_show(hbox);
 	gtk_container_add(GTK_CONTAINER(frame), hbox);
-	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
 
-	check = gtk_check_button_new_with_label("Locked");
+	check = gtk_check_button_new_with_label("Multi Track\nRate Locking");
 	hw_rate_locking_check = check;
 	gtk_widget_show(check);
 	gtk_box_pack_start(GTK_BOX(hbox), check, FALSE, FALSE, 0);
@@ -676,7 +730,7 @@ static void create_rate_state(GtkWidget *box)
 			  (gpointer)"locked");
 
 
-	check = gtk_check_button_new_with_label("Reset");
+	check = gtk_check_button_new_with_label("Multi Track\nRate Reset");
 	hw_rate_reset_check = check;
 	gtk_widget_show(check);
 	gtk_box_pack_start(GTK_BOX(hbox), check, FALSE, FALSE, 0);
@@ -718,14 +772,15 @@ static void create_volume_change(GtkWidget *box)
 	hbox = gtk_hbox_new(FALSE, 0);
 	gtk_widget_show(hbox);
 	gtk_container_add(GTK_CONTAINER(frame), hbox);
-	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
 
 	label = gtk_label_new("Rate");
 	gtk_widget_show(label);
 	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, FALSE, 0);
 	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
 
-	spinbutton_adj = gtk_adjustment_new(16, 0, 255, 1, 10, 10);
+	spinbutton_adj = gtk_adjustment_new(16, 0, 255, 1, 10, 0); /* NPM: last parm changed to 0, gets rid of 'Gtk-WARNING **: GtkSpinButton: setting an
+> adjustment with non-zero page size is deprecated' -- change suggested by James Morris on linux-audio-dev */
 	hw_volume_change_adj = spinbutton_adj;
 	spinbutton = gtk_spin_button_new(GTK_ADJUSTMENT(spinbutton_adj), 1, 0);
 	gtk_widget_show(spinbutton);
@@ -736,6 +791,22 @@ static void create_volume_change(GtkWidget *box)
 	
 }
 
+/* NPM: Put Label in "Hardware Settings" for value of IEC958 Input Status */
+static void create_iec958_input_status(GtkWidget *box)
+{
+  if (card_has_delta_iec958_input_status) {
+	GtkWidget *frame;
+
+	frame = gtk_frame_new("IEC958 Input Status");
+	gtk_widget_show(frame);
+	gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0);
+
+	hw_iec958_input_status_label = gtk_label_new("input: ()");
+	gtk_widget_show(hw_iec958_input_status_label);
+	gtk_container_add(GTK_CONTAINER(frame), hw_iec958_input_status_label);
+	}
+}
+
 static void create_spdif_output_settings_profi_data(GtkWidget *box)
 {
 	GtkWidget *frame;
@@ -751,7 +822,7 @@ static void create_spdif_output_settings_profi_data(GtkWidget *box)
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 
 	radiobutton = gtk_radio_button_new_with_label(group, "Non-audio");
@@ -788,7 +859,7 @@ static void create_spdif_output_settings_profi_stream(GtkWidget *box)
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 	radiobutton = gtk_radio_button_new_with_label(group, "Stereophonic");
 	hw_profi_stream_stereo_radio = radiobutton;
@@ -824,7 +895,7 @@ static void create_spdif_output_settings_profi_emphasis(GtkWidget *box)
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 
 	radiobutton = gtk_radio_button_new_with_label(group, "No emphasis");
@@ -883,7 +954,7 @@ static void create_spdif_output_settings_profi(GtkWidget *notebook, int page)
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 	create_spdif_output_settings_profi_data(vbox);
 	create_spdif_output_settings_profi_stream(vbox);
@@ -891,7 +962,7 @@ static void create_spdif_output_settings_profi(GtkWidget *notebook, int page)
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 	create_spdif_output_settings_profi_emphasis(vbox);
 }
@@ -910,7 +981,7 @@ static void create_spdif_output_settings_consumer_copyright(GtkWidget *box)
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 
 	radiobutton = gtk_radio_button_new_with_label(group, "Copyrighted");
@@ -946,7 +1017,7 @@ static void create_spdif_output_settings_consumer_copy(GtkWidget *box)
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 	radiobutton = gtk_radio_button_new_with_label(group,
 						      "1-st generation");
@@ -982,7 +1053,7 @@ static void create_spdif_output_settings_consumer_emphasis(GtkWidget *box)
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 	radiobutton = gtk_radio_button_new_with_label(group, "No emphasis");
 	hw_consumer_emphasis_none_radio = radiobutton;
@@ -1017,7 +1088,7 @@ static void create_spdif_output_settings_consumer_category(GtkWidget *box)
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 	radiobutton = gtk_radio_button_new_with_label(group, "DAT");
 	hw_consumer_category_dat_radio = radiobutton;
@@ -1065,7 +1136,7 @@ static void create_spdif_output_settings_consumer(GtkWidget *notebook, int page)
 	hbox = gtk_hbox_new(FALSE, 0);
 	gtk_widget_show(hbox);
 	gtk_container_add(GTK_CONTAINER(notebook), hbox);
-	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
 
 	label = gtk_label_new("Consumer");
         gtk_widget_show(label);
@@ -1076,7 +1147,7 @@ static void create_spdif_output_settings_consumer(GtkWidget *notebook, int page)
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 	create_spdif_output_settings_consumer_copyright(vbox);
 	create_spdif_output_settings_consumer_copy(vbox);
@@ -1084,14 +1155,14 @@ static void create_spdif_output_settings_consumer(GtkWidget *notebook, int page)
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 	create_spdif_output_settings_consumer_emphasis(vbox);
 
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 	create_spdif_output_settings_consumer_category(vbox);
 }
@@ -1108,13 +1179,13 @@ static void create_spdif_output_settings(GtkWidget *box)
 	frame = gtk_frame_new("S/PDIF Output Settings");
 	gtk_widget_show(frame);
 	gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(frame), 2);
 
 
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 	hbox = gtk_hbox_new(FALSE, 0);
 	gtk_widget_show(hbox);
@@ -1125,7 +1196,7 @@ static void create_spdif_output_settings(GtkWidget *box)
 	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
 	gtk_widget_show(radiobutton);
 	gtk_box_pack_start(GTK_BOX(hbox), radiobutton, FALSE, FALSE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(radiobutton), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(radiobutton), 2);
 	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
 			  (GtkSignalFunc)spdif_output_toggled, 
 			  (gpointer)"Professional");
@@ -1135,7 +1206,7 @@ static void create_spdif_output_settings(GtkWidget *box)
 	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
 	gtk_widget_show(radiobutton);
 	gtk_box_pack_start(GTK_BOX(hbox), radiobutton, FALSE, FALSE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(radiobutton), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(radiobutton), 2);
 	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
 			  (GtkSignalFunc)spdif_output_toggled, 
 			  (gpointer)"Consumer");
@@ -1165,12 +1236,12 @@ static void create_spdif_input_select(GtkWidget *box)
 	frame = gtk_frame_new("Digital Input");
 	gtk_widget_show(frame);
 	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(frame), 2);
 
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(frame), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
 	radiobutton = gtk_radio_button_new_with_label(group, "Coaxial");
 	hw_spdif_input_coaxial_radio = radiobutton;
@@ -1218,13 +1289,13 @@ static void create_phono_input(GtkWidget *box)
 
         frame = gtk_frame_new("Phono Input Switch");
         gtk_widget_show(frame);
-        gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 7);
-        gtk_container_set_border_width(GTK_CONTAINER(frame), 6);
+        gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 2);
+        gtk_container_set_border_width(GTK_CONTAINER(frame), 2);
 
         vbox = gtk_vbox_new(FALSE, 0);
         gtk_widget_show(vbox);
         gtk_container_add(GTK_CONTAINER(frame), vbox);
-        gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+        gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
         radiobutton = gtk_radio_button_new_with_label(group, "Phono");
         hw_phono_input_on_radio = radiobutton;
@@ -1267,7 +1338,7 @@ static void create_input_interface(GtkWidget *box)
         vbox = gtk_vbox_new(FALSE, 0);
         gtk_widget_show(vbox);
         gtk_container_add(GTK_CONTAINER(frame), vbox);
-        gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+        gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
         radiobutton = gtk_radio_button_new_with_label(group, "Internal");
         input_interface_internal = radiobutton;
@@ -1319,7 +1390,6 @@ static void create_hardware(GtkWidget *main, GtkWidget *notebook, int page)
 	GtkWidget *vbox1;
 	GtkWidget *scrolledwindow;
 	GtkWidget *viewport;
-	GtkWidget *hseparator;
 
 	hbox = gtk_hbox_new(FALSE, 0);
 	gtk_widget_show(hbox);
@@ -1356,9 +1426,9 @@ static void create_hardware(GtkWidget *main, GtkWidget *notebook, int page)
 	gtk_widget_show(hbox1);
 	gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 0);
 
-	hseparator = gtk_hseparator_new();
-	gtk_widget_show(hseparator);
-	gtk_box_pack_start(GTK_BOX(vbox), hseparator, FALSE, FALSE, 2);
+//	hseparator = gtk_hseparator_new();
+//	gtk_widget_show(hseparator);
+//	gtk_box_pack_start(GTK_BOX(vbox), hseparator, FALSE, FALSE, 2);
 
 	hbox2 = gtk_hbox_new(FALSE, 0);
 	gtk_widget_show(hbox2);
@@ -1373,6 +1443,7 @@ static void create_hardware(GtkWidget *main, GtkWidget *notebook, int page)
 	create_rate_state(vbox1);
 	create_actual_rate(vbox1);
 	create_volume_change(vbox1);
+	create_iec958_input_status(vbox1);
 	create_input_interface(hbox2);
 	create_phono_input(hbox2);
 	create_spdif_input_select(hbox2);
@@ -1412,31 +1483,21 @@ static void create_about(GtkWidget *main, GtkWidget *notebook, int page)
 	vbox = gtk_vbox_new(FALSE, 0);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(viewport), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
-
-
-	/* Create text as labels */
-	label = gtk_label_new("");
-        gtk_widget_show(label);
-	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 6);
-
-	/* create first line */
-	label = gtk_label_new("Envy24 Control Utility " VERSION);
-        gtk_widget_show(label);
-	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 6);
-
-	/* create second line */
-	label = gtk_label_new("A GTK Tool for Envy24 PCI Audio Chip");
-        gtk_widget_show(label);
-	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 6);
-
-
-	/* create third line */
-	label = gtk_label_new("Copyright(c) 2000 by Jaroslav Kysela <perex@perex.cz>");
-        gtk_widget_show(label);
-	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
 
+	char temp_text[1024];
+	sprintf(temp_text, 
+		"<span size=\"large\">Envy24 Control Utility ( %s )</span>\n\n\
+<span size=\"medium\">A GTK Tool for Envy24 PCI Audio Chip</span>\n\n\
+<span size=\"small\">Copyright (C) 2000 by Jaroslav Kysela &lt;perex&#64;perex.cz&gt;</span>\n\
+<span size=\"small\">Copyright (C) 2003 by Søren Wedel Nielsen</span>\n\
+<span size=\"small\">Copyright (C) 2005 by Alan Horstmann</span>\n\
+<span size=\"small\">Copyright (C) 2010 Niels Mayer ( http://nielsmayer.com )</span>\n\
+<span size=\"small\">Copyright (C) 2010 Tim E. Real</span>\n\
+", VERSION);
+	/* Create text as label */
 	label = gtk_label_new("");
+	gtk_label_set_markup(GTK_LABEL(label), temp_text);
         gtk_widget_show(label);
 	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 6);
 }
@@ -1495,40 +1556,50 @@ static void create_analog_volume(GtkWidget *main, GtkWidget *notebook, int page)
 	/* create DAC */
 	for(i = 0; i < envy_dac_volumes(); i++) {
 		char name[32];
-		sprintf(name, "DAC %d", i);
+		sprintf(name, "DAC %d", i+1); /* NPM: for consistency w/ other panels, start w/ "DAC 1" */
 		frame = gtk_frame_new(name);
 		gtk_widget_show(frame);
 		//gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
 		gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
-		gtk_container_set_border_width(GTK_CONTAINER(frame), 6);
+		gtk_container_set_border_width(GTK_CONTAINER(frame), 3);
 
 		vbox = gtk_vbox_new(FALSE, 0);
 		gtk_widget_show(vbox);
 		gtk_container_add(GTK_CONTAINER(frame), vbox);
-		gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+		gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
 
 		/* Add friendly labels for DMX 6Fires */
 		if(card_is_dmx6fire && (i < 6)){
 			label = gtk_label_new(dmx6fire_outputs[i]);
 			gtk_widget_show(label);
-			gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 6);
+			gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
 		}
 
-		adj = gtk_adjustment_new(0, -(envy_dac_max()), 0, 1, 16, 0);
+		/* NPM: display peak levels on DAC's in "Analog Volume" panel  */
+		if (i < MAX_OUTPUT_CHANNELS) { /* make sure within bounds of dac_peak_label[] */
+		  dac_peak_label[i] = label = gtk_label_new("(Off)");
+		  gtk_widget_modify_font(label, pango_font_description_from_string ("Monospace"));
+		  gtk_widget_show(label);
+		  gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
+		}
+
+		adj = gtk_adjustment_new(0, -(envy_dac_max()), 0, 1, ANALOG_GAIN_STEP_SIZE, 0); /* NPM: using step size of 12 gives -6dB step-size */
 		av_dac_volume_adj[i] = adj;
 		vscale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
-		gtk_scale_set_draw_value(GTK_SCALE(vscale), FALSE);
+		/* NPM: above, set step size of 12 ==> -6dB step-size. Place dB-labelled markers at those locations */
+		draw_dac_scale_markings(GTK_SCALE(vscale), (i%channel_group_modulus) ? GTK_POS_RIGHT : GTK_POS_LEFT);
+		gtk_scale_set_draw_value(GTK_SCALE(vscale), FALSE); /* NPM: don't draw scale value since we're displaying in dB's */
 		gtk_widget_show(vscale);
-		gtk_box_pack_start(GTK_BOX(vbox), vscale, TRUE, TRUE, 6);
+		gtk_box_pack_start(GTK_BOX(vbox), vscale, TRUE, TRUE, 0);
 		gtk_scale_set_digits(GTK_SCALE(vscale), 0);
 		gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
 				   GTK_SIGNAL_FUNC(dac_volume_adjust), 
 				   (gpointer)(long)(i));
 
-	        label = gtk_label_new("000");
-	        av_dac_volume_label[i] =(GtkLabel *)label;
+	        av_dac_volume_label[i] = label = gtk_label_new("-63.5");
+		gtk_widget_modify_font(label, pango_font_description_from_string ("Monospace"));
 	        gtk_widget_show(label);
-		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 6);
+		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
 
 
 		if (i >= envy_dac_senses())
@@ -1551,41 +1622,51 @@ static void create_analog_volume(GtkWidget *main, GtkWidget *notebook, int page)
 	/* create ADC */
 	for (i = 0; i < envy_adc_volumes(); i++) {
 		char name[32];
-		sprintf(name, "ADC %d", i);
+		sprintf(name, "ADC %d", i+1); /* NPM: for consistency w/ other panels, start w/ "ADC 1" */
 		frame = gtk_frame_new(name);
 		gtk_widget_show(frame);
 		//gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
 		gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
-		gtk_container_set_border_width(GTK_CONTAINER(frame), 6);
+		gtk_container_set_border_width(GTK_CONTAINER(frame), 3);
 
 		vbox = gtk_vbox_new(FALSE, 0);
 		gtk_widget_show(vbox);
 		gtk_container_add(GTK_CONTAINER(frame), vbox);
-		gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+		gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
 
 		/* Add friendly labels for DMX 6Fires */
 		if(card_is_dmx6fire && (i < 6)){
 			label = gtk_label_new(dmx6fire_inputs[i]);
 			gtk_widget_show(label);
-			gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 6);
+			gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
 		}
 
-		adj = gtk_adjustment_new(0, -(envy_adc_max()), 0, 1, 16, 0);
+		/* NPM: display peak levels on ADC's in "Analog Volume" panel  */
+		if (i < MAX_INPUT_CHANNELS) { /* make sure within bounds of adc_peak_label[] */
+		  adc_peak_label[i] = label = gtk_label_new("(Off)");
+		  gtk_widget_modify_font(label, pango_font_description_from_string ("Monospace"));
+		  gtk_widget_show(label);
+		  gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
+		}
+
+		adj = gtk_adjustment_new(0, -(envy_adc_max()), 0, 1, ANALOG_GAIN_STEP_SIZE, 0); /* using step size of 12 gives -6dB step-size */
 		av_adc_volume_adj[i] = adj;
 		vscale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
-		gtk_scale_set_draw_value(GTK_SCALE(vscale), FALSE);
+		/* NPM: above, set step size of 12 ==> -6dB step-size. Place dB-labelled markers at those locations */
+		draw_adc_scale_markings(GTK_SCALE(vscale), (i%channel_group_modulus) ? GTK_POS_RIGHT : GTK_POS_LEFT);
+		gtk_scale_set_draw_value(GTK_SCALE(vscale), FALSE); /* NPM: don't draw scale value since we're displaying in dB's */
 		gtk_widget_show(vscale);
-		gtk_box_pack_start(GTK_BOX(vbox), vscale, TRUE, TRUE, 6);
-		gtk_scale_set_value_pos(GTK_SCALE(vscale), GTK_POS_BOTTOM);
+		gtk_box_pack_start(GTK_BOX(vbox), vscale, TRUE, TRUE, 0);
 		gtk_scale_set_digits(GTK_SCALE(vscale), 0);
 		gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
 				   GTK_SIGNAL_FUNC(adc_volume_adjust), 
 				   (gpointer)(long)(i));
 
-	        label = gtk_label_new("000");
-	        av_adc_volume_label[i] =(GtkLabel *)label;
-	        gtk_widget_show(label);
-		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 6);
+		/* NPM */
+	        av_adc_volume_label[i] = label = gtk_label_new("-63.5");
+		gtk_widget_modify_font(label, pango_font_description_from_string ("Monospace"));
+		gtk_widget_show(label);
+		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
 
 		if (i >= envy_adc_senses())
 			continue;
@@ -1612,36 +1693,35 @@ static void create_analog_volume(GtkWidget *main, GtkWidget *notebook, int page)
 		gtk_widget_show(frame);
 		//gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
 		gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
-		gtk_container_set_border_width(GTK_CONTAINER(frame), 6);
+		gtk_container_set_border_width(GTK_CONTAINER(frame), 3);
 
 		vbox = gtk_vbox_new(FALSE, 0);
 		gtk_widget_show(vbox);
 		gtk_container_add(GTK_CONTAINER(frame), vbox);
-		gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+		gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
 
 		/* Add friendly labels for DMX 6Fires */
 		if(card_is_dmx6fire && (i < 6)){
 			label = gtk_label_new(dmx6fire_inputs[i]);
 			gtk_widget_show(label);
-			gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 6);
+			gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3);
 		}
 
-		adj = gtk_adjustment_new(0, -36, 0, 1, 16, 0);
+		adj = gtk_adjustment_new(0, -36, 0, 1, 6, 0);
 		av_ipga_volume_adj[i] = adj;
 		vscale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
 		gtk_scale_set_draw_value(GTK_SCALE(vscale), FALSE);
 		gtk_widget_show(vscale);
-		gtk_box_pack_start(GTK_BOX(vbox), vscale, TRUE, TRUE, 6);
-		gtk_scale_set_value_pos(GTK_SCALE(vscale), GTK_POS_BOTTOM);
+		gtk_box_pack_start(GTK_BOX(vbox), vscale, TRUE, TRUE, 3);
 		gtk_scale_set_digits(GTK_SCALE(vscale), 0);
 		gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
 				   GTK_SIGNAL_FUNC(ipga_volume_adjust), 
 				   (gpointer)(long)(i));
 
-	        label = gtk_label_new("000");
-	        av_ipga_volume_label[i] = (GtkLabel *)label;
+	        av_ipga_volume_label[i] = label = gtk_label_new("-63.5");
+		gtk_widget_modify_font(label, pango_font_description_from_string ("Monospace"));
 	        gtk_widget_show(label);
-		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 6);
+		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3);
 	}
 }
 
@@ -1869,7 +1949,8 @@ static void create_profiles(GtkWidget *main, GtkWidget *notebook, int page)
 	gtk_box_pack_start(GTK_BOX(hbox1), label_card_nr, FALSE, FALSE, 20);
 	gtk_label_set_justify(GTK_LABEL(label_card_nr), GTK_JUSTIFY_LEFT);
 
-	card_button_adj = gtk_adjustment_new(16, 0, MAX_CARD_NUMBERS - 1, 1, 10, 10);
+	card_button_adj = gtk_adjustment_new(16, 0, MAX_CARD_NUMBERS - 1, 1, 10, 0); /* NPM: set last parm to 0 to get rid of 'Gtk-WARNING **: GtkSpinButton: setting an
+> adjustment with non-zero page size is deprecated' -- change suggested by James Morris on linux-audio-dev */
 	card_number_adj = card_button_adj;
 	card_button = gtk_spin_button_new(GTK_ADJUSTMENT (card_button_adj), 1, 0);
 	gtk_widget_show(card_button);
@@ -1936,14 +2017,14 @@ static void create_outer(GtkWidget *main)
 	gtk_widget_show(vbox);
 	gtk_box_pack_start(GTK_BOX(main), vbox, FALSE, FALSE, 0);
 
-	label = gtk_label_new(" Rt-clk Menu >>");
+	label = gtk_label_new("(Rt Menu) >>");
 	//gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 	gtk_widget_show(label);
 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 3);
 	frame = gtk_frame_new("Digital Mixer");
 	gtk_widget_show(frame);
 	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, TRUE, 0);
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(frame), 1);
 
 	/* Create controls in the digital mixer frame */
 
@@ -1958,7 +2039,7 @@ static void create_outer(GtkWidget *main)
 	drawing = gtk_drawing_area_new();
 	mixer_mix_drawing = drawing;
 	gtk_widget_set_name(drawing, "DigitalMixer");
-	gtk_box_pack_start(GTK_BOX(hbox1), drawing, TRUE, FALSE, 6);
+	gtk_box_pack_start(GTK_BOX(hbox1), drawing, TRUE, FALSE, 3);
 	if (tall_equal_mixer_ht > 1 ) {
 		gtk_widget_set_usize(drawing, 60, 264 + 60 * (tall_equal_mixer_ht - 1));
 	} else {
@@ -1976,17 +2057,16 @@ static void create_outer(GtkWidget *main)
 	gtk_box_pack_start(GTK_BOX(vbox), hbox1, TRUE, FALSE, 0);
 	gtk_container_set_border_width(GTK_CONTAINER(hbox1), 6);
 
-	label = gtk_label_new("Left");
+	peak_label[IDX_LMIX] = label = gtk_label_new("(Off)");
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 	gtk_widget_show(label);
 	gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, TRUE, 0);
 
-	label = gtk_label_new("Right");
+	peak_label[IDX_RMIX] = label = gtk_label_new("(Off)");
 	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
 	gtk_widget_show(label);
 	gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, TRUE, 0);
 
-
 	mixer_clear_peaks_button = gtk_button_new_with_label("Reset Peaks");
 	gtk_widget_show(mixer_clear_peaks_button);
 	gtk_box_pack_start(GTK_BOX(vbox), mixer_clear_peaks_button, TRUE, FALSE, 0);
@@ -2016,7 +2096,7 @@ static void create_blank(GtkWidget *main, GtkWidget *notebook, int page)
 
 static void usage(void)
 {
-	fprintf(stderr, "usage: envy24control [-c card#] [-D control-name] [-o num-outputs] [-i num-inputs] [-p num-pcm-outputs] [-s num-spdif-in/outs] [-v] [-f profiles-file] [profile name|profile id] [-m channel-num] [-w initial-window-width] [-t height-num]\n");
+	fprintf(stderr, "usage: envy24control [-c card#] [-D control-name] [-o num-outputs] [-i num-inputs] [-p num-pcm-outputs] [-s num-spdif-in/outs] [-v] [-f profiles-file] [profile name|profile id] [-m channel-num] [-w initial-window-width] [-t height-num] [-n]\n");
 	fprintf(stderr, "\t-c, --card\tAlsa card number to control\n");
 	fprintf(stderr, "\t-D, --device\tcontrol-name\n");
 	fprintf(stderr, "\t-o, --outputs\tLimit number of analog line outputs to display\n");
@@ -2029,6 +2109,20 @@ static void usage(void)
 	fprintf(stderr, "\t-M, --midienhanced\tUse an enhanced mapping from midi controller to db slider\n");
 	fprintf(stderr, "\t-w, --window_width\tSet initial window width (try 2,6 or 8; 280,626, or 968)\n");
 	fprintf(stderr, "\t-t, --tall_eq_mixer_heights\tSet taller height mixer displays (1-9)\n");
+	fprintf(stderr, "\t-n, --no_scale_mark\tDisable scale marks, which may be incorrect on certain cards (?), or whose Gtk-detent at the mark position may be annoying\n");
+}
+
+/* NPM for efficiency&power-savings, replaced multiple 40ms&100ms timeouts
+   for each of the callbacks contained here, with a single 100ms one which
+   calls gtk_timeout_add(100, (GtkFunction)envy24control_poll, ...) */
+void envy24control_poll() {
+  level_meters_timeout_callback(NULL);
+  master_clock_status_timeout_callback(NULL);
+  internal_clock_status_timeout_callback(NULL);
+  rate_locking_status_timeout_callback(NULL);
+  rate_reset_status_timeout_callback(NULL);
+  if (card_has_delta_iec958_input_status)
+    iec958_input_status_timeout_callback(NULL); /* NPM */
 }
 
 int main(int argc, char **argv)
@@ -2065,10 +2159,13 @@ int main(int argc, char **argv)
 		{"window_width", 1, 0, 'w'},
 		{"view_spdif_playback", 0, 0, 'v'},
 		{"tall_eq_mixer_heights", 1, 0, 't'},
+		{"no_scale_mark", 1, 0, 'n'}, /* NPM: add option to disable scale marks, which may be incorrect on certain cards (?), or whose Gtk-detent behavior annoys users */
+		{"channel_group_modulus", 1, 0, 'g'}, /* NPM: add optional count to control grouping behavior of labels */
+		{"bg_color", 1, 0, 'b'}, /* NPM: add optional 'bg_color' for peak level metering */
+		{"lights_color", 1, 0, 'l'}, /* NPM: add optional 'lights_color' for peak level metering */
 		{ NULL }
 	};
 
-
 	snd_ctl_card_info_alloca(&hw_info);
 	snd_ctl_elem_value_alloca(&val);
 
@@ -2084,24 +2181,49 @@ int main(int argc, char **argv)
 	view_spdif_playback = 0;
 	profiles_file_name = DEFAULT_PROFILERC;
 	default_profile = NULL;
-	while ((c = getopt_long(argc, argv, "D:c:f:i:m:Mo:p:s:w:vt:", long_options, NULL)) != -1) {
+
+	while ((c = getopt_long(argc, argv, "D:c:f:i:m:Mo:p:s:w:vt:ng:b:l:", long_options, NULL)) != -1) {
 		switch (c) {
 		case 'D':
-			name = optarg;
-			card_number = atoi(strchr(name, ':') + sizeof(char));
-			if (card_number < 0 || card_number >= MAX_CARD_NUMBERS) {
-				fprintf(stderr, "envy24control: invalid card number %d\n", card_number);
-				exit(1);
-			}
+		/*
+		 * NPM: use ALSA code to fix/validate
+		 * https://bugzilla.redhat.com/show_bug.cgi?id=602900
+		 * The old code assumed ':' present, e.g. "-Dhw:66", (w/
+		 * .asoundrc "ctl.66 {type hw, card M66}") and would
+		 * coredump if given "-D66". Here, by not worrying about
+		 * "hw:" and passing "optarg" as-is via 'name' to
+		 * snd_ctl_open() below, resolves the issue, giving similar
+		 * behavior as 'amixer'.  However, letting snd_ctl_open()
+		 * validate gives less helpful error messages on
+		 * failure: "envy24control -Dhw:foo"
+		 *           ==> "snd_ctl_open: No such device"
+		 * So validate the arg as ALSA CTL, providing
+		 * a more specific error message and fail first if not valid.
+		 */
+			name = optarg; /* NPM: e.g. pass "-D66" unaltered to snd_ctl_open() and let it validate valid ALSA CTL name */
+			if (index(optarg, ':')) { /* NPM: handle e.g. optarg == "hw:M66" */
+			    card_number = snd_card_get_index(strchr(optarg, ':') + sizeof(char));
+			    if (card_number < 0) {
+			      fprintf(stderr, "envy24control: invalid ALSA audio device, invalid index or name for card: %s\n", optarg);
+			      exit(1);
+			    }
+			  }
 			break;
 		case 'c':
-			i = atoi(optarg);
-			if (i < 0 || i >= MAX_CARD_NUMBERS) {
-				fprintf(stderr, "envy24control: invalid card number %d\n", i);
+	        /*
+		 * NPM: use snd_card_get_index() to fix/validate
+		 * https://bugzilla.redhat.com/show_bug.cgi?id=602900
+		 * nb:"The accepted format is an integer value in ASCII
+		 * representation or the card identifier (the id parameter
+		 * for sound-card drivers). The control device name like
+		 * /dev/snd/controlC0 is accepted, too."
+		 */
+			card_number = snd_card_get_index(optarg);
+			if (card_number < 0) { /* NPM: code orig from alsa-utils/alsamixer/cli.c */
+				fprintf(stderr, "envy24control: invalid ALSA index or name for audio card: %s\n", optarg);
 				exit(1);
 			}
-			card_number = i;
-			sprintf(tmpname, "hw:%d", i);
+			sprintf(tmpname, "hw:%d", card_number); /* e.g. "hw:M66" for arg "-cM66" passed to snd_ctl_open() below */
 			name = tmpname;
 			break;
 		case 'f':
@@ -2164,6 +2286,30 @@ int main(int argc, char **argv)
 			if ((tall_equal_mixer_ht < 0) || (tall_equal_mixer_ht >= 10))
 				tall_equal_mixer_ht = 0;
 			break;
+		case 'n':	/* NPM */
+		        no_scale_marks = TRUE;
+			break;
+		case 'g':	/* NPM */
+			channel_group_modulus = atoi(optarg);
+			if (channel_group_modulus <= 0)
+			  channel_group_modulus = 1;
+			if (channel_group_modulus >= MAX_INPUT_CHANNELS)
+			  channel_group_modulus = MAX_INPUT_CHANNELS;
+			break;
+		case 'b':	/* NPM */
+		  meter_bg = (GdkColor *)g_malloc(sizeof(GdkColor)); /* free()'d on exit() */
+		  if (!gdk_color_parse(optarg, meter_bg)) { 
+		    fprintf(stderr, "envy24control: unable to parse arguments --bg_color '%s'\n", optarg);
+		    exit(1);
+		  }
+		  break;
+		case 'l':	/* NPM */
+		  meter_fg = (GdkColor *)g_malloc(sizeof(GdkColor)); /* free()'d on exit() */
+		  if (!gdk_color_parse(optarg, meter_fg)) {
+		    fprintf(stderr, "envy24control: unable to parse arguments --lights_color '%s'\n", optarg);
+		    exit(1);
+		  }
+		  break;
 		default:
 			usage();
 			exit(1);
@@ -2221,6 +2367,16 @@ int main(int argc, char **argv)
 	if(card_eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE)
 		card_is_dmx6fire = TRUE;
 
+	/* NPM: determine if "Delta IEC958 Input Status" available
+	   excluding ICE1712_SUBDEVICE_DELTA44 since it has no IEC958 in */
+	if ((card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTA1010
+	     || card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTA1010LT
+	     || card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTA66
+	     || card_eeprom.subvendor == ICE1712_SUBDEVICE_AUDIOPHILE
+	     || card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTADIO2496
+	     || card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTA410))
+	  card_has_delta_iec958_input_status = TRUE;
+
 	/* Set a better default for input_channels and output_channels */
 	if(!input_channels_set)
 		if(card_is_dmx6fire)
@@ -2249,6 +2405,8 @@ int main(int argc, char **argv)
 	if (midi_channel >= 0)
 		midi_fd = midi_init(argv[0], midi_channel, midi_enhanced);
 
+	gtk_timeout_add(100, (GtkFunction)envy24control_poll, (gpointer) NULL); /* NPM for efficiency&power-savings, replaced multiple 40ms&100ms timeouts with this single one */
+
 	fprintf(stderr, "using\t --- input_channels: %i\n\t --- output_channels: %i\n\t --- pcm_output_channels: %i\n\t --- spdif in/out channels: %i\n", \
 		input_channels, output_channels, pcm_output_channels, spdif_channels);
 
@@ -2303,11 +2461,6 @@ int main(int argc, char **argv)
 	if (midi_fd >= 0) {
 		gdk_input_add(midi_fd, GDK_INPUT_READ, midi_process, NULL);
 	}
-	gtk_timeout_add(40, level_meters_timeout_callback, NULL);
-	gtk_timeout_add(100, master_clock_status_timeout_callback, NULL);
-	gtk_timeout_add(100, internal_clock_status_timeout_callback, NULL);
-	gtk_timeout_add(100, rate_locking_status_timeout_callback, NULL);
-	gtk_timeout_add(100, rate_reset_status_timeout_callback, NULL);
 
 
 	gtk_widget_show(window);
diff --git a/envy24control/envy24control.h b/envy24control/envy24control.h
index f5c1e39..ec7b8f7 100644
--- a/envy24control/envy24control.h
+++ b/envy24control/envy24control.h
@@ -15,7 +15,7 @@
 #endif
 #define MAX_PROFILES 8
 #define MAX_PROFILE_NAME_LENGTH 20
-#define DEFAULT_PROFILERC "~/envy24control/profiles.conf"
+#define DEFAULT_PROFILERC "~/.envy24control/profiles.conf" /* NPM: use hidden directory for profiles */
 #define SYS_PROFILERC "/etc/envy24control/profiles.conf"
 #ifndef MKDIR
 #define MKDIR "/bin/mkdir"
@@ -58,6 +58,55 @@
 #define MAX_SPDIF_CHANNELS	2
 /* max number of PCM output channels */
 #define MAX_PCM_OUTPUT_CHANNELS	8
+/* NPM: the digital mixer max-attenuation in dB, per snd ice1712 architecture diagram
+   http://nielsmayer.com/npm/envy24mixer-architecture.png
+   taken from http://alsa.cybermirror.org/manuals/icensemble/envy24.pdf */
+/* NPM: the control values for the digital mixer are 0-96 and not the
+   dB attenuation values of MAX_MIXER_ATTENUATION_DB...
+   The following values comprise all the signals mixed in the ice1712's digital
+   mixer: MULTI_PLAYBACK_VOLUME, HW_MULTI_CAPTURE_VOLUME, IEC958_MULTI_CAPTURE_VOLUME:
+    > amixer -c M66 cget iface=MIXER,name='Multi Playback Volume'
+    numid=11,iface=MIXER,name='Multi Playback Volume'
+      ; type=INTEGER,access=rw---R--,values=2,min=0,max=96,step=0
+      : values=78,67
+      | dBscale-min=-144.00dB,step=1.50dB,mute=0
+    > amixer -c M66 cget iface=MIXER,name="H/W Multi Capture Volume"
+    numid=27,iface=MIXER,name='H/W Multi Capture Volume'
+      ; type=INTEGER,access=rw---R--,values=2,min=0,max=96,step=0
+      : values=0,0
+      | dBscale-min=-144.00dB,step=1.50dB,mute=0
+    > amixer -c M66 cget iface=MIXER,name="IEC958 Multi Capture Volume"
+    numid=31,iface=MIXER,name='IEC958 Multi Capture Volume'
+      ; type=INTEGER,access=rw------,values=2,min=0,max=96,step=0
+      : values=16,0
+*/
+#define MAX_MIXER_ATTENUATION_VALUE 96 /* for -144dB */
+#define LOW_MIXER_ATTENUATION_VALUE 33 /* for -49.5dB nb: 64-->-48dB where 96-64=32 */
+#define MIN_MIXER_ATTENUATION_VALUE 0  /* for 0dB */
+
+/*
+ * NPM: DAC and ADC constants
+ */
+#define MIN_ADC_GAIN -63
+#define MAX_ADC_GAIN 18
+#define MIN_DAC_GAIN -63
+#define MAX_DAC_GAIN 0
+#define ANALOG_GAIN_STEP_SIZE 12  /* this value gives a known -18dB step size for 24 bit attenuators, -6dB step for 16 bit attenuators */
+#define MIXER_ATTENUATOR_STEP_SIZE 8  /* this value gives a known -12dB step size for 24 bit attenuators, -6dB step for 16 bit attenuators */
+
+/*
+ * NPM: For peak meters
+ */
+#define MULTI_TRACK_PEAK_CHANNELS 22
+#define IDX_LMIX 20
+#define IDX_RMIX 21
+#define MAX_METERING_LEVEL 255 	/* level corresponding to 0dB output for ice1712 hardware peak meters */
+// #define MIN_METERING_LEVEL_DB -48.164799306 /* == 20*log10(1/(MAX_METERING_LEVEL+1)) */
+// #define MIN_METERING_LEVEL_DB −48.130803609 /* == 20*log10(1/MAX_METERING_LEVEL)     */
+
+/*
+ * NPM: 
+ */
 
 typedef struct {
 	unsigned int subvendor;	/* PCI[2c-2f] */
@@ -87,6 +136,11 @@ extern GtkWidget *mixer_clear_peaks_button;
 extern GtkWidget *mixer_drawing[20];
 extern GtkObject *mixer_adj[20][2];
 extern GtkWidget *mixer_vscale[20][2];
+extern GtkWidget *mixer_label[20][2]; /* NPM */
+extern GtkWidget *peak_label[MULTI_TRACK_PEAK_CHANNELS];     /* NPM */
+extern GtkWidget *adc_peak_label[MAX_INPUT_CHANNELS];	     /* NPM */
+extern GtkWidget *dac_peak_label[MAX_OUTPUT_CHANNELS];       /* NPM */
+
 extern GtkWidget *mixer_solo_toggle[20][2];
 extern GtkWidget *mixer_mute_toggle[20][2];
 extern GtkWidget *mixer_stereo_toggle[20];
@@ -111,6 +165,8 @@ extern GtkWidget *hw_rate_reset_check;
 extern GtkObject *hw_volume_change_adj;
 extern GtkWidget *hw_volume_change_spin;
 
+extern GtkWidget *hw_iec958_input_status_label; /* NPM */
+
 extern GtkWidget *hw_spdif_profi_nonaudio_radio;
 extern GtkWidget *hw_spdif_profi_audio_radio;
 
@@ -154,14 +210,17 @@ extern GtkWidget *input_interface_wavetable;
 extern GtkObject *av_dac_volume_adj[];
 extern GtkObject *av_adc_volume_adj[];
 extern GtkObject *av_ipga_volume_adj[];
-extern GtkLabel *av_dac_volume_label[];
-extern GtkLabel *av_adc_volume_label[];
-extern GtkLabel *av_ipga_volume_label[];
+extern GtkWidget *av_dac_volume_label[];
+extern GtkWidget *av_adc_volume_label[];
+extern GtkWidget *av_ipga_volume_label[];
 extern GtkWidget *av_dac_sense_radio[][4];
 extern GtkWidget *av_adc_sense_radio[][4];
 
 /* flags */
 extern int card_is_dmx6fire;
+extern int no_scale_marks;	/* NPM: --no_scale_marks option */
+extern GdkColor *meter_bg, *meter_fg; /* NPM: --bg_color --lights_color options */
+extern int card_has_delta_iec958_input_status; /* NPM added to support "Delta IEC958 Input Status" */
 
 gint level_meters_configure_event(GtkWidget *widget, GdkEventConfigure *event);
 gint level_meters_expose_event(GtkWidget *widget, GdkEventExpose *event);
@@ -189,6 +248,7 @@ gint master_clock_status_timeout_callback(gpointer data);
 gint internal_clock_status_timeout_callback(gpointer data);
 gint rate_locking_status_timeout_callback(gpointer data);
 gint rate_reset_status_timeout_callback(gpointer data);
+gint iec958_input_status_timeout_callback(gpointer data);
 void internal_clock_toggled(GtkWidget *togglebutton, gpointer data);
 void rate_locking_update(void);
 void rate_locking_toggled(GtkWidget *togglebutton, gpointer data);
@@ -209,6 +269,7 @@ void spdif_input_update(void);
 void spdif_input_toggled(GtkWidget *togglebutton, gpointer data);
 void analog_input_select_toggled(GtkWidget *togglebutton, gpointer data);
 void phono_input_toggled(GtkWidget *togglebutton, gpointer data);
+void iec958_input_status_update(void); /* NPM */
 
 void hardware_init(void);
 void hardware_postinit(void);
@@ -241,3 +302,8 @@ void adc_sense_toggled(GtkWidget *togglebutton, gpointer data);
 void control_input_callback(gpointer data, gint source, GdkInputCondition condition);
 void mixer_input_callback(gpointer data, gint source, GdkInputCondition condition);
 
+/* NPM: volume/db-related stuff added to volume.c */
+char* peak_level_to_db(int ival);
+void draw_24bit_attenuator_scale_markings(GtkScale *scale, GtkPositionType position, int draw_legend_p);
+void draw_dac_scale_markings(GtkScale *scale, GtkPositionType position);
+void draw_adc_scale_markings(GtkScale *scale, GtkPositionType position);
diff --git a/envy24control/hardware.c b/envy24control/hardware.c
index 73e3f0a..6d4f742 100644
--- a/envy24control/hardware.c
+++ b/envy24control/hardware.c
@@ -31,6 +31,7 @@ static snd_ctl_elem_value_t *analog_input_select;
 static snd_ctl_elem_value_t *breakbox_led;
 static snd_ctl_elem_value_t *spdif_on_off;
 static snd_ctl_elem_value_t *phono_input;
+static snd_ctl_elem_value_t *iec958_in_status; /* NPM: add feature to display "Delta IEC958 Input Status" */
 
 static inline int is_update_needed(void);
 
@@ -270,6 +271,31 @@ gint rate_reset_status_timeout_callback(gpointer data)
     return TRUE;
 }
 
+/* NPM: add feature to display "Delta IEC958 Input Status" */
+static int iec958_input_status_enabled = TRUE;
+gint iec958_input_status_timeout_callback(gpointer data)
+{
+  if (GTK_WIDGET_VISIBLE(hw_iec958_input_status_label) && iec958_input_status_enabled) {
+    int err;
+    if ((err = snd_ctl_elem_read(ctl, iec958_in_status)) < 0) {
+      char temp_text[1024];
+      sprintf(temp_text,
+	      "<span size=\"small\">Unable to read IEC958 Input Status:\n     %s</span>",
+	      snd_strerror(err));
+      gtk_label_set_markup(GTK_LABEL(hw_iec958_input_status_label),
+			   temp_text);
+      iec958_input_status_enabled = FALSE; /* NPM: to prevent constant retries on HW that doesn't support this feature, if it fails the first time it tries, assume it won't succeed later */
+    }
+    else if (snd_ctl_elem_value_get_boolean(iec958_in_status, 0))
+      gtk_label_set_markup(GTK_LABEL(hw_iec958_input_status_label),
+			   "<span size=\"medium\">Input Active</span>");
+    else
+      gtk_label_set_markup(GTK_LABEL(hw_iec958_input_status_label),
+			   "<span size=\"medium\">No Signal Detected</span>");
+  }
+  return TRUE;
+}
+
 void rate_locking_update(void)
 {
 	int err;
@@ -752,7 +778,8 @@ void hardware_init(void)
 	    snd_ctl_elem_value_malloc(&analog_input_select) < 0 ||
 	    snd_ctl_elem_value_malloc(&breakbox_led) < 0 ||
 	    snd_ctl_elem_value_malloc(&spdif_on_off) < 0 ||
-	    snd_ctl_elem_value_malloc(&phono_input) < 0) {
+	    snd_ctl_elem_value_malloc(&phono_input) < 0  ||
+	    snd_ctl_elem_value_malloc(&iec958_in_status) < 0) { /* NPM: add feature to display "Delta IEC958 Input Status" */
 		g_print("Cannot allocate memory\n");
 		exit(1);
 	}
@@ -798,6 +825,8 @@ void hardware_init(void)
 	snd_ctl_elem_value_set_interface(phono_input, SND_CTL_ELEM_IFACE_MIXER);
 	snd_ctl_elem_value_set_name(phono_input, "Phono Analog Input Switch");
 
+	snd_ctl_elem_value_set_interface(iec958_in_status, SND_CTL_ELEM_IFACE_MIXER); /* NPM: add feature to display "Delta IEC958 Input Status" */
+	snd_ctl_elem_value_set_name(iec958_in_status, "Delta IEC958 Input Status"); /* NPM: add feature to display "Delta IEC958 Input Status" */
 }
 
 void hardware_postinit(void)
@@ -810,4 +839,6 @@ void hardware_postinit(void)
 	spdif_output_update();
 	analog_input_select_update();
 	phono_input_update();
+	if (card_has_delta_iec958_input_status)
+	  iec958_input_status_timeout_callback(NULL); /* NPM */
 }
diff --git a/envy24control/levelmeters.c b/envy24control/levelmeters.c
index fa44979..936489a 100644
--- a/envy24control/levelmeters.c
+++ b/envy24control/levelmeters.c
@@ -1,6 +1,11 @@
 /*****************************************************************************
    levelmeters.c - Stereo level meters
    Copyright (C) 2000 by Jaroslav Kysela <perex@perex.cz>
+   Missing peak-level meter feature, and associated rewrite of metering for
+   lower X resource usage, along with using a logarithmic display that attempts
+   correspondence to mixer labels; updating text display of these levels in
+   dBFS appears in their associated panels.
+   Copyright (C) 2010 by Niels Mayer ( http://nielsmayer.com ).
    
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
@@ -17,41 +22,71 @@
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 ******************************************************************************/
 
+#include <math.h>
 #include "envy24control.h"
 
-static GdkGC *penGreenShadow[21] = { NULL, };
+static GdkGC *penWhiteLight[21] = { NULL, };
 static GdkGC *penGreenLight[21] = { NULL, };
-static GdkGC *penOrangeShadow[21] = { NULL, };
+static GdkGC *penForeground[21] = { NULL, };
+static GdkGC *penBackground[21] = { NULL, };
 static GdkGC *penOrangeLight[21] = { NULL, };
-static GdkGC *penRedShadow[21] = { NULL, };
 static GdkGC *penRedLight[21] = { NULL, };
+static GdkColor *peak_label_color = NULL; /* NPM set in level_meters_configure_event() */
+
 static GdkPixmap *pixmap[21] = { NULL, };
 static snd_ctl_elem_value_t *peaks;
 
 extern int input_channels, output_channels, pcm_output_channels, spdif_channels, view_spdif_playback;
 
-static void update_peak_switch(void)
-{
+static void update_peak_switch(void) {
 	int err;
 
 	if ((err = snd_ctl_elem_read(ctl, peaks)) < 0)
 		g_print("Unable to read peaks: %s\n", snd_strerror(err));
 }
 
-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);
-	} else {
-		*l1 = *l2 = snd_ctl_elem_value_get_integer(peaks, idx - 1);
-	}
+/*
+ * 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 RESET -1
+// NPM: Note special case in original envy24control code, which puts stereo mix track at
+// "index 0" which is actually "(peaks, 20)" and "(peaks, 21)" cases below
+// thus peak_lmix <--> peak_levels[IDX_LMIX] ; peak_rmix <--> peak_levels[IDX_RMIX]
+static int peak_levels[MULTI_TRACK_PEAK_CHANNELS] = {0,};
+static int peak_changed[MULTI_TRACK_PEAK_CHANNELS] = {0,};
+static int previous_levels[MULTI_TRACK_PEAK_CHANNELS] = {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) { /* "if (stereo)" -- special case idx=0 as digital mix pair */
+    if ((peak_changed[IDX_LMIX] != RESET) && (peak_changed[IDX_RMIX] != RESET)) { /* don't change values if doing "Reset Peaks" */
+      if ((*l1 = snd_ctl_elem_value_get_integer(peaks, IDX_LMIX)) > peak_levels[IDX_LMIX]) {
+	peak_levels[IDX_LMIX] = (*l1);
+	peak_changed[IDX_LMIX] = TRUE;
+      }
+      if ((*l2 = snd_ctl_elem_value_get_integer(peaks, IDX_RMIX)) > peak_levels[IDX_RMIX]) {
+	peak_levels[IDX_RMIX] = (*l2);
+	peak_changed[IDX_RMIX] = TRUE;
+      }
+    }
+  }
+  else {
+    if (peak_changed[idx-1] != RESET) {
+      if ((*l1 = snd_ctl_elem_value_get_integer(peaks, idx - 1)) > peak_levels[idx - 1]) {
+	peak_levels[idx - 1] = (*l1);
+	peak_changed[idx - 1] = TRUE;
+      }
+    }
+  }
 }
 
-static GdkGC *get_pen(int idx, int nRed, int nGreen, int nBlue)
-{
+static GdkGC *get_pen(int idx, int nRed, int nGreen, int nBlue) {
 	GdkColor *c;
 	GdkGC *gc;
 	
@@ -65,8 +100,7 @@ static GdkGC *get_pen(int idx, int nRed, int nGreen, int nBlue)
 	return gc;
 }
 
-static int get_index(gchar *name)
-{
+static int get_index(const gchar *name) {
 	int result;
 
 	if (!strcmp(name, "DigitalMixer"))
@@ -79,77 +113,344 @@ static int get_index(gchar *name)
 	return result;
 }
 
-static void redraw_meters(int idx, int width, int height, int level1, int level2)
-{
-	int stereo = idx == 0;
-	int segment_width = stereo ? (width / 2) - 8 : width - 12;
-	int segments = (height - 6) / 4;
-	int green_segments = (segments / 4) * 3;
-	int red_segments = 2;
-	int orange_segments = segments - green_segments - red_segments;
-	int seg;
-	int segs_on1 = ((segments * level1) + 128) / 255;
-	int segs_on2 = ((segments * level2) + 128) / 255;
-
-	// g_print("segs_on1 = %i (%i), segs_on2 = %i (%i)\n", segs_on1, level1, segs_on2, level2);
-	for (seg = 0; seg < green_segments; seg++) {
-		gdk_draw_rectangle(pixmap[idx],
-				   segs_on1 > 0 ? penGreenLight[idx] : penGreenShadow[idx],
-				   TRUE,
-				   6, 3 + ((segments - seg - 1) * 4),
-				   segment_width,
-				   3);
-		if (stereo)
-			gdk_draw_rectangle(pixmap[idx],
-					   segs_on2 > 0 ? penGreenLight[idx] : penGreenShadow[idx],
-					   TRUE,
-					   2 + (width / 2),
-					   3 + ((segments - seg - 1) * 4),
-					   segment_width,
-					   3);
-		segs_on1--;
-		segs_on2--;
-	}
-	for (seg = green_segments; seg < green_segments + orange_segments; seg++) {
-		gdk_draw_rectangle(pixmap[idx],
-				   segs_on1 > 0 ? penOrangeLight[idx] : penOrangeShadow[idx],
-				   TRUE,
-				   6, 3 + ((segments - seg - 1) * 4),
-				   segment_width,
-				   3);
-		if (stereo)
-			gdk_draw_rectangle(pixmap[idx],
-					   segs_on2 > 0 ? penOrangeLight[idx] : penOrangeShadow[idx],
-					   TRUE,
-					   2 + (width / 2),
-					   3 + ((segments - seg - 1) * 4),
-					   segment_width,
-					   3);
-		segs_on1--;
-		segs_on2--;
-	}
-	for (seg = green_segments + orange_segments; seg < segments; seg++) {
-		gdk_draw_rectangle(pixmap[idx],
-				   segs_on1 > 0 ? penRedLight[idx] : penRedShadow[idx],
-				   TRUE,
-				   6, 3 + ((segments - seg - 1) * 4),
-				   segment_width,
-				   3);
-		if (stereo)
-			gdk_draw_rectangle(pixmap[idx],
-					   segs_on2 > 0 ? penRedLight[idx] : penRedShadow[idx],
-					   TRUE,
-					   2 + (width / 2),
-					   3 + ((segments - seg - 1) * 4),
-					   segment_width,
-					   3);
-		segs_on1--;
-		segs_on2--;
-	}
+/*
+ * NPM: per http://alsa.cybermirror.org/manuals/icensemble/envy24.pdf the
+ * the values in each entry of iface=PCM,name='Multi Track Peak',numid=45
+ * represent: "Peak data derived from the absolute value of 9 msb. 00h
+ * min - FFh max volume. Reading the register resets the meter to 00h."
+ */
+
+//NPM difft colors for -1dB, -3dB, and -6dB peak levels
+#define GET_COLOR_FOR_PEAKLEVEL(level) \
+  (level > 228)                        \
+      ? (penRedLight[idx])             \
+      : ((level > 181)                 \
+	 ? (penOrangeLight[idx])       \
+	 : ((level > 128)              \
+	    ? (penWhiteLight[idx])     \
+	    : (penGreenLight[idx])))   
+
+/*
+ * NPM: Called by redraw_meters(), this is a special case for when "Reset
+ * Peaks" is clicked: then just refresh meters, ignore value, clear RESET
+ * and let the next pass-through draw for the first time in the cleared
+ * meter...
+ */
+static void draw_meters_reset(int idx, int width, int height,
+			      int stereo, int segment_width) {
+//  GdkColor color;
+  GtkWidget* lbl;
+
+//  if (!gdk_color_parse("bg", &color))
+//    g_print("gdk_color_parse('bg') fail\n");
+
+  gdk_draw_rectangle(pixmap[idx],
+		     penBackground[idx], 
+		     TRUE,
+		     //X
+		     6,
+		     //Y
+		     0,
+		     //WIDTH
+		     segment_width,
+		     //HEIGHT
+		     height
+		     );
+  /* NPM: Reset peak labels for "Monitor Inputs" and "Monitor PCMs" panels */
+  gtk_label_set_text(GTK_LABEL((stereo) ? peak_label[IDX_LMIX] : peak_label[idx-1]),
+		     peak_level_to_db((stereo) ? peak_levels[IDX_LMIX] : peak_levels[idx-1])); /* put new value in label */
+  gtk_widget_modify_fg((stereo) ? peak_label[IDX_LMIX] : peak_label[idx-1],
+		       GTK_STATE_NORMAL, NULL);
+
+  /* NPM: Reset "Analog Volume" panel's peak levels -- never happens for "stereo" case */
+  if (!stereo) {
+    /* NPM: Reset peak labels for DACs in "Analog Volume" panel */
+    if (((idx-1) >= 0) && ((idx-1) < envy_dac_volumes())) { /* index 0-8 corresponds to one of the eight DAC's */
+      if (((idx-1) < MAX_OUTPUT_CHANNELS) /* make sure within bounds of dac_peak_label[] */
+	  && (lbl = dac_peak_label[idx-1]) != NULL) {
+	gtk_label_set_text(GTK_LABEL(lbl), peak_level_to_db(peak_levels[idx-1])); /* put new value in label */
+	gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, NULL); /* reset fg color */
+      }
+    }
+    /* NPM: Reset peak labels for ADCs in "Analog Volume" panel */
+    else if (((idx-1) >= (MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS)) /* ADC channels begin at 11 = MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS */
+	     && ((idx-1) < (MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS + envy_adc_volumes()))) { /* ADC channels end at 19 */
+      if ((((idx-1) - (MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS)) < MAX_INPUT_CHANNELS) /* make sure within bounds of adc_peak_label[] */
+	   && (lbl = adc_peak_label[(idx-1) - (MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS)]) != NULL) {
+	gtk_label_set_text(GTK_LABEL(lbl), peak_level_to_db(peak_levels[idx-1])); /* put new value in label */
+	gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, NULL); /* reset fg color */
+      }
+    }
+  }
+  if (stereo) {
+    gdk_draw_rectangle(pixmap[idx],
+		       penBackground[idx], 
+		       TRUE,
+		       //X
+		       2 + (width / 2),
+		       //Y
+		       0,
+		       //WIDTH
+		       segment_width,
+		       //HEIGHT
+		       height
+		       );
+    /* put new value in label */
+    gtk_label_set_text(GTK_LABEL(peak_label[IDX_RMIX]), peak_level_to_db(peak_levels[IDX_RMIX])); 
+    gtk_widget_modify_fg(peak_label[IDX_RMIX], GTK_STATE_NORMAL, NULL);
+
+    peak_changed[IDX_LMIX] = FALSE;
+    peak_changed[IDX_RMIX] = FALSE;
+  }
+  else {
+    peak_changed[idx-1] = FALSE;
+  }
+}
+
+/* 
+ * NPM: Called through redraw_meters(), via draw_meters_and_peaks(), 
+ * this handles updating gtk labels/colors related to updated peak values.
+ * Note 'index' [0 to MULTI_TRACK_PEAK_CHANNELS-1] into global peak_label[]
+ * which is initialized by envy24control.c:create_mixer_frame().
+ */
+static void draw_peak_labels(int index, int stereo, int peak1_level, int peak2_level) {
+  GtkWidget* lbl;
+
+  gtk_label_set_text(GTK_LABEL((stereo) ? peak_label[IDX_LMIX] : peak_label[index]),
+		     peak_level_to_db(peak1_level)); /* put new value in label */
+  if (peak1_level >= MAX_METERING_LEVEL) {			       /* if at 0dB, make label red; RESET reverts to normal color */
+    lbl = (stereo) ? peak_label[IDX_LMIX] : peak_label[index];
+    gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, peak_label_color);
+  }
+
+  /* NPM: Update "Analog Volume" panel's peak levels: the normal non-"stereo"
+     case of single channel peak monitors of input or PCMs */
+  if (!stereo) {		
+    /* NPM: Update peak labels for DACs in "Analog Volume" panel */
+    if ((index >= 0) && (index < envy_dac_volumes())) { /* index 0-8 corresponds to one of the eight DAC's */
+      if ((index < MAX_OUTPUT_CHANNELS) /* make sure within bounds of dac_peak_label[] */
+	  && (lbl = dac_peak_label[index]) != NULL) {
+	gtk_label_set_text(GTK_LABEL(lbl), peak_level_to_db(peak1_level)); /* put new value in label */
+	if (peak1_level >= MAX_METERING_LEVEL)
+	  gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, peak_label_color);
+      }
+    }
+    /* NPM: Update peak labels for ADCs in "Analog Volume" panel */
+    else if ((index >= (MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS)) /* ADC channels begin at 11 = MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS */
+	     && (index <= (MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS + envy_adc_volumes()))) { /* ADC channels end at 19 */
+      if (((index - (MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS)) < MAX_INPUT_CHANNELS) /* make sure within bounds of adc_peak_label[] */
+	  && (lbl = adc_peak_label[index - (MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS)]) != NULL) {
+	gtk_label_set_text(GTK_LABEL(lbl), peak_level_to_db(peak1_level)); /* put new value in label */
+	if (peak1_level >= MAX_METERING_LEVEL)
+	  gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, peak_label_color);
+      }
+    }
+  }
+  /* Handle special "stereo" case for right-channel of digital mixer */
+  else if (peak_changed[IDX_RMIX]) { //for stereo, draw RMIX, but skip redraw if same
+    gtk_label_set_text(GTK_LABEL(peak_label[IDX_RMIX]),
+		       peak_level_to_db(peak2_level)); /* put new value in label */
+    if (peak2_level >= MAX_METERING_LEVEL) /* if at 0dB, make label "selected"; RESET reverts to normal color */
+      gtk_widget_modify_fg(peak_label[IDX_RMIX], GTK_STATE_NORMAL, peak_label_color);
+  }
+}
+
+//NPM: below, fudging value 51.0 instead of 48.164799306 = 20*log10(1/256)
+// or 48.130803609 = 20*log10(1/255) so as to offset meter in direction of
+// scale markings.
+#define METER_LEVEL(level, height)				\
+  ((level==0)							\
+   ? 0								\
+   : ((int) (((double)(height))					\
+	     * ((20.0 * log10(((double)(level))			\
+			      / ((double)MAX_METERING_LEVEL))	\
+		 + 51.0)				\
+		/  51.0) ))-1                           \
+   )
+
+/* 
+ * NPM: Called by redraw_meters(), this is the normal case 
+ * where we draw the meter and peaks, if changed.
+ */
+static void draw_meters_and_peaks(int idx, int width, int height, int level1, int level2, 
+				  int stereo, int segment_width) {
+  int meter1 = (stereo)
+    ? METER_LEVEL(peak_levels[IDX_LMIX], height)
+    : METER_LEVEL(peak_levels[idx - 1],  height);
+  int meter2 = (stereo)
+    ? METER_LEVEL(peak_levels[IDX_RMIX], height)
+    : 0;
+  int peak1 = height - meter1;
+  int peak2 = (stereo) ? height - meter2: 0;
+
+  /*
+   * draw the peak(s), only if changed
+   */
+  if ( (stereo && (peak_changed[IDX_LMIX] || peak_changed[IDX_RMIX]))
+       || peak_changed[idx-1]) {
+    int peak2_level, peak1_level
+      = (stereo) ? peak_levels[IDX_LMIX] : peak_levels[idx-1];
+
+    /* Draw the peak as a single line */
+    gdk_draw_line(pixmap[idx],
+		  GET_COLOR_FOR_PEAKLEVEL(peak1_level),
+		  //X1
+		  6,
+		  //Y1
+		  peak1 - 1,
+		  //X2
+		  5 + segment_width,
+		  //Y2
+		  peak1 - 1
+		  );
+    /* Handle special "stereo" case for right-channel of digital mixer */
+    if (stereo && peak_changed[IDX_RMIX]) { //for stereo, draw RMIX, but skip redraw if same
+      peak2_level = peak_levels[IDX_RMIX];
+      gdk_draw_line(pixmap[idx],
+		    GET_COLOR_FOR_PEAKLEVEL(peak2_level),
+		    //X1
+		    2 + (width / 2),
+		    //Y1
+		    peak2 - 1,
+		    //X2
+		    1 + (width / 2) + segment_width,
+		    //Y2
+		    peak2 - 1
+		    );
+    }
+    else
+      peak2_level = -1;	/* not used unless above case, which is also in draw_peak_labels()... but initialize anyways */
+
+    draw_peak_labels(idx-1, stereo, peak1_level, peak2_level);
+
+    /* reset peak_changed[] status now that new peak values rendered */
+    if (stereo) {
+      if (peak_changed[IDX_LMIX])
+	peak_changed[IDX_LMIX] = FALSE;
+      if (peak_changed[IDX_RMIX])
+	peak_changed[IDX_RMIX] = FALSE;
+    } 
+    else {
+      peak_changed[idx-1] = FALSE;
+    }
+  }
+
+  /*
+   * draw the meters
+   * level1 at 0 --> no dspl
+   * level1 at 1 --> draw rectange at (1/255)*height
+   * level1 at 255 --> draw rectangle (255/255)*height
+   */
+  meter1 = METER_LEVEL(level1, height);
+  if (stereo)
+    meter2 = METER_LEVEL(level2, height);
+  if (level1 != (stereo ? previous_levels[IDX_LMIX] : previous_levels[idx-1]) ) { //skip redraw if same
+    gdk_draw_rectangle(pixmap[idx],
+		       penBackground[idx],
+		       TRUE,
+		       //X
+		       6,                               // draw black downward from peak
+		       //Y
+		       peak1,
+		       //WIDTH
+		       segment_width,
+		       //HEIGHT
+		       height - meter1 - peak1
+		       );
+    gdk_draw_rectangle(pixmap[idx],
+		       penForeground[idx],
+		       TRUE,
+		       //X
+		       6,
+		       //Y
+		       height - meter1,
+		       //WIDTH
+		       segment_width,
+		       //HEIGHT
+		       meter1
+		       );                             
+    /* save current level value, skip redraw next time if no change */
+    if (stereo)
+      previous_levels[IDX_LMIX] = level1;
+    else
+      previous_levels[idx-1] = level1;
+  }
+  if (stereo && (level2 != previous_levels[IDX_RMIX])) { //for stereo, draw RMIX, but skip redraw if same
+    gdk_draw_rectangle(pixmap[idx],
+		       penBackground[idx],
+		       TRUE,
+		       //X
+		       2 + (width / 2),
+		       //Y
+		       peak2,
+		       //WIDTH
+		       segment_width,
+		       //HEIGHT
+		       height - meter2 - peak2
+		       );
+    gdk_draw_rectangle(pixmap[idx],
+		       penForeground[idx],
+		       TRUE,
+		       //X
+		       2 + (width / 2),
+		       //Y
+		       height - meter2,
+		       //WIDTH
+		       segment_width,
+		       //HEIGHT
+		       meter2
+		       );
+    /* save current level value, skip redraw next time if no change */
+    previous_levels[IDX_RMIX] = level2; 
+  }
+}
+
+static void redraw_meters(int idx, int width, int height, int level1, int level2) {
+  int stereo = (idx == 0);
+  int segment_width = (stereo)
+    ? (width / 2) - 8
+    : width - 12;
+
+  if ( (stereo && ((peak_changed[IDX_LMIX] == RESET) || (peak_changed[IDX_RMIX] == RESET)))
+       || peak_changed[idx-1] == RESET)	//needs full refresh, reset peaks button was clicked
+    draw_meters_reset(idx, width, height, stereo, segment_width);
+  else 
+    draw_meters_and_peaks(idx, width, height, level1, level2, stereo, segment_width);
+}
+
+/* NPM: called out of level_meters_configure_event() at initialization to
+ pickup foreground color for level metering from --lights_color
+ command-line, or create default. */
+static void levelmeters_init_fg(GtkWidget* widget, GdkGC *gc) {
+  if (meter_fg == NULL) {	/* if --lights_color command-line argument not provided */
+    meter_fg = (GdkColor *)g_malloc(sizeof(GdkColor)); /* free()'d on exit() */
+    if (!gdk_color_parse("#1e90ff", meter_fg)) { /* "dodgerblue" per http://en.wikipedia.org/wiki/X11_color_names */
+      free((void*) meter_fg); /* if for some impossible reason above fails, continue on valiantly */
+      meter_fg = &(widget->style->text_aa[GTK_STATE_ACTIVE]); /* should never happen, but this would pick up color from existing gtk style w/o needing any addl color allocs */
+    }
+    else 
+      gdk_color_alloc(gdk_colormap_get_system(), meter_fg);
+  }
+  gdk_gc_set_foreground(gc, meter_fg);
 }
 
-gint level_meters_configure_event(GtkWidget *widget, GdkEventConfigure *event)
-{
+/* NPM: called out of level_meters_configure_event() at initialization to
+ pickup background color for level metering from --bg_color command-line
+ argument, or create default. */
+static void levelmeters_init_bg(GtkWidget* widget, GdkGC *gc) {
+  if (meter_bg == NULL) { /* if --bg_color command-line argument not provided */
+    meter_bg = (GdkColor *)g_malloc(sizeof(GdkColor)); /* free()'d on exit() */
+    if (!gdk_color_parse("#304050", meter_bg)) { /* a dark background color */
+      free((void*) meter_bg); /* if for some impossible reason above fails, continue on valiantly */
+      meter_bg = &(widget->style->text_aa[GTK_STATE_PRELIGHT]); /* should never happen, but this would pick up color from existing gtk style w/o needing any addl color allocs */
+    }
+    else 
+      gdk_color_alloc(gdk_colormap_get_system(), meter_bg);
+  }
+  gdk_gc_set_foreground(gc, meter_bg); 
+}
+
+gint level_meters_configure_event(GtkWidget *widget, GdkEventConfigure *event) {
 	int idx = get_index(gtk_widget_get_name(widget));
 
 	if (pixmap[idx] != NULL)
@@ -158,25 +459,52 @@ gint level_meters_configure_event(GtkWidget *widget, GdkEventConfigure *event)
 				     widget->allocation.width,
 				     widget->allocation.height,
 				     -1);
-	penGreenShadow[idx] = get_pen(idx, 0, 0x77ff, 0);
+	penWhiteLight[idx] = get_pen(idx, 0xffff, 0xffff, 0xffff);
 	penGreenLight[idx] = get_pen(idx, 0, 0xffff, 0);
-	penOrangeShadow[idx] = get_pen(idx, 0xddff, 0x55ff, 0);
-	penOrangeLight[idx] = get_pen(idx, 0xffff, 0x99ff, 0);
-	penRedShadow[idx] = get_pen(idx, 0xaaff, 0, 0);
+
+	/* NPM: Setup penForeground[idx] color for meters */
+	levelmeters_init_fg(widget, (penForeground[idx] = gdk_gc_new(pixmap[idx])));
+	/* NPM: Setup penBackground[idx] color for meters */
+	levelmeters_init_bg(widget, (penBackground[idx] = gdk_gc_new(pixmap[idx])));
+
+	penOrangeLight[idx] = get_pen(idx, 0xff11, 0x9911, 0);
+
+	peak_label_color = (GdkColor *)g_malloc(sizeof(GdkColor)); /* free()'d on exit() */
+        gdk_color_parse("red", peak_label_color);
+	gdk_color_alloc(gdk_colormap_get_system(), peak_label_color);
+
 	penRedLight[idx] = get_pen(idx, 0xffff, 0, 0);
+
 	gdk_draw_rectangle(pixmap[idx],
 			   widget->style->black_gc,
 			   TRUE,
 			   0, 0,
 			   widget->allocation.width,
 			   widget->allocation.height);
+
+	/* NPM: ensure redraw_meters() below does a full refresh, per meter  */
+	if (idx == 0) {		/* "if stereo" -- special case for L/R output pair of digital mixer */
+	  // g_print("level_meters_configure_event() for stereo\n");
+	  peak_levels[IDX_LMIX]     = 0;
+	  peak_levels[IDX_RMIX]     = 0;
+	  previous_levels[IDX_LMIX] = 0;
+	  previous_levels[IDX_RMIX] = 0;
+	  peak_changed[IDX_LMIX]    = RESET;
+	  peak_changed[IDX_RMIX]    = RESET;
+	}
+	else {
+	  // g_print("level_meters_configure_event() for %i\n", idx);
+	  peak_levels[idx-1]        = 0;
+	  previous_levels[idx-1]    = 0;
+	  peak_changed[idx-1]       = RESET;
+	}
+	
 	// g_print("configure: %i:%i\n", widget->allocation.width, widget->allocation.height);
 	redraw_meters(idx, widget->allocation.width, widget->allocation.height, 0, 0);
 	return TRUE;
 }
 
-gint level_meters_expose_event(GtkWidget *widget, GdkEventExpose *event)
-{
+gint level_meters_expose_event(GtkWidget *widget, GdkEventExpose *event) {
 	int idx = get_index(gtk_widget_get_name(widget));
 	int l1, l2;
 	
@@ -191,8 +519,7 @@ gint level_meters_expose_event(GtkWidget *widget, GdkEventExpose *event)
 	return FALSE;
 }
 
-gint level_meters_timeout_callback(gpointer data)
-{
+gint level_meters_timeout_callback(gpointer data) {
 	GtkWidget *widget;
 	int idx, l1, l2;
 
@@ -209,6 +536,47 @@ gint level_meters_timeout_callback(gpointer data)
 					0, 0,
 					widget->allocation.width, widget->allocation.height);
 		}
+		/* NPM: both cases below are special-case hack to get
+		   "Analog Volume" PCM peak levels updating correctly,
+		   should "Analog Volume" panel be selected before "Monitor
+		   PCM outs" panel. In that situation,
+		   "(GTK_WIDGET_VISIBLE(widget) && (pixmap[idx] != NULL))"
+		   fails as level_meters_configure_event() hasn't been
+		   called yet (it gets called when user selects "Monitor
+		   PCM outs" panel).
+		*/
+		else if ((idx != 0)
+			 && ((idx-1) < envy_dac_volumes())
+			 && (peak_changed[idx-1] == TRUE)) { 
+		  draw_peak_labels(idx-1, FALSE, l1, l2);
+		  peak_changed[idx-1] = FALSE;
+		  // g_print("NPM PCM outputs hack calling draw_peak_labels(%i): %i\n", idx-1, l1);
+		}
+		/* NPM: make it work, even after user does a RESET, while
+		   in "Analog Volume" panel, before "Monitor PCM outs"
+		   created/configured */
+		else if ((idx != 0)
+			 && ((idx-1) < envy_dac_volumes())
+			 && (peak_changed[idx-1] == RESET)) { /* note that get_levels() never retrieved l1, l2 due to unfulfilled RESET */
+		  GtkWidget* lbl;
+		  /* NPM: Reset colors of peak labels for DACs in "Analog Volume" panel */
+		  if ((idx-1) < envy_dac_volumes()	/* index 0-8 corresponds to one of the eight DAC's */
+		      && ((idx-1) < MAX_OUTPUT_CHANNELS) /* make sure within bounds of dac_peak_label[] */
+		      && (lbl = dac_peak_label[idx-1]) != NULL)
+		    gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, NULL); /* reset color */
+
+		  /* NPM: Reset colors of peak labels for ADCs in "Analog Volume" panel */
+		  else if (((idx-1) >= (MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS)) /* ADC channels begin at 11 = MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS */
+			   && ((idx-1) < (MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS + envy_adc_volumes())) /* ADC channels end at 19 */
+			   && (((idx-1) - (MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS)) < MAX_INPUT_CHANNELS) /* make sure within bounds of adc_peak_label[] */
+			   && (lbl = adc_peak_label[(idx-1) - (MAX_PCM_OUTPUT_CHANNELS+MAX_SPDIF_CHANNELS)]) != NULL)
+		    gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, NULL); /* reset color */
+
+		  peak_changed[idx-1] = FALSE; /* hack -- force get_levels() to retrieve levels despite RESET */
+		  get_levels(idx, &l1, &l2); 
+		  draw_peak_labels(idx-1, FALSE, l1, l2);
+		  // g_print("NPM PCM outputs RESET hack calling draw_peak_labels(%i): %i\n", idx-1, l1);
+		}
 	}
 	if (view_spdif_playback) {
 		for (idx = MAX_PCM_OUTPUT_CHANNELS + 1; idx <= MAX_OUTPUT_CHANNELS + spdif_channels; idx++) {
@@ -255,12 +623,20 @@ gint level_meters_timeout_callback(gpointer data)
 	return TRUE;
 }
 
-void level_meters_reset_peaks(GtkButton *button, gpointer data)
-{
+
+/* 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;
+    previous_levels[i] = 0;
+    peak_changed[i]    = RESET;
+  }
+
+  level_meters_timeout_callback((gpointer) data);
 }
 
-void level_meters_init(void)
-{
+void level_meters_init(void) {
 	int err;
 
 	snd_ctl_elem_value_malloc(&peaks);
@@ -272,7 +648,6 @@ void level_meters_init(void)
 			SND_CTL_ELEM_IFACE_MIXER);
 }
 
-void level_meters_postinit(void)
-{
+void level_meters_postinit(void) {
 	level_meters_timeout_callback(NULL);
 }
diff --git a/envy24control/mixer.c b/envy24control/mixer.c
index f2b4e9a..b315c84 100644
--- a/envy24control/mixer.c
+++ b/envy24control/mixer.c
@@ -62,8 +62,8 @@ void mixer_update_stream(int stream, int vol_flag, int sw_flag)
 		v[1] = snd_ctl_elem_value_get_integer(vol, 1);
 		if (v[0] != v[1])
 			toggle_set(mixer_stereo_toggle[stream-1], FALSE);
-		gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][0]), 96 - v[0]);
-		gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][1]), 96 - v[1]);
+		gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][0]), MAX_MIXER_ATTENUATION_VALUE - v[0]);
+		gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][1]), MAX_MIXER_ATTENUATION_VALUE - v[1]);
 		midi_controller((stream-1)*2,   v[0]);
 		midi_controller((stream-1)*2+1, v[1]);
 	}
@@ -174,6 +174,45 @@ static void set_volume1(int stream, int left, int right)
 	}
 }
 
+/* 
+ * NPM: mixer_volume_to_db() -- called out of mixer_adjust(). Use of proper
+ * ALSA API snd_ctl_convert_to_dB() to return dB values suggested by
+ * Tim E. Real on linux-audio-devel list.
+ */
+static char temp_label[16];
+static char* mixer_volume_to_db(int stream, int ival) {
+  if (ival != 0) {
+//  g_print("mixer_volume_to_db(%i, %i)\n", stream, ival);
+    snd_ctl_elem_id_t *elem_id;
+    snd_ctl_elem_id_alloca(&elem_id);
+    snd_ctl_elem_id_set_interface(elem_id, SND_CTL_ELEM_IFACE_MIXER);
+    /* NPM: IEC958_MULTI_CAPTURE_VOLUME, for stream=19 or 20 gives incorrect
+     * results, use HW_MULTI_CAPTURE_VOLUME for all.
+     * Verified by TER. Those two controls have no dB values, but they
+     * should, they're just part of the same mixer ! */
+    //snd_ctl_elem_id_set_name(elem_id, (stream <= 10) ? MULTI_PLAYBACK_VOLUME : (stream <= 18 ? HW_MULTI_CAPTURE_VOLUME : IEC958_MULTI_CAPTURE_VOLUME));
+    snd_ctl_elem_id_set_name(elem_id, (stream <= 10) ? MULTI_PLAYBACK_VOLUME : HW_MULTI_CAPTURE_VOLUME);
+    /* TER: First line is 'proper' way, but second line is corrected
+     *  workaround for lack of dB values for IEC958 controls. */
+    //snd_ctl_elem_id_set_index(elem_id, stream <= 18 ? (stream - 1) % 10 : (stream - 1) % 18 );
+    snd_ctl_elem_id_set_index(elem_id, stream <= 18 ? (stream - 1) % 10 : 0 );
+    long db_gain = 0;
+    snd_ctl_convert_to_dB(ctl, elem_id, ival, &db_gain); /* convert 'ival' attenuation to mixer from integer to dB for display */
+    float fval = ((float)db_gain / 100.0);
+    if (fval > -10)
+      sprintf(temp_label, "%+2.1f  ", fval);
+    if (fval < -100)
+      sprintf(temp_label, "%+2.1f", fval);
+    else
+      sprintf(temp_label, "%+2.1f ", fval);
+  }
+  else
+    sprintf(temp_label,   "(Off) ");
+
+  return (temp_label);
+}
+
+
 void mixer_adjust(GtkAdjustment *adj, gpointer data)
 {
 	int stream = (long)data >> 16;
@@ -181,10 +220,22 @@ void mixer_adjust(GtkAdjustment *adj, gpointer data)
 	int stereo = is_active(mixer_stereo_toggle[stream-1]) ? 1 : 0;
 	int vol[2] = { -1, -1 };
 	
-	vol[button] = 96 - adj->value;
+	vol[button] = MAX_MIXER_ATTENUATION_VALUE - adj->value;
 	if (stereo) {
 		gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][button ^ 1]), adj->value);
-		vol[button ^ 1] = 96 - adj->value;
+		vol[button ^ 1] = MAX_MIXER_ATTENUATION_VALUE - adj->value;
+	}
+	if (vol[0] != -1) {
+	  if (vol[0] <= (MAX_MIXER_ATTENUATION_VALUE - LOW_MIXER_ATTENUATION_VALUE))
+	    vol[0] = MIN_MIXER_ATTENUATION_VALUE; /* reset to "off" if at bottom of shortened mixer scale */
+	  gtk_label_set_text(GTK_LABEL(mixer_label[stream-1][0]),
+			     (gchar*)mixer_volume_to_db(stream, vol[0]));
+	}
+	if (vol[1] != -1) {
+	  if (vol[1] <= (MAX_MIXER_ATTENUATION_VALUE - LOW_MIXER_ATTENUATION_VALUE))
+	    vol[1] = MIN_MIXER_ATTENUATION_VALUE; /* reset to "off" if at bottom of shortened mixer scale */
+	  gtk_label_set_text(GTK_LABEL(mixer_label[stream-1][1]),
+			     (gchar*)mixer_volume_to_db(stream, vol[1]));
 	}
 	set_volume1(stream, vol[0], vol[1]);
 }
diff --git a/envy24control/volume.c b/envy24control/volume.c
index 4386e35..ffc3086 100644
--- a/envy24control/volume.c
+++ b/envy24control/volume.c
@@ -20,6 +20,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <math.h>
 #include "envy24control.h"
 
 #define toggle_set(widget, state) \
@@ -209,26 +210,195 @@ void adc_sense_update(int idx)
 	toggle_set(av_adc_sense_radio[idx][state], TRUE);
 }
 
+/*
+ */
+
+static char temp_label[16];
+
+/*
+ * NPM: Per Fons Adriaensen''s message to linux-audio-user's list
+ * July 2010 ( http://www.linuxaudio.org/mailarchive/lad/2010/7/13/171540 )
+ * "L dB (L < 0) corresponds to 255 * (10 ^ L / 20)"
+ * Alternately: http://en.wikipedia.org/wiki/Decibel#Field_quantities
+ * 20 log10(V1/V0) where V1 is voltage measured and V0 is reference.
+ * ... of course, the value of the digital peak meters isn't the "voltage"
+ * for example an output of 1/255 --> −48.130803609dB
+ * whereas 255/255 --> 0dB
+ *         254/255 --> −0.034129276
+ *         250/255 --> −0.172003435
+ * http://alsa.cybermirror.org/manuals/icensemble/envy24.pdf states 
+ * "Peak data derived from the absolute value of 9 msb.
+ *  00h min - FFh max volume. Reading the register
+ *  resets the meter to 00h."
+ */
+char* peak_level_to_db(int ival) {
+  if (ival != 0) {
+    double value = 20.0 * log10((double)ival/(double)MAX_METERING_LEVEL);
+    //"(Off)"
+    //"0dBFS" <-- seems to cause a resize oscillation, use 0.0dB instead
+    //"0.0dB"
+    //"-0.10"      
+    //"-9.90"
+    //"-48.0"
+    if (value == 0.0)
+      sprintf(temp_label, "0.0dB");
+    else if (value > -10.0)
+      sprintf(temp_label, "%+1.2f", value);
+    else
+      sprintf(temp_label, "%+2.1f", value);
+    return (temp_label);
+  }
+  else
+    return ("(Off)");
+}
 
 /*
+ * NPM: "subroutine" used twice in create_mixer_frame() to draw markings
+ * for each digital mixer input attenuation slider.  Each slider is drawn
+ * optionally with or without a legend describing the dBs attenuation at
+ * the given level.  Each slider controls attentuation of its input from
+ * +0dB to -144.0dB (and "Off").
  */
+void draw_24bit_attenuator_scale_markings(GtkScale *scale, GtkPositionType position, int draw_legend_p) {
+  if (!no_scale_marks) {
+    gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE,
+		       position, draw_legend_p ? "<span color='green' size='x-small'>+0</span>": NULL);
+    gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE+1*MIXER_ATTENUATOR_STEP_SIZE,
+		       position, draw_legend_p ? "<span color='blue' size='x-small'>-12</span>" : NULL);
+    gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE+2*MIXER_ATTENUATOR_STEP_SIZE,
+		       position, draw_legend_p ? "<span color='blue' size='x-small'>-24</span>" : NULL);
+    gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE+3*MIXER_ATTENUATOR_STEP_SIZE,
+		       position, draw_legend_p ? "<span color='blue' size='x-small'>-36</span>" : NULL);
+    gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE+4*MIXER_ATTENUATOR_STEP_SIZE,
+		       position, draw_legend_p ? "<span color='blue' size='x-small'>-48</span>" : NULL);
+    gtk_scale_add_mark(scale, (float) LOW_MIXER_ATTENUATION_VALUE,
+		       position, NULL); /* NPM: last marker needs to not be a label, else the last level gets placed incorrectly (gtk2-2.18.9-3.fc12.x86_64 bug?) */
+
+//    gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE,
+//		       position, draw_legend_p ? "<span color='green' size='x-small'>+0</span>": NULL);
+//    gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE+1*MIXER_ATTENUATOR_STEP_SIZE,
+//		       position, draw_legend_p ? "<span color='blue' size='x-small'>-18</span>" : NULL);
+//    gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE+2*MIXER_ATTENUATOR_STEP_SIZE,
+//		       position, draw_legend_p ? "<span color='blue' size='x-small'>-36</span>" : NULL);
+//    gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE+3*MIXER_ATTENUATOR_STEP_SIZE,
+//		       position, draw_legend_p ? "<span color='blue' size='x-small'>-54</span>" : NULL);
+//    //  gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE+4*MIXER_ATTENUATOR_STEP_SIZE,
+//    //		     position, draw_legend_p ? "<span color='blue' size='x-small'>-72</span>" : NULL);
+//    gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE+5*MIXER_ATTENUATOR_STEP_SIZE,
+//		       position, draw_legend_p ? "<span color='blue' size='x-small'>-90</span>" : NULL);
+//    //  gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE+6*MIXER_ATTENUATOR_STEP_SIZE,
+//    //		     position, draw_legend_p ? "<span color='blue' size='x-small'>-108</span>" : NULL);
+//    gtk_scale_add_mark(scale, (float) MIN_MIXER_ATTENUATION_VALUE+7*MIXER_ATTENUATOR_STEP_SIZE,
+//		       position, draw_legend_p ? "<span color='blue' size='x-small'>-126</span>" : NULL);
+//    gtk_scale_add_mark(scale, (float) MAX_MIXER_ATTENUATION_VALUE,
+//		       position, NULL); /* NPM: last marker needs to not be a label, else the last level gets placed incorrectly (gtk2-2.18.9-3.fc12.x86_64 bug?) */
+  }
+}
+
+/* NPM: used in create_analog_volume() to draw dB markings on DAC attenuators */
+void draw_dac_scale_markings(GtkScale *scale, GtkPositionType position) {
+  if (!no_scale_marks) {
+  gtk_scale_add_mark(scale, (float) -envy_dac_max(),
+		     position, "<span color='green' size='x-small'>+0</span>");
+  gtk_scale_add_mark(scale, (float) -envy_dac_max()+1*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-6</span>");
+  gtk_scale_add_mark(scale, (float) -envy_dac_max()+2*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-12</span>");
+  gtk_scale_add_mark(scale, (float) -envy_dac_max()+3*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-18</span>");
+  gtk_scale_add_mark(scale, (float) -envy_dac_max()+4*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-24</span>");
+  gtk_scale_add_mark(scale, (float) -envy_dac_max()+5*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-30</span>");
+  gtk_scale_add_mark(scale, (float) -envy_dac_max()+6*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-36</span>");
+//  gtk_scale_add_mark(scale, (float) -envy_dac_max()+7*ANALOG_GAIN_STEP_SIZE,
+//		     position, "<span color='blue' size='x-small'>-42</span>");
+  gtk_scale_add_mark(scale, (float) -envy_dac_max()+8*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-48</span>");
+//  gtk_scale_add_mark(scale, (float) -envy_dac_max()+9*ANALOG_GAIN_STEP_SIZE,
+//		     position, "<span color='blue' size='x-small'>-54</span>");
+  gtk_scale_add_mark(scale, (float) -envy_dac_max()+10*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-60</span>");
+  gtk_scale_add_mark(scale, (float) 0,
+		     position, NULL); /* NPM: last marker needs to not be a label, else the last level gets placed incorrectly (gtk2-2.18.9-3.fc12.x86_64 bug?) */
+  }
+}
+
+/* NPM: used in create_analog_volume() to draw dB markings on ADC attenuators/amplifiers */
+void draw_adc_scale_markings(GtkScale *scale, GtkPositionType position) {
+  if (!no_scale_marks) {
+  gtk_scale_add_mark(scale, (float) -envy_adc_max(),
+		     position, "<span color='red' size='x-small'>+18</span>");
+  gtk_scale_add_mark(scale, (float) -envy_adc_max()+1*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='red' size='x-small'>+12</span>");
+  gtk_scale_add_mark(scale, (float) -envy_adc_max()+2*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='red' size='x-small'>+6</span>");
+  gtk_scale_add_mark(scale, (float) -envy_adc_max()+3*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='green' size='x-small'>+0</span>");
+  gtk_scale_add_mark(scale, (float) -envy_adc_max()+4*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-6</span>");
+  gtk_scale_add_mark(scale, (float) -envy_adc_max()+5*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-12</span>");
+//  gtk_scale_add_mark(scale, (float) -envy_adc_max()+6*ANALOG_GAIN_STEP_SIZE,
+//		     position, "<span color='blue' size='x-small'>-18</span>");
+  gtk_scale_add_mark(scale, (float) -envy_adc_max()+7*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-24</span>");
+//  gtk_scale_add_mark(scale, (float) -envy_adc_max()+8*ANALOG_GAIN_STEP_SIZE,
+//		     position, "<span color='blue' size='x-small'>-30</span>");
+  gtk_scale_add_mark(scale, (float) -envy_adc_max()+9*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-36</span>");
+//  gtk_scale_add_mark(scale, (float) -envy_adc_max()+10*ANALOG_GAIN_STEP_SIZE,
+//		     position, "<span color='blue' size='x-small'>-42</span>");
+  gtk_scale_add_mark(scale, (float) -envy_adc_max()+11*ANALOG_GAIN_STEP_SIZE,
+		     position, "<span color='blue' size='x-small'>-48</span>");
+//  gtk_scale_add_mark(scale, (float) -envy_adc_max()+12*ANALOG_GAIN_STEP_SIZE,
+//		     position, "<span color='blue' size='x-small'>-54</span>");
+//  gtk_scale_add_mark(scale, (float) -envy_adc_max()+13*ANALOG_GAIN_STEP_SIZE,
+//		     position, "<span color='blue' size='x-small'>-60</span>");
+  gtk_scale_add_mark(scale, (float) 0,
+		     position, NULL); /* NPM: last marker needs to not be a label, else the last level gets placed incorrectly (gtk2-2.18.9-3.fc12.x86_64 bug?) */
+  }
+}
 
 void dac_volume_adjust(GtkAdjustment *adj, gpointer data)
 {
 	int idx = (int)(long)data;
 	snd_ctl_elem_value_t *val;
 	int err, ival = -(int)adj->value;
-	char text[16];
 
 	snd_ctl_elem_value_alloca(&val);
 	snd_ctl_elem_value_set_interface(val, SND_CTL_ELEM_IFACE_MIXER);
 	snd_ctl_elem_value_set_name(val, DAC_VOLUME_NAME);
 	snd_ctl_elem_value_set_index(val, idx);
 	snd_ctl_elem_value_set_integer(val, 0, ival);
-	sprintf(text, "%03i", ival);
-	gtk_label_set_text(av_dac_volume_label[idx], text);
-	if ((err = snd_ctl_elem_write(ctl, val)) < 0)
-		g_print("Unable to write dac volume: %s\n", snd_strerror(err));
+
+	if ((err = snd_ctl_elem_write(ctl, val)) < 0) {
+	  g_print("Unable to write dac volume: %s\n", snd_strerror(err));
+	  sprintf(temp_label, "(Err)");
+	}
+	else if (ival == 0) {
+	  sprintf(temp_label, "(Off)");
+	}
+	else {
+	  /* NPM: changed to output dB values. Use of proper ALSA API
+	     snd_ctl_convert_to_dB() to return dB values suggested by
+	     Tim E. Real on linux-audio-devel list. */
+	  snd_ctl_elem_id_t *elem_id;
+	  snd_ctl_elem_id_alloca(&elem_id);
+	  snd_ctl_elem_id_set_interface(elem_id, SND_CTL_ELEM_IFACE_MIXER);
+	  snd_ctl_elem_id_set_name(elem_id, DAC_VOLUME_NAME);
+	  snd_ctl_elem_id_set_index(elem_id, idx); // TER: Added
+	  long db_gain = 0;
+	  snd_ctl_convert_to_dB(ctl, elem_id, ival, &db_gain); /* convert ival integer to dB */
+	  float fval = ((float)db_gain / 100.0);
+	  if (fval <= -10)
+	    sprintf(temp_label, "%+2.1f", fval);
+	  else
+	    sprintf(temp_label, "%+2.1f ", fval);
+	}
+
+	gtk_label_set_text(GTK_LABEL(av_dac_volume_label[idx]), temp_label);
 }
 
 void adc_volume_adjust(GtkAdjustment *adj, gpointer data)
@@ -236,17 +406,43 @@ void adc_volume_adjust(GtkAdjustment *adj, gpointer data)
 	int idx = (int)(long)data;
 	snd_ctl_elem_value_t *val;
 	int err, ival = -(int)adj->value;
-	char text[16];
 
 	snd_ctl_elem_value_alloca(&val);
 	snd_ctl_elem_value_set_interface(val, SND_CTL_ELEM_IFACE_MIXER);
 	snd_ctl_elem_value_set_name(val, ADC_VOLUME_NAME);
 	snd_ctl_elem_value_set_index(val, idx);
 	snd_ctl_elem_value_set_integer(val, 0, ival);
-	sprintf(text, "%03i", ival);
-	gtk_label_set_text(av_adc_volume_label[idx], text);
-	if ((err = snd_ctl_elem_write(ctl, val)) < 0)
-		g_print("Unable to write adc volume: %s\n", snd_strerror(err));
+
+	if ((err = snd_ctl_elem_write(ctl, val)) < 0) {
+	  g_print("Unable to write adc volume: %s\n", snd_strerror(err));
+	  sprintf(temp_label, "(Err)");
+	}
+	else if (ival == 0) {
+	  sprintf(temp_label, "(Off)");
+	}
+	else {
+	/* NPM: changed to output dB values. Use of proper ALSA API
+	   snd_ctl_convert_to_dB() to return dB values suggested by
+	   Tim E. Real on linux-audio-devel list. */
+	  snd_ctl_elem_id_t *elem_id;
+	  snd_ctl_elem_id_alloca(&elem_id);
+	  snd_ctl_elem_id_clear(elem_id);
+	  snd_ctl_elem_id_set_interface(elem_id, SND_CTL_ELEM_IFACE_MIXER);
+	  snd_ctl_elem_id_set_name(elem_id, ADC_VOLUME_NAME);
+	  long db_gain = 0;
+	  snd_ctl_convert_to_dB(ctl, elem_id, ival, &db_gain);
+	  float fval = ((float)db_gain / 100.0);
+	  if (fval >= 10)
+	    sprintf(temp_label, "%+2.1f", fval);
+	  else if (fval > 0)
+	    sprintf(temp_label, "%+2.1f ", fval);
+	  else if (fval <= -10)
+	    sprintf(temp_label, "%+2.1f", fval);
+	  else
+	    sprintf(temp_label, "%+2.1f ", fval);
+	}
+
+	gtk_label_set_text(GTK_LABEL(av_adc_volume_label[idx]), temp_label);
 }
 
 void ipga_volume_adjust(GtkAdjustment *adj, gpointer data)
@@ -262,7 +458,7 @@ void ipga_volume_adjust(GtkAdjustment *adj, gpointer data)
 	snd_ctl_elem_value_set_index(val, idx);
 	snd_ctl_elem_value_set_integer(val, 0, ival);
 	sprintf(text, "%03i", ival);
-	gtk_label_set_text(av_ipga_volume_label[idx], text);
+	gtk_label_set_text(GTK_LABEL(av_ipga_volume_label[idx]), text);
 	if ((err = snd_ctl_elem_write(ctl, val)) < 0)
 		g_print("Unable to write ipga volume: %s\n", snd_strerror(err));
 }
