always draw leds at startup
[tunertool] / src / tuner.c
index f8af9a6..102b8d8 100644 (file)
 #define TUNER_VERSION "0.4"
 
 #ifdef HILDON
-#  if HILDON==1
-#    include <hildon/hildon-defines.h>
-#    include <hildon/hildon-program.h>
-#    include <hildon/hildon-number-editor.h>
-#  elif defined(MAEMO1)
-#    include <hildon-widgets/hildon-app.h>
-#    include <hildon-widgets/hildon-appview.h>
-#  else
-#    include <hildon-widgets/hildon-program.h>
-#  endif
+#include <hildon/hildon-defines.h>
+#include <hildon/hildon-program.h>
+#include <hildon/hildon-number-editor.h>
 
 #include <libosso.h>
 
@@ -45,8 +38,8 @@
 #endif /* ifdef HILDON */
 
 #ifdef MAEMO
-# define DEFAULT_AUDIOSRC "dsppcmsrc"
-# define DEFAULT_AUDIOSINK "dsppcmsink"
+# define DEFAULT_AUDIOSRC "pulsesrc"
+# define DEFAULT_AUDIOSINK "pulsesink"
 #else
 # define DEFAULT_AUDIOSRC "alsasrc"
 # define DEFAULT_AUDIOSINK "alsasink"
 #include <math.h>
 #include <gst/gst.h>
 #include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+
+#include "gstpitch.h"
+#include "settings.h"
 
 #define between(x,a,b) (((x)>=(a)) && ((x)<=(b)))
 
@@ -81,7 +78,12 @@ struct app_data
   GstElement *bin1;
   GstElement *bin2;
   GstElement *tonesrc;
+  GstElement *pitch;
   guint stop_timer_id;
+  guint vol_timer_id;
+  gdouble target_vol;
+
+  gboolean display_keepalive;
 #ifdef MAEMO
   osso_context_t *osso_context;
   gpointer app;
@@ -96,12 +98,7 @@ enum
   NUM_NOTES = 96
 };
 
-enum
-{
-  CALIB_MIN = 430,
-  CALIB_MAX = 450,
-  CALIB_DEFAULT = 440
-};
+
 
 #define NUM_LEDS (66)
 #define NUM_WKEYS (15) /* # of white keys in the piano keyboard */
@@ -209,6 +206,8 @@ static Note equal_tempered_scale[] = {
 static GdkColor ledOnColor = { 0, 0 * 255, 180 * 255, 95 * 255 };
 static GdkColor ledOnColor2 = { 0, 180 * 255, 180 * 255, 0 * 255 };
 static GdkColor ledOffColor = { 0, 80 * 255, 80 * 255, 80 * 255 };
+static GdkColor whiteColor = { 0, 65535, 65535, 65535 };
+static GdkColor blackColor = { 0, 0, 0, 0 };
 
 static void
 recalculate_scale (double a4)
@@ -221,17 +220,6 @@ recalculate_scale (double a4)
   }
 }
 
-#ifdef HILDON
-static void
-fix_hildon_number_editor (GtkWidget * widget, gpointer data)
-{
-  if (GTK_IS_EDITABLE (widget)) {
-    gtk_editable_set_editable (GTK_EDITABLE (widget), FALSE);
-    g_object_set (G_OBJECT (widget), "can-focus", FALSE, NULL);
-  }
-}
-#endif
-
 static void
 calibration_changed (GObject * object, GParamSpec * pspec, gpointer user_data)
 {
@@ -245,6 +233,7 @@ calibration_changed (GObject * object, GParamSpec * pspec, gpointer user_data)
 
   if (value >= CALIB_MIN && value <= CALIB_MAX) {
     recalculate_scale (value);
+    settings_set_calibration (value);
   }
 }
 
@@ -336,7 +325,7 @@ draw_leds (AppData * appdata, gint n)
 
 /* update frequency info */
 static void
