1 /* wavbreaker - A tool to split a wave file up into multiple waves.
2 * Copyright (C) 2002-2006 Timothy Robinson
3 * Copyright (C) 2006-2019 Thomas Perl
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include <config.h>
21
22 #include "moodbar.h"
23 #include "popupmessage.h"
24 #include "wavbreaker.h"
25
26 #if defined(WANT_MOODBAR)
27
28 #include <errno.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <sys/wait.h>
32 #include <libgen.h>
33
34 #include <locale.h>
35 #include "gettext.h"
36
37 static pid_t moodbar_pid;
38 static gboolean moodbar_cancelled;
39 static GtkWidget *moodbar_wait_dialog;
40 static guint moodbar_update_source_id;
41 static gchar *moodbar_filename;
42
43 static void
cancel_moodbar_process(GtkWidget * widget,gpointer user_data)44 cancel_moodbar_process(GtkWidget *widget, gpointer user_data)
45 {
46 moodbar_cancelled = TRUE;
47 if (moodbar_pid != 0) {
48 kill(moodbar_pid, SIGKILL);
49 moodbar_pid = 0;
50 }
51
52 if (moodbar_filename) {
53 /* remove (partial) .mood file */
54 unlink(moodbar_filename);
55 free(moodbar_filename);
56 moodbar_filename = NULL;
57 }
58 }
59
60 static void
hide_moodbar_process(GtkWidget * widget,gpointer user_data)61 hide_moodbar_process(GtkWidget *widget, gpointer user_data)
62 {
63 gtk_widget_hide(GTK_WIDGET(user_data));
64 }
65
66 void
moodbar_abort()67 moodbar_abort()
68 {
69 cancel_moodbar_process(NULL, NULL);
70 }
71
72 static gboolean
update_moodbar_func(gpointer user_data)73 update_moodbar_func(gpointer user_data)
74 {
75 GtkWidget *child = user_data;
76
77 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(child));
78
79 int child_status;
80 if (waitpid(moodbar_pid, &child_status, WNOHANG) != 0) {
81 gtk_widget_destroy(moodbar_wait_dialog);
82 moodbar_wait_dialog = NULL;
83
84 if (child_status != 0 && !moodbar_cancelled) {
85 popupmessage_show(NULL, _("Cannot launch \"moodbar\""), _("wavbreaker could not launch the moodbar application, which is needed to generate the moodbar. You can download the moodbar package from:\n\n http://amarok.kde.org/wiki/Moodbar"));
86 }
87
88 moodbar_update_source_id = 0;
89
90 wavbreaker_update_moodbar_state();
91
92 return FALSE;
93 }
94
95 return TRUE;
96 }
97
98 static gchar *
get_moodbar_filename(const gchar * filename)99 get_moodbar_filename(const gchar *filename)
100 {
101 /* replace ".xxx" with ".mood" */
102 gchar *fn = (gchar*)malloc(strlen(filename)+2);
103 strcpy(fn, filename);
104 strcpy((gchar*)(fn+strlen(fn)-4), ".mood");
105 return fn;
106 }
107
108 void
moodbar_generate(GtkWidget * window,const gchar * filename)109 moodbar_generate(GtkWidget *window, const gchar *filename)
110 {
111 struct stat st;
112 GtkWidget *child, *cancel_button;
113
114 if (moodbar_filename) {
115 free(moodbar_filename);
116 }
117 moodbar_filename = get_moodbar_filename(filename);
118
119 if (stat(moodbar_filename, &st) == 0) {
120 return;
121 }
122
123 if (moodbar_wait_dialog != NULL) {
124 return;
125 }
126
127 moodbar_cancelled = FALSE;
128 moodbar_pid = fork();
129
130 if (moodbar_pid == 0) {
131 if (execlp("moodbar", "moodbar", "-o", moodbar_filename, filename, (char*)NULL) == -1) {
132 fprintf(stderr, "Error running moodbar: %s (Have you installed the \"moodbar\" package?)\n", strerror(errno));
133 _exit(-1);
134 }
135 } else if (moodbar_pid > 0) {
136 moodbar_wait_dialog = gtk_message_dialog_new(GTK_WINDOW(window),
137 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
138 GTK_MESSAGE_INFO,
139 GTK_BUTTONS_NONE,
140 _("Generating moodbar"));
141
142 child = gtk_progress_bar_new();
143 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(moodbar_wait_dialog))), child, FALSE, TRUE, 0);
144
145 cancel_button = gtk_button_new_with_mnemonic(_("_Hide window"));
146 g_signal_connect(G_OBJECT(cancel_button), "clicked", G_CALLBACK(hide_moodbar_process), moodbar_wait_dialog);
147 gtk_dialog_add_action_widget(GTK_DIALOG(moodbar_wait_dialog), cancel_button, -1);
148
149 cancel_button = gtk_button_new_with_mnemonic(_("_Cancel"));
150 g_signal_connect(G_OBJECT(cancel_button), "clicked", G_CALLBACK(cancel_moodbar_process), NULL);
151 gtk_dialog_add_action_widget(GTK_DIALOG(moodbar_wait_dialog), cancel_button, -1);
152
153 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(moodbar_wait_dialog),
154 _("The moodbar tool analyzes your audio file and generates a colorful representation of the audio data."));
155 gtk_window_set_title(GTK_WINDOW(moodbar_wait_dialog), _("Generating moodbar"));
156 gtk_widget_show_all(moodbar_wait_dialog);
157
158 // Update progress bar/window in idle thread
159 if (moodbar_update_source_id) {
160 g_source_remove(moodbar_update_source_id);
161 }
162 moodbar_update_source_id = g_timeout_add(500, update_moodbar_func, child);
163 } else {
164 fprintf(stderr, "fork() failed for moodbar process: %s\n", strerror(errno));
165 }
166 }
167
168 MoodbarData *
moodbar_open(const gchar * filename)169 moodbar_open(const gchar *filename)
170 {
171 gchar *fn = get_moodbar_filename(filename);
172
173 FILE *fp = fopen(fn, "rb");
174
175 if (!fp) {
176 free(fn);
177 return NULL;
178 }
179
180 MoodbarData *result = calloc(sizeof(MoodbarData), 1);
181
182 fseek(fp, 0, SEEK_END);
183 long length = ftell(fp);
184 fseek(fp, 0, SEEK_SET);
185
186 result->numFrames = length/3;
187
188 result->frames = calloc(result->numFrames, sizeof(GdkRGBA));
189
190 unsigned long pos = 0;
191
192 guchar tmp[3];
193 while (fread(&tmp, 3, 1, fp) > 0) {
194 result->frames[pos].red = (float)tmp[0]/255.f;
195 result->frames[pos].green = (float)tmp[1]/255.f;
196 result->frames[pos].blue = (float)tmp[2]/255.f;
197 pos++;
198 }
199
200 fclose(fp);
201 free(fn);
202
203 return result;
204 }
205
206 void
moodbar_free(MoodbarData * data)207 moodbar_free(MoodbarData *data)
208 {
209 free(data->frames);
210 free(data);
211 }
212
213 #else
214 void
moodbar_generate(GtkWidget * window,const gchar * filename)215 moodbar_generate(GtkWidget *window, const gchar *filename)
216 {
217 }
218
219 MoodbarData *
moodbar_open(const gchar * filename)220 moodbar_open(const gchar *filename)
221 {
222 return NULL;
223 }
224
225 void
moodbar_free(MoodbarData * data)226 moodbar_free(MoodbarData *data)
227 {
228 }
229 #endif
230