11 G_DEFINE_TYPE(Audio, audio, GTK_TYPE_FRAME);
13 EB_Error_Code audio_save_wave(RESULT *res, gchar *file)
15 char binary_data[EB_SIZE_PAGE];
16 EB_Error_Code error_code;
17 EB_Position end_position;
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)
26 end_position.offset -= EB_SIZE_PAGE;
29 error_code = eb_set_binary_wave(res->binfo->book, &res->pos, &end_position);
30 if (error_code != EB_SUCCESS)
32 LOG(LOG_CRITICAL, "Failed to set binary wave: %s", eb_error_message(error_code));
36 fp = fopen(file, "wb");
39 LOG(LOG_CRITICAL, "Failed to open file : %s", file);
40 return EB_ERR_BAD_FILE_NAME;
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)
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))
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);
60 write_len = fwrite(binary_data, read_len, 1, fp);
65 void audio_save_as(GtkWidget *w, gpointer data)
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);
71 RESULT *res = (RESULT*)data;
72 if(audio_save_wave(res, path) != EB_SUCCESS)
73 LOG(LOG_WARNING, _("Failed to save audio"));
78 gboolean audio_context_menu(GtkWidget *w, GdkEventButton *event, gpointer user_data)
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());
90 #ifdef ENABLE_GSTREAMER
92 gboolean audio_bus_cb(GstBus *bus, GstMessage *msg, gpointer data)
94 GstElement *pipeline = GST_ELEMENT(data);
95 switch (GST_MESSAGE_TYPE (msg))
99 gst_element_set_state(pipeline, GST_STATE_NULL);
100 gst_object_unref(GST_OBJECT (pipeline));
104 case GST_MESSAGE_ERROR:
109 gst_message_parse_error(msg, &error, &debug);
112 LOG(LOG_INFO, "%s\n", error->message);
124 static void audio_pad_added_cb(GstElement *dec, GstPad *pad, gpointer data)
126 GstElement *sink = (GstElement*)data;
127 GstPad *sinkpad = gst_element_get_pad(sink, "sink");
129 gst_pad_link(pad, sinkpad);
130 gst_object_unref(sinkpad);
133 void audio_play(GtkWidget *w, gpointer data)
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;
139 gst_bus_add_watch(bus, audio_bus_cb, (gpointer)pipeline);
140 gst_object_unref(bus);
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");
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);
151 gst_element_set_state(pipeline, GST_STATE_PLAYING);
156 static void audio_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec)
158 Audio *self = AUDIO(object);
163 res = g_value_get_pointer(value);
164 g_signal_connect(G_OBJECT(self->save_btn), "clicked", G_CALLBACK(audio_save_as), res);
166 g_signal_connect(G_OBJECT(self->play_btn), "clicked", G_CALLBACK(audio_play), res);
169 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
174 static void audio_class_init(AudioClass *klass)
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));
181 static void audio_init(Audio *self)
183 self->play_btn = NULL;
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);
193 GtkWidget *label = gtk_label_new(_("Audio"));
194 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
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);
202 void audio_render(Audio *self, RenderTextCtx *ctx)
204 GtkTextIter iter1, iter2;
205 if(render_get_last_mark(ctx, "wave", &iter1, &iter2))
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));