-update_frequency (AppData * appdata, gint frequency)
+update_frequency (AppData * appdata, gfloat frequency)
 {
   gchar *buffer;
   gint i, j;
@@ -359,7 +348,7 @@ update_frequency (AppData * appdata, gint frequency)
   gtk_label_set_text (GTK_LABEL (appdata->targetFrequency), buffer);
   g_free (buffer);
 
-  buffer = g_strdup_printf ("Played frequency is %d Hz", frequency);
+  buffer = g_strdup_printf ("Played frequency is %.2f Hz", frequency);
   gtk_label_set_text (GTK_LABEL (appdata->currentFrequency), buffer);
   g_free (buffer);
 
@@ -375,10 +364,11 @@ message_handler (GstBus * bus, GstMessage * message, gpointer data)
     const gchar *name = gst_structure_get_name (s);
 
     if (strcmp (name, "pitch") == 0) {
-      gint frequency;
+      gfloat frequency;
 
-      frequency = g_value_get_int (gst_structure_get_value (s, "frequency"));
-      update_frequency (data, frequency);
+      frequency = g_value_get_float (gst_structure_get_value (s, "frequency"));
+      if (frequency != 0)
+        update_frequency (data, frequency);
     }
   }
   /* we handled the message we want, and ignored the ones we didn't want.
@@ -426,8 +416,11 @@ expose_event (GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
   if (!gc) {
     gc = gdk_gc_new (appdata->drawingarea2->window);
   }
-  gdk_gc_set_rgb_fg_color (gc, &appdata->drawingarea2->style->fg[0]);
+  gdk_gc_set_rgb_fg_color (gc, &whiteColor);
+  gdk_draw_rectangle (appdata->drawingarea2->window, gc, TRUE, 0, 0,
+      NUM_WKEYS * WKEY_WIDTH, appdata->drawingarea2->allocation.height - 1);
 
+  gdk_gc_set_rgb_fg_color (gc, &blackColor);
   gdk_draw_rectangle (appdata->drawingarea2->window, gc, FALSE, 0, 0,
       NUM_WKEYS * WKEY_WIDTH, appdata->drawingarea2->allocation.height - 1);
 
@@ -492,6 +485,16 @@ stop_pipelines (gpointer user_data)
   return FALSE;
 }
 
+static gboolean
+fake_frequency (gpointer user_data)
+{
+  AppData * appdata = (AppData *) user_data;
+
+  update_frequency (appdata, 440.0);
+
+  return TRUE;
+}
+
 #ifdef MAEMO
 static void
 osso_hw_state_cb (osso_hw_state_t *state, gpointer user_data)
@@ -561,6 +564,15 @@ display_keepalive (gpointer user_data)
   return FALSE;
 }
 
+static void
+display_keepalive_stop (AppData * appdata)
+{
+  if (appdata->display_timer_id) {
+    g_source_remove (appdata->display_timer_id);
+    appdata->display_timer_id = 0;
+  }
+}
+
 static gboolean
 topmost_notify (GObject * object, GParamSpec * pspec, gpointer user_data)
 {
@@ -576,7 +588,7 @@ topmost_notify (GObject * object, GParamSpec * pspec, gpointer user_data)
     set_pipeline_states (appdata, GST_STATE_PLAYING);
 
     /* keep display on */
-    if (appdata->display_timer_id == 0)
+    if (appdata->display_keepalive && appdata->display_timer_id == 0)
       display_keepalive (user_data);
   }
   else {
@@ -585,32 +597,114 @@ topmost_notify (GObject * object, GParamSpec * pspec, gpointer user_data)
     /* stop pipelines fully if the app stays in the background for 30 seconds */
     appdata->stop_timer_id = g_timeout_add (30000, (GSourceFunc) stop_pipelines, user_data);
     /* let display dim and switch off */
-    if (appdata->display_timer_id) {
-      g_source_remove (appdata->display_timer_id);
-      appdata->display_timer_id = 0;
-    }
+    display_keepalive_stop (appdata);
   }
 
   return FALSE;
 }
 #endif
 
