* src/tuner.c (key_press_event, key_release_event): renamed to button_*_event
[tunertool] / src / tuner.c
1 /* vim: set sts=2 sw=2 et: */
2 /* Tuner
3  * Copyright (C) 2006 Josep Torra <j.torra@telefonica.net>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #define TUNER_VERSION "0.4"
27
28 #ifdef HILDON
29 #  if HILDON==1
30 #    include <hildon/hildon-defines.h>
31 #    include <hildon/hildon-program.h>
32 #    include <hildon/hildon-number-editor.h>
33 #  elif defined(MAEMO1)
34 #    include <hildon-widgets/hildon-app.h>
35 #    include <hildon-widgets/hildon-appview.h>
36 #  else
37 #    include <hildon-widgets/hildon-program.h>
38 #  endif
39
40 #include <libosso.h>
41
42 #define OSSO_PACKAGE "tuner-tool"
43 #define OSSO_VERSION TUNER_VERSION
44
45 #endif /* ifdef HILDON */
46
47 #ifdef MAEMO
48 # define DEFAULT_AUDIOSRC "dsppcmsrc"
49 # define DEFAULT_AUDIOSINK "dsppcmsink"
50 #else
51 # define DEFAULT_AUDIOSRC "alsasrc"
52 # define DEFAULT_AUDIOSINK "alsasink"
53 #endif
54
55
56 #include <string.h>
57 #include <math.h>
58 #include <gst/gst.h>
59 #include <gtk/gtk.h>
60
61 #define between(x,a,b) (((x)>=(a)) && ((x)<=(b)))
62
63 #define MAGIC (1.059463094359f) /* 2^(1/2) */
64
65 extern gboolean plugin_pitch_init (GstPlugin * plugin);
66 extern gboolean plugin_tonesrc_init (GstPlugin * plugin);
67
68 typedef struct
69 {
70   const gchar *name;
71   gfloat frequency;
72 } Note;
73
74 enum
75 {
76   NUM_NOTES = 96
77 };
78
79 enum
80 {
81   CALIB_MIN = 430,
82   CALIB_MAX = 450,
83   CALIB_DEFAULT = 440
84 };
85
86 #define NUM_LEDS (66)
87 #define NUM_WKEYS (15) /* # of white keys in the piano keyboard */
88 #define WKEY_WIDTH (45)
89
90 static Note equal_tempered_scale[] = {
91   {"C0", 16.35},
92   {"C#0/Db0", 17.32},
93   {"D0", 18.35},
94   {"D#0/Eb0", 19.45},
95   {"E0", 20.60},
96   {"F0", 21.83},
97   {"F#0/Gb0", 23.12},
98   {"G0", 24.50},
99   {"G#0/Ab0", 25.96},
100   {"A0", 27.50},
101   {"A#0/Bb0", 29.14},
102   {"B0", 30.87},
103   {"C1", 32.70},
104   {"C#1/Db1", 34.65},
105   {"D1", 36.71},
106   {"D#1/Eb1", 38.89},
107   {"E1", 41.20},
108   {"F1", 43.65},
109   {"F#1/Gb1", 46.25},
110   {"G1", 49.00},
111   {"G#1/Ab1", 51.91},
112   {"A1", 55.00},
113   {"A#1/Bb1", 58.27},
114   {"B1", 61.74},
115   {"C2", 65.41},
116   {"C#2/Db2", 69.30},
117   {"D2", 73.42},
118   {"D#2/Eb2", 77.78},
119   {"E2", 82.41},
120   {"F2", 87.31},
121   {"F#2/Gb2", 92.50},
122   {"G2", 98.00},
123   {"G#2/Ab2", 103.83},
124   {"A2", 110.00},
125   {"A#2/Bb2", 116.54},
126   {"B2", 123.47},
127   {"C3", 130.81},
128   {"C#3/Db3", 138.59},
129   {"D3", 146.83},
130   {"D#3/Eb3", 155.56},
131   {"E3", 164.81},
132   {"F3", 174.61},
133   {"F#3/Gb3", 185.00},
134   {"G3", 196.00},
135   {"G#3/Ab3", 207.65},
136   {"A3", 220.00},
137   {"A#3/Bb3", 233.08},
138   {"B3", 246.94},
139   {"C4", 261.63},
140   {"C#4/Db4", 277.18},
141   {"D4", 293.66},
142   {"D#4/Eb4", 311.13},
143   {"E4", 329.63},
144   {"F4", 349.23},
145   {"F#4/Gb4", 369.99},
146   {"G4", 392.00},
147   {"G#4/Ab4", 415.30},
148   {"A4", 440.00},
149   {"A#4/Bb4", 466.16},
150   {"B4", 493.88},
151   {"C5", 523.25},
152   {"C#5/Db5", 554.37},
153   {"D5", 587.33},
154   {"D#5/Eb5", 622.25},
155   {"E5", 659.26},
156   {"F5", 698.46},
157   {"F#5/Gb5", 739.99},
158   {"G5", 783.99},
159   {"G#5/Ab5", 830.61},
160   {"A5", 880.00},
161   {"A#5/Bb5", 932.33},
162   {"B5", 987.77},
163   {"C6", 1046.50},
164   {"C#6/Db6", 1108.73},
165   {"D6", 1174.66},
166   {"D#6/Eb6", 1244.51},
167   {"E6", 1318.51},
168   {"F6", 1396.91},
169   {"F#6/Gb6", 1479.98},
170   {"G6", 1567.98},
171   {"G#6/Ab6", 1661.22},
172   {"A6", 1760.00},
173   {"A#6/Bb6", 1864.66},
174   {"B6", 1975.53},
175   {"C7", 2093.00},
176   {"C#7/Db7", 2217.46},
177   {"D7", 2349.32},
178   {"D#7/Eb7", 2489.02},
179   {"E7", 2637.02},
180   {"F7", 2793.83},
181   {"F#7/Gb7", 2959.96},
182   {"G7", 3135.96},
183   {"G#7/Ab7", 3322.44},
184   {"A7", 3520.00},
185   {"A#7/Bb7", 3729.31},
186   {"B7", 3951.07},
187 };
188
189 static GdkColor ledOnColor = { 0, 0 * 255, 180 * 255, 95 * 255 };
190 static GdkColor ledOnColor2 = { 0, 180 * 255, 180 * 255, 0 * 255 };
191 static GdkColor ledOffColor = { 0, 80 * 255, 80 * 255, 80 * 255 };
192
193 static GtkWidget *targetFrequency;
194 static GtkWidget *currentFrequency;
195 static GtkWidget *drawingarea1;
196 static GtkWidget *drawingarea2;
197
198 static void
199 recalculate_scale (double a4)
200 {
201   int i;
202
203   for (i = 0; i < NUM_NOTES; i++) {
204     equal_tempered_scale[i].frequency = a4 * pow (MAGIC, i - 57);
205     /* fprintf(stdout, "%s: %.2f\n", equal_tempered_scale[i].name, equal_tempered_scale[i].frequency); */
206   }
207 }
208
209 #ifdef HILDON
210 static void
211 fix_hildon_number_editor (GtkWidget * widget, gpointer data)
212 {
213   if (GTK_IS_EDITABLE (widget)) {
214     gtk_editable_set_editable (GTK_EDITABLE (widget), FALSE);
215     g_object_set (G_OBJECT (widget), "can-focus", FALSE, NULL);
216   }
217 }
218 #endif
219
220 static void
221 calibration_changed (GObject * object, GParamSpec * pspec, gpointer user_data)
222 {
223   gint value;
224
225 #ifdef HILDON
226   value = hildon_number_editor_get_value (HILDON_NUMBER_EDITOR (object));
227 #else
228   value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (object));
229 #endif
230
231   if (value >= CALIB_MIN && value <= CALIB_MAX) {
232     recalculate_scale (value);
233     g_debug ("Calibration changed to %d Hz", value);
234   }
235 }
236
237 static void
238 on_window_destroy (GtkObject * object, gpointer user_data)
239 {
240   gtk_main_quit ();
241 }
242
243 static void
244 toggle_fullscreen (GtkWindow * window)
245 {
246   static gboolean fullscreen = FALSE;
247
248   fullscreen = !fullscreen;
249   if (fullscreen)
250     gtk_window_fullscreen (GTK_WINDOW (window));
251   else
252     gtk_window_unfullscreen (GTK_WINDOW (window));
253 }
254
255 static gboolean 
256 key_press_event (GtkWidget * widget, GdkEventKey * event, GtkWindow * window)
257 {
258   switch (event->keyval) {
259 #ifdef HILDON
260     case HILDON_HARDKEY_FULLSCREEN:
261       toggle_fullscreen(window);
262       break;
263 #endif
264     default:
265       break;
266   }
267
268   return FALSE;
269 }
270
271 static void
272 draw_leds (gint n)
273 {
274   gint i, j, k;
275   static GdkGC *gc = NULL;
276   gint width = drawingarea1->allocation.width;
277   gint led_width = ((gfloat) width / (gfloat) (NUM_LEDS)) * 0.8;
278   gint led_space = ((gfloat) width / (gfloat) (NUM_LEDS)) * 0.2;
279   gint led_total = led_width + led_space;
280   gint padding = (width - NUM_LEDS * led_total) / 2;
281
282   if (!gc) {
283     gc = gdk_gc_new (drawingarea1->window);
284   }
285   gdk_gc_set_rgb_fg_color (gc, &drawingarea1->style->fg[0]);
286
287   gdk_draw_rectangle (drawingarea1->window, gc, TRUE, 0, 0,
288       drawingarea1->allocation.width, drawingarea1->allocation.height);
289
290   if (abs (n) > (NUM_LEDS / 2))
291     n = n / n * (NUM_LEDS / 2);
292
293   if (n > 0) {
294     j = NUM_LEDS / 2 + 1;
295     k = NUM_LEDS / 2 + n;
296   } else {
297     j = NUM_LEDS / 2 + n;
298     k = NUM_LEDS / 2 - 1;
299   }
300
301   // Draw all leds
302   for (i = 0; i < NUM_LEDS; i++) {
303     if (i == NUM_LEDS / 2) {
304       if (n == 0)
305         gdk_gc_set_rgb_fg_color (gc, &ledOnColor2);
306       else
307         gdk_gc_set_rgb_fg_color (gc, &ledOffColor);
308
309       gdk_draw_rectangle (drawingarea1->window, gc, TRUE, padding + (i * led_total) + ((led_total - 4) / 2), 2, 4,
310           36);
311     } else {
312       if ((i >= j) && (i <= k))
313         gdk_gc_set_rgb_fg_color (gc, &ledOnColor);
314       else
315         gdk_gc_set_rgb_fg_color (gc, &ledOffColor);
316
317       gdk_draw_rectangle (drawingarea1->window, gc, TRUE, padding + (i * led_total), 10, led_width,
318           20);
319     }
320   }
321 }
322
323 /* update frequency info */
324 static void
325 update_frequency (gint frequency)
326 {
327   gchar *buffer;
328   gint i, j;
329   gfloat diff, min_diff;
330
331   min_diff = frequency - (equal_tempered_scale[0].frequency - 10);
332   for (i = j = 0; i < NUM_NOTES; i++) {
333     diff = frequency - equal_tempered_scale[i].frequency;
334     if (fabs (diff) <= fabs (min_diff)) {
335       min_diff = diff;
336       j = i;
337     } else {
338       break;
339     }
340   }
341
342   buffer =
343       g_strdup_printf ("Nearest note is %s with %.2f Hz frequency",
344       equal_tempered_scale[j].name, equal_tempered_scale[j].frequency);
345   gtk_label_set_text (GTK_LABEL (targetFrequency), buffer);
346   g_free (buffer);
347
348   buffer = g_strdup_printf ("Played frequency is %d Hz", frequency);
349   gtk_label_set_text (GTK_LABEL (currentFrequency), buffer);
350   g_free (buffer);
351
352   draw_leds ((gint) roundf (min_diff));
353 }
354
355 /* receive spectral data from element message */
356 gboolean
357 message_handler (GstBus * bus, GstMessage * message, gpointer data)
358 {
359   if (message->type == GST_MESSAGE_ELEMENT) {
360     const GstStructure *s = gst_message_get_structure (message);
361     const gchar *name = gst_structure_get_name (s);
362
363     if (strcmp (name, "pitch") == 0) {
364       gint frequency;
365
366       frequency = g_value_get_int (gst_structure_get_value (s, "frequency"));
367       update_frequency (frequency);
368     }
369   }
370   /* we handled the message we want, and ignored the ones we didn't want.
371    * so the core can unref the message for us */
372   return TRUE;
373 }
374
375 gfloat
376 keynote2freq (gint x, gint y)
377 {
378   gint i, j, height, found;
379   gfloat frequency = 0;
380
381   height = drawingarea2->allocation.height;
382
383   j = 0;
384   found = 0;
385   for (i = 0; i < NUM_WKEYS; i++) {
386     // Test for a white key  
387     j++;
388     if (between (x, i * WKEY_WIDTH, i * WKEY_WIDTH + (WKEY_WIDTH - 1)) && between (y, 0, height))
389       found = j;
390     // Test for a black key
391     if (((i % 7) != 2) && ((i % 7) != 6) && (i != 14)) {
392       j++;
393       if (between (x, 24 + i * 45, 24 + i * 45 + 42)
394           && between (y, 0, height / 2))
395         found = j;
396     }
397     if (found) {
398       frequency = equal_tempered_scale[48 + found - 1].frequency;
399       break;
400     }
401   }
402   return frequency;
403 }
404
405 static gboolean
406 expose_event (GtkWidget * widget, GdkEventExpose * event)
407 {
408   gint i;
409   static GdkGC *gc = NULL;
410
411   if (!gc) {
412     gc = gdk_gc_new (drawingarea2->window);
413   }
414   gdk_gc_set_rgb_fg_color (gc, &drawingarea2->style->fg[0]);
415
416   gdk_draw_rectangle (drawingarea2->window, gc, FALSE, 0, 0,
417       NUM_WKEYS * WKEY_WIDTH, drawingarea2->allocation.height - 1);
418
419   for (i = 0; i < NUM_WKEYS - 1; i++)
420     gdk_draw_rectangle (drawingarea2->window, gc, FALSE, i * WKEY_WIDTH, 0,
421         WKEY_WIDTH, drawingarea2->allocation.height - 1);
422
423   for (i = 0; i < NUM_WKEYS - 1; i++) {
424     if (((i % 7) != 2) && ((i % 7) != 6))
425       gdk_draw_rectangle (drawingarea2->window, gc, TRUE, 24 + i * WKEY_WIDTH, 0,
426           42, drawingarea2->allocation.height / 2);
427   }
428   return FALSE;
429 }
430
431 static gboolean
432 button_press_event (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
433 {
434   GstElement *piano = GST_ELEMENT (user_data);
435
436   if (event->button == 1) {
437     g_object_set (piano, "freq", (gdouble) keynote2freq (event->x, event->y),
438         "volume", 0.8, NULL);
439   }
440
441   return TRUE;
442 }
443
444 static gboolean
445 button_release_event (GtkWidget * widget, GdkEventButton * event,
446     gpointer user_data)
447 {
448   GstElement *piano = GST_ELEMENT (user_data);
449
450   if (event->button == 1) {
451     g_object_set (piano, "volume", 0.0, NULL);
452   }
453
454   return TRUE;
455 }
456
457 int
458 main (int argc, char *argv[])
459 {
460 #ifdef HILDON
461 #if defined(MAEMO1)
462   HildonApp *app = NULL;
463   HildonAppView *view = NULL;
464 #else
465   HildonProgram *app = NULL;
466   HildonWindow *view = NULL;
467 #endif
468   osso_context_t *osso_context = NULL;  /* handle to osso */
469 #endif
470
471   GstElement *bin1, *bin2;
472   GstElement *src1, *pitch, *sink1;
473   GstElement *src2, *sink2;
474   GstBus *bus;
475
476   GtkWidget *mainWin;
477   GtkWidget *mainBox;
478   GtkWidget *box;
479   GtkWidget *label;
480   GtkWidget *alignment;
481   GtkWidget *calibrate;
482   GtkWidget *sep;
483
484 #ifndef HILDON
485   GdkPixbuf *icon = NULL;
486   GError *error = NULL;
487 #endif
488   gboolean piano_enabled = TRUE;
489
490   /* Init GStreamer */
491   gst_init (&argc, &argv);
492   /* Register the GStreamer plugins */
493   plugin_pitch_init (NULL);
494   plugin_tonesrc_init (NULL);
495
496   recalculate_scale (CALIB_DEFAULT);
497
498   /* Init the gtk - must be called before any hildon stuff */
499   gtk_init (&argc, &argv);
500
501 #ifdef HILDON
502 #if defined(MAEMO1)
503   /* Create the hildon application and setup the title */
504   app = HILDON_APP (hildon_app_new ());
505   hildon_app_set_title (app, "Tuner Tool");
506   hildon_app_set_two_part_title (app, TRUE);
507 #else
508   app = HILDON_PROGRAM (hildon_program_get_instance ());
509   g_set_application_name ("Tuner Tool");
510 #endif
511
512   /* Initialize maemo application */
513   osso_context = osso_initialize (OSSO_PACKAGE, OSSO_VERSION, TRUE, NULL);
514
515   /* Check that initialization was ok */
516   if (osso_context == NULL) {
517     g_print ("Bummer, osso failed\n");
518   }
519   g_assert (osso_context);
520
521   mainBox = gtk_vbox_new (FALSE, 0);
522   gtk_container_set_border_width (GTK_CONTAINER (mainBox), 0);
523 #if defined(MAEMO1)
524   view = HILDON_APPVIEW (hildon_appview_new ("Tuner"));
525   hildon_appview_set_fullscreen_key_allowed (view, TRUE);
526   mainWin = GTK_WIDGET (app);
527 #else
528   view = HILDON_WINDOW (hildon_window_new ());
529   mainWin = GTK_WIDGET (view);
530 #endif
531 #else
532   mainWin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
533   gtk_window_set_title (GTK_WINDOW (mainWin), "Tuner " TUNER_VERSION);
534   icon = gdk_pixbuf_new_from_file ("tuner64.png", &error);
535   if (icon != NULL) {
536     g_print ("Setting icon\n");
537     gtk_window_set_icon (GTK_WINDOW (mainWin), icon);
538   }
539   mainBox = gtk_vbox_new (FALSE, 0);
540   gtk_container_set_border_width (GTK_CONTAINER (mainBox), 0);
541 #endif
542
543   /* Bin for tuner functionality */
544   bin1 = gst_pipeline_new ("bin1");
545
546   src1 = gst_element_factory_make (DEFAULT_AUDIOSRC, "src1");
547   pitch = gst_element_factory_make ("pitch", "pitch");
548   g_object_set (G_OBJECT (pitch), "message", TRUE, "minfreq", 10,
549       "maxfreq", 4000, NULL);
550
551   sink1 = gst_element_factory_make ("fakesink", "sink1");
552   g_object_set (G_OBJECT (sink1), "silent", 1, NULL);
553
554   gst_bin_add_many (GST_BIN (bin1), src1, pitch, sink1, NULL);
555   if (!gst_element_link_many (src1, pitch, sink1, NULL)) {
556     fprintf (stderr, "cant link elements\n");
557     exit (1);
558   }
559
560   bus = gst_element_get_bus (bin1);
561   gst_bus_add_watch (bus, message_handler, NULL);
562   gst_object_unref (bus);
563
564   /* Bin for piano functionality */
565   bin2 = gst_pipeline_new ("bin2");
566
567   //src2 = gst_element_factory_make ("audiotestsrc", "src2");
568   //g_object_set (G_OBJECT (src2), "volume", 0.0, "wave", 7, NULL);
569   src2 = gst_element_factory_make ("tonesrc", "src2");
570   g_object_set (G_OBJECT (src2), "volume", 0.0, NULL);
571   sink2 = gst_element_factory_make (DEFAULT_AUDIOSINK, "sink2");
572
573   gst_bin_add_many (GST_BIN (bin2), src2, sink2, NULL);
574   if (!gst_element_link_many (src2, sink2, NULL)) {
575     piano_enabled = FALSE;
576   }
577
578   /* GUI */
579   g_signal_connect (G_OBJECT (mainWin), "destroy",
580       G_CALLBACK (on_window_destroy), NULL);
581   g_signal_connect (G_OBJECT(mainWin), "key_press_event", 
582       G_CALLBACK(key_press_event), mainWin);
583
584   /* Note label */
585   targetFrequency = gtk_label_new ("");
586   gtk_box_pack_start (GTK_BOX (mainBox), targetFrequency, FALSE, FALSE, 5);
587
588   /* Leds */
589   drawingarea1 = gtk_drawing_area_new ();
590   gtk_widget_set_size_request (drawingarea1, 636, 40);
591   gtk_box_pack_start (GTK_BOX (mainBox), drawingarea1, FALSE, FALSE, 5);
592
593   /* Current frequency lable */
594   currentFrequency = gtk_label_new ("");
595   gtk_box_pack_start (GTK_BOX (mainBox), currentFrequency, FALSE, FALSE, 5);
596
597   /* Calibration spinner */
598   box = gtk_hbox_new (FALSE, 0);
599   alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
600   label = gtk_label_new ("Calibration");
601   gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 5);
602
603 #ifdef HILDON
604   calibrate = hildon_number_editor_new (CALIB_MIN, CALIB_MAX);
605   hildon_number_editor_set_value (HILDON_NUMBER_EDITOR (calibrate),
606       CALIB_DEFAULT);
607   /* we don't want that ugly cursor there */
608   gtk_container_forall (GTK_CONTAINER (calibrate),
609       (GtkCallback) fix_hildon_number_editor, NULL);
610   g_signal_connect (G_OBJECT (calibrate), "notify::value",
611       G_CALLBACK (calibration_changed), NULL);
612 #else
613   calibrate = gtk_spin_button_new_with_range (CALIB_MIN, CALIB_MAX, 1);
614   gtk_spin_button_set_value (GTK_SPIN_BUTTON (calibrate), CALIB_DEFAULT);
615   g_signal_connect (G_OBJECT (calibrate), "value_changed",
616       G_CALLBACK (calibration_changed), NULL);
617 #endif
618   gtk_box_pack_start (GTK_BOX (box), calibrate, FALSE, FALSE, 5);
619   gtk_container_add (GTK_CONTAINER (alignment), box);
620   gtk_box_pack_start (GTK_BOX (mainBox), alignment, FALSE, FALSE, 5);
621
622   /* Separator */
623   sep = gtk_hseparator_new ();
624
625   /* Credits */
626   gtk_box_pack_start (GTK_BOX (mainBox), sep, FALSE, FALSE, 5);
627
628   label = gtk_label_new ("Tuner Tool developed by Josep Torra.\n"
629       "http://n770galaxy.blogspot.com/");
630   gtk_box_pack_start (GTK_BOX (mainBox), label, FALSE, FALSE, 5);
631
632   /* Piano keyboard */
633   alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
634   drawingarea2 = gtk_drawing_area_new ();
635   gtk_widget_set_size_request (drawingarea2, NUM_WKEYS * WKEY_WIDTH + 1, 130);
636   gtk_container_add (GTK_CONTAINER (alignment), drawingarea2);
637   gtk_box_pack_start (GTK_BOX (mainBox), alignment, FALSE, FALSE, 5);
638
639   g_signal_connect (G_OBJECT (drawingarea2), "expose_event",
640       G_CALLBACK (expose_event), NULL);
641   if (piano_enabled) {
642     g_signal_connect (G_OBJECT (drawingarea2), "button_press_event",
643         G_CALLBACK (button_press_event), (gpointer) src2);
644
645     g_signal_connect (G_OBJECT (drawingarea2), "button_release_event",
646         G_CALLBACK (button_release_event), (gpointer) src2);
647
648     gtk_widget_set_events (drawingarea2, GDK_EXPOSURE_MASK
649         | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
650   } else {
651     gtk_widget_set_events (drawingarea2, GDK_EXPOSURE_MASK);
652   }
653 #ifdef HILDON
654   gtk_container_add (GTK_CONTAINER (view), mainBox);
655 #if defined(MAEMO1)
656   hildon_app_set_appview (app, view);
657   gtk_widget_show_all (GTK_WIDGET (app));
658 #else
659   hildon_program_add_window (app, view);
660   gtk_widget_show_all (GTK_WIDGET (view));
661 #endif
662 #else
663   gtk_container_add (GTK_CONTAINER (mainWin), mainBox);
664   gtk_widget_show_all (GTK_WIDGET (mainWin));
665 #endif
666
667   gst_element_set_state (bin1, GST_STATE_PLAYING);
668   gst_element_set_state (bin2, GST_STATE_PLAYING);
669   gtk_main ();
670   gst_element_set_state (bin2, GST_STATE_NULL);
671   gst_element_set_state (bin1, GST_STATE_NULL);
672
673   gst_object_unref (bin1);
674   gst_object_unref (bin2);
675
676   return 0;
677 }