Mercurial > audlegacy-plugins
changeset 2951:6abe60a81301
reimplemented cuesheet plugin using subtune.
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Sat, 11 Oct 2008 20:03:01 +0900 |
parents | dcd8d93ba781 |
children | 63bf9d97ce65 |
files | src/cue/Makefile src/cue/cuesheet.c src/cue/cuesheet.h src/cue/watchdog.c |
diffstat | 4 files changed, 608 insertions(+), 534 deletions(-) [+] |
line wrap: on
line diff
--- a/src/cue/Makefile Sat Oct 11 02:02:41 2008 +0900 +++ b/src/cue/Makefile Sat Oct 11 20:03:01 2008 +0900 @@ -1,6 +1,6 @@ -PLUGIN = cuesheet${PLUGIN_SUFFIX} +PLUGIN = cuesheet_ng${PLUGIN_SUFFIX} -SRCS = cuesheet.c +SRCS = cuesheet.c watchdog.c include ../../buildsys.mk include ../../extra.mk
--- a/src/cue/cuesheet.c Sat Oct 11 02:02:41 2008 +0900 +++ b/src/cue/cuesheet.c Sat Oct 11 20:03:01 2008 +0900 @@ -15,51 +15,21 @@ * details. */ -#include "config.h" - -/* #define AUD_DEBUG 1 */ - -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <ctype.h> -#include <audacious/plugin.h> -#include <audacious/output.h> - -#define MAX_CUE_LINE_LENGTH 1000 -#define MAX_CUE_TRACKS 1000 +#include "cuesheet.h" -static void cache_cue_file(gchar *f); -static void free_cue_info(void); -static void fix_cue_argument(char *line); -static gboolean is_our_file(gchar *filespec); -static void play(InputPlayback *data); -static void play_cue_uri(InputPlayback *data, gchar *uri); -static void seek(InputPlayback *data, gint time); -static void stop(InputPlayback *data); -static void cue_pause(InputPlayback *data, short); -static Tuple *get_tuple(gchar *uri); -static Tuple *get_aud_tuple_uri(gchar *uri); -static void cue_init(void); -static void cue_cleanup(void); -static gpointer watchdog_func(gpointer data); +#define USE_WATCHDOG 1 static GThread *watchdog_thread = NULL; static GThread *play_thread = NULL; static GThread *real_play_thread = NULL; -static GMutex *cue_mutex; -static GCond *cue_cond; -static enum { - STOP, - RUN, - EXIT, -} watchdog_state; +GMutex *cue_mutex; +GCond *cue_cond; static GMutex *cue_block_mutex; static GCond *cue_block_cond; -static InputPlayback *caller_ip = NULL; +InputPlayback *caller_ip = NULL; static gchar *cue_file = NULL; static gchar *cue_title = NULL; @@ -68,42 +38,45 @@ static gchar *cue_year = NULL; static gchar *cue_track = NULL; -static gint last_cue_track = 0; -static gint cur_cue_track = 0; -static gint target_time = 0; -static GMutex *cue_target_time_mutex; +gint last_cue_track = 0; +gint cur_cue_track = 0; +gulong target_time = 0; +GMutex *cue_target_time_mutex; +static gint full_length = 0; -static struct { - gchar *title; - gchar *performer; - gint index; -} cue_tracks[MAX_CUE_TRACKS]; +cue_tracks_t cue_tracks[MAX_CUE_TRACKS]; + +watchdog_state_t watchdog_state; -static gint finetune_seek = 0; +gint finetune_seek = 0; -static InputPlayback *real_ip = NULL; - -static gchar *cue_fmts[] = { "cue", NULL }; +InputPlayback *real_ip = NULL; +static gchar *cue_fmts[] = {"cue", NULL}; InputPlugin cue_ip = { - .description = "Cuesheet Plugin", /* description */ - .init = cue_init, /* init */ - .is_our_file = is_our_file, - .play_file = play, - .stop = stop, - .pause = cue_pause, - .seek = seek, - .cleanup = cue_cleanup, /* cleanup */ - .get_song_tuple = get_tuple, - .vfs_extensions = cue_fmts, + .description = "Cuesheet2 Plugin", /* description */ + .init = cue_init, /* init */ + .play_file = play, + .stop = stop, + .pause = cue_pause, + .seek = seek, + .mseek = mseek, + .get_time = get_time, + .cleanup = cue_cleanup, /* cleanup */ + .get_song_tuple = get_song_tuple, + .vfs_extensions = cue_fmts, + .is_our_file = is_our_file, + .probe_for_tuple = probe_for_tuple, + .have_subtune = TRUE }; InputPlugin *cue_iplist[] = { &cue_ip, NULL }; DECLARE_PLUGIN(cue, NULL, NULL, cue_iplist, NULL, NULL, NULL, NULL, NULL); -static void cue_init(void) +void +cue_init(void) { cue_mutex = g_mutex_new(); cue_cond = g_cond_new(); @@ -111,24 +84,27 @@ cue_block_cond = g_cond_new(); cue_target_time_mutex = g_mutex_new(); +#if USE_WATCHDOG /* create watchdog thread */ g_mutex_lock(cue_mutex); watchdog_state = STOP; g_mutex_unlock(cue_mutex); watchdog_thread = g_thread_create(watchdog_func, NULL, TRUE, NULL); AUDDBG("watchdog_thread = %p\n", watchdog_thread); - aud_uri_set_plugin("cue://", &cue_ip); +#endif } -static void cue_cleanup(void) +void +cue_cleanup(void) { +#if USE_WATCHDOG g_mutex_lock(cue_mutex); watchdog_state = EXIT; g_mutex_unlock(cue_mutex); g_cond_broadcast(cue_cond); g_thread_join(watchdog_thread); - +#endif g_cond_free(cue_cond); g_mutex_free(cue_mutex); g_cond_free(cue_block_cond); @@ -136,42 +112,52 @@ g_mutex_free(cue_target_time_mutex); } -static int is_our_file(gchar *filename) +Tuple * +probe_for_tuple(gchar *uri, VFSFile *fd) +{ + Tuple *tuple = NULL; + + AUDDBG("uri=%s\n",uri); + + if(!is_our_file(uri)) + return NULL; + + /* Get subtune information */ + tuple = get_song_tuple(uri); + return tuple; +} + + +int +is_our_file(gchar *filename) { gchar *ext; - /* is it a cue:// URI? */ - if (!strncasecmp(filename, "cue://", 6)) - return TRUE; - ext = strrchr(filename, '.'); - if(!ext) return FALSE; - + if (!strncasecmp(ext, ".cue", 4)) - { - gint i; - - /* add the files, build cue urls, etc. */ - cache_cue_file(filename); //filename should be uri. - - for (i = 0; i < last_cue_track; i++) - { - gchar *tmp = g_strdup_printf("cue://%s?%d", filename, i); - aud_playlist_add_url(aud_playlist_get_active(), tmp); - g_free(tmp); - } - - free_cue_info(); - - return -1; - } + return TRUE; return FALSE; } -static void play(InputPlayback *data) +gint +get_time(InputPlayback *playback) +{ + gint raw_time = playback->output->output_time(); + gint cooked_time; + + /* translate actual time into subtune time */ + cooked_time = raw_time - cue_tracks[cur_cue_track].index; + + /* return raw_time; */ + return cooked_time; /* visualization will be missing. --yaz */ +} + +void +play(InputPlayback *data) { gchar *uri = g_strdup(data->filename); @@ -179,121 +165,140 @@ AUDDBG("play: uri = %s\n", uri); caller_ip = data; - /* this isn't a cue:// uri? */ - if (strncasecmp("cue://", uri, 6)) - { - gchar *tmp = g_strdup_printf("cue://%s?0", uri); - g_free(uri); - uri = tmp; - } - play_thread = g_thread_self(); - data->set_pb_ready(data); // it should be done in real input plugin? --yaz - play_cue_uri(data, uri); - g_free(uri); + + play_thread = g_thread_self(); + data->set_pb_ready(data); /* it should be done in real + input plugin? --yaz */ + play_cue_uri(data, uri); + g_free(uri); uri = NULL; } -static Tuple *get_tuple(gchar *uri) -{ - Tuple *ret; - - /* this isn't a cue:// uri? */ - if (strncasecmp("cue://", uri, 6)) - { - gchar *tmp = g_strdup_printf("cue://%s?0", uri); - ret = get_aud_tuple_uri(tmp); - g_free(tmp); - return ret; - } - - return get_aud_tuple_uri(uri); -} - -static void _aud_tuple_copy_field(Tuple *tuple, Tuple *tuple2, const gint nfield, const gchar *field) +void +_aud_tuple_copy_field(Tuple *tuple, Tuple *tuple2, const gint nfield, const gchar *field) { const gchar *str = aud_tuple_get_string(tuple, nfield, field); aud_tuple_disassociate(tuple2, nfield, field); aud_tuple_associate_string(tuple2, nfield, field, str); } -static Tuple *get_aud_tuple_uri(gchar *uri) + +/* this function will be called back for subtune-info in adding to + * playlist. */ +Tuple * +get_song_tuple(gchar *uri) /* *.cue or *.cue?1- */ { - gchar *path2 = g_strdup(uri + 6); - gchar *_path = strchr(path2, '?'); + Tuple *phys_tuple, *out; + ProbeResult *pr = NULL; + InputPlugin *dec = NULL; gint track = 0; - ProbeResult *pr; - InputPlugin *dec; - - Tuple *phys_tuple=NULL, *out; + /* check subtune */ + gchar *path2 = g_strdup(uri); + gchar *_path = strchr(path2, '?'); - if (_path != NULL && *_path == '?') - { - *_path = '\0'; - _path++; - track = atoi(_path); - } - - cache_cue_file(path2); //path2 should be uri. + /* subtune specifed */ + if (_path != NULL && *_path == '?') { + *_path = '\0'; + _path++; + track = atoi(_path) - 1; /* subtune number */ + } - if (cue_file == NULL) - return NULL; - - AUDDBG("cue_file = %s\n", cue_file); + /* parse file of uri and find actual file to play */ + cache_cue_file(path2); - pr = aud_input_check_file(cue_file, FALSE); - if (pr == NULL) - return NULL; - dec = pr->ip; - if (dec == NULL) - return NULL; + /* obtain probe result for actual file */ + pr = aud_input_check_file(cue_file, FALSE); + if (pr == NULL) + return NULL; + dec = pr->ip; + if (dec == NULL) + return NULL; - if (dec->get_song_tuple) - phys_tuple = dec->get_song_tuple(cue_file); + /* get tuple for actual file */ + if (dec->get_song_tuple) + phys_tuple = dec->get_song_tuple(cue_file); if(!phys_tuple) return NULL; - out = aud_tuple_new(); + + /* build tuple to be returned */ + gchar *realfn = g_filename_from_uri(cue_file, NULL, NULL); + if(!realfn) + return NULL; - _aud_tuple_copy_field(phys_tuple, out, FIELD_FILE_PATH, NULL); - _aud_tuple_copy_field(phys_tuple, out, FIELD_FILE_NAME, NULL); - _aud_tuple_copy_field(phys_tuple, out, FIELD_FILE_EXT, NULL); + gchar *ext = strrchr(realfn, '.'); + ext++; + + /* copy physical tuple */ + out = aud_tuple_new(); _aud_tuple_copy_field(phys_tuple, out, FIELD_CODEC, NULL); _aud_tuple_copy_field(phys_tuple, out, FIELD_QUALITY, NULL); _aud_tuple_copy_field(phys_tuple, out, FIELD_COPYRIGHT, NULL); _aud_tuple_copy_field(phys_tuple, out, FIELD_COMMENT, NULL); - aud_tuple_associate_int(out, FIELD_LENGTH, NULL, aud_tuple_get_int(phys_tuple, FIELD_LENGTH, NULL)); + full_length = aud_tuple_get_int(phys_tuple, FIELD_LENGTH, NULL); aud_tuple_free(phys_tuple); - aud_tuple_associate_string(out, FIELD_TITLE, NULL, cue_tracks[track].title); - aud_tuple_associate_string(out, FIELD_ARTIST, NULL, cue_tracks[track].performer ? - cue_tracks[track].performer : cue_performer); - aud_tuple_associate_string(out, FIELD_ALBUM, NULL, cue_title); - aud_tuple_associate_string(out, FIELD_GENRE, NULL, cue_genre); - if(cue_year) - aud_tuple_associate_int(out, FIELD_YEAR, NULL, atoi(cue_year)); - aud_tuple_associate_int(out, FIELD_TRACK_NUMBER, NULL, track + 1); + /* make path related parts */ + aud_tuple_associate_string(out, FIELD_FILE_PATH, NULL, + g_path_get_dirname(realfn)); + aud_tuple_associate_string(out, FIELD_FILE_NAME, NULL, + g_path_get_basename(realfn)); + aud_tuple_associate_string(out, FIELD_FILE_EXT, NULL, ext); + + /* set subtune information */ + out->nsubtunes = last_cue_track; + out->subtunes = NULL; /* ok? */ + /* subtune specified */ + if(_path) { + aud_tuple_associate_string(out, FIELD_TITLE, NULL, + cue_tracks[track].title); + aud_tuple_associate_string(out, FIELD_ARTIST, NULL, + cue_tracks[track].performer ? + cue_tracks[track].performer : cue_performer); + aud_tuple_associate_string(out, FIELD_ALBUM, NULL, cue_title); + aud_tuple_associate_string(out, FIELD_GENRE, NULL, cue_genre); + if(cue_year) + aud_tuple_associate_int(out, FIELD_YEAR, NULL, atoi(cue_year)); + aud_tuple_associate_int(out, FIELD_TRACK_NUMBER, NULL, track+1); + aud_tuple_associate_int(out, FIELD_LENGTH, NULL, + cue_tracks[track].duration); + } return out; } -static void seek(InputPlayback * data, gint time) + +void +mseek(InputPlayback *input, gulong time) { + AUDDBG("cur_cue_track=%d\n",cur_cue_track); + g_mutex_lock(cue_target_time_mutex); - target_time = time * 1000; + target_time = time + cue_tracks[cur_cue_track].index; g_mutex_unlock(cue_target_time_mutex); - AUDDBG("seek: playback = %p\n", data); - AUDDBG("cue: seek: target_time = %d\n", target_time); + AUDDBG("cue: mseek: target_time = %lu\n", target_time); - if (real_ip != NULL) { - real_ip->plugin->seek(real_ip, time); + if (real_ip != NULL) { + if(real_ip->plugin->mseek) + real_ip->plugin->mseek(real_ip, target_time); + else + real_ip->plugin->seek(real_ip, target_time/1000); } } -static void stop(InputPlayback * data) +void +seek(InputPlayback *input, gint time) +{ + gulong millisecond = time * 1000; + mseek(input, millisecond); +} + +void +stop(InputPlayback * data) { AUDDBG("f: stop: playback = %p\n", data); @@ -313,11 +318,12 @@ if (caller_ip != NULL) caller_ip->playing = 0; +#if USE_WATCHDOG g_mutex_lock(cue_mutex); watchdog_state = STOP; g_mutex_unlock(cue_mutex); g_cond_signal(cue_cond); - +#endif free_cue_info(); if (real_ip != NULL) { @@ -332,71 +338,47 @@ } /*play_thread*/ + AUDDBG("e: stop\n"); } -static gboolean do_stop(gpointer data) -{ - AUDDBG("f: do_stop\n"); - audacious_drct_stop(); - AUDDBG("e: do_stop\n"); - - return FALSE; //only once -} - -static gboolean do_setpos(gpointer data) +void +cue_pause(InputPlayback * data, short p) { - Playlist *playlist = aud_playlist_get_active(); - gint pos = aud_playlist_get_position_nolock(playlist); - gint incr = *(gint *)data; - - pos = pos + incr; - if(pos < 0) - pos = 0; - - AUDDBG("do_setpos: pos = %d\n\n", pos); - - if (!playlist) - return FALSE; - - /* being done from the main loop thread, does not require locks */ - aud_playlist_set_position(playlist, (guint)pos); - - return FALSE; //one-shot + if (real_ip != NULL) + real_ip->plugin->pause(real_ip, p); } -static void cue_pause(InputPlayback * data, short p) +void +set_info_override(gchar * unused, gint length, gint rate, gint freq, gint nch) { - if (real_ip != NULL) - real_ip->plugin->pause(real_ip, p); + gchar *title; + Playlist *playlist = aud_playlist_get_active(); + gint cur_len; + + g_return_if_fail(playlist != NULL); + + /* annoying.. */ + if (playlist->position->tuple == NULL) + { + gint pos = aud_playlist_get_position(playlist); + aud_playlist_get_tuple(playlist, pos); + } + + title = g_strdup(playlist->position->title); + cur_len = cue_tracks[cur_cue_track].duration; + cue_ip.set_info(title, cur_len, rate, freq, nch); } -static void set_info_override(gchar * unused, gint length, gint rate, gint freq, gint nch) + +void +play_cue_uri(InputPlayback * data, gchar *uri) { - gchar *title; - Playlist *playlist = aud_playlist_get_active(); - - g_return_if_fail(playlist != NULL); - - /* annoying. */ - if (playlist->position->tuple == NULL) - { - gint pos = aud_playlist_get_position(playlist); - aud_playlist_get_tuple(playlist, pos); - } - - title = g_strdup(playlist->position->title); - - cue_ip.set_info(title, length, rate, freq, nch); -} - -static void play_cue_uri(InputPlayback * data, gchar *uri) -{ - gchar *path2 = g_strdup(uri + 6); // "cue://" is stripped. + gchar *path2 = g_strdup(uri); /* file:// */ gchar *_path = strchr(path2, '?'); - gint track = 0; - ProbeResult *pr; - InputPlugin *real_ip_plugin; + gint track = 0; + ProbeResult *pr; + InputPlugin *real_ip_plugin; Tuple *tuple = NULL; AUDDBG("f: play_cue_uri\n"); @@ -404,389 +386,251 @@ AUDDBG("play_cue_uri: path2 = %s\n", path2); /* stop watchdog thread */ +#if USE_WATCHDOG g_mutex_lock(cue_mutex); watchdog_state = STOP; g_mutex_unlock(cue_mutex); g_cond_signal(cue_cond); +#endif if (_path != NULL && *_path == '?') { *_path = '\0'; _path++; - track = atoi(_path); - } - cur_cue_track = track; - cache_cue_file(path2); //path2 should be uri. + track = atoi(_path) - 1; + AUDDBG("track=%d\n",track); + } + cur_cue_track = track; + cache_cue_file(path2); /* path2 should be uri. */ if (cue_file == NULL || !aud_vfs_file_test(cue_file, G_FILE_TEST_EXISTS)) return; - pr = aud_input_check_file(cue_file, FALSE); - if (pr == NULL) - return; + pr = aud_input_check_file(cue_file, FALSE); /* find actual input plugin */ + if (pr == NULL) + return; + + real_ip_plugin = pr->ip; - real_ip_plugin = pr->ip; + if (real_ip_plugin != NULL) + { + if (real_ip) + g_free(real_ip); - if (real_ip_plugin != NULL) - { - if (real_ip) - g_free(real_ip); + /* duplicate original playback and modify */ + real_ip = (InputPlayback *)g_memdup(data, sizeof(InputPlayback)); + real_ip->plugin = real_ip_plugin; + real_ip->plugin->set_info = set_info_override; + real_ip->filename = cue_file; - /* duplicate original playback and modify */ - real_ip = (InputPlayback *)g_memdup(data, sizeof(InputPlayback)); - real_ip->plugin = real_ip_plugin; - real_ip->plugin->set_info = set_info_override; - real_ip->filename = cue_file; + data->playing = 1; - data->playing = 1; + real_play_thread = + g_thread_create((GThreadFunc)(real_ip->plugin->play_file), + (gpointer)real_ip, TRUE, NULL); + g_usleep(50000); /* wait for 50msec while real input plugin + is initializing. */ - real_play_thread = g_thread_create((GThreadFunc)(real_ip->plugin->play_file), (gpointer)real_ip, TRUE, NULL); - g_usleep(50000); // wait for 50msec while real input plugin is initializing. - - if(real_ip->plugin->mseek) { + if(real_ip->plugin->mseek) { AUDDBG("mseek\n"); - real_ip->plugin->mseek(real_ip, finetune_seek ? finetune_seek : cue_tracks[track].index); - } - else - real_ip->plugin->seek(real_ip, finetune_seek ? finetune_seek / 1000 : cue_tracks[track].index / 1000 + 1); + real_ip->plugin->mseek(real_ip, finetune_seek ? + finetune_seek : cue_tracks[track].index); + } + else + real_ip->plugin->seek(real_ip, finetune_seek ? + finetune_seek / 1000 : + cue_tracks[track].index / 1000 + 1); g_mutex_lock(cue_target_time_mutex); target_time = finetune_seek ? finetune_seek : cue_tracks[track].index; g_mutex_unlock(cue_target_time_mutex); - AUDDBG("cue: play_cue_uri: target_time = %d\n", target_time); + AUDDBG("cue: play_cue_uri: target_time = %lu\n", target_time); tuple = real_ip->plugin->get_song_tuple(cue_file); if(tuple) { - cue_tracks[last_cue_track].index = aud_tuple_get_int(tuple, FIELD_LENGTH, NULL); + cue_tracks[last_cue_track].index = + aud_tuple_get_int(tuple, FIELD_LENGTH, NULL); aud_tuple_free(tuple); tuple = NULL; } /* kick watchdog thread */ +#if USE_WATCHDOG g_mutex_lock(cue_mutex); watchdog_state = RUN; g_mutex_unlock(cue_mutex); g_cond_signal(cue_cond); AUDDBG("watchdog activated\n"); - +#endif finetune_seek = 0; if(real_play_thread) { g_mutex_lock(cue_block_mutex); - g_cond_wait(cue_block_cond, cue_block_mutex); // block until stop() is called. - g_mutex_unlock(cue_block_mutex); + /* block until stop() is called. */ + g_cond_wait(cue_block_cond, cue_block_mutex); + g_mutex_unlock(cue_block_mutex); } - } + } AUDDBG("e: play_cue_uri\n"); } -/******************************************************* watchdog */ + +/******************************************************** cuefile */ -/* - * This is fairly hard to explain. - * - * Basically we loop until we have reached the correct track. - * Then we set a finetune adjustment to make sure we stay in the - * right place. - * - * I used to recurse here (it was prettier), but that didn't work - * as well as I was hoping. - * - * Anyhow, yeah. The logic here isn't great, but it works, so I'm - * cool with it. - * - * - nenolod - */ -static gpointer watchdog_func(gpointer data) +void +free_cue_info(void) { - gint time = 0; - Playlist *playlist = NULL; - GTimeVal sleep_time; - - AUDDBG("f: watchdog\n"); - - while(1) { -#if 0 - AUDDBG("time = %d cur = %d cidx = %d nidx = %d last = %d\n", - time, cur_cue_track, - cue_tracks[cur_cue_track].index, - cue_tracks[cur_cue_track+1].index, last_cue_track); -#endif - g_get_current_time(&sleep_time); - g_time_val_add(&sleep_time, 10000); // interval is 10msec. + g_free(cue_file); cue_file = NULL; + g_free(cue_title); cue_title = NULL; + g_free(cue_performer); cue_performer = NULL; + g_free(cue_genre); cue_genre = NULL; + g_free(cue_year); cue_year = NULL; + g_free(cue_track); cue_track = NULL; - g_mutex_lock(cue_mutex); - switch(watchdog_state) { - case EXIT: - AUDDBG("e: watchdog exit\n"); - g_mutex_unlock(cue_mutex); // stop() will lock cue_mutex. - stop(real_ip); // need not to care about real_ip != NULL here. - g_thread_exit(NULL); - break; - case RUN: - if(!playlist) - playlist = aud_playlist_get_active(); - g_cond_timed_wait(cue_cond, cue_mutex, &sleep_time); - break; - case STOP: - AUDDBG("watchdog deactivated\n"); - g_cond_wait(cue_cond, cue_mutex); - playlist = aud_playlist_get_active(); - break; - } - g_mutex_unlock(cue_mutex); - - if(watchdog_state != RUN) - continue; + for (; last_cue_track > 0; last_cue_track--) { + g_free(cue_tracks[last_cue_track-1].performer); + cue_tracks[last_cue_track-1].performer = NULL; + g_free(cue_tracks[last_cue_track-1].title); + cue_tracks[last_cue_track-1].title = NULL; + } + AUDDBG("free_cue_info: last_cue_track = %d\n", last_cue_track); + last_cue_track = 0; +} - time = audacious_drct_get_output_time(); -#if 0 - AUDDBG("time = %d target_time = %d\n", time, target_time); -#endif - if(time == 0 || time <= target_time) - continue; +void +cache_cue_file(char *f) +{ + VFSFile *file = aud_vfs_fopen(f, "rb"); + gchar line[MAX_CUE_LINE_LENGTH+1]; - // prev track - if (time < cue_tracks[cur_cue_track].index) - { - static gint incr = 0; - gint oldpos = cur_cue_track; - AUDDBG("i: watchdog prev\n"); - AUDDBG("time = %d cur = %d cidx = %d nidx = %d\n", time, cur_cue_track, - cue_tracks[cur_cue_track].index, - cue_tracks[cur_cue_track+1].index); + if(!file) + return; - while(time < cue_tracks[cur_cue_track].index) { - cur_cue_track--; - incr = cur_cue_track - oldpos; // relative position - if (time >= cue_tracks[cur_cue_track].index) - finetune_seek = time; + while (TRUE) { + gint p, q; - AUDDBG("cue: prev_track: time = %d cue_tracks[cur_cue_track].index = %d\n", - time, cue_tracks[cur_cue_track].index); - AUDDBG("cue: prev_track: finetune_seek = %d\n", finetune_seek); - } - - g_mutex_lock(cue_target_time_mutex); - target_time = finetune_seek ? finetune_seek : cue_tracks[cur_cue_track].index; - g_mutex_unlock(cue_target_time_mutex); - AUDDBG("cue: prev_track: target_time = %d\n", target_time); - g_idle_add_full(G_PRIORITY_HIGH , do_setpos, &incr, NULL); - continue; + if (aud_vfs_fgets(line, MAX_CUE_LINE_LENGTH+1, file) == NULL) { + aud_vfs_fclose(file); + cue_tracks[last_cue_track-1].duration = + full_length - cue_tracks[last_cue_track-1].index; + return; } - // next track - if (cur_cue_track + 1 < last_cue_track && time > cue_tracks[cur_cue_track + 1].index) - { - static gint incr = 0; - gint oldpos = cur_cue_track; - AUDDBG("i: watchdog next\n"); - AUDDBG("time = %d cur = %d cidx = %d nidx = %d last = %d lidx = %d\n", time, cur_cue_track, - cue_tracks[cur_cue_track].index, - cue_tracks[cur_cue_track+1].index, - last_cue_track, cue_tracks[last_cue_track].index); - while(time > cue_tracks[cur_cue_track + 1].index) { - cur_cue_track++; - incr = cur_cue_track - oldpos; // relative position - if (time >= cue_tracks[cur_cue_track].index) - finetune_seek = time; - AUDDBG("cue: next_track: time = %d cue_tracks[cur_cue_track].index = %d\n", - time, cue_tracks[cur_cue_track].index); - AUDDBG("cue: next_track: finetune_seek = %d\n", finetune_seek); + for (p = 0; line[p] && isspace((int) line[p]); p++); + if (!line[p]) + continue; + for (q = p; line[q] && !isspace((int) line[q]); q++); + if (!line[q]) + continue; + line[q] = '\0'; + for (q++; line[q] && isspace((int) line[q]); q++); + if (strcasecmp(line+p, "REM") == 0) { + for (p = q; line[p] && !isspace((int) line[p]); p++); + if (!line[p]) + continue; + line[p] = '\0'; + for (p++; line[p] && isspace((int) line[p]); p++); + if(strcasecmp(line+q, "GENRE") == 0) { + fix_cue_argument(line+p); + if (last_cue_track == 0) + cue_genre = aud_str_to_utf8(line + p); } - - g_mutex_lock(cue_target_time_mutex); - target_time = finetune_seek ? finetune_seek : cue_tracks[cur_cue_track].index; - g_mutex_unlock(cue_target_time_mutex); - AUDDBG("cue: next_track: target_time = %d\n", target_time); - if(aud_cfg->stopaftersong) { - g_idle_add_full(G_PRIORITY_HIGH, do_stop, (void *)real_ip, NULL); - continue; - } - else { - g_idle_add_full(G_PRIORITY_HIGH , do_setpos, &incr, NULL); - continue; + if(strcasecmp(line+q, "DATE") == 0) { + gchar *tmp; + fix_cue_argument(line+p); + if (last_cue_track == 0) { + tmp = g_strdup(line + p); + if (tmp) { + cue_year = strtok(tmp, "/"); + } + } } } + else if (strcasecmp(line+p, "PERFORMER") == 0) { + fix_cue_argument(line+q); - // last track - if (cur_cue_track + 1 == last_cue_track && - (cue_tracks[last_cue_track].index - time < 500 || - time > cue_tracks[last_cue_track].index) ){ // may not happen. for safety. - if(!real_ip->output->buffer_playing()) { - gint pos = aud_playlist_get_position(playlist); - if (pos + 1 == aud_playlist_get_length(playlist)) { - AUDDBG("i: watchdog eof reached\n\n"); - if(aud_cfg->repeat) { - static gint incr = 0; - incr = -pos; - g_idle_add_full(G_PRIORITY_HIGH , do_setpos, &incr, NULL); - continue; - } - else { - g_idle_add_full(G_PRIORITY_HIGH, do_stop, (void *)real_ip, NULL); - continue; - } + if (last_cue_track == 0) + cue_performer = aud_str_to_utf8(line + q); + else + cue_tracks[last_cue_track - 1].performer = aud_str_to_utf8(line + q); + } + else if (strcasecmp(line+p, "FILE") == 0) { + gchar *tmp = g_path_get_dirname(f); + fix_cue_argument(line+q); + cue_file = g_strdup_printf("%s/%s", tmp, line+q); + g_free(tmp); + } + else if (strcasecmp(line+p, "TITLE") == 0) { + fix_cue_argument(line+q); + if (last_cue_track == 0) + cue_title = aud_str_to_utf8(line + q); + else + cue_tracks[last_cue_track-1].title = aud_str_to_utf8(line + q); + } + else if (strcasecmp(line+p, "TRACK") == 0) { + gint track; + + fix_cue_argument(line+q); + for (p = q; line[p] && isdigit((int) line[p]); p++); + line[p] = '\0'; + for (; line[q] && line[q] == '0'; q++); + if (!line[q]) + continue; + track = atoi(line+q); + if (track >= MAX_CUE_TRACKS) + continue; + last_cue_track = track; + cue_tracks[last_cue_track-1].index = 0; + cue_tracks[last_cue_track-1].performer = NULL; + cue_tracks[last_cue_track-1].title = NULL; + } + else if (strcasecmp(line+p, "INDEX") == 0) { + gint min, sec, frac; + for (p = q; line[p] && !isspace((int) line[p]); p++); + if (!line[p]) + continue; + line[p] = '\0'; + for (p++; line[p] && isspace((int) line[p]); p++); + if(strcasecmp(line+q, "01") == 0) { + fix_cue_argument(line+p); + if(sscanf(line+p, "%d:%d:%d", &min, &sec, &frac) == 3) { + cue_tracks[last_cue_track-1].index = + min * 60000 + sec * 1000 + frac * 1000 / 75; } - else { - if(aud_cfg->stopaftersong) { - g_idle_add_full(G_PRIORITY_HIGH, do_stop, (void *)real_ip, NULL); - continue; - } - AUDDBG("i: watchdog end of cue, advance in playlist\n\n"); - static gint incr = 1; - g_idle_add_full(G_PRIORITY_HIGH , do_setpos, &incr, NULL); - continue; + } + else if(strcasecmp(line+q, "00") == 0) { + if(sscanf(line+p, "%d:%d:%d", &min, &sec, &frac) == 3) { + gint index0 = min * 60000 + sec * 1000 + frac * 10; + cue_tracks[last_cue_track-2].duration = + index0 - cue_tracks[last_cue_track-2].index; } } } } - AUDDBG("e: watchdog\n"); - return NULL; // dummy. -} -/******************************************************** cuefile */ - -static void free_cue_info(void) -{ - g_free(cue_file); cue_file = NULL; - g_free(cue_title); cue_title = NULL; - g_free(cue_performer); cue_performer = NULL; - g_free(cue_genre); cue_genre = NULL; - g_free(cue_year); cue_year = NULL; - g_free(cue_track); cue_track = NULL; - - for (; last_cue_track > 0; last_cue_track--) { - g_free(cue_tracks[last_cue_track-1].performer); - cue_tracks[last_cue_track-1].performer = NULL; - g_free(cue_tracks[last_cue_track-1].title); - cue_tracks[last_cue_track-1].title = NULL; - } - AUDDBG("free_cue_info: last_cue_track = %d\n", last_cue_track); - last_cue_track = 0; + aud_vfs_fclose(file); } -static void cache_cue_file(char *f) +void +fix_cue_argument(char *line) { - VFSFile *file = aud_vfs_fopen(f, "rb"); - gchar line[MAX_CUE_LINE_LENGTH+1]; - - if(!file) - return; - - while (TRUE) { - gint p; - gint q; - - if (aud_vfs_fgets(line, MAX_CUE_LINE_LENGTH+1, file) == NULL) { - aud_vfs_fclose(file); - return; - } - - for (p = 0; line[p] && isspace((int) line[p]); p++); - if (!line[p]) - continue; - for (q = p; line[q] && !isspace((int) line[q]); q++); - if (!line[q]) - continue; - line[q] = '\0'; - for (q++; line[q] && isspace((int) line[q]); q++); - if (strcasecmp(line+p, "REM") == 0) { - for (p = q; line[p] && !isspace((int) line[p]); p++); - if (!line[p]) - continue; - line[p] = '\0'; - for (p++; line[p] && isspace((int) line[p]); p++); - if(strcasecmp(line+q, "GENRE") == 0) { - fix_cue_argument(line+p); - if (last_cue_track == 0) - cue_genre = aud_str_to_utf8(line + p); - } - if(strcasecmp(line+q, "DATE") == 0) { - gchar *tmp; - fix_cue_argument(line+p); - if (last_cue_track == 0) { - tmp = g_strdup(line + p); - if (tmp) { - cue_year = strtok(tmp, "/"); // XXX: always in the same format? - } - } - } - } - else if (strcasecmp(line+p, "PERFORMER") == 0) { - fix_cue_argument(line+q); - - if (last_cue_track == 0) - cue_performer = aud_str_to_utf8(line + q); - else - cue_tracks[last_cue_track - 1].performer = aud_str_to_utf8(line + q); - } - else if (strcasecmp(line+p, "FILE") == 0) { - gchar *tmp = g_path_get_dirname(f); - fix_cue_argument(line+q); - cue_file = g_strdup_printf("%s/%s", tmp, line+q); //XXX need to check encoding? - g_free(tmp); - } - else if (strcasecmp(line+p, "TITLE") == 0) { - fix_cue_argument(line+q); - if (last_cue_track == 0) - cue_title = aud_str_to_utf8(line + q); - else - cue_tracks[last_cue_track-1].title = aud_str_to_utf8(line + q); - } - else if (strcasecmp(line+p, "TRACK") == 0) { - gint track; - - fix_cue_argument(line+q); - for (p = q; line[p] && isdigit((int) line[p]); p++); - line[p] = '\0'; - for (; line[q] && line[q] == '0'; q++); - if (!line[q]) - continue; - track = atoi(line+q); - if (track >= MAX_CUE_TRACKS) - continue; - last_cue_track = track; - cue_tracks[last_cue_track-1].index = 0; - cue_tracks[last_cue_track-1].performer = NULL; - cue_tracks[last_cue_track-1].title = NULL; - } - else if (strcasecmp(line+p, "INDEX") == 0) { - gint min, sec, frac; - for (p = q; line[p] && !isspace((int) line[p]); p++); - if (!line[p]) - continue; - for (p++; line[p] && isspace((int) line[p]); p++); - for (q = p; line[q] && !isspace((int) line[q]); q++); - - if(sscanf(line+p, "%d:%d:%d", &min, &sec, &frac) == 3) { - cue_tracks[last_cue_track-1].index = min * 60000 + sec * 1000 + frac * 1000 / 75; + if (line[0] == '"') { + gchar *l2; + for (l2 = line+1; *l2 && *l2 != '"'; l2++) + *(l2-1) = *l2; + *(l2-1) = *l2; + for (; *line && *line != '"'; line++) { + if (*line == '\\' && *(line+1)) { + for (l2 = line+1; *l2 && *l2 != '"'; l2++) + *(l2-1) = *l2; + *(l2-1) = *l2; } } + *line = '\0'; } - - aud_vfs_fclose(file); + else { + for (; *line && *line != '\r' && *line != '\n'; line++); + *line = '\0'; + } } - -static void fix_cue_argument(char *line) -{ - if (line[0] == '"') { - gchar *l2; - for (l2 = line+1; *l2 && *l2 != '"'; l2++) - *(l2-1) = *l2; - *(l2-1) = *l2; - for (; *line && *line != '"'; line++) { - if (*line == '\\' && *(line+1)) { - for (l2 = line+1; *l2 && *l2 != '"'; l2++) - *(l2-1) = *l2; - *(l2-1) = *l2; - } - } - *line = '\0'; - } - else { - for (; *line && *line != '\r' && *line != '\n'; line++); - *line = '\0'; - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cue/cuesheet.h Sat Oct 11 20:03:01 2008 +0900 @@ -0,0 +1,64 @@ +#ifndef _CUE_H_ +#define _CUE_H_ + +#include "config.h" + +#define AUD_DEBUG 1 + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <audacious/plugin.h> +#include <audacious/output.h> + +#define MAX_CUE_LINE_LENGTH 1000 +#define MAX_CUE_TRACKS 1000 + +extern GMutex *cue_mutex; +extern GCond *cue_cond; + +typedef enum { + STOP = 0, + RUN, + EXIT +} watchdog_state_t; + +extern watchdog_state_t watchdog_state; + +extern gint last_cue_track; +extern gint cur_cue_track; +extern gulong target_time; +extern GMutex *cue_target_time_mutex; + +typedef struct cue_tracks { + gchar *title; + gchar *performer; + gint index; + gint duration; +} cue_tracks_t; + +extern cue_tracks_t cue_tracks[]; +extern gint finetune_seek; +extern InputPlayback *real_ip; +extern InputPlayback *caller_ip; + +/* prototypes */ +void cache_cue_file(gchar *f); +void free_cue_info(void); +void fix_cue_argument(char *line); +int is_our_file(gchar *filename); +void play(InputPlayback *data); +void play_cue_uri(InputPlayback *data, gchar *uri); +void mseek(InputPlayback *data, gulong time); +void seek(InputPlayback *data, gint time); +void stop(InputPlayback *data); +void cue_pause(InputPlayback *data, short); +Tuple *get_song_tuple(gchar *uri); +void cue_init(void); +gint get_time(InputPlayback *playback); +void cue_cleanup(void); +gpointer watchdog_func(gpointer data); +Tuple *probe_for_tuple(gchar *songFilename, VFSFile *fd); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cue/watchdog.c Sat Oct 11 20:03:01 2008 +0900 @@ -0,0 +1,166 @@ +#include "cuesheet.h" + +gboolean +do_stop(gpointer data) +{ + AUDDBG("f: do_stop\n"); + audacious_drct_stop(); + AUDDBG("e: do_stop\n"); + + return FALSE; /* only once */ +} + +gboolean +do_setpos(gpointer data) +{ + Playlist *playlist = aud_playlist_get_active(); + gint pos = aud_playlist_get_position_nolock(playlist); + gint incr = *(gint *)data; + + /* mpris needs state change */ + audacious_drct_stop(); + + pos = pos + incr; + if(pos < 0) + pos = 0; + + AUDDBG("do_setpos: pos = %d\n\n", pos); + + if (!playlist) + return FALSE; + + /* being done from the main loop thread, does not require locks */ + aud_playlist_set_position(playlist, (guint)pos); + + /* mpris needs state change */ + audacious_drct_play(); + + return FALSE; /* only once */ +} + +gpointer +watchdog_func(gpointer data) +{ + gint time = 0; + Playlist *playlist = NULL; + GTimeVal sleep_time; + + AUDDBG("enter\n"); + + while(1) { +#if 0 + AUDDBG("time = %d cur = %d cidx = %d nidx = %d last = %d\n", + time, + cur_cue_track, + cue_tracks[cur_cue_track].index, + cue_tracks[cur_cue_track+1].index, + last_cue_track); +#endif + g_get_current_time(&sleep_time); + g_time_val_add(&sleep_time, 500000); /* interval is 0.5sec. */ + + g_mutex_lock(cue_mutex); + switch(watchdog_state) { + case EXIT: + AUDDBG("e: watchdog exit\n"); + g_mutex_unlock(cue_mutex); /* stop() will lock cue_mutex */ + stop(real_ip); /* no need to care real_ip != NULL here. */ + g_thread_exit(NULL); + break; + case RUN: + if(!playlist) + playlist = aud_playlist_get_active(); + g_cond_timed_wait(cue_cond, cue_mutex, &sleep_time); + break; + case STOP: + AUDDBG("watchdog deactivated\n"); + g_cond_wait(cue_cond, cue_mutex); + playlist = aud_playlist_get_active(); + break; + } + g_mutex_unlock(cue_mutex); + + if(watchdog_state != RUN) + continue; + + /* get raw time */ + time = real_ip->output->output_time(); + +#if 0 + AUDDBG("time = %d target_time = %lu durattion = %d\n", + time, + target_time, + cue_tracks[cur_cue_track].duration); +#endif + + if(time == 0 || time <= target_time) + continue; + + /* next track */ + if(time >= cue_tracks[cur_cue_track].index + + cue_tracks[cur_cue_track].duration) + { + static gint incr = 0; + AUDDBG("i: watchdog next\n"); + AUDDBG("time = %d cur = %d cidx = %d nidx = %d last = %d lidx = %d\n", + time, + cur_cue_track, + cue_tracks[cur_cue_track].index, + cue_tracks[cur_cue_track+1].index, + last_cue_track, + cue_tracks[last_cue_track].index); + + incr = 1; /* is this ok? */ + + if(aud_cfg->stopaftersong) { + g_idle_add_full(G_PRIORITY_HIGH, do_stop, (void *)real_ip, NULL); + continue; + } + else { + g_idle_add_full(G_PRIORITY_HIGH , do_setpos, &incr, NULL); + continue; + } + } + + /* last track */ + if (cur_cue_track + 1 == last_cue_track && + (cue_tracks[last_cue_track].index - time < 500 || + time > cue_tracks[last_cue_track].index) ){ + AUDDBG("last track\n"); + gint pos = aud_playlist_get_position(playlist); + if (pos + 1 == aud_playlist_get_length(playlist)) { + + AUDDBG("i: watchdog eof reached\n\n"); + + if(aud_cfg->repeat) { + static gint incr = 0; + incr = -pos; + g_idle_add_full(G_PRIORITY_HIGH , do_setpos, &incr, NULL); + continue; + } + else { + g_idle_add_full(G_PRIORITY_HIGH, do_stop, + (void *)real_ip, NULL); + continue; + } + } + else { + if(aud_cfg->stopaftersong) { + g_idle_add_full(G_PRIORITY_HIGH, do_stop, + (void *)real_ip, NULL); + continue; + } + + AUDDBG("i: watchdog end of cue, advance in playlist\n\n"); + + static gint incr = 1; + g_idle_add_full(G_PRIORITY_HIGH , do_setpos, &incr, NULL); + continue; + } + } + } + + AUDDBG("e: watchdog\n"); + + return NULL; /* dummy */ +}