+static void
+settings_notify (GConfClient * client, guint cnxn_id, GConfEntry * entry, gpointer user_data)
+{
+  AppData * appdata = (AppData *) user_data;
+
+  g_debug ("%s changed", gconf_entry_get_key (entry));
+
+  if (strcmp (gconf_entry_get_key (entry), GCONF_KEY_ALGORITHM) == 0) {
+    if (gconf_entry_get_value (entry) != NULL && gconf_entry_get_value (entry)->type == GCONF_VALUE_INT) {
+      g_object_set (G_OBJECT (appdata->pitch), 
+          "algorithm", gconf_value_get_int (gconf_entry_get_value (entry)),
+          NULL);
+    }
+  }
+  else if (strcmp (gconf_entry_get_key (entry), GCONF_KEY_CALIBRATION) == 0) {
+    /* TODO */
+  }
+  else if (strcmp (gconf_entry_get_key (entry), GCONF_KEY_DISPLAY_KEEPALIVE) == 0) {
+    if (gconf_entry_get_value (entry) != NULL && gconf_entry_get_value (entry)->type == GCONF_VALUE_BOOL) {
+      appdata->display_keepalive = gconf_value_get_bool (gconf_entry_get_value (entry));
+
+      if (appdata->display_keepalive && appdata->display_timer_id == 0)
+        display_keepalive (user_data);
+      else
+        display_keepalive_stop (appdata);
+    }
+  }
+  else {
+    g_warning ("unknown GConf key `%s'", gconf_entry_get_key (entry));
+  }
+}
+
+static void 
+settings_activate (GtkWidget * widget, GtkWidget * main_win)
+{
+  settings_dialog_show (GTK_WINDOW (main_win));
+}
+
+static void 
+about_activate (GtkWidget * widget, GtkWindow * main_win)
+{
+  GtkWidget *vbox;
+  GtkWidget *label;
+  GtkWidget *dialog;
+  dialog = gtk_dialog_new_with_buttons("About tuner", main_win,
+      GTK_DIALOG_MODAL | 
+      GTK_DIALOG_DESTROY_WITH_PARENT |
+      GTK_DIALOG_NO_SEPARATOR,
+      NULL, NULL);
+
+  g_signal_connect (G_OBJECT (dialog), "delete_event", G_CALLBACK (gtk_widget_destroy), NULL);
+
+  vbox = gtk_vbox_new (FALSE, HILDON_MARGIN_DEFAULT);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), HILDON_MARGIN_DEFAULT);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
+  label = gtk_label_new ("Tuner Tool is developed by Josep Torra and Jari Tenhunen.\n"
+      "http://n770galaxy.blogspot.com/\n");
+  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 5);
+
+  gtk_widget_show_all (dialog);
+  gtk_dialog_run (GTK_DIALOG (dialog));
+
+  gtk_widget_destroy (dialog);
+}
+
+static HildonAppMenu *
+create_menu (GtkWidget *parent)
+{
+  HildonSizeType button_size = HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH;
+  HildonAppMenu *menu = HILDON_APP_MENU (hildon_app_menu_new ());
+  GtkButton *button;
+
+  button = GTK_BUTTON (hildon_gtk_button_new (button_size));
+  gtk_button_set_label (button, "Settings");
+  g_signal_connect_after (G_OBJECT (button), "clicked",
+      G_CALLBACK (settings_activate), parent);
+  hildon_app_menu_append (menu, button);
+
+  button = GTK_BUTTON (hildon_gtk_button_new (button_size));
+  gtk_button_set_label (button, "About");
+  g_signal_connect_after (G_OBJECT (button), "clicked",
+      G_CALLBACK (about_activate), parent);
+  hildon_app_menu_append (menu, button);
+
+  gtk_widget_show_all (GTK_WIDGET (menu));
+
+  return menu;
+}
+
 int
 main (int argc, char *argv[])
 {
   AppData * appdata = NULL;
 #ifdef HILDON
-#if defined(MAEMO1)
-  HildonApp *app = NULL;
-  HildonAppView *view = NULL;
-#else
   HildonProgram *app = NULL;
-  HildonWindow *view = NULL;
-#endif
   osso_hw_state_t hw_state_mask = { TRUE, FALSE, FALSE, TRUE, 0 };
 #endif
+  gint calib;
 
-  GstElement *src1, *src2, *pitch, *sink1;
+  GstElement *src1, *src2, *sink1;
   GstElement *sink2;
   GstBus *bus;
 
@@ -621,6 +715,7 @@ main (int argc, char *argv[])
   GtkWidget *alignment;
   GtkWidget *calibrate;
   GtkWidget *sep;
+  HildonAppMenu *menu;
 
 #ifndef HILDON
   GdkPixbuf *icon = NULL;
@@ -636,21 +731,12 @@ main (int argc, char *argv[])
   plugin_pitch_init (NULL);
   plugin_tonesrc_init (NULL);
 
-  recalculate_scale (CALIB_DEFAULT);
 
   /* Init the gtk - must be called before any hildon stuff */
   gtk_init (&argc, &argv);
 
-#ifdef HILDON
-#if defined(MAEMO1)
-  /* Create the hildon application and setup the title */
-  app = HILDON_APP (hildon_app_new ());
-  hildon_app_set_title (app, "Tuner Tool");
-  hildon_app_set_two_part_title (app, TRUE);
-#else
   app = HILDON_PROGRAM (hildon_program_get_instance ());
   g_set_application_name ("Tuner Tool");
-#endif
 
   appdata->app = app;
 
@@ -667,42 +753,37 @@ main (int argc, char *argv[])
   if (osso_hw_set_event_cb (appdata->osso_context, &hw_state_mask, osso_hw_state_cb, appdata) != OSSO_OK)
     g_warning ("setting osso_hw_state_cb failed!");
 
+  settings_init (&settings_notify, appdata);
+
+  calib = settings_get_calibration (CALIB_DEFAULT);
+  recalculate_scale (calib);
+
   mainBox = gtk_vbox_new (FALSE, 0);
   gtk_container_set_border_width (GTK_CONTAINER (mainBox), 0);
-#if defined(MAEMO1)
-  view = HILDON_APPVIEW (hildon_appview_new ("Tuner"));
-  hildon_appview_set_fullscreen_key_allowed (view, TRUE);
-  mainWin = GTK_WIDGET (app);
-#else
-  view = HILDON_WINDOW (hildon_window_new ());
-  mainWin = GTK_WIDGET (view);
+  mainWin = hildon_stackable_window_new ();
   g_signal_connect (G_OBJECT (app), "notify::is-topmost", G_CALLBACK (topmost_notify), appdata);
-#endif
-#else
-  mainWin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-  gtk_window_set_title (GTK_WINDOW (mainWin), "Tuner " TUNER_VERSION);
-  icon = gdk_pixbuf_new_from_file ("tuner64.png", &error);
-  if (icon != NULL) {
-    g_print ("Setting icon\n");
-    gtk_window_set_icon (GTK_WINDOW (mainWin), icon);
-  }
-  mainBox = gtk_vbox_new (FALSE, 0);
-  gtk_container_set_border_width (GTK_CONTAINER (mainBox), 0);
-#endif
+
+  menu = create_menu (mainWin);
+  hildon_program_set_common_app_menu (app, menu);
 
   /* Bin for tuner functionality */
   appdata->bin1 = gst_pipeline_new ("bin1");
 
   src1 = gst_element_factory_make (DEFAULT_AUDIOSRC, "src1");
-  pitch = gst_element_factory_make ("pitch", "pitch");
-  g_object_set (G_OBJECT (pitch), "message", TRUE, "minfreq", 10,
-      "maxfreq", 4000, NULL);
+  g_object_set (G_OBJECT (src1), "device", "source.voice.raw", NULL);
+
+  appdata->pitch = gst_element_factory_make ("pitch", "pitch");
+
+  g_object_set (G_OBJECT (appdata->pitch), "message", TRUE, "minfreq", 10,
+      "maxfreq", 4000, 
+      "algorithm", settings_get_algorithm (DEFAULT_ALGORITHM),
+      NULL);
 
   sink1 = gst_element_factory_make ("fakesink", "sink1");
   g_object_set (G_OBJECT (sink1), "silent", 1, NULL);
 
-  gst_bin_add_many (GST_BIN (appdata->bin1), src1, pitch, sink1, NULL);
-  if (!gst_element_link_many (src1, pitch, sink1, NULL)) {
+  gst_bin_add_many (GST_BIN (appdata->bin1), src1, appdata->pitch, sink1, NULL);
+  if (!gst_element_link_many (src1, appdata->pitch, sink1, NULL)) {
     fprintf (stderr, "cant link elements\n");
     exit (1);
   }
@@ -731,7 +812,7 @@ main (int argc, char *argv[])
   g_signal_connect (G_OBJECT (mainWin), "destroy",
       G_CALLBACK (on_window_destroy), NULL);
   g_signal_connect (G_OBJECT(mainWin), "key_press_event", 
-      G_CALLBACK(key_press_event), mainWin);
+      G_CALLBACK (key_press_event), mainWin);
 
   /* Note label */
   appdata->targetFrequency = gtk_label_new ("");
@@ -753,17 +834,14 @@ main (int argc, char *argv[])
   gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 5);
 
 #ifdef HILDON
