Re: FIxed alsa-tools' envy24control missing peak level meters and "Reset Peaks"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Neils,

On Monday 12 July 2010 23:41, Niels Mayer wrote:
> I've been long annoyed by alsa-tools' envy24control (*) lack of
> peak-level indication in it's metering, and the non-implementation of
> its "Reset Peaks" button:
> https://bugzilla.redhat.com/show_bug.cgi?id=602903
>
> I've fixed that annoyance. Now, a small white line appears above the
> highest level on each meter, and can be reset via "Reset Peaks"
> button.
>
> Original source:
> http://git.alsa-project.org/?p=alsa-tools.git;a=blob_plain;f=envy24control/
>levelmeters.c;hb=HEAD Patch:
> http://nielsmayer.com/npm/602903.patch

I wish I had been aware of your interest in this - in 2006-08 I coded rising 
peak and clip indicators for envy24 control, and have my versions patched.  
Unfortunately, I never got to a final re-work to submit; it has been on that 
'todo' list.  I was responsible for patches that introduced the present 
layout of envy24control, incl 'tall_eq_mixer_heights' etc.

Right now I am in the middle of other things, but I have quickly attached my 
existing patch, as you might like to try it.  I suspect many of the cc's on 
this mail will bounce (not-subscribed) so perhaps you could re-post it there.  
No guarantees though with current ALSA - I haven't updated since 1.0.18, and 
most boxes here use 1.0.12.  But I feel sure you will be able to get the 
patch to apply.  Come back with any issues.

<snip>

> Next steps:
>
> (1) Think about building-in meter ballistics from Fons Adriaensen's
> jkmeter (
> http://www.kokkinizita.net/linuxaudio/downloads/jkmeter-0.4.0.tar.bz2 ).
> Which helps implent Bob Katz' "K System" (
> http://www.digido.com/level-practices-part-2-includes-the-k-system.html
> ). Although it probably most makes sense to implement such metering on
> the main "digital mixer" meter of envy24control, if it's not too
> inefficient, I'd want it available on all meters, despite the warning
> from Fons ( http://old.nabble.com/First-release-of-jkmeter-td18798950.html
> ).
>
> > This is the type of meter you want for live recording,
> > mixing and mastering. It probably makes no sense to
> > use it on all tracks of a DAW, where keeping digital
> > level within limits is the main purpose of metering.

With the attached patch, all channels have rising peaks that reset at regular 
intervals, or hold (have a play with values in 'Extras').  The marker is 
half-width only.  No meter ballistics, though!

> (2) Fix https://bugzilla.redhat.com/show_bug.cgi?id=602900 which
> causes 'envy24control' to crash when given "-D" argument.
> and behave incorrectly when given a correct non-numeric name for an
> audio device: e.g.
>
> >> envy24control  --card M66
> >> invalid card type (driver is USB-Audio)
> >> envy24control --card M66 --device M66
> >> Segmentation fault (core dumped)
>
> (3) Apply more reasonable defaults and automatically size to correct
>
> dimensions. I use, for example:
> >> envy24control --card 2 --outputs 4 --input 4 --pcm_output 8
> >> --view_spdif_playback --midichannel 1 --midienhanced --window_width 1275
> >> --tall_eq_mixer_heights 1 &

Bear in mind that different hardware uses this, with different graphic 
environments; what seems the obvious ideal to you may not be so for others.  
Ultimately that is the job of command line arguments, as you do now.

I use this with DMX6fire and Hoontech DSP2000.

> (4) Add midi output, in addition to midi input, which would monitor
> the hardware peak metering from the ice1712
> ("amixer -c M66 cget iface=PCM,name='Multi Track Peak',numid=45")
> and output a MIDI note-on on the corresponding MIDI channel whenever a
> specified threshold value was exceeded. This could be used to
> implement "automatic gain control" in association with the
> midi-controllable ADC gain provided by envy24control.

Regards

