Mercurial > audlegacy
comparison Plugins/Input/timidity/src/xmms-timidity.c @ 285:d1762728ea4b trunk
[svn] Timidity support, via external contractor dai+audacious@cdr.jp.
author | nenolod |
---|---|
date | Wed, 14 Dec 2005 08:51:51 -0800 |
parents | |
children | 5ca6e39394b5 |
comparison
equal
deleted
inserted
replaced
284:763afa52f416 | 285:d1762728ea4b |
---|---|
1 /* | |
2 xmms-timidity - MIDI Plugin for XMMS | |
3 Copyright (C) 2004 Konstantin Korikov <lostclus@ua.fm> | |
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., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 */ | |
19 | |
20 #ifdef HAVE_CONFIG_H | |
21 #include <config.h> | |
22 #endif | |
23 | |
24 #include <audacious/configfile.h> | |
25 #include <audacious/titlestring.h> | |
26 #include <gtk/gtk.h> | |
27 #include <string.h> | |
28 #include <timidity.h> | |
29 | |
30 #include "xmms-timidity.h" | |
31 #include "interface.h" | |
32 | |
33 InputPlugin xmmstimid_ip = { | |
34 NULL, | |
35 NULL, | |
36 NULL, | |
37 xmmstimid_init, | |
38 xmmstimid_about, | |
39 xmmstimid_configure, | |
40 xmmstimid_is_our_file, | |
41 NULL, | |
42 xmmstimid_play_file, | |
43 xmmstimid_stop, | |
44 xmmstimid_pause, | |
45 xmmstimid_seek, | |
46 NULL, | |
47 xmmstimid_get_time, | |
48 NULL, | |
49 NULL, | |
50 xmmstimid_cleanup, | |
51 NULL, | |
52 NULL, | |
53 NULL, | |
54 NULL, | |
55 xmmstimid_get_song_info, | |
56 NULL, | |
57 NULL | |
58 }; | |
59 | |
60 static struct { | |
61 gchar *config_file; | |
62 gint rate; | |
63 gint bits; | |
64 gint channels; | |
65 gint buffer_size; | |
66 } xmmstimid_cfg; | |
67 | |
68 static gboolean xmmstimid_initialized = FALSE; | |
69 static pthread_t xmmstimid_decode_thread; | |
70 static gboolean xmmstimid_audio_error = FALSE; | |
71 static MidSongOptions xmmstimid_opts; | |
72 static MidSong *xmmstimid_song; | |
73 static gboolean xmmstimid_going; | |
74 static gboolean xmmstimid_eof; | |
75 static gint xmmstimid_seek_to; | |
76 | |
77 static GtkWidget *xmmstimid_conf_wnd = NULL, *xmmstimid_about_wnd = NULL; | |
78 static GtkEntry | |
79 *xmmstimid_conf_config_file; | |
80 static GtkToggleButton | |
81 *xmmstimid_conf_rate_11000, | |
82 *xmmstimid_conf_rate_22000, | |
83 *xmmstimid_conf_rate_44100; | |
84 static GtkToggleButton | |
85 *xmmstimid_conf_bits_8, | |
86 *xmmstimid_conf_bits_16; | |
87 static GtkToggleButton | |
88 *xmmstimid_conf_channels_1, | |
89 *xmmstimid_conf_channels_2; | |
90 | |
91 InputPlugin *get_iplugin_info(void) { | |
92 xmmstimid_ip.description = g_strdup_printf( | |
93 "TiMidity Player %s", VERSION); | |
94 return &xmmstimid_ip; | |
95 } | |
96 | |
97 void xmmstimid_init(void) { | |
98 ConfigFile *cf; | |
99 | |
100 xmmstimid_cfg.config_file = NULL; | |
101 xmmstimid_cfg.rate = 44100; | |
102 xmmstimid_cfg.bits = 16; | |
103 xmmstimid_cfg.channels = 2; | |
104 xmmstimid_cfg.buffer_size = 512; | |
105 | |
106 cf = xmms_cfg_open_default_file(); | |
107 if (cf != NULL) { | |
108 xmms_cfg_read_string(cf, "TIMIDITY", "config_file", | |
109 &xmmstimid_cfg.config_file); | |
110 xmms_cfg_read_int(cf, "TIMIDITY", "rate", | |
111 &xmmstimid_cfg.rate); | |
112 xmms_cfg_read_int(cf, "TIMIDITY", "bits", | |
113 &xmmstimid_cfg.bits); | |
114 xmms_cfg_read_int(cf, "TIMIDITY", "channels", | |
115 &xmmstimid_cfg.channels); | |
116 xmms_cfg_free(cf); | |
117 } | |
118 | |
119 if (xmmstimid_cfg.config_file == NULL) | |
120 xmmstimid_cfg.config_file = g_strdup("/etc/timidity/timidity.cfg"); | |
121 | |
122 if (mid_init(xmmstimid_cfg.config_file) != 0) { | |
123 xmmstimid_initialized = FALSE; | |
124 return; | |
125 } | |
126 xmmstimid_initialized = TRUE; | |
127 } | |
128 | |
129 void xmmstimid_about(void) { | |
130 if (xmmstimid_about_wnd == NULL) { | |
131 gchar *name_version; | |
132 xmmstimid_about_wnd = create_xmmstimid_about_wnd(); | |
133 name_version = g_strdup_printf( | |
134 "TiMidity Plugin %s", VERSION); | |
135 gtk_label_set_text( | |
136 GTK_LABEL(gtk_object_get_data( | |
137 GTK_OBJECT(xmmstimid_about_wnd), | |
138 "name_version")), name_version); | |
139 g_free(name_version); | |
140 } | |
141 | |
142 gtk_widget_show(xmmstimid_about_wnd); | |
143 gdk_window_raise(xmmstimid_about_wnd->window); | |
144 } | |
145 | |
146 void xmmstimid_conf_ok(GtkButton *button, gpointer user_data); | |
147 | |
148 void xmmstimid_configure(void) { | |
149 GtkToggleButton *tb; | |
150 if (xmmstimid_conf_wnd == NULL) { | |
151 xmmstimid_conf_wnd = create_xmmstimid_conf_wnd(); | |
152 | |
153 #define get_conf_wnd_item(type, name) \ | |
154 type (gtk_object_get_data(GTK_OBJECT(xmmstimid_conf_wnd), name)) | |
155 | |
156 xmmstimid_conf_config_file = get_conf_wnd_item( | |
157 GTK_ENTRY, "config_file"); | |
158 xmmstimid_conf_rate_11000 = get_conf_wnd_item( | |
159 GTK_TOGGLE_BUTTON, "rate_11000"); | |
160 xmmstimid_conf_rate_22000 = get_conf_wnd_item( | |
161 GTK_TOGGLE_BUTTON, "rate_22000"); | |
162 xmmstimid_conf_rate_44100 = get_conf_wnd_item( | |
163 GTK_TOGGLE_BUTTON, "rate_44100"); | |
164 xmmstimid_conf_bits_8 = get_conf_wnd_item( | |
165 GTK_TOGGLE_BUTTON, "bits_8"); | |
166 xmmstimid_conf_bits_16 = get_conf_wnd_item( | |
167 GTK_TOGGLE_BUTTON, "bits_16"); | |
168 xmmstimid_conf_channels_1 = get_conf_wnd_item( | |
169 GTK_TOGGLE_BUTTON, "channels_1"); | |
170 xmmstimid_conf_channels_2 = get_conf_wnd_item( | |
171 GTK_TOGGLE_BUTTON, "channels_2"); | |
172 | |
173 gtk_signal_connect_object( | |
174 get_conf_wnd_item(GTK_OBJECT, "conf_ok"), | |
175 "clicked", GTK_SIGNAL_FUNC(xmmstimid_conf_ok), | |
176 NULL); | |
177 } | |
178 | |
179 gtk_entry_set_text(xmmstimid_conf_config_file, | |
180 xmmstimid_cfg.config_file); | |
181 switch (xmmstimid_cfg.rate) { | |
182 case 11000: tb = xmmstimid_conf_rate_11000; break; | |
183 case 22000: tb = xmmstimid_conf_rate_22000; break; | |
184 case 44100: tb = xmmstimid_conf_rate_44100; break; | |
185 default: tb = NULL; | |
186 } | |
187 if (tb != NULL) gtk_toggle_button_set_active(tb, TRUE); | |
188 switch (xmmstimid_cfg.bits) { | |
189 case 8: tb = xmmstimid_conf_bits_8; break; | |
190 case 16: tb = xmmstimid_conf_bits_16; break; | |
191 default: tb = NULL; | |
192 } | |
193 if (tb != NULL) gtk_toggle_button_set_active(tb, TRUE); | |
194 switch (xmmstimid_cfg.channels) { | |
195 case 1: tb = xmmstimid_conf_channels_1; break; | |
196 case 2: tb = xmmstimid_conf_channels_2; break; | |
197 default: tb = NULL; | |
198 } | |
199 if (tb != NULL) gtk_toggle_button_set_active(tb, TRUE); | |
200 | |
201 gtk_widget_show(xmmstimid_conf_wnd); | |
202 gdk_window_raise(xmmstimid_conf_wnd->window); | |
203 } | |
204 | |
205 void xmmstimid_conf_ok(GtkButton *button, gpointer user_data) { | |
206 gchar *config_file, *filename; | |
207 ConfigFile *cf; | |
208 | |
209 g_free(xmmstimid_cfg.config_file); | |
210 xmmstimid_cfg.config_file = g_strdup( | |
211 gtk_entry_get_text(xmmstimid_conf_config_file)); | |
212 | |
213 if (gtk_toggle_button_get_active(xmmstimid_conf_rate_11000)) | |
214 xmmstimid_cfg.rate = 11000; | |
215 else if (gtk_toggle_button_get_active(xmmstimid_conf_rate_22000)) | |
216 xmmstimid_cfg.rate = 22000; | |
217 else if (gtk_toggle_button_get_active(xmmstimid_conf_rate_44100)) | |
218 xmmstimid_cfg.rate = 44100; | |
219 if (gtk_toggle_button_get_active(xmmstimid_conf_bits_8)) | |
220 xmmstimid_cfg.bits = 8; | |
221 else if (gtk_toggle_button_get_active(xmmstimid_conf_bits_16)) | |
222 xmmstimid_cfg.bits = 16; | |
223 if (gtk_toggle_button_get_active(xmmstimid_conf_channels_1)) | |
224 xmmstimid_cfg.channels = 1; | |
225 else if (gtk_toggle_button_get_active(xmmstimid_conf_channels_2)) | |
226 xmmstimid_cfg.channels = 2; | |
227 | |
228 filename = g_strconcat(g_get_home_dir(), "/.audacious/config", NULL); | |
229 cf = xmms_cfg_open_file(filename); | |
230 if (cf == NULL) cf = xmms_cfg_new(); | |
231 | |
232 xmms_cfg_write_string(cf, "TIMIDITY", "config_file", | |
233 xmmstimid_cfg.config_file); | |
234 xmms_cfg_write_int(cf, "TIMIDITY", "rate", | |
235 xmmstimid_cfg.rate); | |
236 xmms_cfg_write_int(cf, "TIMIDITY", "bits", | |
237 xmmstimid_cfg.bits); | |
238 xmms_cfg_write_int(cf, "TIMIDITY", "channels", | |
239 xmmstimid_cfg.channels); | |
240 | |
241 xmms_cfg_write_file(cf, filename); | |
242 xmms_cfg_free(cf); | |
243 g_free(filename); | |
244 | |
245 gtk_widget_hide(xmmstimid_conf_wnd); | |
246 } | |
247 | |
248 int xmmstimid_is_our_file(char *filename) { | |
249 gchar *ext; | |
250 | |
251 ext = strrchr(filename, '.'); | |
252 if (ext && !( | |
253 strcasecmp(ext, ".mid") && | |
254 strcasecmp(ext, ".midi"))) return 1; | |
255 | |
256 return 0; | |
257 } | |
258 | |
259 static void *xmmstimid_play_loop(void *arg) { | |
260 size_t buffer_size; | |
261 void *buffer; | |
262 size_t bytes_read; | |
263 AFormat fmt; | |
264 | |
265 buffer_size = ((xmmstimid_opts.format == MID_AUDIO_S16LSB) ? 16 : 8) * | |
266 xmmstimid_opts.channels / 8 * | |
267 xmmstimid_opts.buffer_size; | |
268 | |
269 buffer = g_malloc(buffer_size); | |
270 if (buffer == NULL) pthread_exit(NULL); | |
271 | |
272 fmt = (xmmstimid_opts.format == MID_AUDIO_S16LSB) ? FMT_S16_LE : FMT_S8; | |
273 | |
274 while (xmmstimid_going) { | |
275 bytes_read = mid_song_read_wave(xmmstimid_song, | |
276 buffer, buffer_size); | |
277 | |
278 if (bytes_read != 0) | |
279 xmmstimid_ip.add_vis_pcm( | |
280 mid_song_get_time(xmmstimid_song), | |
281 fmt, xmmstimid_opts.channels, | |
282 bytes_read, buffer); | |
283 else xmmstimid_eof = TRUE; | |
284 | |
285 while (xmmstimid_going && xmmstimid_seek_to == -1 && | |
286 (bytes_read == 0 || | |
287 xmmstimid_ip.output->buffer_free() < bytes_read)) | |
288 xmms_usleep(10000); | |
289 | |
290 if (xmmstimid_seek_to != -1) { | |
291 mid_song_seek(xmmstimid_song, xmmstimid_seek_to * 1000); | |
292 xmmstimid_ip.output->flush(xmmstimid_seek_to * 1000); | |
293 xmmstimid_seek_to = -1; | |
294 bytes_read = 0; | |
295 } | |
296 | |
297 if (xmmstimid_going && bytes_read != 0) | |
298 xmmstimid_ip.output->write_audio(buffer, bytes_read); | |
299 } | |
300 | |
301 g_free(buffer); | |
302 | |
303 pthread_exit(NULL); | |
304 } | |
305 | |
306 static gchar *xmmstimid_get_title(gchar *filename) { | |
307 TitleInput *input; | |
308 gchar *temp, *ext, *title, *path, *temp2; | |
309 | |
310 input = bmp_title_input_new(); | |
311 | |
312 path = g_strdup(filename); | |
313 temp = g_strdup(filename); | |
314 ext = strrchr(temp, '.'); | |
315 if (ext) | |
316 *ext = '\0'; | |
317 temp2 = strrchr(path, '/'); | |
318 if (temp2) | |
319 *temp2 = '\0'; | |
320 | |
321 input->file_name = g_basename(filename); | |
322 input->file_ext = ext ? ext+1 : NULL; | |
323 input->file_path = g_strdup_printf("%s/", path); | |
324 | |
325 title = xmms_get_titlestring(xmms_get_gentitle_format(), input); | |
326 if (title == NULL) | |
327 title = g_strdup(input->file_name); | |
328 | |
329 g_free(temp); | |
330 g_free(path); | |
331 g_free(input); | |
332 | |
333 return title; | |
334 } | |
335 | |
336 void xmmstimid_play_file(char *filename) { | |
337 MidIStream *stream; | |
338 gchar *title; | |
339 | |
340 if (!xmmstimid_initialized) { | |
341 xmmstimid_init(); | |
342 if (!xmmstimid_initialized) return; | |
343 } | |
344 | |
345 if (xmmstimid_song != NULL) { | |
346 mid_song_free(xmmstimid_song); | |
347 xmmstimid_song = NULL; | |
348 } | |
349 | |
350 stream = mid_istream_open_file(filename); | |
351 if (stream == NULL) return; | |
352 | |
353 xmmstimid_audio_error = FALSE; | |
354 | |
355 xmmstimid_opts.rate = xmmstimid_cfg.rate; | |
356 xmmstimid_opts.format = (xmmstimid_cfg.bits == 16) ? | |
357 MID_AUDIO_S16LSB : MID_AUDIO_S8; | |
358 xmmstimid_opts.channels = xmmstimid_cfg.channels; | |
359 xmmstimid_opts.buffer_size = xmmstimid_cfg.buffer_size; | |
360 | |
361 xmmstimid_song = mid_song_load(stream, &xmmstimid_opts); | |
362 mid_istream_close(stream); | |
363 | |
364 if (xmmstimid_song == NULL) { | |
365 xmmstimid_ip.set_info_text("Couldn't load MIDI file"); | |
366 return; | |
367 } | |
368 | |
369 if (xmmstimid_ip.output->open_audio( | |
370 (xmmstimid_opts.format == MID_AUDIO_S16LSB) ? | |
371 FMT_S16_LE : FMT_S8, | |
372 xmmstimid_opts.rate, xmmstimid_opts.channels) == 0) { | |
373 xmmstimid_audio_error = TRUE; | |
374 mid_song_free(xmmstimid_song); | |
375 xmmstimid_song = NULL; | |
376 return; | |
377 } | |
378 | |
379 title = xmmstimid_get_title(filename); | |
380 xmmstimid_ip.set_info(title, | |
381 mid_song_get_total_time(xmmstimid_song), | |
382 0, xmmstimid_opts.rate, xmmstimid_opts.channels); | |
383 g_free(title); | |
384 | |
385 mid_song_start(xmmstimid_song); | |
386 xmmstimid_going = TRUE; | |
387 xmmstimid_eof = FALSE; | |
388 xmmstimid_seek_to = -1; | |
389 | |
390 if (pthread_create(&xmmstimid_decode_thread, | |
391 NULL, xmmstimid_play_loop, NULL) != 0) { | |
392 mid_song_free(xmmstimid_song); | |
393 xmmstimid_stop(); | |
394 } | |
395 } | |
396 | |
397 void xmmstimid_stop(void) { | |
398 if (xmmstimid_song != NULL && xmmstimid_going) { | |
399 xmmstimid_going = FALSE; | |
400 pthread_join(xmmstimid_decode_thread, NULL); | |
401 xmmstimid_ip.output->close_audio(); | |
402 mid_song_free(xmmstimid_song); | |
403 xmmstimid_song = NULL; | |
404 } | |
405 } | |
406 | |
407 void xmmstimid_pause(short p) { | |
408 xmmstimid_ip.output->pause(p); | |
409 } | |
410 | |
411 void xmmstimid_seek(int time) { | |
412 xmmstimid_seek_to = time; | |
413 xmmstimid_eof = FALSE; | |
414 | |
415 while (xmmstimid_seek_to != -1) | |
416 xmms_usleep(10000); | |
417 } | |
418 | |
419 int xmmstimid_get_time(void) { | |
420 if (xmmstimid_audio_error) | |
421 return -2; | |
422 if (xmmstimid_song == NULL) | |
423 return -1; | |
424 if (!xmmstimid_going || (xmmstimid_eof && | |
425 xmmstimid_ip.output->buffer_playing())) | |
426 return -1; | |
427 | |
428 return mid_song_get_time(xmmstimid_song); | |
429 } | |
430 | |
431 void xmmstimid_cleanup(void) { | |
432 if (xmmstimid_initialized) | |
433 mid_exit(); | |
434 } | |
435 | |
436 void xmmstimid_get_song_info(char *filename, char **title, int *length) { | |
437 MidIStream *stream; | |
438 MidSongOptions opts; | |
439 MidSong *song; | |
440 | |
441 if (!xmmstimid_initialized) { | |
442 xmmstimid_init(); | |
443 if (!xmmstimid_initialized) return; | |
444 } | |
445 | |
446 stream = mid_istream_open_file(filename); | |
447 if (stream == NULL) return; | |
448 | |
449 opts.rate = xmmstimid_cfg.rate; | |
450 opts.format = (xmmstimid_cfg.bits == 16) ? | |
451 MID_AUDIO_S16LSB : MID_AUDIO_S8; | |
452 opts.channels = xmmstimid_cfg.channels; | |
453 opts.buffer_size = 8; | |
454 | |
455 song = mid_song_load(stream, &opts); | |
456 mid_istream_close(stream); | |
457 | |
458 if (song == NULL) return; | |
459 | |
460 *length = mid_song_get_total_time(song); | |
461 *title = xmmstimid_get_title(filename); | |
462 | |
463 mid_song_free(song); | |
464 } | |
465 |