-  calibrate = hildon_number_editor_new (CALIB_MIN, CALIB_MAX);
+  calibrate = calibration_editor_new (CALIB_MIN, CALIB_MAX);
   hildon_number_editor_set_value (HILDON_NUMBER_EDITOR (calibrate),
-      CALIB_DEFAULT);
-  /* we don't want that ugly cursor there */
-  gtk_container_forall (GTK_CONTAINER (calibrate),
-      (GtkCallback) fix_hildon_number_editor, NULL);
+      calib);
   g_signal_connect (G_OBJECT (calibrate), "notify::value",
       G_CALLBACK (calibration_changed), NULL);
 #else
   calibrate = gtk_spin_button_new_with_range (CALIB_MIN, CALIB_MAX, 1);
-  gtk_spin_button_set_value (GTK_SPIN_BUTTON (calibrate), CALIB_DEFAULT);
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (calibrate), calib);
   g_signal_connect (G_OBJECT (calibrate), "value_changed",
       G_CALLBACK (calibration_changed), NULL);
 #endif
@@ -773,14 +851,8 @@ main (int argc, char *argv[])
 
   /* Separator */
   sep = gtk_hseparator_new ();
-
-  /* Credits */
   gtk_box_pack_start (GTK_BOX (mainBox), sep, FALSE, FALSE, 5);
 