Alan
diff -ru envy24control/envy24control.c Aenvy24control/envy24control.c
--- envy24control/envy24control.c	2006-08-22 19:25:52.000000000 +0100
+++ Aenvy24control/envy24control.c	2008-07-28 23:07:28.000000000 +0100
@@ -1,5 +1,5 @@
 /*****************************************************************************
-   envy24control.c - Env24 chipset (ICE1712) control utility
+   envy24control.c - Env24 chipset (ICE1712) control utility **AH Peaks/clips mod v1 3.1.06
    Copyright (C) 2000 by Jaroslav Kysela <perex@xxxxxxx>
 
    (2003/03/22) Changed to hbox/vbox layout.
@@ -74,6 +74,12 @@
 GtkObject *hw_volume_change_adj;
 GtkWidget *hw_volume_change_spin;
 
+GtkWidget *clip_peaks_check;
+GtkWidget *auto_reset_clips_check;
+GtkWidget *riding_peaks_check;
+GtkWidget *auto_reset_riders_check;
+GtkObject *sw_peaks_reset_time_adj;
+
 GtkWidget *hw_spdif_profi_nonaudio_radio;
 GtkWidget *hw_spdif_profi_audio_radio;
 
@@ -210,7 +216,7 @@
 	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_widget_set_usize(drawing, 36, (60 * tall_equal_mixer_ht + 202));
 	gtk_box_pack_start(GTK_BOX(vbox1), drawing, FALSE, FALSE, 1);
 
 	label = gtk_label_new("");
@@ -733,9 +739,106 @@
 	gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinbutton), TRUE);
 	gtk_signal_connect(GTK_OBJECT(spinbutton_adj), "value_changed",
 			   GTK_SIGNAL_FUNC(volume_change_rate_adj), NULL);
-	
+
+}
+static void create_peak_bars(GtkWidget *box)
+{
+	GtkWidget *frame;
+	GtkWidget *vbox;
+	GtkWidget *vbox1;
+	GtkWidget *hbox;
+	GtkWidget *check;
+	GtkWidget *label;
+	GtkObject *spinbutton_adj;
+	GtkWidget *spinbutton;
+
+
+	frame = gtk_frame_new("Peak Bars");
+	gtk_widget_show(frame);
+	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0);
+
+	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);
+
+	frame = gtk_frame_new("Clip Bar 98%");
+        gtk_widget_show(frame);
+	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
+
+	vbox1 = gtk_vbox_new(FALSE, 0);
+	gtk_widget_show(vbox1);
+	gtk_container_add(GTK_CONTAINER(frame), vbox1);
+//	gtk_container_set_border_width(GTK_CONTAINER(vbox1), 0);
+
+	check = gtk_check_button_new_with_label("Active");
+	clip_peaks_check = check;
+	gtk_widget_show(check);
+	gtk_box_pack_start(GTK_BOX(vbox1), check, FALSE, FALSE, 0);
+	gtk_signal_connect(GTK_OBJECT(check), "toggled",
+			  (GtkSignalFunc)peak_bars_toggled,
+			  (gpointer)"clip_peaks");
+
+	check = gtk_check_button_new_with_label("Auto Reset");
+	auto_reset_clips_check = check;
+	gtk_widget_show(check);
+	gtk_box_pack_start(GTK_BOX(vbox1), check, FALSE, FALSE, 0);
+	gtk_signal_connect(GTK_OBJECT(check), "toggled",
+			  (GtkSignalFunc)peak_bars_toggled,
+			  (gpointer)"auto_reset_clip");
+
+	frame = gtk_frame_new("Riding Peaks");
+        gtk_widget_show(frame);
+	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 6);
+
+	vbox1 = gtk_vbox_new(FALSE, 0);
+	gtk_widget_show(vbox1);
+	gtk_container_add(GTK_CONTAINER(frame), vbox1);
+
+	check = gtk_check_button_new_with_label("Active");
+	riding_peaks_check = check;
+	gtk_widget_show(check);
+	gtk_box_pack_start(GTK_BOX(vbox1), check, FALSE, FALSE, 0);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check),TRUE);
+	gtk_signal_connect(GTK_OBJECT(check), "toggled",
+			  (GtkSignalFunc)peak_bars_toggled,
+			  (gpointer)"riding_peaks");
+
+	check = gtk_check_button_new_with_label("Auto Reset");
+	auto_reset_riders_check = check;
+	gtk_widget_show(check);
+	gtk_box_pack_start(GTK_BOX(vbox1), check, FALSE, FALSE, 0);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check),TRUE);
+	gtk_signal_connect(GTK_OBJECT(check), "toggled",
+			  (GtkSignalFunc)peak_bars_toggled,
+			  (gpointer)"auto_reset_riders");
+
+	frame = gtk_frame_new("Reset Time");
+        gtk_widget_show(frame);
+	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
+
+	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);
+
+	label = gtk_label_new("Setting");
+	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(5, 0, 9, 1, 1, 1);
+	sw_peaks_reset_time_adj = spinbutton_adj;
+	spinbutton = gtk_spin_button_new(GTK_ADJUSTMENT(spinbutton_adj), 1, 0);
+	gtk_widget_show(spinbutton);
+	gtk_box_pack_start(GTK_BOX(hbox), spinbutton, TRUE, FALSE, 0);
+	gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinbutton), TRUE);
+	gtk_signal_connect(GTK_OBJECT(spinbutton_adj), "value_changed",
+			   GTK_SIGNAL_FUNC(peaks_reset_time_adj), NULL);
+
 }
 
+
 static void create_spdif_output_settings_profi_data(GtkWidget *box)
 {
 	GtkWidget *frame;
@@ -1379,6 +1482,45 @@
 	create_spdif_output_settings(hbox);
 }
 
+static void create_extras(GtkWidget *main, GtkWidget *notebook, int page)
+{
+	GtkWidget *label;
+	GtkWidget *vbox;
+	GtkWidget *hbox;
+	GtkWidget *scrolledwindow;
+	GtkWidget *viewport;
+
+	hbox = gtk_hbox_new(FALSE, 0);
+	gtk_widget_show(hbox);
+	gtk_container_add(GTK_CONTAINER(notebook), hbox);
+
+        label = gtk_label_new("Extras");
+        gtk_widget_show(label);
+	gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook),
+				   gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page),
+				   label);
+
+//	/* build scrolling area */                         /* Leave in for later */
+//	scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
+//	gtk_widget_show(scrolledwindow);
+//	gtk_box_pack_start(GTK_BOX(hbox), scrolledwindow, TRUE, TRUE, 0);
+//	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow),
+//					GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
+
+//	viewport = gtk_viewport_new(NULL, NULL);
+//	gtk_widget_show(viewport);
+//	gtk_container_add(GTK_CONTAINER(scrolledwindow), viewport);
+
+
+	vbox = gtk_vbox_new(FALSE, 0);
+	gtk_widget_show(vbox);
+	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 6);
+//	gtk_container_add(GTK_CONTAINER(hbox), vbox);
+//	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
+
+	create_peak_bars(vbox);
+}
+
 static void create_about(GtkWidget *main, GtkWidget *notebook, int page)
 {
 	GtkWidget *label;
@@ -1421,7 +1563,7 @@
 	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 6);
 
 	/* create first line */
