# HG changeset patch # User Richard Laager # Date 1136950942 0 # Node ID a8bffa7fb6ac89ec4ee71c90fec94bbd258efe6c # Parent f88f145884c0cbd3532bec5221173397d6a37e27 [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 diff -r f88f145884c0 -r a8bffa7fb6ac ChangeLog --- 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) diff -r f88f145884c0 -r a8bffa7fb6ac src/gtkprefs.c --- 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; } diff -r f88f145884c0 -r a8bffa7fb6ac src/gtksound.c --- 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; }