changeset 12815:a8bffa7fb6ac

[gaim-migrate @ 15163] SF Patch #1400794 from charkins "This patch adds a software volume control in gaim when libao is used. This patch could use some testing on platforms other than linux/x86." "this patch also removes a small duplicated code block from the sound prefs code." "Updating the patch again to fix . . . two other lines in [sound_page()] that should be using GAIM_HIG_BOX_SPACE." I modified this to make the volume control insensitive when sounds are not going through libao (i.e. the method is "Console beep", "Command" or "No sounds"). committer: Tailor Script <tailor@pidgin.im>
author Richard Laager <rlaager@wiktel.com>
date Wed, 11 Jan 2006 03:42:22 +0000
parents f88f145884c0
children ff267281e882
files ChangeLog src/gtkprefs.c src/gtksound.c
diffstat 3 files changed, 122 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Jan 11 03:37:59 2006 +0000
+++ b/ChangeLog	Wed Jan 11 03:42:22 2006 +0000
@@ -49,6 +49,7 @@
 	Sounds:
 	* Beautiful new default sounds (Brad Turcotte)
 	* Use libao for playing sounds via NAS instead of accessing NAS directly
+	* A volume control in the preferences
 
 	Log Viewer:
 	* Log viewer aggregates logs from the same "Person" (Richard Laager)
--- a/src/gtkprefs.c	Wed Jan 11 03:37:59 2006 +0000
+++ b/src/gtkprefs.c	Wed Jan 11 03:42:22 2006 +0000
@@ -1328,6 +1328,20 @@
 
 	gtk_widget_set_sensitive(vbox, strcmp(method, "none"));
 }
+
+static void
+sound_changed3_cb(const char *name, GaimPrefType type, gpointer value,
+				   gpointer data)
+{
+	GtkWidget *hbox = data;
+	const char *method = value;
+
+	gtk_widget_set_sensitive(hbox,
+				 !strcmp(method, "automatic") ||
+				 !strcmp(method, "arts") ||
+				 !strcmp(method, "esd") ||
+				 !strcmp(method, "nas"));
+}
 #endif
 
 
@@ -1429,6 +1443,27 @@
 					  G_CALLBACK(sound_chosen_cb), NULL, GINT_TO_POINTER(sound_row_sel));
 }
 
+#ifdef USE_AO
+static gchar* prefs_sound_volume_format(GtkScale *scale, gdouble val)
+{
+	if(val == 0) {
+ 		return g_strdup_printf("Silent");
+	} else if(val < 35) {
+		return g_strdup_printf("Quiet");
+	} else if(val > 65) {
+		return g_strdup_printf("Loud");
+	} else {
+		return g_strdup_printf("Normal");
+	}
+}
+
+static void prefs_sound_volume_changed(GtkRange *range)
+{
+	int val = (int)gtk_range_get_value(GTK_RANGE(range));
+	gaim_prefs_set_int("/gaim/gtk/sound/volume", val);
+}
+#endif
+
 static void prefs_sound_sel(GtkTreeSelection *sel, GtkTreeModel *model) {
 	GtkTreeIter  iter;
 	GValue val;
@@ -1497,7 +1532,7 @@
 	gtk_size_group_add_widget(sg, dd);
 	gtk_misc_set_alignment(GTK_MISC(dd), 0, 0.5);
 
-	hbox = gtk_hbox_new(FALSE, 5);
+	hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
 
 	label = gtk_label_new_with_mnemonic(_("Sound c_ommand:\n(%s for filename)"));
@@ -1517,11 +1552,11 @@
 	g_signal_connect(G_OBJECT(entry), "changed",
 					 G_CALLBACK(sound_cmd_yeah), NULL);
 
+	gaim_prefs_connect_callback(prefs, "/gaim/gtk/sound/method",
+								sound_changed1_cb, hbox);
 	gtk_widget_set_sensitive(hbox,
 			!strcmp(gaim_prefs_get_string("/gaim/gtk/sound/method"),
 					"custom"));
-	gaim_prefs_connect_callback(prefs, "/gaim/gtk/sound/method",
-								sound_changed1_cb, hbox);
 
 	gaim_set_accessible_label (entry, label);
 #endif /* _WIN32 */
@@ -1532,6 +1567,31 @@
 	gaim_gtk_prefs_checkbox(_("_Sounds while away"),
 				   "/core/sound/while_away", vbox);
 
+#ifdef USE_AO
+	hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+	label = gtk_label_new_with_mnemonic(_("Volume:"));
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+	sw = gtk_hscale_new_with_range(0.0, 100.0, 5.0);
+	gtk_range_set_increments(GTK_RANGE(sw), 5.0, 25.0);
+	gtk_range_set_value(GTK_RANGE(sw), gaim_prefs_get_int("/gaim/gtk/sound/volume"));
+	g_signal_connect (G_OBJECT (sw), "format-value",
+			  G_CALLBACK (prefs_sound_volume_format),
+			  NULL);
+	g_signal_connect (G_OBJECT (sw), "value-changed",
+			  G_CALLBACK (prefs_sound_volume_changed),
+			  NULL);
+	gtk_box_pack_start(GTK_BOX(hbox), sw, TRUE, TRUE, 0);
+
+	gaim_prefs_connect_callback(prefs, "/gaim/gtk/sound/method",
+								sound_changed3_cb, hbox);
+	sound_changed3_cb("/gaim/gtk/sound/method", GAIM_PREF_STRING,
+			  gaim_prefs_get_string("/gaim/gtk/sound/method"), hbox);
+#endif
+
 #ifndef _WIN32
 	gtk_widget_set_sensitive(vbox,
 			strcmp(gaim_prefs_get_string("/gaim/gtk/sound/method"), "none"));
@@ -1614,7 +1674,7 @@
 	g_free(pref);
 	gtk_entry_set_text(GTK_ENTRY(sound_entry), (file && *file != '\0') ? file : "(default)");
 	gtk_editable_set_editable(GTK_EDITABLE(sound_entry), FALSE);
-	gtk_box_pack_start(GTK_BOX(hbox), sound_entry, FALSE, FALSE, 5);
+	gtk_box_pack_start(GTK_BOX(hbox), sound_entry, FALSE, FALSE, GAIM_HIG_BOX_SPACE);
 
 	button = gtk_button_new_with_label(_("Test"));
 	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(test_sound), NULL);