-	label = gtk_label_new("Envy24 Control Utility " VERSION);
+	label = gtk_label_new("Envy24 Control Utility v" VERSION "  **AH Peaks/clips mod v1-3.1.06");
         gtk_widget_show(label);
 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 6);
 
@@ -1960,9 +2102,9 @@
 	gtk_widget_set_name(drawing, "DigitalMixer");
 	gtk_box_pack_start(GTK_BOX(hbox1), drawing, TRUE, FALSE, 6);
 	if (tall_equal_mixer_ht > 1 ) {
-		gtk_widget_set_usize(drawing, 60, 264 + 60 * (tall_equal_mixer_ht - 1));
+		gtk_widget_set_usize(drawing, 60, 262 + 60 * (tall_equal_mixer_ht - 1));
 	} else {
-		gtk_widget_set_usize(drawing, 60, 264);
+		gtk_widget_set_usize(drawing, 60, 262);
 	}
 	gtk_signal_connect(GTK_OBJECT(drawing), "expose_event",
 			   (GtkSignalFunc)level_meters_expose_event, NULL);
@@ -2285,6 +2427,7 @@
 	create_hardware(outerbox, notebook, page++);
 	if (envy_analog_volume_available())
 		create_analog_volume(outerbox, notebook, page++);
+	create_extras(outerbox, notebook, page++);
 	create_profiles(outerbox, notebook, page++);
 	create_about(outerbox, notebook, page++);
 	create_blank(outerbox, notebook, page++);
Only in Aenvy24control: envy24control.c.orig
diff -ru envy24control/envy24control.h Aenvy24control/envy24control.h
--- envy24control/envy24control.h	2006-08-22 19:25:52.000000000 +0100
+++ Aenvy24control/envy24control.h	2008-07-28 22:52:14.000000000 +0100
@@ -1,4 +1,4 @@
-#include <stdio.h>
+#include <stdio.h>       /*  AH Peaks/clips mod v1 3.1.06   */
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
@@ -166,6 +166,8 @@
 gint level_meters_configure_event(GtkWidget *widget, GdkEventConfigure *event);
 gint level_meters_expose_event(GtkWidget *widget, GdkEventExpose *event);
 gint level_meters_timeout_callback(gpointer data);