-  label = gtk_label_new ("Tuner Tool developed by Josep Torra.\n"
-      "http://n770galaxy.blogspot.com/");
-  gtk_box_pack_start (GTK_BOX (mainBox), label, FALSE, FALSE, 5);
-
   /* Piano keyboard */
   alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
   appdata->drawingarea2 = gtk_drawing_area_new ();
@@ -802,23 +874,24 @@ main (int argc, char *argv[])
   } else {
     gtk_widget_set_events (appdata->drawingarea2, GDK_EXPOSURE_MASK);
   }
-#ifdef HILDON
-  gtk_container_add (GTK_CONTAINER (view), mainBox);
-#if defined(MAEMO1)
-  hildon_app_set_appview (app, view);
-  gtk_widget_show_all (GTK_WIDGET (app));
-#else
-  hildon_program_add_window (app, view);
-  gtk_widget_show_all (GTK_WIDGET (view));
-#endif
-#else
+
   gtk_container_add (GTK_CONTAINER (mainWin), mainBox);
+  hildon_program_add_window (app, HILDON_WINDOW (mainWin));
   gtk_widget_show_all (GTK_WIDGET (mainWin));
-#endif
+
+  appdata->display_keepalive = settings_get_display_keepalive (DEFAULT_DISPLAY_KEEPALIVE);
+
+  if (appdata->display_keepalive)
+    display_keepalive (appdata);
+
+  draw_leds (appdata, 0);
 
   set_pipeline_states (appdata, GST_STATE_PLAYING);
-  display_keepalive (appdata);
+
+  //g_timeout_add (2000, (GSourceFunc) fake_frequency, appdata);
+
   gtk_main ();
+
   set_pipeline_states (appdata, GST_STATE_NULL);
 
   gst_object_unref (appdata->bin1);