@@ -1629,13 +1689,6 @@
 	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 1);
 	gtk_widget_show_all(ret);
 
-#ifndef _WIN32
-	gtk_widget_set_sensitive(vbox,
-			strcmp(gaim_prefs_get_string("/gaim/gtk/sound/method"), "none"));
-	gaim_prefs_connect_callback(prefs, "/gaim/gtk/sound/method",
-								sound_changed2_cb, vbox);
-#endif
-
 	return ret;
 }
 
--- a/src/gtksound.c	Wed Jan 11 03:37:59 2006 +0000
+++ b/src/gtksound.c	Wed Jan 11 03:42:22 2006 +0000
@@ -52,6 +52,7 @@
 };
 
 #define PLAY_SOUND_TIMEOUT 15000
+#define SQRT2_2 0.70710678118654752440
 
 static guint mute_login_sounds_timeout = 0;
 static gboolean mute_login_sounds = FALSE;
@@ -321,6 +322,7 @@
 	gaim_prefs_add_bool("/gaim/gtk/sound/mute", FALSE);
 	gaim_prefs_add_string("/gaim/gtk/sound/command", "");
 	gaim_prefs_add_string("/gaim/gtk/sound/method", "automatic");
+	gaim_prefs_add_int("/gaim/gtk/sound/volume", 50);
 
 #ifdef USE_AO
 	gaim_debug_info("sound", "Initializing sound output drivers.\n");
@@ -384,8 +386,51 @@
 
     return FALSE; /* do not run again */
 }
+
+static void
+scale_pcm_data(char *data, int nframes, ao_sample_format *format,
+			   double intercept, double minclip, double maxclip,
+			   float scale)
+{
+	int i;
+	float v;
+	gint16 *data16 = (gint16*)data;
+	gint32 *data32 = (gint32*)data;
+#ifdef G_HAVE_GINT64
+	gint64 *data64 = (gint64*)data;
 #endif
 
+	switch(format->bits) {
+		case 16:
+			for(i = 0; i < nframes * format->channels; i++) {
+				v = ((data16[i] - intercept) * scale) + intercept;
+				v = CLAMP(v, minclip, maxclip);
+				data16[i]=(gint16)v;
+			}
+			break;
+		case 32:
+			for(i = 0; i < nframes * format->channels; i++) {
+				v = ((data32[i] - intercept) * scale) + intercept;
+				v = CLAMP(v, minclip, maxclip);
+				data32[i]=(gint32)v;
+			}
+			break;
+#ifdef G_HAVE_GINT64
+		case 64:
+			for(i = 0; i < nframes * format->channels; i++) {
+				v = ((data64[i] - intercept) * scale) + intercept;
+				v = CLAMP(v, minclip, maxclip);
+				data64[i]=(gint64)v;
+			}
+			break;
+#endif
+		default:
+			gaim_debug_warning("gtksound", "Cannot scale %d bit pcm data.\n", format->bits);
+			break;
+	}
+}
+#endif /* USE_AO */
+
 static void
 gaim_gtk_sound_play_file(const char *filename)
 {
@@ -393,6 +438,7 @@
 #ifdef USE_AO
 	pid_t pid;
 	AFfilehandle file;
+	int volume = 50;
 #endif
 
 	if (!sound_initialized)
@@ -449,23 +495,31 @@
 		return;
 	}
 #ifdef USE_AO
+	volume = gaim_prefs_get_int("/gaim/gtk/sound/volume");
+	volume = CLAMP(volume, 0, 100);
+
 	pid = fork();
 	if (pid < 0)
 		return;
 	else if (pid == 0) {
 		/* Child process */
+		float scale = ((float) volume * volume) / 2500;
 		file = afOpenFile(filename, "rb", NULL);
 		if(file) {
 			ao_device *device;
 			ao_sample_format format;
 			int in_fmt;
 			int bytes_per_frame;
+			double slope, intercept, minclip, maxclip;
 
 			format.rate = afGetRate(file, AF_DEFAULT_TRACK);
 			format.channels = afGetChannels(file, AF_DEFAULT_TRACK);
 			afGetSampleFormat(file, AF_DEFAULT_TRACK, &in_fmt,
 					&format.bits);
 
+			afGetPCMMapping(file, AF_DEFAULT_TRACK, &slope,
+					&intercept, &minclip, &maxclip);
+
 			/* XXX: libao doesn't seem to like 8-bit sounds, so we'll
 			 * let libaudiofile make them a bit better for us */
 			if(format.bits == 8)
@@ -497,6 +551,9 @@
 
 				while((frames_read = afReadFrames(file, AF_DEFAULT_TRACK,
 								buf, buf_frames))) {
+					if(volume != 50)
+						scale_pcm_data(buf, frames_read, &format, intercept,
+									   minclip, maxclip, scale);
 					if(!ao_play(device, buf, frames_read * bytes_per_frame))
 						break;
 				}