* src/tuner.c (main, window_is_active_notify):
[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 GstElement *bin1 = NULL;
199 static GstElement *bin2 = NULL;
200
201 static void
202 recalculate_scale (double a4)
203 {
204   int i;
205
206   for (i = 0; i < NUM_NOTES; i++) {
207     equal_tempered_scale[i].frequency = a4 * pow (MAGIC, i - 57);
208     /* fprintf(stdout, "%s: %.2f\n", equal_tempered_scale[i].name, equal_tempered_scale[i].frequency); */
209   }
210 }
211
212 #ifdef HILDON
213 static void
214 fix_hildon_number_editor (GtkWidget * widget, gpointer data)
215 {
216   if (GTK_IS_EDITABLE (widget)) {
217     gtk_editable_set_editable (GTK_EDITABLE (widget), FALSE);
218     g_object_set (G_OBJECT (widget), "can-focus", FALSE, NULL);
219   }
220 }
221 #endif
222
223 static void
224 calibration_changed (GObject * object, GParamSpec * pspec, gpointer user_data)
225 {
226   gint value;
227
228 #ifdef HILDON
229   value = hildon_number_editor_get_value (HILDON_NUMBER_EDITOR (object));
230 #else
231   value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (object));
232 #endif
233
234   if (value >= CALIB_MIN && value <= CALIB_MAX) {
235     recalculate_scale (value);
236     g_debug ("Calibration changed to %d Hz", value);
237   }
238 }
239
240 static void
241 on_window_destroy (GtkObject * object, gpointer user_data)
242 {
243   gtk_main_quit ();
244 }
245
246 static void
247 toggle_fullscreen (GtkWindow * window)
248 {
249   static gboolean fullscreen = FALSE;
250
251   fullscreen = !fullscreen;
252   if (fullscreen)
253     gtk_window_fullscreen (GTK_WINDOW (window));
254   else
255     gtk_window_unfullscreen (GTK_WINDOW (window));
256 }
257
258 static gboolean 
259 key_press_event (GtkWidget * widget, GdkEventKey * event, GtkWindow * window)
260 {
261   switch (event->keyval) {
262 #ifdef HILDON
263     case HILDON_HARDKEY_FULLSCREEN:
264       toggle_fullscreen(window);
265       break;
266 #endif
267     default:
268       break;
269   }
270
271   return FALSE;
272 }
273
274 static void
275 draw_leds (gint n)
276 {
277   gint i, j, k;
278   static GdkGC *gc = NULL;
279   gint width = drawingarea1->allocation.width;
280   gint led_width = ((gfloat) width / (gfloat) (NUM_LEDS)) * 0.8;
281   gint led_space = ((gfloat) width / (gfloat) (NUM_LEDS)) * 0.2;
282   gint led_total = led_width + led_space;
283   gint padding = (width - NUM_LEDS * led_total) / 2;
284
285   if (!gc) {
286     gc = gdk_gc_new (drawingarea1->window);
287   }
288   gdk_gc_set_rgb_fg_color (gc, &drawingarea1->style->fg[0]);
289
290   gdk_draw_rectangle (drawingarea1->window, gc, TRUE, 0, 0,
291       drawingarea1->allocation.width, drawingarea1->allocation.height);
292
293   if (abs (n) > (NUM_LEDS / 2))
294     n = n / n * (NUM_LEDS / 2);
295
296   if (n > 0) {
297     j = NUM_LEDS / 2 + 1;
298     k = NUM_LEDS / 2 + n;
299   } else {
300     j = NUM_LEDS / 2 + n;
301     k = NUM_LEDS / 2 - 1;
302   }
303
304   // Draw all leds
305   for (i = 0; i < NUM_LEDS; i++) {
306     if (i == NUM_LEDS / 2) {
307       if (n == 0)
308         gdk_gc_set_rgb_fg_color (gc, &ledOnColor2);
309       else
310         gdk_gc_set_rgb_fg_color (gc, &ledOffColor);
311
312       gdk_draw_rectangle (drawingarea1->window, gc, TRUE, padding + (i * led_total) + ((led_total - 4) / 2), 2, 4,
313           36);
314     } else {
315       if ((i >= j) && (i <= k))
316         gdk_gc_set_rgb_fg_color (gc, &ledOnColor);
317       else
318         gdk_gc_set_rgb_fg_color (gc, &ledOffColor);
319
320       gdk_draw_rectangle (drawingarea1->window, gc, TRUE, padding + (i * led_total), 10, led_width,
321           20);
322     }
323   }
324 }
325
326 /* update frequency info */
327 static void
328 update_frequency (gint frequency)
329 {
330   gchar *buffer;
331   gint i, j;
332   gfloat diff, min_diff;
333
334   min_diff = frequency - (equal_tempered_scale[0].frequency - 10);
335   for (i = j = 0; i < NUM_NOTES; i++) {
336     diff = frequency - equal_tempered_scale[i].frequency;
337     if (fabs (diff) <= fabs (min_diff)) {
338       min_diff = diff;
339       j = i;
340     } else {
341       break;
342     }
343   }
344
345   buffer =
346       g_strdup_printf ("Nearest note is %s with %.2f Hz frequency",
347       equal_tempered_scale[j].name, equal_tempered_scale[j].frequency);
348   gtk_label_set_text (GTK_LABEL (targetFrequency), buffer);
349   g_free (buffer);
350
351   buffer = g_strdup_printf ("Played frequency is %d Hz", frequency);
352   gtk_label_set_text (GTK_LABEL (currentFrequency), buffer);
353   g_free (buffer);
354
355   draw_leds ((gint) roundf (min_diff));
356 }
357
358 /* receive spectral data from element message */
359 gboolean
360 message_handler (GstBus * bus, GstMessage * message, gpointer data)
361 {
362   if (message->type == GST_MESSAGE_ELEMENT) {
363     const GstStructure *s = gst_message_get_structure (message);
364     const gchar *name = gst_structure_get_name (s);
365
366     if (strcmp (name, "pitch") == 0) {
367       gint frequency;
368
369       frequency = g_value_get_int (gst_structure_get_value (s, "frequency"));
370       update_frequency (frequency);
371     }
372   }
373   /* we handled the message we want, and ignored the ones we didn't want.
374    * so the core can unref the message for us */
375   return TRUE;
376 }
377
378 gfloat
379 keynote2freq (gint x, gint y)
380 {
381   gint i, j, height, found;
382   gfloat frequency = 0;
383
384   height = drawingarea2->allocation.height;
385
386   j = 0;
387   found = 0;
388   for (i = 0; i < NUM_WKEYS; i++) {
389     // Test for a white key  
390     j++;
391     if (between (x, i * WKEY_WIDTH, i * WKEY_WIDTH + (WKEY_WIDTH - 1)) && between (y, 0, height))
392       found = j;
393     // Test for a black key
394     if (((i % 7) != 2) && ((i % 7) != 6) && (i != 14)) {
395       j++;
396       if (between (x, 24 + i * 45, 24 + i * 45 + 42)
397           && between (y, 0, height / 2))
398         found = j;
399     }
400     if (found) {
401       frequency = equal_tempered_scale[48 + found - 1].frequency;
402       break;
403     }
404   }
405   return frequency;
406 }
407
408 static gboolean
409 expose_event (GtkWidget * widget, GdkEventExpose * event)
410 {
411   gint i;
412   static GdkGC *gc = NULL;
413
414   if (!gc) {
415     gc = gdk_gc_new (drawingarea2->window);
416   }
417   gdk_gc_set_rgb_fg_color (gc, &drawingarea2->style->fg[0]);
418
419   gdk_draw_rectangle (drawingarea2->window, gc, FALSE, 0, 0,
420       NUM_WKEYS * WKEY_WIDTH, drawingarea2->allocation.height - 1);
421
422   for (i = 0; i < NUM_WKEYS - 1; i++)
423     gdk_draw_rectangle (drawingarea2->window, gc, FALSE, i * WKEY_WIDTH, 0,
424         WKEY_WIDTH, drawingarea2->allocation.height - 1);
425
426   for (i = 0; i < NUM_WKEYS - 1; i++) {
427     if (((i % 7) != 2) && ((i % 7) != 6))
428       gdk_draw_rectangle (drawingarea2->window, gc, TRUE, 24 + i * WKEY_WIDTH, 0,
429           42, drawingarea2->allocation.height / 2);
430   }
431   return FALSE;
432 }
433
434 static gboolean
435 button_press_event (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
436 {
437   GstElement *piano = GST_ELEMENT (user_data);
438
439   if (event->button == 1) {
440     g_object_set (piano, "freq", (gdouble) keynote2freq (event->x, event->y),
441         "volume", 0.8, NULL);
442   }
443
444   return TRUE;
445 }
446
447 static gboolean
448 button_release_event (GtkWidget * widget, GdkEventButton * event,
449     gpointer user_data)
450 {
451   GstElement *piano = GST_ELEMENT (user_data);
452
453   if (event->button == 1) {
454     g_object_set (piano, "volume", 0.0, NULL);
455   }
456
457   return TRUE;
458 }
459
460 static gboolean
461 window_is_active_notify (GObject * object, GParamSpec * pspec, gpointer user_data)
462 {
463   if (gtk_window_is_active (GTK_WINDOW (object))) {
464     if (bin1)
465       gst_element_set_state(bin1, GST_STATE_PLAYING);
466     if (bin2)
467       gst_element_set_state(bin2, GST_STATE_PLAYING);
468   }
469   else {
470     if (bin1)
471       gst_element_set_state(bin1, GST_STATE_PAUSED);
472     if (bin2)
473       gst_element_set_state(bin2, GST_STATE_PAUSED);
474   }
475
476   return FALSE;
477 }
478
479 int
480 main (int argc, char *argv[])
481 {
482 #ifdef HILDON
483 #if defined(MAEMO1)
484   HildonApp *app = NULL;
485   HildonAppView *view = NULL;
486 #else
487   HildonProgram *app = NULL;
488   HildonWindow *view = NULL;
489 #endif
490   osso_context_t *osso_context = NULL;  /* handle to osso */
491 #endif
492
493   GstElement *src1, *pitch, *sink1;
494   GstElement *src2, *sink2;
495   GstBus *bus;
496
497   GtkWidget *mainWin;
498   GtkWidget *mainBox;
499   GtkWidget *box;
500   GtkWidget *label;
501   GtkWidget *alignment;
502   GtkWidget *calibrate;
503   GtkWidget *sep;
504
505 #ifndef HILDON
506   GdkPixbuf *icon = NULL;
507   GError *error = NULL;
508 #endif
509   gboolean piano_enabled = TRUE;
510
511   /* Init GStreamer */
512   gst_init (&argc, &argv);
513   /* Register the GStreamer plugins */
514   plugin_pitch_init (NULL);
515   plugin_tonesrc_init (NULL);
516
517   recalculate_scale (CALIB_DEFAULT);
518
519   /* Init the gtk - must be called before any hildon stuff */
520   gtk_init (&argc, &argv);
521
522 #ifdef HILDON
523 #if defined(MAEMO1)
524   /* Create the hildon application and setup the title */
525   app = HILDON_APP (hildon_app_new ());
526   hildon_app_set_title (app, "Tuner Tool");
527   hildon_app_set_two_part_title (app, TRUE);
528 #else
529   app = HILDON_PROGRAM (hildon_program_get_instance ());
530   g_set_application_name ("Tuner Tool");
531 #endif
532
533   /* Initialize maemo application */
534   osso_context = osso_initialize (OSSO_PACKAGE, OSSO_VERSION, TRUE, NULL);
535
536   /* Check that initialization was ok */
537   if (osso_context == NULL) {
538     g_print ("Bummer, osso failed\n");
539   }
540   g_assert (osso_context);
541
542   mainBox = gtk_vbox_new (FALSE, 0);
543   gtk_container_set_border_width (GTK_CONTAINER (mainBox), 0);
544 #if defined(MAEMO1)
545   view = HILDON_APPVIEW (hildon_appview_new ("Tuner"));
546   hildon_appview_set_fullscreen_key_allowed (view, TRUE);
547   mainWin = GTK_WIDGET (app);
548 #else
549   view = HILDON_WINDOW (hildon_window_new ());
550   mainWin = GTK_WIDGET (view);
551 #endif
552 #else
553   mainWin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
554   gtk_window_set_title (GTK_WINDOW (mainWin), "Tuner " TUNER_VERSION);
555   icon = gdk_pixbuf_new_from_file ("tuner64.png", &error);
556   if (icon != NULL) {
557     g_print ("Setting icon\n");
558     gtk_window_set_icon (GTK_WINDOW (mainWin), icon);
559   }
560   mainBox = gtk_vbox_new (FALSE, 0);
561   gtk_container_set_border_width (GTK_CONTAINER (mainBox), 0);
562 #endif
563
564   if (GTK_IS_WINDOW (mainWin))
565     g_signal_connect (G_OBJECT (mainWin), "notify::is-active", G_CALLBACK (window_is_active_notify), NULL);
566
567   /* Bin for tuner functionality */
568   bin1 = gst_pipeline_new ("bin1");
569
570   src1 = gst_element_factory_make (DEFAULT_AUDIOSRC, "src1");
571   pitch = gst_element_factory_make ("pitch", "pitch");
572   g_object_set (G_OBJECT (pitch), "message", TRUE, "minfreq", 10,
573       "maxfreq", 4000, NULL);
574
575   sink1 = gst_element_factory_make ("fakesink", "sink1");
576   g_object_set (G_OBJECT (sink1), "silent", 1, NULL);
577
578   gst_bin_add_many (GST_BIN (bin1), src1, pitch, sink1, NULL);
579   if (!gst_element_link_many (src1, pitch, sink1, NULL)) {
580     fprintf (stderr, "cant link elements\n");
581     exit (1);
582   }
583
584   bus = gst_element_get_bus (bin1);
585   gst_bus_add_watch (bus, message_handler, NULL);
586   gst_object_unref (bus);
587
588   /* Bin for piano functionality */
589   bin2 = gst_pipeline_new ("bin2");
590
591   //src2 = gst_element_factory_make ("audiotestsrc", "src2");
592   //g_object_set (G_OBJECT (src2), "volume", 0.0, "wave", 7, NULL);
593   src2 = gst_element_factory_make ("tonesrc", "src2");
594   g_object_set (G_OBJECT (src2), "volume", 0.0, NULL);
595   sink2 = gst_element_factory_make (DEFAULT_AUDIOSINK, "sink2");
596
597   gst_bin_add_many (GST_BIN (bin2), src2, sink2, NULL);
598   if (!gst_element_link_many (src2, sink2, NULL)) {
599     piano_enabled = FALSE;
600   }
601
602   /* GUI */
603   g_signal_connect (G_OBJECT (mainWin), "destroy",
604       G_CALLBACK (on_window_destroy), NULL);
605   g_signal_connect (G_OBJECT(mainWin), "key_press_event", 
606       G_CALLBACK(key_press_event), mainWin);
607
608   /* Note label */
609   targetFrequency = gtk_label_new ("");
610   gtk_box_pack_start (GTK_BOX (mainBox), targetFrequency, FALSE, FALSE, 5);
611
612   /* Leds */
613   drawingarea1 = gtk_drawing_area_new ();
614   gtk_widget_set_size_request (drawingarea1, 636, 40);
615   gtk_box_pack_start (GTK_BOX (mainBox), drawingarea1, FALSE, FALSE, 5);
616
617   /* Current frequency lable */
618   currentFrequency = gtk_label_new ("");
619   gtk_box_pack_start (GTK_BOX (mainBox), currentFrequency, FALSE, FALSE, 5);
620
621   /* Calibration spinner */
622   box = gtk_hbox_new (FALSE, 0);
623   alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
624   label = gtk_label_new ("Calibration");
625   gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 5);
626
627 #ifdef HILDON
628   calibrate = hildon_number_editor_new (CALIB_MIN, CALIB_MAX);
629   hildon_number_editor_set_value (HILDON_NUMBER_EDITOR (calibrate),
630       CALIB_DEFAULT);
631   /* we don't want that ugly cursor there */
632   gtk_container_forall (GTK_CONTAINER (calibrate),
633       (GtkCallback) fix_hildon_number_editor, NULL);
634   g_signal_connect (G_OBJECT (calibrate), "notify::value",
635       G_CALLBACK (calibration_changed), NULL);
636 #else
637   calibrate = gtk_spin_button_new_with_range (CALIB_MIN, CALIB_MAX, 1);
638   gtk_spin_button_set_value (GTK_SPIN_BUTTON (calibrate), CALIB_DEFAULT);
639   g_signal_connect (G_OBJECT (calibrate), "value_changed",
640       G_CALLBACK (calibration_changed), NULL);
641 #endif
642   gtk_box_pack_start (GTK_BOX (box), calibrate, FALSE, FALSE, 5);
643   gtk_container_add (GTK_CONTAINER (alignment), box);
644   gtk_box_pack_start (GTK_BOX (mainBox), alignment, FALSE, FALSE, 5);
645
646   /* Separator */
647   sep = gtk_hseparator_new ();
648
649   /* Credits */
650   gtk_box_pack_start (GTK_BOX (mainBox), sep, FALSE, FALSE, 5);
651
652   label = gtk_label_new ("Tuner Tool developed by Josep Torra.\n"
653       "http://n770galaxy.blogspot.com/");
654   gtk_box_pack_start (GTK_BOX (mainBox), label, FALSE, FALSE, 5);
655
656   /* Piano keyboard */
657   alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
658   drawingarea2 = gtk_drawing_area_new ();
659   gtk_widget_set_size_request (drawingarea2, NUM_WKEYS * WKEY_WIDTH + 1, 130);
660   gtk_container_add (GTK_CONTAINER (alignment), drawingarea2);
661   gtk_box_pack_start (GTK_BOX (mainBox), alignment, FALSE, FALSE, 5);
662
663   g_signal_connect (G_OBJECT (drawingarea2), "expose_event",
664       G_CALLBACK (expose_event), NULL);
665   if (piano_enabled) {
666     g_signal_connect (G_OBJECT (drawingarea2), "button_press_event",
667         G_CALLBACK (button_press_event), (gpointer) src2);
668
669     g_signal_connect (G_OBJECT (drawingarea2), "button_release_event",
670         G_CALLBACK (button_release_event), (gpointer) src2);
671
672     gtk_widget_set_events (drawingarea2, GDK_EXPOSURE_MASK
673         | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
674   } else {
675     gtk_widget_set_events (drawingarea2, GDK_EXPOSURE_MASK);
676   }
677 #ifdef HILDON
678   gtk_container_add (GTK_CONTAINER (view), mainBox);
679 #if defined(MAEMO1)
680   hildon_app_set_appview (app, view);
681   gtk_widget_show_all (GTK_WIDGET (app));
682 #else
683   hildon_program_add_window (app, view);
684   gtk_widget_show_all (GTK_WIDGET (view));
685 #endif
686 #else
687   gtk_container_add (GTK_CONTAINER (mainWin), mainBox);
688   gtk_widget_show_all (GTK_WIDGET (mainWin));
689 #endif
690
691   gst_element_set_state (bin1, GST_STATE_PLAYING);
692   gst_element_set_state (bin2, GST_STATE_PLAYING);
693   gtk_main ();
694   gst_element_set_state (bin2, GST_STATE_NULL);
695   gst_element_set_state (bin1, GST_STATE_NULL);
696
697   gst_object_unref (bin1);
698   gst_object_unref (bin2);
699
700   return 0;
701 }