OSDN Git Service

add optional tree layout of the results list; [--enable-gstreamer] builds fine, yet...
[eb123/eb123.git] / src / audio.c
1
2 #include "defs.h"
3
4 #include "eb123.h"
5 #include "ebgstsrc.h"
6 #include "history.h"
7 #include "mainwnd.h"
8 #include "render.h"
9 #include "audio.h"
10
11 G_DEFINE_TYPE(Audio, audio, GTK_TYPE_FRAME);
12
13 EB_Error_Code audio_save_wave(RESULT *res, gchar *file)
14 {
15     char binary_data[EB_SIZE_PAGE];
16     EB_Error_Code error_code;
17     EB_Position end_position;
18     ssize_t read_len;
19     size_t write_len;
20     FILE *fp;
21
22     end_position.page = res->pos.page + (res->size / EB_SIZE_PAGE);
23     end_position.offset = res->pos.offset + (res->size % EB_SIZE_PAGE);
24     if (EB_SIZE_PAGE <= end_position.offset)
25     {
26         end_position.offset -= EB_SIZE_PAGE;
27         end_position.page++;
28     }
29     error_code = eb_set_binary_wave(res->binfo->book, &res->pos, &end_position);
30     if (error_code != EB_SUCCESS)
31     {
32         LOG(LOG_CRITICAL, "Failed to set binary wave: %s", eb_error_message(error_code));
33         return error_code;
34     }
35
36     fp = fopen(file, "wb");
37     if(!fp)
38     {
39         LOG(LOG_CRITICAL, "Failed to open file : %s", file);
40         return EB_ERR_BAD_FILE_NAME;
41     }
42
43     for(;;)
44     {
45         error_code = eb_read_binary(res->binfo->book, EB_SIZE_PAGE, binary_data, &read_len);
46         if(error_code != EB_SUCCESS || read_len == 0)
47         {
48             fclose(fp);
49             return error_code;
50         }
51
52         // If there are extra data (32 bytes) before fmt chunk,remove them.
53         if((strncmp("fmt ", &binary_data[44], 4) == 0) && (strncmp("fmt ", &binary_data[12], 4) != 0))
54         {
55             LOG(LOG_CRITICAL, "Warning: extra header found in WAVE data.");
56             write_len = fwrite(binary_data, 12, 1, fp);
57             write_len = fwrite(&binary_data[44], read_len - 44, 1, fp);
58         }
59         else
60             write_len = fwrite(binary_data, read_len, 1, fp);
61     }
62     return EB_SUCCESS;
63 }
64
65 void audio_save_as(GtkWidget *w, gpointer data)
66 {       
67     static gchar *path = NULL;
68     path = app_browse_disk(_("Save Audio As"), mainwnd_get_wnd(), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_SAVE_AS, path);
69     if(path)
70     {
71         RESULT *res = (RESULT*)data;
72         if(audio_save_wave(res, path) != EB_SUCCESS)
73             LOG(LOG_WARNING, _("Failed to save audio"));
74     }
75
76 }
77
78 gboolean audio_context_menu(GtkWidget *w, GdkEventButton *event, gpointer user_data)
79 {
80     if(event->button != 3) return FALSE;
81     GtkWidget *menu = gtk_menu_new(), *item;
82     item = gtk_image_menu_item_new_from_stock(GTK_STOCK_SAVE_AS, NULL);
83     g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(audio_save_as), user_data);
84     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
85     gtk_widget_show_all(menu);
86     gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
87     return TRUE;
88 }
89
90 #ifdef ENABLE_GSTREAMER
91
92 gboolean audio_bus_cb(GstBus *bus, GstMessage *msg, gpointer data)
93 {
94     GstElement *pipeline = GST_ELEMENT(data);
95     switch (GST_MESSAGE_TYPE (msg))
96     {
97         case GST_MESSAGE_EOS:
98         {
99             gst_element_set_state(pipeline, GST_STATE_NULL);
100             gst_object_unref(GST_OBJECT (pipeline));
101             break;
102         }
103
104         case GST_MESSAGE_ERROR:
105         {
106             gchar  *debug;
107             GError *error;
108
109             gst_message_parse_error(msg, &error, &debug);
110             g_free(debug);
111
112             LOG(LOG_INFO, "%s\n", error->message);
113             g_error_free(error);
114
115             break;
116         }
117          default:
118             break;
119     }
120
121     return TRUE;
122 }
123
124 static void audio_pad_added_cb(GstElement *dec, GstPad *pad, gpointer data)
125 {
126     GstElement *sink = (GstElement*)data;
127     GstPad *sinkpad = gst_element_get_pad(sink, "sink");
128
129     gst_pad_link(pad, sinkpad);
130     gst_object_unref(sinkpad);
131 }
132
133 void audio_play(GtkWidget *w, gpointer data)
134 {
135     GstElement *src, *dec, *sink, *pipeline = gst_pipeline_new ("pipeline");
136     GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE (pipeline));
137     RESULT *res = (RESULT*)data;
138
139     gst_bus_add_watch(bus, audio_bus_cb, (gpointer)pipeline);
140     gst_object_unref(bus);
141
142     src = g_object_new(EB_GST_TYPE_SRC, NULL);
143     EB_GST_SRC(src)->res = res;
144     dec = gst_element_factory_make("wavparse", "decoder");
145     sink = gst_element_factory_make("alsasink", "sink");
146
147     gst_bin_add_many(GST_BIN(pipeline), src, dec, sink, NULL);
148     gst_element_link(src, dec);
149     g_signal_connect(dec, "pad-added", G_CALLBACK(audio_pad_added_cb), sink);
150
151     gst_element_set_state(pipeline, GST_STATE_PLAYING);
152 }
153
154 #endif
155
156 static void audio_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec)
157 {
158     Audio *self = AUDIO(object);
159     RESULT *res;
160     switch(param_id)
161     {
162         case 1:
163             res = g_value_get_pointer(value);
164             g_signal_connect(G_OBJECT(self->save_btn), "clicked", G_CALLBACK(audio_save_as), res);
165             if(self->play_btn)
166                 g_signal_connect(G_OBJECT(self->play_btn), "clicked", G_CALLBACK(audio_play), res);
167             break;
168         default:
169             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
170             break;
171     }
172 }
173
174 static void audio_class_init(AudioClass *klass)
175 {
176     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
177     gobject_class->set_property = audio_set_property;
178     g_object_class_install_property(gobject_class, 1, g_param_spec_pointer("link", _("Link"), _("Link"), G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
179 }
180
181 static void audio_init(Audio *self)
182 {
183     self->play_btn = NULL;
184     GtkWidget *img;
185     GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
186     gtk_container_add(GTK_CONTAINER(self), hbox);
187 #ifdef ENABLE_GSTREAMER
188     self->play_btn = gtk_button_new();
189     img = gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_SMALL_TOOLBAR);
190     gtk_button_set_image(GTK_BUTTON(self->play_btn), img);
191     gtk_box_pack_start(GTK_BOX(hbox), self->play_btn, FALSE, TRUE, 0);
192 #else
193     GtkWidget *label = gtk_label_new(_("Audio"));
194     gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
195 #endif
196     self->save_btn = gtk_button_new();
197     img = gtk_image_new_from_stock(GTK_STOCK_SAVE_AS, GTK_ICON_SIZE_SMALL_TOOLBAR);
198     gtk_container_add(GTK_CONTAINER(self->save_btn), img);
199     gtk_box_pack_start(GTK_BOX(hbox), self->save_btn, FALSE, TRUE, 0);
200 }
201
202 void audio_render(Audio *self, RenderTextCtx *ctx)
203 {
204     GtkTextIter iter1, iter2;
205     if(render_get_last_mark(ctx, "wave", &iter1, &iter2))
206     {
207         gtk_text_buffer_delete(ctx->buf, &iter1, &iter2);
208         gtk_text_buffer_get_end_iter(ctx->buf, &iter1);
209         gtk_text_buffer_insert(ctx->buf, &iter1, "\n", -1);
210         gtk_text_buffer_get_end_iter(ctx->buf, &iter1);
211         GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(ctx->buf, &iter1);
212         gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(ctx->view), GTK_WIDGET(self), anchor);
213         gtk_text_buffer_insert(ctx->buf, &iter1, "\n", -1);
214         g_object_set_data_full(G_OBJECT(self), "audio", ctx->link, result_free);
215         gtk_widget_show_all(GTK_WIDGET(self));
216         gtk_widget_realize(GTK_WIDGET(self));
217     }
218 }
219