Mercurial > audlegacy
view Plugins/Input/console/Audacious_Driver.cpp @ 412:451d2dc68ba8 trunk
[svn] Support .cmf .sci & .laa without stealing .mid from timidity.
author | chainsaw |
---|---|
date | Mon, 09 Jan 2006 13:15:02 -0800 |
parents | e296500f595a |
children | 8ddd961ef0ff |
line wrap: on
line source
/* * Audacious: Cross platform multimedia player * Copyright (c) 2005 Audacious Team * * Driver for Game_Music_Emu library. See details at: * http://www.slack.net/~ant/libs/ */ #include "Audacious_Driver.h" extern "C" { #include <glib.h> #include <glib/gi18n.h> #include <gtk/gtk.h> #include "libaudacious/configdb.h" #include "libaudacious/util.h" #include "libaudacious/titlestring.h" #include "libaudacious/vfs.h" #include "audacious/input.h" #include "audacious/output.h" #include "libaudcore/playback.h" }; struct AudaciousConsoleConfig audcfg = { 180, FALSE, 32000 }; #include <cstring> #include <stdio.h> #ifdef WORDS_BIGENDIAN # define MY_FMT FMT_S16_BE #else # define MY_FMT FMT_S16_LE #endif static Spc_Emu *spc = NULL; static Nsf_Emu *nsf = NULL; static Gbs_Emu *gbs = NULL; static Gym_Emu *gym = NULL; static Vgm_Emu *vgm = NULL; static GThread *decode_thread; GStaticMutex playback_mutex = G_STATIC_MUTEX_INIT; static void *play_loop_spc(gpointer arg); static void *play_loop_nsf(gpointer arg); static void *play_loop_gbs(gpointer arg); static void *play_loop_gym(gpointer arg); static void *play_loop_vgm(gpointer arg); static void console_init(void); extern "C" void console_aboutbox(void); static void console_stop(void); static void console_pause(gshort p); static int get_time(void); static gboolean console_ip_is_going; extern InputPlugin console_ip; static int playing_type; static int is_our_file(gchar *filename) { VFSFile *file; gchar magic[4]; if (file = vfs_fopen(filename, "rb")) { vfs_fread(magic, 1, 4, file); if (!strncmp(magic, "SNES", 4)) { vfs_fclose(file); return PLAY_TYPE_SPC; } if (!strncmp(magic, "NESM", 4)) { vfs_fclose(file); return PLAY_TYPE_NSF; } if (!strncmp(magic, "GYMX", 4)) { vfs_fclose(file); return PLAY_TYPE_GYM; } vfs_fclose(file); } if (file = vfs_fopen(filename, "rb")) { vfs_fread(magic, 1, 3, file); if (!strncmp(magic, "GBS", 3)) { vfs_fclose(file); return PLAY_TYPE_GBS; } if (!strncmp(magic, "Vgm", 3)) { vfs_fclose(file); return PLAY_TYPE_VGM; } vfs_fclose(file); } return 0; } static gchar *get_title_spc(gchar *filename) { gchar *title; Emu_Std_Reader reader; Spc_Emu::header_t header; reader.open(filename); reader.read(&header, sizeof(header)); if (header.version > 10) { TitleInput *tinput; tinput = bmp_title_input_new(); tinput->performer = g_strdup(header.game); tinput->album_name = g_strdup(header.game); tinput->track_name = g_strdup(header.song); tinput->file_name = g_path_get_basename(filename); tinput->file_path = g_path_get_dirname(filename); title = xmms_get_titlestring(xmms_get_gentitle_format(), tinput); g_free(tinput); } else title = g_path_get_basename(filename); return title; } static gchar *get_title_nsf(gchar *filename) { gchar *title; title = g_path_get_basename(filename); return title; } static gchar *get_title_gbs(gchar *filename) { gchar *title; title = g_path_get_basename(filename); return title; } static gchar *get_title_gym(gchar *filename) { gchar *title; Emu_Std_Reader reader; Gym_Emu::header_t header; reader.open(filename); reader.read(&header, sizeof(header)); if (header.song) { TitleInput *tinput; tinput = bmp_title_input_new(); tinput->performer = g_strdup(header.game); tinput->album_name = g_strdup(header.game); tinput->track_name = g_strdup(header.song); tinput->file_name = g_path_get_basename(filename); tinput->file_path = g_path_get_dirname(filename); title = xmms_get_titlestring(xmms_get_gentitle_format(), tinput); g_free(tinput); } else title = g_path_get_basename(filename); return title; } static gchar *get_title_vgm(gchar *filename) { gchar *title; title = g_path_get_basename(filename); return title; } static gchar *get_title(gchar *filename) { switch (is_our_file(filename)) { case PLAY_TYPE_SPC: return get_title_spc(filename); break; case PLAY_TYPE_NSF: return get_title_nsf(filename); break; case PLAY_TYPE_GBS: return get_title_gbs(filename); break; case PLAY_TYPE_GYM: return get_title_gym(filename); break; case PLAY_TYPE_VGM: return get_title_vgm(filename); break; } return NULL; } static void get_song_info(char *filename, char **title, int *length) { (*title) = get_title(filename); if (audcfg.loop_length) (*length) = audcfg.loop_length; else (*length) = -1; } static void play_file_spc(char *filename) { gchar *name; Emu_Std_Reader reader; Spc_Emu::header_t header; gint samplerate; if (audcfg.resample == TRUE) samplerate = audcfg.resample_rate; else samplerate = Spc_Emu::native_sample_rate; reader.open(filename); reader.read(&header, sizeof(header)); spc = new Spc_Emu; spc->init(samplerate); spc->load(header, reader); spc->start_track(0); console_ip_is_going = TRUE; name = get_title(filename); if (audcfg.loop_length) console_ip.set_info(name, audcfg.loop_length * 1000, spc->voice_count() * 1000, samplerate, 2); else console_ip.set_info(name, -1, spc->voice_count() * 1000, samplerate, 2); g_free(name); if (!console_ip.output->open_audio(MY_FMT, samplerate, 2)) return; playing_type = PLAY_TYPE_SPC; decode_thread = g_thread_create(play_loop_spc, spc, TRUE, NULL); } static void play_file_nsf(char *filename) { gchar *name; Emu_Std_Reader reader; Nsf_Emu::header_t header; gint samplerate; if (audcfg.resample == TRUE) samplerate = audcfg.resample_rate; else samplerate = 44100; reader.open(filename); reader.read(&header, sizeof(header)); nsf = new Nsf_Emu; nsf->init(samplerate); nsf->load(header, reader); nsf->start_track(0); console_ip_is_going = TRUE; name = get_title(filename); if (audcfg.loop_length) console_ip.set_info(name, audcfg.loop_length * 1000, nsf->voice_count() * 1000, samplerate, 2); else console_ip.set_info(name, -1, nsf->voice_count() * 1000, samplerate, 2); g_free(name); if (!console_ip.output->open_audio(MY_FMT, samplerate, 2)) return; playing_type = PLAY_TYPE_NSF; decode_thread = g_thread_create(play_loop_nsf, nsf, TRUE, NULL); } static void play_file_gbs(char *filename) { gchar *name; Emu_Std_Reader reader; Gbs_Emu::header_t header; gint samplerate; if (audcfg.resample == TRUE) samplerate = audcfg.resample_rate; else samplerate = 44100; reader.open(filename); reader.read(&header, sizeof(header)); gbs = new Gbs_Emu; gbs->init(samplerate); gbs->load(header, reader); gbs->start_track(0); console_ip_is_going = TRUE; name = get_title(filename); if (audcfg.loop_length) console_ip.set_info(name, audcfg.loop_length * 1000, gbs->voice_count() * 1000, samplerate, 2); else console_ip.set_info(name, -1, gbs->voice_count() * 1000, samplerate, 2); g_free(name); if (!console_ip.output->open_audio(MY_FMT, samplerate, 2)) return; playing_type = PLAY_TYPE_GBS; decode_thread = g_thread_create(play_loop_gbs, gbs, TRUE, NULL); } static void play_file_gym(char *filename) { gchar *name; Emu_Std_Reader reader; Gym_Emu::header_t header; gint samplerate; if (audcfg.resample == TRUE) samplerate = audcfg.resample_rate; else samplerate = 44100; reader.open(filename); reader.read(&header, sizeof(header)); gym = new Gym_Emu; gym->init(samplerate); gym->load(header, reader); gym->start_track(0); console_ip_is_going = TRUE; name = get_title(filename); if (gym->track_length() > 0) console_ip.set_info(name, gym->track_length() * 1000, gym->voice_count() * 1000, samplerate, 2); else if (audcfg.loop_length) console_ip.set_info(name, audcfg.loop_length * 1000, gym->voice_count() * 1000, samplerate, 2); else console_ip.set_info(name, -1, gym->voice_count() * 1000, samplerate, 2); g_free(name); if (!console_ip.output->open_audio(MY_FMT, samplerate, 2)) return; playing_type = PLAY_TYPE_GYM; decode_thread = g_thread_create(play_loop_gym, gym, TRUE, NULL); } static void play_file_vgm(char *filename) { gchar *name; Emu_Std_Reader reader; Vgm_Emu::header_t header; gint samplerate; if (audcfg.resample == TRUE) samplerate = audcfg.resample_rate; else samplerate = 44100; reader.open(filename); reader.read(&header, sizeof(header)); vgm = new Vgm_Emu; vgm->init(samplerate); vgm->load(header, reader); vgm->start_track(0); console_ip_is_going = TRUE; name = get_title(filename); if (audcfg.loop_length) console_ip.set_info(name, audcfg.loop_length * 1000, vgm->voice_count() * 1000, samplerate, 2); else console_ip.set_info(name, -1, vgm->voice_count() * 1000, samplerate, 2); g_free(name); if (!console_ip.output->open_audio(MY_FMT, samplerate, 2)) return; playing_type = PLAY_TYPE_VGM; decode_thread = g_thread_create(play_loop_vgm, vgm, TRUE, NULL); } static void play_file(char *filename) { switch (is_our_file(filename)) { case PLAY_TYPE_SPC: play_file_spc(filename); break; case PLAY_TYPE_NSF: play_file_nsf(filename); break; case PLAY_TYPE_GBS: play_file_gbs(filename); break; case PLAY_TYPE_GYM: play_file_gym(filename); break; case PLAY_TYPE_VGM: play_file_vgm(filename); break; } } static void seek(gint time) { // XXX: Not yet implemented } InputPlugin console_ip = { NULL, NULL, NULL, console_init, console_aboutbox, NULL, is_our_file, NULL, play_file, console_stop, console_pause, seek, NULL, get_time, NULL, NULL, NULL, NULL, NULL, NULL, NULL, get_song_info, NULL, NULL }; static void console_stop(void) { console_ip_is_going = FALSE; g_thread_join(decode_thread); console_ip.output->close_audio(); } extern "C" InputPlugin *get_iplugin_info(void) { console_ip.description = g_strdup_printf(_("SPC, GYM, NSF, VGM and GBS module decoder")); return &console_ip; } static void console_pause(gshort p) { console_ip.output->pause(p); } static void *play_loop_spc(gpointer arg) { g_static_mutex_lock(&playback_mutex); Spc_Emu *my_spc = (Spc_Emu *) arg; Music_Emu::sample_t buf[1024]; for (;;) { if (!console_ip_is_going) break; my_spc->play(1024, buf); if ((console_ip.output->output_time() / 1000) > audcfg.loop_length && audcfg.loop_length != 0) break; produce_audio(console_ip.output->written_time(), MY_FMT, 1, 2048, buf, NULL); while(console_ip.output->buffer_free() < 2048) xmms_usleep(10000); } delete spc; console_ip.output->close_audio(); console_ip_is_going = FALSE; playing_type = PLAY_TYPE_NONE; g_static_mutex_unlock(&playback_mutex); g_thread_exit(NULL); return NULL; } static void *play_loop_nsf(gpointer arg) { g_static_mutex_lock(&playback_mutex); Nsf_Emu *my_nsf = (Nsf_Emu *) arg; Music_Emu::sample_t buf[1024]; for (;;) { if (!console_ip_is_going) break; my_nsf->play(1024, buf); if ((console_ip.output->output_time() / 1000) > audcfg.loop_length && audcfg.loop_length != 0) break; produce_audio(console_ip.output->written_time(), MY_FMT, 1, 2048, buf, NULL); while(console_ip.output->buffer_free() < 2048) xmms_usleep(10000); } delete nsf; console_ip.output->close_audio(); console_ip_is_going = FALSE; playing_type = PLAY_TYPE_NONE; g_static_mutex_unlock(&playback_mutex); g_thread_exit(NULL); return NULL; } static void *play_loop_gbs(gpointer arg) { g_static_mutex_lock(&playback_mutex); Gbs_Emu *my_gbs = (Gbs_Emu *) arg; Music_Emu::sample_t buf[1024]; for (;;) { if (!console_ip_is_going) break; my_gbs->play(1024, buf); if ((console_ip.output->output_time() / 1000) > audcfg.loop_length && audcfg.loop_length != 0) break; produce_audio(console_ip.output->written_time(), MY_FMT, 1, 2048, buf, NULL); while(console_ip.output->buffer_free() < 2048) xmms_usleep(10000); } delete gbs; console_ip.output->close_audio(); console_ip_is_going = FALSE; playing_type = PLAY_TYPE_NONE; g_static_mutex_unlock(&playback_mutex); g_thread_exit(NULL); return NULL; } static void *play_loop_gym(gpointer arg) { g_static_mutex_lock(&playback_mutex); Gym_Emu *my_gym = (Gym_Emu *) arg; Music_Emu::sample_t buf[1024]; for (;;) { if (!console_ip_is_going) break; my_gym->play(1024, buf); if ((console_ip.output->output_time() / 1000) > gym->track_length() && gym->track_length() != 0) break; if ((console_ip.output->output_time() / 1000) > audcfg.loop_length && audcfg.loop_length != 0) break; produce_audio(console_ip.output->written_time(), MY_FMT, 1, 2048, buf, NULL); while(console_ip.output->buffer_free() < 2048) xmms_usleep(10000); } delete gym; console_ip.output->close_audio(); console_ip_is_going = FALSE; playing_type = PLAY_TYPE_NONE; g_static_mutex_unlock(&playback_mutex); g_thread_exit(NULL); return NULL; } static void *play_loop_vgm(gpointer arg) { g_static_mutex_lock(&playback_mutex); Vgm_Emu *my_vgm = (Vgm_Emu *) arg; Music_Emu::sample_t buf[1024]; for (;;) { if (!console_ip_is_going) break; my_vgm->play(1024, buf); if ((console_ip.output->output_time() / 1000) > audcfg.loop_length && audcfg.loop_length != 0) break; produce_audio(console_ip.output->written_time(), MY_FMT, 1, 2048, buf, NULL); while(console_ip.output->buffer_free() < 2048) xmms_usleep(10000); } delete vgm; console_ip.output->close_audio(); console_ip_is_going = FALSE; playing_type = PLAY_TYPE_NONE; g_static_mutex_unlock(&playback_mutex); g_thread_exit(NULL); return NULL; } static int get_time(void) { if (console_ip_is_going == TRUE) return console_ip.output->output_time(); else return -1; } static void console_init(void) { ConfigDb *db; db = bmp_cfg_db_open(); bmp_cfg_db_get_int(db, "console", "loop_length", &audcfg.loop_length); bmp_cfg_db_get_bool(db, "console", "resample", &audcfg.resample); bmp_cfg_db_get_int(db, "console", "resample_rate", &audcfg.resample_rate); bmp_cfg_db_close(db); } extern "C" void console_aboutbox(void) { xmms_show_message(_("About the Console Music Decoder"), _("Console music decoder engine based on Game_Music_Emu 0.2.4.\n" "Audacious implementation by: William Pitcock <nenolod@nenolod.net>"), _("Ok"), FALSE, NULL, NULL); }