+void peak_bars_toggled(GtkWidget *togglebutton, gpointer data);
+void peaks_reset_time_adj(GtkAdjustment *adj, gpointer data);
 void level_meters_reset_peaks(GtkButton *button, gpointer data);
 void level_meters_init(void);
 void level_meters_postinit(void);
Only in Aenvy24control: envy24control.h.orig
Only in Aenvy24control: envy24control.o
Only in Aenvy24control: envy24control-orig.c
Only in Aenvy24control: envy24control-orig.h
Only in Aenvy24control: hardware.o
diff -ru envy24control/levelmeters.c Aenvy24control/levelmeters.c
--- envy24control/levelmeters.c	2006-08-22 19:25:52.000000000 +0100
+++ Aenvy24control/levelmeters.c	2008-07-28 23:32:34.000000000 +0100
@@ -1,5 +1,5 @@
 /*****************************************************************************
-   levelmeters.c - Stereo level meters
+   levelmeters.c - Stereo level meters     **AH Peaks/clips mod v1 3.1.06
    Copyright (C) 2000 by Jaroslav Kysela <perex@xxxxxxx>
    
    This program is free software; you can redistribute it and/or
@@ -30,6 +30,11 @@
 
 extern int input_channels, output_channels, pcm_output_channels, spdif_channels, view_spdif_playback;
 
+	int peaks_store[2][22] = {0};  /* Holds info for clip & riding peaks indicators */
+	int count_time[2][22] = {0};   /* Holds reset time counts for peaks indicators  */
+	int peaks_setup[4] = {0,0,1,1}; /* Correspond to the 4 peak bar check buttons */
+	int time_count_val = 49;  /* Approx 2 secs reset -varied by spinbutton  */
+
 static void update_peak_switch(void)
 {
 	int err;
@@ -38,6 +43,11 @@
 		g_print("Unable to read peaks: %s\n", snd_strerror(err));
 }
 
+static int is_active(GtkWidget *widget)
+{
+	return GTK_TOGGLE_BUTTON(widget)->active ? 1 : 0;
+}
+
 static void get_levels(int idx, int *l1, int *l2)
 {
 	*l1 = *l2 = 0;
@@ -87,9 +97,10 @@
 	int green_segments = (segments / 4) * 3;
 	int red_segments = 2;
 	int orange_segments = segments - green_segments - red_segments;
-	int seg;
+	int seg, peak;
 	int segs_on1 = ((segments * level1) + 128) / 255;
 	int segs_on2 = ((segments * level2) + 128) / 255;
+	const short int clip_level = 250;
 
 	// g_print("segs_on1 = %i (%i), segs_on2 = %i (%i)\n", segs_on1, level1, segs_on2, level2);
 	for (seg = 0; seg < green_segments; seg++) {
@@ -146,6 +157,73 @@
 		segs_on1--;
 		segs_on2--;
 	}
+
+	if (peaks_setup[2]) { /* Draw rising peak segments */
+		peak = peaks_store[1][idx];
+		seg = ((segments * peak) + 128) / 255;
+		if (peak > level1) {
+			if (seg >= 1) {
+				gdk_draw_rectangle(pixmap[idx],
+						   penOrangeLight[idx],
+						   TRUE,
+						   6 , 3 + ((segments - seg ) * 4),
+						   (segment_width / 2),
+						   3);
+			}
+		} else {
+			peaks_store[1][idx] = level1;
+			count_time[1][idx] = 0;
+		}
+		if (stereo) { /* Draw right channel of Dig mixer, use [21] */
+			peak = peaks_store[1][21];
+			seg = ((segments * peak) + 128) / 255;
+			if (peak > level2) {
+				if (seg >= 1) {
+					gdk_draw_rectangle(pixmap[idx],
+							   penOrangeLight[idx],
+							   TRUE,
+							   2 + (width / 2),
+							   3 + ((segments - seg ) * 4),
+							   (segment_width / 2),
+							   3);
+				}
+			} else {
+				peaks_store[1][21] = level2;
+				count_time[1][21] = 0;
+			}
+		}
+	}
+
+	if (peaks_setup[0]) { /* Draw clip peak segments */
+		if (level1 >= clip_level) {
+			peaks_store[0][idx] = 1;
+			count_time[0][idx] = 0;
+		} else {
+			if (peaks_store[0][idx] > 0)  /* Previous peak */
+				gdk_draw_rectangle(pixmap[idx],
+						   penRedLight[idx],
+						   TRUE,
+						   6 + (segment_width / 2), 3,
+						   (segment_width / 2),
+						   3);
+		}
+
+		if (stereo) { /* Draw right channel of Dig mixer, use [21] */
+			if (level2 >= clip_level) {
+				peaks_store[0][21] = 1;
+				count_time[0][21] = 0;
+			} else {
+				if (peaks_store[0][21] > 0)  /* Previous peak */
+					gdk_draw_rectangle(pixmap[idx],
+							   penRedLight[idx],
+							   TRUE,
+							   2 + (width / 2) + (segment_width / 2), 3,
+							   (segment_width / 2),
+							   3);
+			}
+		}
+	}
+
 }
 
 gint level_meters_configure_event(GtkWidget *widget, GdkEventConfigure *event)
