1 /* UADE2 plugin for XMMS
2  *
3  * Copyright (C) 2005-2006  Heikki Orsila
4  *
5  * This source code module is dual licensed under GPL and Public Domain.
6  * Hence you may use _this_ module (not another code module) in any way you
7  * want in your projects.
8  */
9 
10 #include <libgen.h>
11 #include <assert.h>
12 #include <stdint.h>
13 #include <signal.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <time.h>
17 #include <unistd.h>
18 
19 #include "uadeipc.h"
20 #include "eagleplayer.h"
21 #include "uadeconfig.h"
22 #include "uadecontrol.h"
23 #include "uadeconstants.h"
24 #include "ossupport.h"
25 #include "uadeconf.h"
26 #include "effects.h"
27 #include "sysincludes.h"
28 #include "songdb.h"
29 #include "plugin.h"
30 #include "subsongseek.h"
31 #include "fileinfo.h"
32 #include "songinfo.h"
33 #include "uadestate.h"
34 
35 
36 #define PLUGIN_DEBUG 0
37 
38 #if PLUGIN_DEBUG
39 #define plugindebug(fmt, args...) do { fprintf(stderr, "%s:%d: %s: " fmt, __FILE__, __LINE__, __func__, ## args); } while(0)
40 #else
41 #define plugindebug(fmt, args...)
42 #endif
43 
44 
45 static int initialize_song(char *filename);
46 static void uade_cleanup(void);
47 static void uade_file_info(char *filename);
48 static void uade_get_song_info(char *filename, char **title, int *length);
49 static int uade_get_time(void);
50 static void uade_init(void);
51 static int uadexmms_is_our_file(char *filename);
52 static void uade_pause(short paused);
53 static void uade_play_file(char *filename);
54 static void uade_seek(int time);
55 static void uade_stop(void);
56 static void uade_info_string(void);
57 
58 /* GLOBAL VARIABLE DECLARATIONS */
59 
60 static InputPlugin uade_ip = {
61   .description = "UADE " UADE_VERSION,
62   .init = uade_init,
63   .is_our_file = uadexmms_is_our_file,
64   .play_file = uade_play_file,
65   .stop = uade_stop,
66   .pause = uade_pause,
67   .seek = uade_seek,
68   .get_time = uade_get_time,
69   .cleanup = uade_cleanup,
70   .get_song_info = uade_get_song_info,
71   .file_info_box = uade_file_info,
72 };
73 
74 static const AFormat sample_format = FMT_S16_NE;
75 
76 /* Definition of trigger type:
77    abort_playing variable does not need locking, because it is initialized to
78    false synchronously in play_file, and it is triggered to be true in stop().
79    Other places in the plugin only read the value. We call this type of
80    variable a trigger type.
81 
82    The locking strategy in the plugin is that all lockable variables are
83    initialized in play_file() for each song. Using variables after that
84    requires locking.  When locking is needed, call uade_lock() and
85    uade_unlock(). */
86 
87 static int abort_playing;     /* Trigger type */
88 
89 static struct uade_state state;
90 
91 static char configname[PATH_MAX];
92 static pthread_t decode_thread;
93 static struct uade_config config_backup;
94 static char gui_filename[PATH_MAX];
95 static char gui_formatname[256];
96 static int gui_info_set;
97 static char gui_modulename[256];
98 static char gui_module_filename[PATH_MAX];
99 static char gui_playername[256];
100 static char gui_player_filename[PATH_MAX];
101 static int last_beat_played;  /* Lock before use */
102 
103 static char contentname[PATH_MAX];
104 static time_t content_mtime;
105 
106 static int record_playtime; /* Lock before use */
107 static int plugin_disabled;
108 static char songconfname[PATH_MAX];
109 
110 static time_t config_load_time;
111 
112 
113 int uade_is_paused;           /* Lock before use */
114 int uade_thread_running;      /* Trigger type */
115 int uade_seek_forward;        /* Lock before use */
116 int uade_select_sub;          /* Lock before use */
117 
118 
119 static int uade_config_optimization;
120 
121 
122 static pthread_mutex_t vlock = PTHREAD_MUTEX_INITIALIZER;
123 
124 
test_uade_conf(void)125 static void test_uade_conf(void)
126 {
127   struct stat st;
128 
129   if (stat(configname, &st))
130     return;
131 
132   /* Read only newer files */
133   if (st.st_mtime <= config_load_time)
134     return;
135 
136   config_load_time = st.st_mtime;
137 
138   uade_load_config(&config_backup, configname);
139 }
140 
141 
load_config(void)142 static void load_config(void)
143 {
144   test_uade_conf();
145 }
146 
147 
load_content_db(void)148 static void load_content_db(void)
149 {
150 	struct stat st;
151 	char name[PATH_MAX];
152 	int ret;
153 
154 	if (contentname[0] == 0) {
155 		char *home = uade_open_create_home();
156 		if (home)
157 			snprintf(contentname, sizeof contentname, "%s/.uade2/contentdb", home);
158 	}
159 
160 	/* User database has priority over global database, so we read it
161 	 * first */
162 	if (contentname[0]) {
163 		if (stat(contentname, &st) == 0) {
164 			if (content_mtime < st.st_mtime) {
165 				ret = uade_read_content_db(contentname);
166 				if (stat(contentname, &st) == 0)
167 					content_mtime = st.st_mtime;
168 				if (ret)
169 					return;
170 			}
171 		} else {
172 			FILE *f = fopen(contentname, "w");
173 			if (f)
174 				fclose(f);
175 			uade_read_content_db(contentname);
176 		}
177 	}
178 
179 	snprintf(name, sizeof name, "%s/contentdb.conf", config_backup.basedir.name);
180 	if (stat(name, &st) == 0 && content_mtime < st.st_mtime) {
181 		uade_read_content_db(name);
182 		if (stat(name, &st) == 0)
183 			content_mtime = st.st_mtime;
184 	}
185 }
186 
187 
uade_cleanup(void)188 static void uade_cleanup(void)
189 {
190   if (state.pid)
191     kill(state.pid, SIGTERM);
192 
193   if (contentname[0]) {
194     struct stat st;
195     if (stat(contentname, &st) == 0 && content_mtime >= st.st_mtime)
196       uade_save_content_db(contentname);
197   }
198 }
199 
200 
uade_file_info(char * filename)201 static void uade_file_info(char *filename)
202 {
203   int adder = 0;
204 
205   if (strncmp(filename, "uade://", 7) == 0)
206     adder = 7;
207   uade_gui_file_info(filename + adder, gui_player_filename, gui_modulename, gui_playername, gui_formatname);
208 
209 }
210 
211 
uade_get_cur_subsong(int def)212 int uade_get_cur_subsong(int def)
213 {
214     int subsong;
215     uade_lock();
216     subsong = -1;
217     if (state.song != NULL)
218       subsong = state.song->cur_subsong;
219     uade_unlock();
220     if (subsong == -1)
221 	subsong = def;
222     return subsong;
223 }
224 
225 
uade_get_max_subsong(int def)226 int uade_get_max_subsong(int def)
227 {
228     int subsong;
229     uade_lock();
230     subsong = -1;
231     if (state.song != NULL)
232       subsong = state.song->max_subsong;
233     uade_unlock();
234     if (subsong == -1)
235 	subsong = def;
236     return subsong;
237 }
238 
239 
uade_get_min_subsong(int def)240 int uade_get_min_subsong(int def)
241 {
242     int subsong;
243     uade_lock();
244     subsong = -1;
245     if (state.song != NULL)
246       subsong = state.song->min_subsong;
247     uade_unlock();
248     if (subsong == -1)
249 	subsong = def;
250     return subsong;
251 }
252 
253 
uade_lock(void)254 void uade_lock(void)
255 {
256   if (pthread_mutex_lock(&vlock)) {
257     fprintf(stderr, "UADE2 locking error.\n");
258     exit(-1);
259   }
260 }
261 
262 
uade_unlock(void)263 void uade_unlock(void)
264 {
265   if (pthread_mutex_unlock(&vlock)) {
266     fprintf(stderr, "UADE2 unlocking error.\n");
267     exit(-1);
268   }
269 }
270 
271 
272 /* this function is first called by xmms. returns pointer to plugin table */
get_iplugin_info(void)273 InputPlugin *get_iplugin_info(void)
274 {
275   return &uade_ip;
276 }
277 
278 
279 /* xmms initializes uade by calling this function */
uade_init(void)280 static void uade_init(void)
281 {
282   char *home;
283   int config_loaded;
284 
285   config_load_time = time(NULL);
286 
287   config_loaded = uade_load_initial_config(configname, sizeof configname,
288 					   &config_backup, NULL);
289 
290   load_content_db();
291 
292   uade_load_initial_song_conf(songconfname, sizeof songconfname,
293 			      &config_backup, NULL);
294 
295   home = uade_open_create_home();
296 
297   if (home != NULL) {
298     /* If config exists in home, ignore global uade.conf. */
299     snprintf(configname, sizeof configname, "%s/.uade2/uade.conf", home);
300   }
301 
302   if (config_loaded == 0) {
303     fprintf(stderr, "No config file found for UADE XMMS plugin. Will try to load config from\n");
304     fprintf(stderr, "$HOME/.uade2/uade.conf in the future.\n");
305   }
306 }
307 
308 
309 /* XMMS calls this function to check if filename belongs to this plugin. */
uadexmms_is_our_file(char * filename)310 static int uadexmms_is_our_file(char *filename)
311 {
312   int ret;
313 
314   if (strncmp(filename, "uade://", 7) == 0)
315     return TRUE;
316 
317   uade_lock();
318 
319 
320   /* This is a performance optimization to avoid re-reading uade.conf
321    * when state.config hasn't yet been read. uade_is_our_file() needs the
322    * config. */
323   if (!state.validconfig) {
324     state.config = config_backup;
325     state.validconfig = 1;
326 
327     /* Verify that this condition is true at most once */
328     assert(!uade_config_optimization);
329     uade_config_optimization = 1;
330   }
331 
332   ret = uade_is_our_file(filename, 1, &state) ? TRUE : FALSE;
333 
334   uade_unlock();
335 
336   return ret;
337 }
338 
339 
340 /* Analyze file format, and handshake with uadecore. */
initialize_song(char * filename)341 static int initialize_song(char *filename)
342 {
343   int ret;
344   char modulename[PATH_MAX];
345   char playername[PATH_MAX];
346   char scorename[PATH_MAX];
347 
348   uade_lock();
349 
350   state.config = config_backup;
351   state.validconfig = 1;
352 
353   state.ep = NULL;
354   state.song = NULL;
355 
356   ret = uade_is_our_file(filename, 0, &state);
357 
358   if (!ret)
359     goto error;
360 
361   strlcpy(modulename, filename, sizeof modulename);
362   strlcpy(gui_module_filename, filename, sizeof gui_module_filename);
363 
364   snprintf(scorename, sizeof scorename, "%s/score", state.config.basedir.name);
365 
366   if (strcmp(state.ep->playername, "custom") == 0) {
367     strlcpy(playername, modulename, sizeof playername);
368     modulename[0] = 0;
369     gui_module_filename[0] = 0;
370   } else {
371     snprintf(playername, sizeof playername, "%s/players/%s", state.config.basedir.name, state.ep->playername);
372   }
373 
374   if (!uade_alloc_song(&state, filename))
375     goto error;
376 
377   uade_set_ep_attributes(&state);
378 
379   uade_set_song_attributes(&state, playername, sizeof playername);
380 
381   uade_set_effects(&state);
382 
383   strlcpy(gui_player_filename, playername, sizeof gui_player_filename);
384 
385   ret = uade_song_initialization(scorename, playername, modulename, &state);
386   if (ret) {
387     if (ret != UADECORE_CANT_PLAY && ret != UADECORE_INIT_ERROR) {
388       fprintf(stderr, "Can not initialize song. Unknown error.\n");
389       plugin_disabled = 1;
390     }
391     uade_unalloc_song(&state);
392 
393     goto error;
394   }
395 
396   uade_unlock();
397   return TRUE;
398 
399  error:
400   uade_unlock();
401   return FALSE;
402 }
403 
play_loop(void * arg)404 static void *play_loop(void *arg)
405 {
406   enum uade_control_state controlstate = UADE_S_STATE;
407   int ret;
408   int left = 0;
409   uint8_t space[UADE_MAX_MESSAGE_SIZE];
410   struct uade_msg *um = (struct uade_msg *) space;
411   int subsong_end = 0;
412   uint16_t *sm;
413   int i;
414   unsigned int play_bytes, tailbytes = 0;
415   uint64_t subsong_bytes = 0;
416   char *reason;
417   uint32_t *u32ptr;
418   int writeoffs;
419   int framesize = UADE_CHANNELS * UADE_BYTES_PER_SAMPLE;
420   int song_end_trigger = 0;
421   int64_t skip_bytes = 0;
422 
423   uade_lock();
424   record_playtime = 1;
425   uade_unlock();
426 
427   while (1) {
428     if (controlstate == UADE_S_STATE) {
429 
430       assert(left == 0);
431 
432       if (abort_playing) {
433 	uade_lock();
434 	record_playtime = 0;
435 	uade_unlock();
436 	break;
437       }
438 
439       uade_lock();
440       if (uade_seek_forward) {
441 	skip_bytes += uade_seek_forward * UADE_BYTES_PER_FRAME * state.config.frequency;
442 	uade_ip.output->flush(uade_ip.output->written_time() + uade_seek_forward * 1000);
443 	uade_seek_forward = 0;
444       }
445       if (uade_select_sub != -1) {
446 	state.song->cur_subsong = uade_select_sub;
447 
448 	uade_change_subsong(&state);
449 
450 	uade_ip.output->flush(0);
451 	uade_select_sub = -1;
452 	subsong_end = 0;
453 	subsong_bytes = 0;
454 
455 	/* we do this to avoid timeout, and to not record playtime */
456 	state.song->out_bytes = 0;
457 	record_playtime = 0;
458 
459 	uade_info_string();
460       }
461 
462       if (subsong_end && song_end_trigger == 0) {
463 
464 	if (state.song->cur_subsong == -1 || state.song->max_subsong == -1) {
465 	  song_end_trigger = 1;
466 
467 	} else {
468 
469 	  state.song->cur_subsong++;
470 
471 	  if (state.song->cur_subsong > state.song->max_subsong) {
472 	    song_end_trigger = 1;
473 	  } else {
474 	    int x = 0;
475 
476 	    uade_change_subsong(&state);
477 
478 	    while (uade_ip.output->buffer_playing()) {
479 	      /* Sleep at most 5 secs */
480 	      if (x >= 500) {
481 		fprintf(stderr, "UADE: blocking work-around activated.\n");
482 		break;
483 	      }
484 	      x++;
485 	      xmms_usleep(10000);
486 	    }
487 	    uade_ip.output->flush(0);
488 	    subsong_end = 0;
489 	    subsong_bytes = 0;
490 
491 	    uade_gui_subsong_changed(state.song->cur_subsong);
492 
493 	    uade_info_string();
494 	  }
495 	}
496       }
497       uade_unlock();
498 
499       if (song_end_trigger) {
500 	/* We must drain the audio fast if abort_playing happens (e.g.
501 	   the user changes song when we are here waiting the sound device) */
502 	while (uade_ip.output->buffer_playing() && abort_playing == 0)
503 
504 	  xmms_usleep(10000);
505 	break;
506       }
507 
508       left = uade_read_request(&state.ipc);
509 
510       if (uade_send_short_message(UADE_COMMAND_TOKEN, &state.ipc)) {
511 	fprintf(stderr, "Can not send token.\n");
512 	return NULL;
513       }
514       controlstate = UADE_R_STATE;
515 
516     } else {
517 
518       if (uade_receive_message(um, sizeof(space), &state.ipc) <= 0) {
519 	fprintf(stderr, "Can not receive events from uade\n");
520 	exit(-1);
521       }
522 
523       switch (um->msgtype) {
524 
525       case UADE_COMMAND_TOKEN:
526 	controlstate = UADE_S_STATE;
527 	break;
528 
529       case UADE_REPLY_DATA:
530 	sm = (uint16_t *) um->data;
531 	for (i = 0; i < um->size; i += 2) {
532 	  *sm = ntohs(*sm);
533 	  sm++;
534 	}
535 
536 	if (subsong_end) {
537 	  play_bytes = tailbytes;
538 	  tailbytes = 0;
539 	} else {
540 	  play_bytes = um->size;
541 	}
542 
543 	if (subsong_end == 0 && song_end_trigger == 0 &&
544 	    uade_test_silence(um->data, play_bytes, &state)) {
545 	  subsong_end = 1;
546 	}
547 
548 	subsong_bytes += play_bytes;
549 	uade_lock();
550 	state.song->out_bytes += play_bytes;
551 	uade_unlock();
552 
553 	if (skip_bytes > 0) {
554 	  if (play_bytes <= skip_bytes) {
555 	    skip_bytes -= play_bytes;
556 	    play_bytes = 0;
557 	  } else {
558 	    play_bytes -= skip_bytes;
559 	    skip_bytes = 0;
560 	  }
561 	}
562 
563 	uade_effect_run(&state.effects, (int16_t *) um->data, play_bytes / framesize);
564 	uade_ip.add_vis_pcm(uade_ip.output->written_time(), sample_format, UADE_CHANNELS, play_bytes, um->data);
565 
566 	writeoffs = 0;
567 	while (writeoffs < play_bytes) {
568 	  int writable;
569 	  while ((writable = uade_ip.output->buffer_free()) <= 0) {
570 	    if (abort_playing)
571 	      goto nowrite;
572 	    xmms_usleep(10000);
573 	  }
574 
575 	  if (writable > (play_bytes - writeoffs))
576 	    writable = play_bytes - writeoffs;
577 
578 	  uade_ip.output->write_audio(&um->data[writeoffs], writable);
579 
580 	  writeoffs += writable;
581 	}
582 
583 
584       nowrite:
585 
586 	if (state.config.timeout != -1 && state.config.use_timeouts) {
587 	  if (song_end_trigger == 0) {
588 	    uade_lock();
589 	    if (state.song->out_bytes / (UADE_BYTES_PER_FRAME * state.config.frequency) >= state.config.timeout) {
590 	      song_end_trigger = 1;
591 	      record_playtime = 0;
592 	    }
593 	    uade_unlock();
594 	  }
595 	}
596 
597 	if (state.config.subsong_timeout != -1 && state.config.use_timeouts) {
598 	  if (subsong_end == 0 && song_end_trigger == 0) {
599 	    if (subsong_bytes / (UADE_BYTES_PER_FRAME * state.config.frequency) >= state.config.subsong_timeout) {
600 	      subsong_end = 1;
601 	      record_playtime = 0;
602 	    }
603 	  }
604 	}
605 
606 	assert (left >= um->size);
607 	left -= um->size;
608 	break;
609 
610       case UADE_REPLY_FORMATNAME:
611 	uade_check_fix_string(um, 128);
612 	strlcpy(gui_formatname, (char *) um->data, sizeof gui_formatname);
613 	strlcpy(state.song->formatname, (char *) um->data, sizeof state.song->formatname);
614 	break;
615 
616       case UADE_REPLY_MODULENAME:
617 	uade_check_fix_string(um, 128);
618 	strlcpy(gui_modulename, (char *) um->data, sizeof gui_modulename);
619 	strlcpy(state.song->modulename, (char *) um->data, sizeof state.song->modulename);
620 	break;
621 
622       case UADE_REPLY_MSG:
623 	uade_check_fix_string(um, 128);
624 	plugindebug("Message: %s\n", (char *) um->data);
625 	break;
626 
627       case UADE_REPLY_PLAYERNAME:
628 	uade_check_fix_string(um, 128);
629 	strlcpy(gui_playername, (char *) um->data, sizeof gui_playername);
630 	strlcpy(state.song->playername, (char *) um->data, sizeof state.song->playername);
631 	break;
632 
633       case UADE_REPLY_SONG_END:
634 	if (um->size < 9) {
635 	  fprintf(stderr, "Invalid song end reply\n");
636 	  exit(-1);
637 	}
638 	tailbytes = ntohl(((uint32_t *) um->data)[0]);
639 	/* next ntohl() is only there for a principle. it is not useful */
640 	if (ntohl(((uint32_t *) um->data)[1]) == 0) {
641 	  /* normal happy song end. go to next subsong if any */
642 	  subsong_end = 1;
643 	} else {
644 	  /* unhappy song end (error in the 68k side). skip to next song
645 	     ignoring possible subsongs */
646 	  song_end_trigger = 1;
647 	}
648 	i = 0;
649 	reason = (char *) &um->data[8];
650 	while (reason[i] && i < (um->size - 8))
651 	  i++;
652 	if (reason[i] != 0 || (i != (um->size - 9))) {
653 	  fprintf(stderr, "Broken reason string with song end notice\n");
654 	  exit(-1);
655 	}
656 	/* fprintf(stderr, "Song end (%s)\n", reason); */
657 	break;
658 
659       case UADE_REPLY_SUBSONG_INFO:
660 	if (um->size != 12) {
661 	  fprintf(stderr, "subsong info: too short a message\n");
662 	  exit(-1);
663 	}
664 	u32ptr = (uint32_t *) um->data;
665 	uade_lock();
666 	state.song->min_subsong = ntohl(u32ptr[0]);
667 	state.song->max_subsong = ntohl(u32ptr[1]);
668 	state.song->cur_subsong = ntohl(u32ptr[2]);
669 
670 	if (!(-1 <= state.song->min_subsong && state.song->min_subsong <= state.song->cur_subsong && state.song->cur_subsong <= state.song->max_subsong)) {
671 	  int tempmin = state.song->min_subsong, tempmax = state.song->max_subsong;
672 	  fprintf(stderr, "uade: The player is broken. Subsong info does not match with %s.\n", gui_filename);
673 	  state.song->min_subsong = tempmin <= tempmax ? tempmin : tempmax;
674 	  state.song->max_subsong = tempmax >= tempmin ? tempmax : tempmin;
675 	  if (state.song->cur_subsong > state.song->max_subsong)
676 	    state.song->max_subsong = state.song->cur_subsong;
677 	  else if (state.song->cur_subsong < state.song->min_subsong)
678 	    state.song->min_subsong = state.song->cur_subsong;
679 	}
680 	uade_unlock();
681 	break;
682 
683       default:
684 	fprintf(stderr, "Expected sound data. got %d.\n", um->msgtype);
685 	plugin_disabled = 1;
686 	return NULL;
687       }
688     }
689   }
690 
691   last_beat_played = 1;
692 
693   if (uade_send_short_message(UADE_COMMAND_REBOOT, &state.ipc)) {
694     fprintf(stderr, "Can not send reboot.\n");
695     return NULL;
696   }
697 
698   if (uade_send_short_message(UADE_COMMAND_TOKEN, &state.ipc)) {
699     fprintf(stderr, "Can not send token.\n");
700     return NULL;
701   }
702 
703   do {
704     ret = uade_receive_message(um, sizeof(space), &state.ipc);
705     if (ret < 0) {
706       fprintf(stderr, "Can not receive events from uade.\n");
707       return NULL;
708     }
709     if (ret == 0) {
710       fprintf(stderr, "End of input after reboot.\n");
711       return NULL;
712     }
713   } while (um->msgtype != UADE_COMMAND_TOKEN);
714 
715   return NULL;
716 }
717 
718 
uade_play_file(char * filename)719 static void uade_play_file(char *filename)
720 {
721   char tempname[PATH_MAX];
722   char *t;
723 
724   load_config();
725 
726   uade_lock();
727 
728   abort_playing = 0;
729   last_beat_played = 0;
730   record_playtime = 0;
731 
732   uade_is_paused = 0;
733   uade_select_sub = -1;
734   uade_seek_forward = 0;
735 
736   assert(state.song == NULL);
737 
738   uade_unlock();
739 
740   if (strncmp(filename, "uade://", 7) == 0)
741     filename += 7;
742 
743   strlcpy(tempname, filename, sizeof tempname);
744   t = basename(tempname);
745   if (t == NULL)
746     t = filename;
747   strlcpy(gui_filename, t, sizeof gui_filename);
748   gui_info_set = 0;
749 
750   gui_formatname[0] = 0;
751   gui_modulename[0] = 0;
752   gui_playername[0] = 0;
753   gui_module_filename[0] = 0;
754   gui_player_filename[0] = 0;
755 
756   if (!state.pid) {
757     char configname[PATH_MAX];
758     snprintf(configname, sizeof configname, "%s/uaerc", config_backup.basedir.name);
759     uade_spawn(&state, UADE_CONFIG_UADE_CORE, configname);
760   }
761 
762   if (!uade_ip.output->open_audio(sample_format, config_backup.frequency, UADE_CHANNELS)) {
763     abort_playing = 1;
764     return;
765   }
766 
767   if (plugin_disabled) {
768     fprintf(stderr, "An error has occured. uade plugin is internally disabled.\n");
769     goto err;
770   }
771 
772   /* If content db has changed (newer mtime chan previously read) then force
773      a reload */
774   load_content_db();
775 
776   /* Save current db if an hour has passed */
777   if (contentname[0]) {
778     time_t curtime = time(NULL);
779     if (curtime >= (content_mtime + 3600)) {
780       struct stat st;
781       uade_save_content_db(contentname);
782       if (stat(contentname, &st) == 0)
783 	content_mtime = st.st_mtime;
784     }
785   }
786 
787   if (initialize_song(filename) == FALSE)
788     goto err;
789 
790   if (pthread_create(&decode_thread, NULL, play_loop, NULL)) {
791     fprintf(stderr, "uade: can't create play_loop() thread\n");
792     goto err;
793   }
794 
795   uade_thread_running = 1;
796   return;
797 
798  err:
799   /* close audio that was opened */
800   uade_ip.output->close_audio();
801   abort_playing = 1;
802 
803   uade_lock();
804 
805   if (state.song)
806     uade_unalloc_song(&state);
807 
808   uade_unlock();
809 }
810 
uade_stop(void)811 static void uade_stop(void)
812 {
813   /* Signal other subsystems to proceed to finished state as soon as possible
814    */
815   abort_playing = 1;
816 
817   /* Wait for playing thread to finish */
818   if (uade_thread_running) {
819     pthread_join(decode_thread, NULL);
820     uade_thread_running = 0;
821   }
822 
823   uade_gui_close_subsong_win();
824 
825   if (state.song != NULL) {
826     /* If song ended volutarily, tell the play time for XMMS. */
827     uade_lock();
828     if (record_playtime) {
829       int play_time = (state.song->out_bytes * 1000) / (UADE_BYTES_PER_FRAME * state.config.frequency);
830       if (state.song->md5[0] != 0)
831 	uade_add_playtime(state.song->md5, play_time);
832 
833       state.song->playtime = play_time;
834       state.song->cur_subsong = state.song->max_subsong;
835       uade_info_string();
836     }
837 
838     /* We must free uadesong after playthread has finished and additional
839        GUI windows have been closed. */
840     uade_unalloc_song(&state);
841 
842     uade_unlock();
843   }
844 
845   uade_ip.output->close_audio();
846 }
847 
848 
849 /* XMMS calls this function when pausing or unpausing */
uade_pause(short paused)850 static void uade_pause(short paused)
851 {
852   uade_lock();
853   uade_is_paused = paused;
854   uade_unlock();
855   uade_ip.output->pause(paused);
856 }
857 
858 
859 /* XMMS calls this function when song is seeked */
uade_seek(int time)860 static void uade_seek(int time)
861 {
862   uade_gui_seek_subsong(time);
863 }
864 
865 
866 /* XMMS calls this function periodically to determine current playing time.
867    We use this function to report song name and title after play_file(),
868    and to tell XMMS to end playing if song ends for any reason. */
uade_get_time(void)869 static int uade_get_time(void)
870 {
871   if (abort_playing || last_beat_played)
872     return -1;
873 
874   if (gui_info_set == 0 && state.song->max_subsong != -1) {
875 
876     uade_lock();
877 
878     if (state.song->max_subsong != -1)
879       uade_info_string();
880 
881     gui_info_set = 1;
882     uade_unlock();
883 
884     file_info_update(gui_module_filename, gui_player_filename, gui_modulename, gui_playername, gui_formatname);
885   }
886 
887   return uade_ip.output->output_time();
888 }
889 
890 
uade_get_song_info(char * filename,char ** title,int * length)891 static void uade_get_song_info(char *filename, char **title, int *length)
892 {
893   char tempname[PATH_MAX];
894   char *t;
895 
896   if (strncmp(filename, "uade://", 7) == 0)
897     filename += 7;
898 
899   strlcpy(tempname, filename, sizeof tempname);
900   t = basename(tempname);
901   if (t == NULL)
902     t = filename;
903   if ((*title = strdup(t)) == NULL)
904     plugindebug("Not enough memory for song info.\n");
905   *length = -1;
906 }
907 
908 
uade_info_string(void)909 static void uade_info_string(void)
910 {
911   char info[256];
912   int playtime = state.song->playtime;
913 
914   /* Hack. Set info text and song length late because we didn't know
915   subsong amounts before this. Pass zero as a length so that the
916   graphical play time counter will run but seek is still enabled.
917   Passing -1 as playtime would disable seeking. */
918   if (playtime <= 0)
919     playtime = 0;
920 
921   if (uade_generate_song_title(info, sizeof info, &state))
922     strlcpy(info, gui_filename, sizeof info);
923 
924   uade_ip.set_info(info, playtime, UADE_BYTES_PER_FRAME * state.config.frequency,
925 		   state.config.frequency, UADE_CHANNELS);
926 }
927