Mercurial > audlegacy-plugins
view src/vtx/vtx.c @ 2494:862477de235b
Automated merge with ssh://hg.atheme.org//hg/audacious-plugins
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Mon, 31 Mar 2008 04:45:30 -0500 |
parents | 33ffac81f4c7 |
children | 42a5c9d5830b |
line wrap: on
line source
/* VTXplugin - VTX player for XMMS * * Copyright (C) 2002-2004 Sashnov Alexander * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <audacious/plugin.h> #include <audacious/output.h> #include <audacious/util.h> #include <audacious/configdb.h> #include <audacious/vfs.h> #include <audacious/main.h> #include <audacious/strings.h> #include <audacious/i18n.h> #include "vtx.h" #include <ayemu.h> extern InputPlugin vtx_ip; #define SNDBUFSIZE 1024 char sndbuf[SNDBUFSIZE]; static GThread *play_thread = NULL; int seek_to; int freq = 44100; int chans = 2; /* NOTE: if you change 'bits' you also need change constant FMT_S16_NE * to more appropriate in line * * (vtx_ip.output->open_audio (FMT_S16_NE, * freq, chans) == 0) * in function vtx_play_file() * * and in produce_audio() function call. */ const int bits = 16; ayemu_ay_t ay; ayemu_vtx_t vtx; static gchar *vtx_fmts[] = { "vtx", NULL }; void vtx_init(void) { ConfigDb *db; db = aud_cfg_db_open(); aud_cfg_db_get_int(db, NULL, "src_rate", &freq); if (freq < 4000 || freq > 192000) freq = 44100; aud_cfg_db_close(db); } int vtx_is_our_fd (char *filename, VFSFile *fp) { char buf[2]; aud_vfs_fread (buf, 2, 1, fp); return (!strncasecmp (buf, "ay", 2) || !strncasecmp (buf, "ym", 2)); } int vtx_is_our_file (char *filename) { gboolean ret; VFSFile *fp; fp = aud_vfs_fopen(filename, "rb"); ret = vtx_is_our_fd(filename, fp); aud_vfs_fclose(fp); return ret; } Tuple * vtx_get_song_tuple_from_vtx(const gchar *filename, ayemu_vtx_t *in) { Tuple *out = aud_tuple_new_from_filename(filename); aud_tuple_associate_string(out, FIELD_ARTIST, NULL, in->hdr.author); aud_tuple_associate_string(out, FIELD_TITLE, NULL, in->hdr.title); aud_tuple_associate_int(out, FIELD_LENGTH, NULL, in->hdr.regdata_size / 14 * 1000 / 50); aud_tuple_associate_string(out, FIELD_GENRE, NULL, (in->hdr.chiptype == AYEMU_AY)? "AY chiptunes" : "YM chiptunes"); aud_tuple_associate_string(out, FIELD_ALBUM, NULL, in->hdr.from); aud_tuple_associate_string(out, -1, "game", in->hdr.from); aud_tuple_associate_string(out, FIELD_QUALITY, NULL, "sequenced"); aud_tuple_associate_string(out, FIELD_CODEC, NULL, in->hdr.tracker); aud_tuple_associate_string(out, -1, "tracker", in->hdr.tracker); aud_tuple_associate_int(out, FIELD_YEAR, NULL, in->hdr.year); return out; } Tuple * vtx_get_song_tuple(gchar *filename) { ayemu_vtx_t tmp; if (ayemu_vtx_open (&tmp, filename)) { Tuple *ti = vtx_get_song_tuple_from_vtx(filename, &tmp); ayemu_vtx_free(&tmp); return ti; } return NULL; } /* sound playing thread, runing by vtx_play_file() */ static gpointer play_loop (gpointer args) { InputPlayback *playback = (InputPlayback *) args; void *stream; /* pointer to current position in sound buffer */ unsigned char regs[14]; int need; int left; /* how many sound frames can play with current AY register frame */ int donow; int rate; left = 0; rate = chans * (bits / 8); while (playback->playing && !playback->eof) { /* fill sound buffer */ stream = sndbuf; for (need = SNDBUFSIZE / rate ; need > 0 ; need -= donow) if (left > 0) { /* use current AY register frame */ donow = (need > left) ? left : need; left -= donow; stream = ayemu_gen_sound (&ay, (char *)stream, donow * rate); } else { /* get next AY register frame */ if (ayemu_vtx_get_next_frame (&vtx, (char *)regs) == 0) { playback->eof = TRUE; donow = need; memset (stream, 0, donow * rate); } else { left = freq / vtx.hdr.playerFreq; ayemu_set_regs (&ay, regs); donow = 0; } } while (playback->output->buffer_free () < SNDBUFSIZE && playback->playing && seek_to == -1) g_usleep(10000); if (playback->playing && seek_to == -1) playback->pass_audio(playback, FMT_S16_NE, chans , SNDBUFSIZE, sndbuf, &playback->playing); if (playback->eof) { playback->output->buffer_free (); playback->output->buffer_free (); while (playback->output->buffer_playing()) g_usleep(10000); playback->playing = 0; } /* jump to time in seek_to (in seconds) */ if (seek_to != -1) { vtx.pos = seek_to * 50; /* (time in sec) * 50 = offset in AY register data frames */ playback->output->flush (seek_to * 1000); seek_to = -1; } } ayemu_vtx_free (&vtx); return NULL; } void vtx_play_file (InputPlayback *playback) { gchar *filename = playback->filename; gchar *buf; Tuple *ti; memset (&ay, 0, sizeof(ay)); if (!ayemu_vtx_open (&vtx, filename)) g_print ("libvtx: Error read vtx header from %s\n", filename); else if (!ayemu_vtx_load_data (&vtx)) g_print ("libvtx: Error read vtx data from %s\n", filename); else { ayemu_init(&ay); ayemu_set_chip_type(&ay, vtx.hdr.chiptype, NULL); ayemu_set_chip_freq(&ay, vtx.hdr.chipFreq); ayemu_set_stereo(&ay, vtx.hdr.stereo, NULL); playback->error = FALSE; if (playback->output->open_audio (FMT_S16_NE, freq, chans) == 0) { g_print ("libvtx: output audio error!\n"); playback->error = TRUE; playback->playing = FALSE; return; } playback->eof = FALSE; seek_to = -1; ti = vtx_get_song_tuple_from_vtx(playback->filename, &vtx); buf = aud_tuple_formatter_make_title_string(ti, aud_get_gentitle_format()); playback->set_params (playback, buf, vtx.hdr.regdata_size / 14 * 1000 / 50, 14 * 50 * 8, freq, bits / 8); g_free (buf); aud_tuple_free(ti); playback->playing = TRUE; play_thread = g_thread_self(); playback->set_pb_ready(playback); play_loop(playback); } } void vtx_stop (InputPlayback *playback) { if (playback->playing && play_thread != NULL) { playback->playing = FALSE; g_thread_join (play_thread); play_thread = NULL; playback->output->close_audio (); ayemu_vtx_free (&vtx); } } /* seek to specified number of seconds */ void vtx_seek (InputPlayback *playback, int time) { if (time * 50 < vtx.hdr.regdata_size / 14) { playback->eof = FALSE; seek_to = time; /* wait for affect changes in parallel thread */ while (seek_to != -1) g_usleep (10000); } } /* Pause or unpause */ void vtx_pause (InputPlayback *playback, short p) { playback->output->pause (p); } /* Function to grab the title string */ void vtx_get_song_info (char *filename, char **title, int *length) { ayemu_vtx_t tmp; (*length) = -1; (*title) = NULL; if (ayemu_vtx_open (&tmp, filename)) { Tuple *ti = vtx_get_song_tuple_from_vtx(filename, &tmp); *title = aud_tuple_formatter_process_string(ti, aud_get_gentitle_format()); *length = aud_tuple_get_int(ti, FIELD_LENGTH, NULL); ayemu_vtx_free (&tmp); aud_tuple_free(ti); } } InputPlugin vtx_ip = { .description = "VTX Audio Plugin", /* Plugin description */ .init = vtx_init, /* Initialization */ .about = vtx_about, /* Show aboutbox */ .configure = vtx_config, /* Show/edit configuration */ .is_our_file = vtx_is_our_file, /* Check file, return 1 if the plugin can handle this file */ .play_file = vtx_play_file, /* Play given file */ .stop = vtx_stop, /* Stop playing */ .pause = vtx_pause, /* Pause playing */ .seek = vtx_seek, /* Seek time */ .get_song_info = vtx_get_song_info, /* Get song title and length */ .file_info_box = vtx_file_info, /* Show file-information dialog */ .get_song_tuple = vtx_get_song_tuple, /* Tuple */ .is_our_file_from_vfs = vtx_is_our_fd, /* VFS */ .vfs_extensions = vtx_fmts /* ext assist */ }; InputPlugin *vtx_iplist[] = { &vtx_ip, NULL }; SIMPLE_INPUT_PLUGIN(vtx, vtx_iplist);