@@ -163,7 +241,7 @@
 	penOrangeShadow[idx] = get_pen(idx, 0xddff, 0x55ff, 0);
 	penOrangeLight[idx] = get_pen(idx, 0xffff, 0x99ff, 0);
 	penRedShadow[idx] = get_pen(idx, 0xaaff, 0, 0);
-	penRedLight[idx] = get_pen(idx, 0xffff, 0, 0);
+	penRedLight[idx] = get_pen(idx, 0xffff, 0x2fff, 0x2fff);
 	gdk_draw_rectangle(pixmap[idx],
 			   widget->style->black_gc,
 			   TRUE,
@@ -252,11 +330,83 @@
 					widget->allocation.width, widget->allocation.height);
 		}
 	}
+
+	for (idx = 0; idx<= 21; idx++) { /* Auto-reset the peak bars */
+		if (peaks_setup[1]) { /* Clip bars */
+			count_time[0][idx]++;
+//			g_print("A/R clips");
+			if (count_time[0][idx] > time_count_val*2) {
+				peaks_store[0][idx] = 0;
+				count_time[0][idx] = 0;
+			}
+		}
+		if (peaks_setup[3]) { /* Riding peaks */
+			count_time[1][idx]++;
+//			g_print("ST %i",slow_time);
+			if (count_time[1][idx] > time_count_val) {
+				peaks_store[1][idx] = 0;
+				count_time[1][idx] = 0;
+			}
+		}
+	}
 	return TRUE;
 }
 
+void peak_bars_toggled(GtkWidget *togglebutton, gpointer data)
+{
+	char *what = (char *) data;
+
+	if (!strcmp(what, "clip_peaks")) {
+		if (is_active(togglebutton))
+			peaks_setup[0] = 1;
+		else
+			peaks_setup[0] = 0;
+	} else if (!strcmp(what, "auto_reset_clip")) {
+		if (is_active(togglebutton))
+			peaks_setup[1] = 1;
+		else
+			peaks_setup[1] = 0;
+	} else if (!strcmp(what, "riding_peaks")) {
+		if (is_active(togglebutton))
+			peaks_setup[2] = 1;
+		else
+			peaks_setup[2] = 0;
+	} else if (!strcmp(what, "auto_reset_riders")) {
+		if (is_active(togglebutton))
+			peaks_setup[3] = 1;
+		else
+			peaks_setup[3] = 0;
+	} else {
+		g_print("peak_bars_toggled: %s ???\n", what);
+	}
+
+}
+
+void peaks_reset_time_adj(GtkAdjustment *adj, gpointer data)
+{
+	int val, idx;
+
+	val = adj->value;
+	time_count_val = 9;
+	for (idx = 0; idx < val; idx++)
+		time_count_val = time_count_val * 1.442; /* Create a time count in a non-linear series, approx 2^n */
+//	g_print(" Val %i", val);
+//	g_print(" Time count val %i.", time_count_val);
+}
+
+
+
 void level_meters_reset_peaks(GtkButton *button, gpointer data)
 {
+	int idx;
+
+	for (idx = 0; idx <= 21; idx++) {
+		peaks_store[0][idx] = 0;
+		peaks_store[1][idx] = 0;
+		count_time[0][idx] = 0;
+		count_time[1][idx] = 0;
+	}
+//	g_print("Reset");
 }
 
 void level_meters_init(void)
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux