]> err.no Git - mapper/blobdiff - src/audio-note.c
Move ProgressUpdateInfo struct
[mapper] / src / audio-note.c
index 46370529cce284a00868755d6ee3319fe89d8fbb..8b4e26866c1195a4a9e386753abed4370a11738f 100644 (file)
 #include "ui-common.h"
 #include "audio.h"
 #include "audio-note.h"
+#include "settings.h"
+#include "dialogs.h"
 
 static note_pipeline note_play;
 static note_pipeline note_record;
 static GstBus *bus;
-static gchar *cfile=NULL;
+
+static gboolean audio_note_stop(audio_note_ui *ui);
+
+#define GST_TIME_TO_SECS(t) \
+       (gdouble) (((gdouble)(t)) / (gdouble) GST_SECOND) /* GST_SECOND should be 1e9 */
+
+#define NOTES_BASEDIR_MMC1 "/media/mmc1/MapperAudioNotes"
+#define NOTES_BASEDIR_MMC2 "/media/mmc2/MapperAudioNotes"
+
+static void
+audio_note_set_length(audio_note_ui *ui, gdouble secs)
+{
+gchar buffer[16];
+guint min=0;
+
+if (secs<0.0) {
+       gtk_label_set_text(GTK_LABEL(ui->lbl_time), "--:--");
+       return;
+}
+
+if (secs>=60.0) {
+       min=secs/60.0;
+       secs-=min*60.0;
+}
+
+g_snprintf(buffer, sizeof(buffer), "%u:%05.2f", min, secs);
+gtk_label_set_text(GTK_LABEL(ui->lbl_time), buffer);
+}
+
+static gboolean
+audio_note_position_cb(gpointer data)
+{
+GstFormat fmt=GST_FORMAT_TIME;
+GstElement *pipe;
+gint64 pos, len;
+audio_note_ui *ui=(audio_note_ui *)data;
+
+if (ui->note_record->active)
+       pipe=ui->note_record->pipeline;
+else
+       if (ui->note_play->active)
+               pipe=ui->note_play->pipeline;
+else
+       return TRUE;
+
+if (gst_element_query_position(pipe, &fmt, &pos) && gst_element_query_duration(pipe, &fmt, &len)) {
+       audio_note_set_length(ui, GST_TIME_TO_SECS(pos));
+}
+
+return TRUE;
+}
+
+static void
+audio_note_position_display(audio_note_ui *ui, gboolean ena)
+{
+if (ui->pos_sid!=0) {
+       g_source_remove(ui->pos_sid);
+       ui->pos_sid=0;
+}
+if (ena)
+       ui->pos_sid=g_timeout_add(250, (GSourceFunc)audio_note_position_cb, ui);
+}
 
 static gboolean
 audio_note_record_cb(GtkWidget *widget, gpointer data)
 {
-const gchar *basedir;
 gchar buffer[128];
 audio_note_ui *ui=(audio_note_ui *)data;
-GDate *gd;
 time_t t;
 struct tm *tmp;
 
-/* XXX: Make this a configuration option */
-#ifdef WITH_DEVICE_770
-basedir="/media/mmc1/MapperAudioNotes";
-if (g_mkdir_with_parents(basedir, 0775)==-1) {
-       MACRO_BANNER_SHOW_INFO(_window, _("Failed to create directory for sound files!"));
-       return TRUE;
-}
-#else
-basedir=g_get_home_dir();
-#endif
-
 t=time(NULL);
 tmp=localtime(&t);
 if (tmp == NULL) {
        MACRO_BANNER_SHOW_INFO(_window, _("Failed to get timestamp for file!"));
        return TRUE;
 }
-strftime(buffer, sizeof(buffer), "%Y-%m-%d-%H:%M:%S", tmp);
 
-if (cfile)
-       g_free(cfile);
+/* Bah, stupid FAT can't use : in filenames */
+strftime(buffer, sizeof(buffer), "%Y-%m-%d-%H%M%S", tmp);
 
-cfile=g_strdup_printf("%s/an-%s.wav", basedir, buffer);
+if (ui->cfile)
+       g_free(ui->cfile);
 
-audio_note_record(cfile);
+ui->cfile=g_strdup_printf("%s/an-%s.wav", ui->basedir, buffer);
 
-MACRO_BANNER_SHOW_INFO(_window, _("Recording..."));
+if (audio_note_record(ui->cfile)==TRUE) {
+       audio_note_position_display(ui, TRUE);
+       MACRO_BANNER_SHOW_INFO(_window, _("Recording..."));
+       gtk_widget_set_sensitive(ui->btn_play, FALSE);
+       gtk_widget_set_sensitive(ui->btn_record, FALSE);
+       gtk_widget_set_sensitive(ui->btn_stop, TRUE);
+} else {
+       popup_error(_window, _("Failed to start recording."));
+}
 
 return TRUE;
 }
