2
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
4
* mixer.c: sample mixer application
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Library General Public
8
* License as published by the Free Software Foundation; either
9
* version 2 of the License, or (at your option) any later version.
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Library General Public License for more details.
16
* You should have received a copy of the GNU Library General Public
17
* License along with this library; if not, write to the
18
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19
* Boston, MA 02111-1307, USA.
30
#include <gst/mixer/mixer.h>
32
typedef struct _MyMixerControls {
36
GtkWidget *lock, *mute, *record;
40
/* private stock icons */
41
#define GST_MIXER_STOCK_PHONE "gst-mixer-phone"
42
#define GST_MIXER_STOCK_VIDEO "gst-mixer-video"
43
#define GST_MIXER_STOCK_TONE "gst-mixer-tone"
44
#define GST_MIXER_STOCK_MIXER "gst-mixer-mixer"
50
{ "cd", GTK_STOCK_CDROM },
51
{ "line", GNOME_STOCK_LINE_IN },
52
{ "microphone", GNOME_STOCK_MIC },
53
{ "mixer", GST_MIXER_STOCK_MIXER },
54
{ "pcm", GST_MIXER_STOCK_TONE },
55
{ "phone", GST_MIXER_STOCK_PHONE },
56
{ "speaker", GNOME_STOCK_VOLUME },
57
{ "video", GST_MIXER_STOCK_VIDEO },
58
{ "volume", GST_MIXER_STOCK_TONE },
63
cb_volume_changed (GtkAdjustment *adj,
66
MyMixerControls *ctrl = (MyMixerControls *) data;
68
GList *adjustments = ctrl->adjustments;
73
volumes = g_malloc (sizeof (gint) * g_list_length (adjustments));
75
for ( ; adjustments != NULL; adjustments = adjustments->next) {
76
GtkAdjustment *adj2 = (GtkAdjustment *) adjustments->data;
78
if (ctrl->lock != NULL &&
79
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ctrl->lock))) {
80
gtk_adjustment_set_value (adj2, gtk_adjustment_get_value (adj));
81
volumes[i++] = gtk_adjustment_get_value (adj);
83
volumes[i++] = gtk_adjustment_get_value (adj2);
87
gst_mixer_set_volume (ctrl->mixer, ctrl->track, volumes);
94
cb_lock_toggled (GtkWidget *button,
97
MyMixerControls *ctrl = (MyMixerControls *) data;
99
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
100
/* get the mean value, and set it on the first adjustment.
101
* the cb_olume_changed () callback will take care of the
103
gint volume = 0, num = 0;
104
GList *adjustments = ctrl->adjustments;
106
for ( ; adjustments != NULL; adjustments = adjustments->next) {
107
GtkAdjustment *adj = (GtkAdjustment *) adjustments->data;
110
volume += gtk_adjustment_get_value (adj);
114
if (ctrl->adjustments != NULL) {
115
gtk_adjustment_set_value ((GtkAdjustment *) ctrl->adjustments->data,
122
cb_mute_toggled (GtkWidget *button,
125
MyMixerControls *ctrl = (MyMixerControls *) data;
126
gst_mixer_set_mute (ctrl->mixer, ctrl->track,
127
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
131
cb_record_toggled (GtkWidget *button,
134
MyMixerControls *ctrl = (MyMixerControls *) data;
135
gst_mixer_set_record (ctrl->mixer, ctrl->track,
136
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
140
create_track_widget (GstMixer *mixer,
143
GstMixerTrack *track)
145
GtkWidget *label, *slider, *button, *image;
148
GList *adjlist = NULL;
149
MyMixerControls *ctrl = g_new0 (MyMixerControls, 1);
152
volumes = g_malloc (sizeof (gint) * track->num_channels);
156
ctrl->locked = FALSE;
158
/* image (optional) */
159
for (i = 0; str == NULL && pix[i].label != NULL; i++) {
160
/* we dup the string to make the comparison case-insensitive */
161
gchar *label_l = g_strdup (track->label),
162
*needle_l = g_strdup (pix[i].label);
165
/* make case insensitive */
166
for (pos = 0; label_l[pos] != '\0'; pos++)
167
label_l[pos] = g_ascii_tolower (label_l[pos]);
168
for (pos = 0; needle_l[pos] != '\0'; pos++)
169
needle_l[pos] = g_ascii_tolower (needle_l[pos]);
171
if (g_strrstr (label_l, needle_l) != NULL)
179
if ((image = gtk_image_new_from_stock (str, GTK_ICON_SIZE_MENU)) != NULL) {
180
gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.5);
181
gtk_table_attach_defaults (GTK_TABLE (table), image,
182
column_pos, column_pos + track->num_channels,
188
label = gtk_label_new (track->label);
189
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
190
gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
191
gtk_table_attach_defaults (GTK_TABLE (table), label,
192
column_pos, column_pos + track->num_channels,
195
/* now sliders for each of the tracks */
196
gst_mixer_get_volume (mixer, track, volumes);
197
for (i = 0; i < track->num_channels; i++) {
198
adj = gtk_adjustment_new (volumes[i],
199
track->min_volume, track->max_volume,
201
adjlist = g_list_append (adjlist, (gpointer) adj);
202
g_signal_connect (G_OBJECT (adj), "value_changed",
203
G_CALLBACK (cb_volume_changed), (gpointer) ctrl);
204
slider = gtk_vscale_new (GTK_ADJUSTMENT (adj));
205
gtk_scale_set_draw_value (GTK_SCALE (slider), FALSE);
206
gtk_range_set_inverted (GTK_RANGE (slider), TRUE);
207
gtk_widget_set_size_request (slider, -1, 100);
208
gtk_table_attach_defaults (GTK_TABLE (table), slider,
209
column_pos + i, column_pos + i + 1,
213
ctrl->adjustments = adjlist;
215
/* buttons (lock, mute, rec) */
216
if (track->num_channels > 1) {
217
button = gtk_check_button_new_with_label (_("Lock"));
218
gtk_table_attach_defaults (GTK_TABLE (table), button,
219
column_pos, column_pos + track->num_channels,
221
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
223
g_signal_connect (G_OBJECT (button), "toggled",
224
G_CALLBACK (cb_lock_toggled), (gpointer) ctrl);
227
button = gtk_check_button_new_with_label (_("Mute"));
228
gtk_table_attach_defaults (GTK_TABLE (table), button,
229
column_pos, column_pos + track->num_channels,
231
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
232
GST_MIXER_TRACK_HAS_FLAG (track,
233
GST_MIXER_TRACK_MUTE));
234
g_signal_connect (G_OBJECT (button), "toggled",
235
G_CALLBACK (cb_mute_toggled), (gpointer) ctrl);
238
if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_INPUT)) {
239
button = gtk_check_button_new_with_label (_("Rec."));
240
gtk_table_attach_defaults (GTK_TABLE (table), button,
241
column_pos, column_pos + track->num_channels,
243
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
244
GST_MIXER_TRACK_HAS_FLAG (track,
245
GST_MIXER_TRACK_RECORD));
246
g_signal_connect (G_OBJECT (button), "toggled",
247
G_CALLBACK (cb_record_toggled), (gpointer) ctrl);
248
ctrl->record = button;
255
create_mixer_widget (GstMixer *mixer)
261
/* count number of tracks */
262
tracks = gst_mixer_list_tracks (mixer);
263
for ( ; tracks != NULL; tracks = tracks->next) {
264
tablepos += ((GstMixerTrack *) tracks->data)->num_channels;
265
if (tracks->next != NULL)
269
/* create table for all single tracks */
270
table = gtk_table_new (6, tablepos, FALSE);
271
gtk_container_set_border_width (GTK_CONTAINER (table), 4);
272
gtk_table_set_row_spacings (GTK_TABLE (table), 2);
273
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
277
tracks = gst_mixer_list_tracks (mixer);
278
for ( ; tracks != NULL; tracks = tracks->next) {
279
create_track_widget (mixer, table, tablepos,
280
(GstMixerTrack *) tracks->data);
281
tablepos += ((GstMixerTrack *) tracks->data)->num_channels;
282
if (tracks->next != NULL) {
283
GtkWidget *sep = gtk_vseparator_new ();
284
gtk_table_attach_defaults (GTK_TABLE (table), sep,
285
tablepos, tablepos+1, 0, 6);
294
create_mixer_collection (GtkWidget *notebook)
296
GtkWidget *page, *label;
297
const GList *elements;
298
GList *collection = NULL;
301
/* go through all elements of a certain class and check whether
302
* they implement a mixer. If so, add a page */
303
elements = gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY);
304
for ( ; elements != NULL; elements = elements->next) {
305
GstElementFactory *factory = GST_ELEMENT_FACTORY (elements->data);
310
if (strcmp (factory->details->klass, "Generic/Audio"))
314
title = g_strdup_printf ("gst-mixer-%d", num);
315
element = gst_element_factory_create (factory, title);
321
/* check whether it implements a mixer */
322
if (!gst_element_set_state (element, GST_STATE_READY) ||
323
!GST_IS_MIXER (element)) {
324
gst_element_set_state (element, GST_STATE_NULL);
325
g_object_unref (G_OBJECT (element));
330
/* create mixer UI object */
331
page = create_mixer_widget (GST_MIXER (element));
332
if (g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (element)),
334
g_object_get (element, "device-name", &name, NULL);
338
label = gtk_label_new (name);
340
/* add new notebook page + keep track */
341
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
342
collection = g_list_append (collection, element);
351
cb_about (GtkWidget *widget,
355
const gchar *authors[] = { "Ronald Bultje <rbultje@ronald.bitfreak.net>",
358
about = gnome_about_new (_("GStreamer Volume Control"),
360
"(c) 2003 Ronald Bultje",
361
_("A GNOME/GStreamer-based mixer application"),
365
gtk_widget_show (about);
369
cb_destroy (GtkWidget *widget,
375
static GnomeUIInfo file_menu[] = {
376
GNOMEUIINFO_MENU_EXIT_ITEM (cb_destroy, NULL),
380
static GnomeUIInfo help_menu[] = {
381
GNOMEUIINFO_MENU_ABOUT_ITEM (cb_about, NULL),
382
GNOMEUIINFO_HELP (PACKAGE),
386
static GnomeUIInfo main_menu[] = {
387
GNOMEUIINFO_MENU_FILE_TREE (file_menu),
388
GNOMEUIINFO_MENU_HELP_TREE (help_menu),
393
register_stock_icons (void)
395
GtkIconFactory *icon_factory;
400
{ "mixer.png", GST_MIXER_STOCK_MIXER },
401
{ "phone.png", GST_MIXER_STOCK_PHONE },
402
{ "tone.png", GST_MIXER_STOCK_TONE },
403
{ "video.png", GST_MIXER_STOCK_VIDEO },
408
icon_factory = gtk_icon_factory_new ();
409
gtk_icon_factory_add_default (icon_factory);
411
for (num = 0; list[num].filename != NULL; num++) {
412
gchar *filename = gnome_program_locate_file (NULL,
413
GNOME_FILE_DOMAIN_APP_PIXMAP,
414
list[num].filename, TRUE, NULL);
416
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
417
GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
418
gtk_icon_factory_add (icon_factory, list[num].stock_id, icon_set);
429
GtkWidget *window, *notebook;
430
GList *mixers, *item;
431
struct poptOption options[] = {
432
{NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, "GStreamer", NULL},
436
/* init gstreamer/gnome */
437
options[0].arg = (void *) gst_init_get_popt_table();
438
gnome_program_init (PACKAGE, VERSION, LIBGNOMEUI_MODULE,
440
GNOME_PARAM_POPT_TABLE, options,
441
GNOME_PARAM_APP_DATADIR, DATA_DIR,
443
register_stock_icons ();
445
appfile = gnome_program_locate_file (NULL,
446
GNOME_FILE_DOMAIN_APP_PIXMAP,
447
"mixer.png", TRUE, NULL);
449
gnome_window_icon_set_default_from_file (appfile);
453
/* create main window + menus */
454
window = gnome_app_new (PACKAGE, _("GStreamer Volume Control"));
455
gnome_app_create_menus (GNOME_APP (window), main_menu);
457
/* create all mixers */
458
notebook = gtk_notebook_new ();
459
if (!(mixers = create_mixer_collection (notebook))) {
461
gtk_message_dialog_new (NULL, 0,
464
_("Sorry, no mixer elements and/or devices found"));
465
gtk_widget_show (dialog);
466
gtk_dialog_run (GTK_DIALOG (dialog));
469
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)) == 1)
470
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
473
gnome_app_set_contents (GNOME_APP (window), notebook);
474
g_signal_connect (G_OBJECT (window), "destroy",
475
G_CALLBACK (cb_destroy), NULL);
477
/* show off and run */
478
gtk_widget_show_all (window);
482
for (item = mixers; item != NULL; item = item->next) {
483
GstElement *element = GST_ELEMENT (item->data);
485
gst_element_set_state (element, GST_STATE_NULL);
486
gst_object_unref (GST_OBJECT (element));