#ifdef HILDON
# if HILDON==1
+# include <hildon/hildon-defines.h>
# include <hildon/hildon-program.h>
# include <hildon/hildon-number-editor.h>
# elif defined(MAEMO1)
gfloat frequency;
} Note;
+struct app_data
+{
+ GtkWidget *targetFrequency;
+ GtkWidget *currentFrequency;
+ GtkWidget *drawingarea1;
+ GtkWidget *drawingarea2;
+
+ GstElement *bin1;
+ GstElement *bin2;
+ GstElement *tonesrc;
+ guint stop_timer_id;
+#ifdef MAEMO
+ osso_context_t *osso_context;
+ gpointer app;
+ guint display_timer_id;
+#endif
+};
+
+typedef struct app_data AppData;
+
enum
{
NUM_NOTES = 96
};
#define NUM_LEDS (66)
+#define NUM_WKEYS (15) /* # of white keys in the piano keyboard */
+#define WKEY_WIDTH (45)
static Note equal_tempered_scale[] = {
{"C0", 16.35},
static GdkColor ledOnColor2 = { 0, 180 * 255, 180 * 255, 0 * 255 };
static GdkColor ledOffColor = { 0, 80 * 255, 80 * 255, 80 * 255 };
-GtkWidget *mainWin;
-GtkWidget *targetFrequency;
-GtkWidget *currentFrequency;
-GtkWidget *drawingarea1;
-GtkWidget *drawingarea2;
-
static void
recalculate_scale (double a4)
{
if (value >= CALIB_MIN && value <= CALIB_MAX) {
recalculate_scale (value);
- g_debug ("Calibration changed to %d Hz", value);
}
}
}
static void
-draw_leds (gint n)
+toggle_fullscreen (GtkWindow * window)
+{
+ static gboolean fullscreen = FALSE;
+
+ fullscreen = !fullscreen;
+ if (fullscreen)
+ gtk_window_fullscreen (GTK_WINDOW (window));
+ else
+ gtk_window_unfullscreen (GTK_WINDOW (window));
+}
+
+static gboolean
+key_press_event (GtkWidget * widget, GdkEventKey * event, GtkWindow * window)
+{
+ switch (event->keyval) {
+#ifdef HILDON
+ case HILDON_HARDKEY_FULLSCREEN:
+ toggle_fullscreen (window);
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static void
+draw_leds (AppData * appdata, gint n)
{
gint i, j, k;
static GdkGC *gc = NULL;
+ gint width = appdata->drawingarea1->allocation.width;
+ gint led_width = ((gfloat) width / (gfloat) (NUM_LEDS)) * 0.8;
+ gint led_space = ((gfloat) width / (gfloat) (NUM_LEDS)) * 0.2;
+ gint led_total = led_width + led_space;
+ gint padding = (width - NUM_LEDS * led_total) / 2;
if (!gc) {
- gc = gdk_gc_new (drawingarea1->window);
+ gc = gdk_gc_new (appdata->drawingarea1->window);
}
- gdk_gc_set_rgb_fg_color (gc, &drawingarea1->style->fg[0]);
+ gdk_gc_set_rgb_fg_color (gc, &appdata->drawingarea1->style->fg[0]);
- gdk_draw_rectangle (drawingarea1->window, gc, TRUE, 0, 0,
- drawingarea1->allocation.width, drawingarea1->allocation.height);
+ gdk_draw_rectangle (appdata->drawingarea1->window, gc, TRUE, 0, 0,
+ appdata->drawingarea1->allocation.width, appdata->drawingarea1->allocation.height);
if (abs (n) > (NUM_LEDS / 2))
n = n / n * (NUM_LEDS / 2);
else
gdk_gc_set_rgb_fg_color (gc, &ledOffColor);
- gdk_draw_rectangle (drawingarea1->window, gc, TRUE, (i * 10) + 8, 2, 4,
+ gdk_draw_rectangle (appdata->drawingarea1->window, gc, TRUE, padding + (i * led_total) + ((led_total - 4) / 2), 2, 4,
36);
} else {
if ((i >= j) && (i <= k))
else
gdk_gc_set_rgb_fg_color (gc, &ledOffColor);
- gdk_draw_rectangle (drawingarea1->window, gc, TRUE, (i * 10) + 6, 10, 8,
+ gdk_draw_rectangle (appdata->drawingarea1->window, gc, TRUE, padding + (i * led_total), 10, led_width,
20);
}
}
/* update frequency info */
static void
-update_frequency (gint frequency)
+update_frequency (AppData * appdata, gint frequency)
{
gchar *buffer;
gint i, j;
gfloat diff, min_diff;
- min_diff = fabs (frequency - (equal_tempered_scale[0].frequency - 10));
+ min_diff = frequency - (equal_tempered_scale[0].frequency - 10);
for (i = j = 0; i < NUM_NOTES; i++) {
- diff = fabs (frequency - equal_tempered_scale[i].frequency);
- if (diff <= min_diff) {
+ diff = frequency - equal_tempered_scale[i].frequency;
+ if (fabs (diff) <= fabs (min_diff)) {
min_diff = diff;
j = i;
} else {
buffer =
g_strdup_printf ("Nearest note is %s with %.2f Hz frequency",
equal_tempered_scale[j].name, equal_tempered_scale[j].frequency);
- gtk_label_set_text (GTK_LABEL (targetFrequency), buffer);
+ gtk_label_set_text (GTK_LABEL (appdata->targetFrequency), buffer);
g_free (buffer);
buffer = g_strdup_printf ("Played frequency is %d Hz", frequency);
- gtk_label_set_text (GTK_LABEL (currentFrequency), buffer);
+ gtk_label_set_text (GTK_LABEL (appdata->currentFrequency), buffer);
g_free (buffer);
- draw_leds ((gint) roundf (min_diff));
+ draw_leds (appdata, (gint) roundf (min_diff));
}
/* receive spectral data from element message */
gint frequency;
frequency = g_value_get_int (gst_structure_get_value (s, "frequency"));
- update_frequency (frequency);
+ update_frequency (data, frequency);
}
}
/* we handled the message we want, and ignored the ones we didn't want.
}
gfloat
-keynote2freq (gint x, gint y)
+keynote2freq (AppData * appdata, gint x, gint y)
{
gint i, j, height, found;
gfloat frequency = 0;
- height = drawingarea2->allocation.height;
+ height = appdata->drawingarea2->allocation.height;
j = 0;
found = 0;
- for (i = 0; i < 15; i++) {
+ for (i = 0; i < NUM_WKEYS; i++) {
// Test for a white key
j++;
- if (between (x, i * 45, i * 45 + 44) && between (y, 0, height))
+ if (between (x, i * WKEY_WIDTH, i * WKEY_WIDTH + (WKEY_WIDTH - 1)) && between (y, 0, height))
found = j;
// Test for a black key
if (((i % 7) != 2) && ((i % 7) != 6) && (i != 14)) {
}
static gboolean
-expose_event (GtkWidget * widget, GdkEventExpose * event)
+expose_event (GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
{
+ AppData * appdata = (AppData *) user_data;
gint i;
static GdkGC *gc = NULL;
if (!gc) {
- gc = gdk_gc_new (drawingarea2->window);
+ gc = gdk_gc_new (appdata->drawingarea2->window);
}
- gdk_gc_set_rgb_fg_color (gc, &drawingarea2->style->fg[0]);
+ gdk_gc_set_rgb_fg_color (gc, &appdata->drawingarea2->style->fg[0]);
- gdk_draw_rectangle (drawingarea2->window, gc, FALSE, 0, 0,
- drawingarea2->allocation.width - 1, drawingarea2->allocation.height - 1);
+ gdk_draw_rectangle (appdata->drawingarea2->window, gc, FALSE, 0, 0,
+ NUM_WKEYS * WKEY_WIDTH, appdata->drawingarea2->allocation.height - 1);
- for (i = 0; i < 14; i++)
- gdk_draw_rectangle (drawingarea2->window, gc, FALSE, i * 45, 0,
- 45, drawingarea2->allocation.height - 1);
+ for (i = 0; i < NUM_WKEYS - 1; i++)
+ gdk_draw_rectangle (appdata->drawingarea2->window, gc, FALSE, i * WKEY_WIDTH, 0,
+ WKEY_WIDTH, appdata->drawingarea2->allocation.height - 1);
- for (i = 0; i < 14; i++) {
+ for (i = 0; i < NUM_WKEYS - 1; i++) {
if (((i % 7) != 2) && ((i % 7) != 6))
- gdk_draw_rectangle (drawingarea2->window, gc, TRUE, 24 + i * 45, 0,
- 42, drawingarea2->allocation.height / 2);
+ gdk_draw_rectangle (appdata->drawingarea2->window, gc, TRUE, 24 + i * WKEY_WIDTH, 0,
+ 42, appdata->drawingarea2->allocation.height / 2);
}
return FALSE;
}
static gboolean
-key_press_event (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
+button_press_event (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
{
- GstElement *piano = GST_ELEMENT (user_data);
+ AppData * appdata = (AppData *) user_data;
if (event->button == 1) {
- g_object_set (piano, "freq", (gdouble) keynote2freq (event->x, event->y),
+ g_object_set (appdata->tonesrc, "freq", (gdouble) keynote2freq (appdata, event->x, event->y),
"volume", 0.8, NULL);
}
}
static gboolean
-key_release_event (GtkWidget * widget, GdkEventButton * event,
+button_release_event (GtkWidget * widget, GdkEventButton * event,
gpointer user_data)
{
- GstElement *piano = GST_ELEMENT (user_data);
+ AppData * appdata = (AppData *) user_data;
if (event->button == 1) {
- g_object_set (piano, "volume", 0.0, NULL);
+ g_object_set (appdata->tonesrc, "volume", 0.0, NULL);
}
return TRUE;
}
+static void
+set_pipeline_states (AppData * appdata, GstState state)
+{
+ if (appdata->bin1)
+ gst_element_set_state (appdata->bin1, state);
+
+ if (appdata->bin2)
+ gst_element_set_state (appdata->bin2, state);
+}
+
+static gboolean
+stop_pipelines (gpointer user_data)
+{
+ AppData * appdata = (AppData *) user_data;
+
+ /* dsppcmsrc needs to go to READY or NULL state to make
+ * the DSP sleep and OMAP reach retention mode */
+ set_pipeline_states (appdata, GST_STATE_READY);
+ appdata->stop_timer_id = 0;
+
+ return FALSE;
+}
+
+#ifdef MAEMO
+static void
+osso_hw_state_cb (osso_hw_state_t *state, gpointer user_data)
+{
+ AppData * appdata = (AppData *) user_data;
+
+ if (state->shutdown_ind) {
+ gtk_main_quit ();
+ return;
+ }
+
+ if (state->system_inactivity_ind) {
+ /* do not stop pipelines if the app is on foreground
+ * and display is kept on */
+ if (appdata->display_timer_id == 0) {
+ if (appdata->stop_timer_id != 0)
+ g_source_remove (appdata->stop_timer_id);
+
+ appdata->stop_timer_id = g_timeout_add (5000, (GSourceFunc) stop_pipelines, user_data);
+ }
+ }
+ else {
+#if HILDON == 1
+ if (hildon_program_get_is_topmost (HILDON_PROGRAM (appdata->app))) {
+ if (appdata->stop_timer_id != 0) {
+ g_source_remove (appdata->stop_timer_id);
+ appdata->stop_timer_id = 0;
+ }
+
+ set_pipeline_states (appdata, GST_STATE_PLAYING);
+ }
+ /* not topmost => topmost_notify will set pipelines to PLAYING
+ * when the application is on the foreground again */
+#else
+ if (appdata->stop_timer_id != 0) {
+ g_source_remove (appdata->stop_timer_id);
+ appdata->stop_timer_id = 0;
+ }
+
+ set_pipeline_states (appdata, GST_STATE_PLAYING);
+#endif
+
+ }
+}
+#endif /* MAEMO */
+
+#if HILDON == 1
+static gboolean
+display_keepalive (gpointer user_data)
+{
+ AppData * appdata = (AppData *) user_data;
+
+ /* first (direct) call: call blanking_pause and set up timer */
+ if (appdata->display_timer_id == 0) {
+ osso_display_blanking_pause (appdata->osso_context);
+ appdata->display_timer_id = g_timeout_add (55000, (GSourceFunc) display_keepalive, user_data);
+ return TRUE; /* does not really matter */
+ }
+
+ /* callback from main loop */
+ if (hildon_program_get_is_topmost (HILDON_PROGRAM (appdata->app))) {
+ osso_display_blanking_pause (appdata->osso_context);
+ return TRUE;
+ }
+ /* else */
+ appdata->display_timer_id = 0;
+ return FALSE;
+}
+
+static gboolean
+topmost_notify (GObject * object, GParamSpec * pspec, gpointer user_data)
+{
+ AppData * appdata = (AppData *) user_data;
+
+ if (hildon_program_get_is_topmost (HILDON_PROGRAM (object))) {
+ /* cancel pipeline stop timer if it is ticking */
+ if (appdata->stop_timer_id != 0) {
+ g_source_remove (appdata->stop_timer_id);
+ appdata->stop_timer_id = 0;
+ }
+
+ set_pipeline_states (appdata, GST_STATE_PLAYING);
+
+ /* keep display on */
+ if (appdata->display_timer_id == 0)
+ display_keepalive (user_data);
+ }
+ else {
+ /* pause pipelines so that we don't update the UI needlessly */
+ set_pipeline_states (appdata, GST_STATE_PAUSED);
+ /* 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;
+ }
+ }
+
+ return FALSE;
+}
+#endif
+
int
main (int argc, char *argv[])
{
+ AppData * appdata = NULL;
#ifdef HILDON
#if defined(MAEMO1)
HildonApp *app = NULL;
HildonProgram *app = NULL;
HildonWindow *view = NULL;
#endif
- osso_context_t *osso_context = NULL; /* handle to osso */
+ osso_hw_state_t hw_state_mask = { TRUE, FALSE, FALSE, TRUE, 0 };
#endif
- GstElement *bin1, *bin2;
- GstElement *src1, *pitch, *sink1;
- GstElement *src2, *sink2;
+ GstElement *src1, *src2, *pitch, *sink1;
+ GstElement *sink2;
GstBus *bus;
+ GtkWidget *mainWin;
GtkWidget *mainBox;
GtkWidget *box;
GtkWidget *label;
#endif
gboolean piano_enabled = TRUE;
+ appdata = g_new0(AppData, 1);
+
/* Init GStreamer */
gst_init (&argc, &argv);
/* Register the GStreamer plugins */
g_set_application_name ("Tuner Tool");
#endif
+ appdata->app = app;
+
/* Initialize maemo application */
- osso_context = osso_initialize (OSSO_PACKAGE, OSSO_VERSION, TRUE, NULL);
+ appdata->osso_context = osso_initialize (OSSO_PACKAGE, OSSO_VERSION, TRUE, NULL);
/* Check that initialization was ok */
- if (osso_context == NULL) {
+ if (appdata->osso_context == NULL) {
g_print ("Bummer, osso failed\n");
}
- g_assert (osso_context);
+ g_assert (appdata->osso_context);
+
+ /* could use also display_event_cb but it is available only from chinook onwards */
+ 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!");
mainBox = gtk_vbox_new (FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (mainBox), 0);
#else
view = HILDON_WINDOW (hildon_window_new ());
mainWin = GTK_WIDGET (view);
+ g_signal_connect (G_OBJECT (app), "notify::is-topmost", G_CALLBACK (topmost_notify), appdata);
#endif
#else
mainWin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
#endif
/* Bin for tuner functionality */
- bin1 = gst_pipeline_new ("bin1");
+ 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), "nfft", 8000, "message", TRUE, "minfreq", 10,
- "maxfreq", 4000, "interval", GST_SECOND, NULL);
+ g_object_set (G_OBJECT (pitch), "message", TRUE, "minfreq", 10,
+ "maxfreq", 4000, NULL);
sink1 = gst_element_factory_make ("fakesink", "sink1");
g_object_set (G_OBJECT (sink1), "silent", 1, NULL);
- gst_bin_add_many (GST_BIN (bin1), src1, pitch, sink1, NULL);
+ gst_bin_add_many (GST_BIN (appdata->bin1), src1, pitch, sink1, NULL);
if (!gst_element_link_many (src1, pitch, sink1, NULL)) {
fprintf (stderr, "cant link elements\n");
exit (1);
}
- bus = gst_element_get_bus (bin1);
- gst_bus_add_watch (bus, message_handler, NULL);
+ bus = gst_element_get_bus (appdata->bin1);
+ gst_bus_add_watch (bus, message_handler, appdata);
gst_object_unref (bus);
/* Bin for piano functionality */
- bin2 = gst_pipeline_new ("bin2");
+ appdata->bin2 = gst_pipeline_new ("bin2");
//src2 = gst_element_factory_make ("audiotestsrc", "src2");
//g_object_set (G_OBJECT (src2), "volume", 0.0, "wave", 7, NULL);
g_object_set (G_OBJECT (src2), "volume", 0.0, NULL);
sink2 = gst_element_factory_make (DEFAULT_AUDIOSINK, "sink2");
- gst_bin_add_many (GST_BIN (bin2), src2, sink2, NULL);
+ gst_bin_add_many (GST_BIN (appdata->bin2), src2, sink2, NULL);
if (!gst_element_link_many (src2, sink2, NULL)) {
piano_enabled = FALSE;
}
+ appdata->tonesrc = src2;
+
/* GUI */
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);
/* Note label */
- targetFrequency = gtk_label_new ("");
- gtk_box_pack_start (GTK_BOX (mainBox), targetFrequency, FALSE, FALSE, 5);
+ appdata->targetFrequency = gtk_label_new ("");
+ gtk_box_pack_start (GTK_BOX (mainBox), appdata->targetFrequency, FALSE, FALSE, 5);
/* Leds */
- drawingarea1 = gtk_drawing_area_new ();
- gtk_widget_set_size_request (drawingarea1, 636, 40);
- gtk_box_pack_start (GTK_BOX (mainBox), drawingarea1, FALSE, FALSE, 5);
+ appdata->drawingarea1 = gtk_drawing_area_new ();
+ gtk_widget_set_size_request (appdata->drawingarea1, 636, 40);
+ gtk_box_pack_start (GTK_BOX (mainBox), appdata->drawingarea1, FALSE, FALSE, 5);
/* Current frequency lable */
- currentFrequency = gtk_label_new ("");
- gtk_box_pack_start (GTK_BOX (mainBox), currentFrequency, FALSE, FALSE, 5);
+ appdata->currentFrequency = gtk_label_new ("");
+ gtk_box_pack_start (GTK_BOX (mainBox), appdata->currentFrequency, FALSE, FALSE, 5);
/* Calibration spinner */
box = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (mainBox), label, FALSE, FALSE, 5);
/* Piano keyboard */
- drawingarea2 = gtk_drawing_area_new ();
- gtk_widget_set_size_request (drawingarea2, 636, 130);
- gtk_box_pack_start (GTK_BOX (mainBox), drawingarea2, FALSE, FALSE, 5);
+ alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
+ appdata->drawingarea2 = gtk_drawing_area_new ();
+ gtk_widget_set_size_request (appdata->drawingarea2, NUM_WKEYS * WKEY_WIDTH + 1, 130);
+ gtk_container_add (GTK_CONTAINER (alignment), appdata->drawingarea2);
+ gtk_box_pack_start (GTK_BOX (mainBox), alignment, FALSE, FALSE, 5);
- g_signal_connect (G_OBJECT (drawingarea2), "expose_event",
- G_CALLBACK (expose_event), NULL);
+ g_signal_connect (G_OBJECT (appdata->drawingarea2), "expose_event",
+ G_CALLBACK (expose_event), appdata);
if (piano_enabled) {
- g_signal_connect (G_OBJECT (drawingarea2), "button_press_event",
- G_CALLBACK (key_press_event), (gpointer) src2);
+ g_signal_connect (G_OBJECT (appdata->drawingarea2), "button_press_event",
+ G_CALLBACK (button_press_event), (gpointer) appdata);
- g_signal_connect (G_OBJECT (drawingarea2), "button_release_event",
- G_CALLBACK (key_release_event), (gpointer) src2);
+ g_signal_connect (G_OBJECT (appdata->drawingarea2), "button_release_event",
+ G_CALLBACK (button_release_event), (gpointer) appdata);
- gtk_widget_set_events (drawingarea2, GDK_EXPOSURE_MASK
+ gtk_widget_set_events (appdata->drawingarea2, GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
} else {
- gtk_widget_set_events (drawingarea2, GDK_EXPOSURE_MASK);
+ gtk_widget_set_events (appdata->drawingarea2, GDK_EXPOSURE_MASK);
}
#ifdef HILDON
gtk_container_add (GTK_CONTAINER (view), mainBox);
gtk_widget_show_all (GTK_WIDGET (mainWin));
#endif
- gst_element_set_state (bin1, GST_STATE_PLAYING);
- gst_element_set_state (bin2, GST_STATE_PLAYING);
+ set_pipeline_states (appdata, GST_STATE_PLAYING);
+ display_keepalive (appdata);
gtk_main ();
- gst_element_set_state (bin2, GST_STATE_NULL);
- gst_element_set_state (bin1, GST_STATE_NULL);
+ set_pipeline_states (appdata, GST_STATE_NULL);
- gst_object_unref (bin1);
- gst_object_unref (bin2);
+ gst_object_unref (appdata->bin1);
+ gst_object_unref (appdata->bin2);
return 0;
}