@@ -82,16 +140,36 @@ audio_note_play_cb(GtkWidget *widget, gpointer data)
 {
 audio_note_ui *ui=(audio_note_ui *)data;
 
-audio_note_play(cfile);
-MACRO_BANNER_SHOW_INFO(_window, _("Playing..."));
+if (!ui->cfile) {
+       MACRO_BANNER_SHOW_INFO(_window, _("No active audio note. Record something first."));
+       return TRUE;
+}
+
+if (audio_note_play(ui->cfile)==TRUE) {
+       audio_note_position_display(ui, TRUE);
+       MACRO_BANNER_SHOW_INFO(_window, _("Playing..."));
+       gtk_widget_set_sensitive(ui->btn_play, FALSE);
+       gtk_widget_set_sensitive(ui->btn_record, FALSE);
+       gtk_widget_set_sensitive(ui->btn_stop, TRUE);
+} else {
+       popup_error(_window, _("Failed to start playing."));
+}
 return TRUE;
 }
 
 static gboolean
 audio_note_stop_cb(GtkWidget *widget, gpointer data)
 {
-if (audio_note_stop()==TRUE)
+audio_note_ui *ui=(audio_note_ui *)data;
+
+if (audio_note_stop(ui)==TRUE)
        MACRO_BANNER_SHOW_INFO(_window, _("Stopped..."));
+
+audio_note_position_display(ui, FALSE);
+gtk_widget_set_sensitive(ui->btn_record, TRUE);
+gtk_widget_set_sensitive(ui->btn_play, TRUE);
+gtk_widget_set_sensitive(ui->btn_stop, FALSE);
+
 return TRUE;
 }
 
@@ -99,20 +177,48 @@ audio_note_ui *
 audio_note_new(void)
 {
 audio_note_ui *ui;
+GtkWidget *v;
+
 ui=g_slice_new(audio_note_ui);
-ui->vbox=gtk_vbox_new(FALSE, 0);
+ui->pos_sid=0;
+ui->cfile=NULL;
+
+ui->vbox=gtk_vbox_new(FALSE, 3);
+v=gtk_vbox_new(FALSE, 3);
+ui->hbox=gtk_hbox_new(FALSE, 3);
 ui->lbl_time=gtk_label_new("");
+
 ui->btn_record=gtk_button_new_from_stock(GTK_STOCK_MEDIA_RECORD);
 ui->btn_play=gtk_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
 ui->btn_stop=gtk_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
 
-gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_time, TRUE, TRUE, 0);
-gtk_box_pack_start(GTK_BOX(ui->vbox), ui->btn_record, TRUE, TRUE, 0);
-gtk_box_pack_start(GTK_BOX(ui->vbox), ui->btn_play, TRUE, TRUE, 0);
-gtk_box_pack_start(GTK_BOX(ui->vbox), ui->btn_stop, TRUE, TRUE, 0);
+ui->file_tree=gtk_tree_view_new();
+
+gtk_widget_set_sensitive(ui->btn_play, FALSE);
+gtk_widget_set_sensitive(ui->btn_stop, FALSE);
+
+gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_time, FALSE, FALSE, 0);
+gtk_box_pack_start(GTK_BOX(ui->vbox), ui->hbox, TRUE, TRUE, 0);
+
+gtk_box_pack_start(GTK_BOX(v), ui->btn_record, TRUE, TRUE, 0);
+gtk_box_pack_start(GTK_BOX(v), ui->btn_play, TRUE, TRUE, 0);
+gtk_box_pack_start(GTK_BOX(v), ui->btn_stop, TRUE, TRUE, 0);
+
+gtk_box_pack_start(GTK_BOX(ui->hbox), ui->file_tree, TRUE, TRUE, 0);
+gtk_box_pack_start(GTK_BOX(ui->hbox), v, TRUE, TRUE, 0);
+
+gtk_label_set_text(GTK_LABEL(ui->lbl_time), "--:--");
 
 ui->note_play=&note_play;
 ui->note_record=&note_record;
+ui->basedir=NULL;
+
+/* XXX: Make this a configuration option */
+#ifdef WITH_DEVICE_770
+audio_note_set_basedir(ui, NOTES_BASEDIR_MMC1);
+#else
+audio_note_set_basedir(ui, g_get_home_dir());
+#endif
 
 g_signal_connect(G_OBJECT(ui->btn_record), "clicked", G_CALLBACK(audio_note_record_cb), ui);
 g_signal_connect(G_OBJECT(ui->btn_play), "clicked", G_CALLBACK(audio_note_play_cb), ui);
@@ -121,6 +227,16 @@ g_signal_connect(G_OBJECT(ui->btn_stop), "clicked", G_CALLBACK(audio_note_stop_c
 return ui;
 }
 
+void
+audio_note_set_basedir(audio_note_ui *ui, const gchar *basedir)
+{
+if (ui->basedir)
+       g_free(ui->basedir);
+ui->basedir=g_strdup(basedir);
+if (g_mkdir_with_parents(ui->basedir, 0775)==-1) {
+}
+}
+
 static gboolean
 audio_note_bus_cb(GstBus *bus, GstMessage *msg, gpointer data)
 {
@@ -151,17 +267,34 @@ return TRUE;
 }
 
 static gboolean
-audio_create_pipeline(note_pipeline *np, gboolean rec)
+audio_new_pad_cb(GstElement *wavparse, GstPad *new_pad, gpointer data)
 {
-np->pipeline=gst_pipeline_new("pipeline");
-bus=gst_pipeline_get_bus(GST_PIPELINE(np->pipeline));
-gst_bus_add_watch(bus, audio_note_bus_cb, np);
+GstElement *sink=(GstElement *)data;
+
+if (!gst_element_link(wavparse, sink))
+               g_printerr("Failed to link wavparse to sink\n");
 
+gst_element_sync_state_with_parent(sink);
+
+return FALSE;
+}
+
+static gboolean
+audio_create_pipeline(note_pipeline *np, gboolean rec)
+{
 if (rec==TRUE) {
        g_debug("GST: Creating record pipeline");
-       np->src=gst_element_factory_make(AUDIO_SRC, "source");
-       np->filter=gst_element_factory_make("wavenc", "filter");
-       np->sink=gst_element_factory_make("filesink", "sink");
+       np->pipeline=gst_pipeline_new("rpipeline");
+       g_assert(np->pipeline);
+
+       np->src=gst_element_factory_make(AUDIO_SRC, "asource");
+       g_assert(np->src);
+
+       np->filter=gst_element_factory_make("wavenc", "wavfilter");
+       g_assert(np->filter);
+
+       np->sink=gst_element_factory_make("filesink", "fsink");
+       g_assert(np->sink);
 
        gst_bin_add_many(GST_BIN(np->pipeline), np->src, np->filter, np->sink, NULL);
 
@@ -180,19 +313,35 @@ if (rec==TRUE) {
                gst_element_link(np->src, np->filter);
        gst_caps_unref(np->srccaps);
 #else
-       gst_element_link(np->src, np->filter);  
+       if (!gst_element_link(np->src, np->filter))
+               g_printerr("Failed to link source to filter\n");
 #endif
-       gst_element_link(np->filter, np->sink);
-
+       if (!gst_element_link(np->filter, np->sink))
+               g_printerr("Failed to link filter to source\n");
 } else {
        g_debug("GST: Creating playback pipeline");
-       np->src=gst_element_factory_make("filesrc", "source");
-       np->filter=gst_element_factory_make("wavparse", "filter");
-       np->sink=gst_element_factory_make(AUDIO_SINK, "sink");
+       np->pipeline=gst_pipeline_new("ppipeline");
+       g_assert(np->pipeline);
+
+       np->src=gst_element_factory_make("filesrc", "fsource");
+       g_assert(np->src);
+
+       np->filter=gst_element_factory_make("wavparse", "wavparse");
+       g_assert(np->filter);
+
+       np->sink=gst_element_factory_make(AUDIO_SINK, "asink");
+       g_assert(np->sink);
+
        gst_bin_add_many(GST_BIN(np->pipeline), np->src, np->filter, np->sink, NULL);
-       if (!gst_element_link_many(np->src, np->filter, np->sink, NULL))
-               g_printerr("Failed to link play pipeline\n");
+
+       if (!gst_element_link(np->src, np->filter))
+               g_printerr("Failed to link source to filter\n");
+
+       g_signal_connect(np->filter, "pad_added", G_CALLBACK(audio_new_pad_cb), np->sink);
 }
+bus=gst_pipeline_get_bus(GST_PIPELINE(np->pipeline));
+gst_bus_add_watch(bus, audio_note_bus_cb, np);
+gst_object_unref(bus);
 np->rec=rec;
 np->active=FALSE;
 return TRUE;
@@ -245,22 +394,26 @@ note_record.active=TRUE;
 return TRUE;
 }
 
-gboolean
-audio_note_stop()
+static gboolean
+audio_note_stop(audio_note_ui *ui)
 {
 GstState current;
 GstState pending;
 
+audio_note_position_display(ui, FALSE);
+
 gst_element_get_state(note_record.pipeline, &current, &pending, GST_CLOCK_TIME_NONE);
 if (current==GST_STATE_PLAYING) {
-       gst_element_set_state(note_record.pipeline, GST_STATE_PAUSED);
+       g_debug("Stop: recording");
+       gst_element_set_state(note_record.pipeline, GST_STATE_NULL);
        note_record.active=FALSE;
        return TRUE;
 }
 
 gst_element_get_state(note_play.pipeline, &current, &pending, GST_CLOCK_TIME_NONE);
 if (current==GST_STATE_PLAYING) {
-       gst_element_set_state(note_play.pipeline, GST_STATE_PAUSED);
+       g_debug("Stop: playing");
+       gst_element_set_state(note_play.pipeline, GST_STATE_NULL);
        note_play.active=FALSE;
        return TRUE;
 }