Mercurial > audlegacy-plugins
diff src/vtx/vtx.c @ 749:26ff35aa9b2b trunk
[svn] - vtx input plugin based on a submission from Pavel Vymetalek.
author | nenolod |
---|---|
date | Wed, 28 Feb 2007 04:38:53 -0800 |
parents | |
children | cd854e8ced20 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vtx/vtx.c Wed Feb 28 04:38:53 2007 -0800 @@ -0,0 +1,330 @@ +/* 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/titlestring.h> +#include <audacious/vfs.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 }; + +int +vtx_is_our_fd (char *filename, VFSFile *fp) +{ + char buf[2]; + + 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 = vfs_fopen(filename, "rb"); + ret = vtx_is_our_fd(filename, fp); + vfs_fclose(fp); + + return ret; +} + +TitleInput * +vtx_get_song_tuple_from_vtx(const gchar *filename, ayemu_vtx_t *in) +{ + TitleInput *out = bmp_title_input_new(); + gchar *string; + + out->performer = g_strdup(in->hdr.author); + out->track_name = g_strdup(in->hdr.title); + + out->file_name = g_strdup(g_basename(filename)); + out->file_path = g_path_get_dirname(filename); + if ((string = strrchr(out->file_name, '.'))) + { + out->file_ext = string + 1; + *string = '\0'; + } + + out->length = in->hdr.regdata_size / 14 * 1000 / 50; + + return out; +} + +TitleInput * +vtx_get_song_tuple(gchar *filename) +{ + ayemu_vtx_t tmp; + + if (ayemu_vtx_open (&tmp, filename)) + { + TitleInput *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, 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) + produce_audio(playback->output->written_time (), FMT_S16_NE, + chans , SNDBUFSIZE, sndbuf, &playback->playing); + + if (playback->eof) + { + playback->output->buffer_free (); + playback->output->buffer_free (); + } + + /* 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; + } + } + + /* close sound and release vtx file must be done in vtx_stop() */ + g_thread_exit (NULL); + + return NULL; +} + +void vtx_play_file (InputPlayback *playback) +{ + gchar *filename = playback->filename; + gchar *buf; + TitleInput *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 = xmms_get_titlestring(xmms_get_gentitle_format(), ti); + + vtx_ip.set_info (buf, vtx.hdr.regdata_size / 14 * 1000 / 50, + 14 * 50 * 8, freq, bits / 8); + + g_free (buf); + + bmp_title_input_free(ti); + + playback->playing = TRUE; + play_thread = g_thread_create (play_loop, playback, TRUE, NULL); + } +} + +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)) { + TitleInput *ti = vtx_get_song_tuple_from_vtx(filename, &tmp); + + *title = xmms_get_titlestring(xmms_get_gentitle_format(), ti); + *length = ti->length; + + ayemu_vtx_free (&tmp); + bmp_title_input_free(ti); + } +} + +InputPlugin vtx_ip = { + NULL, /* FILLED BY XMMS */ + NULL, /* FILLED BY XMMS */ + "VTX Plugin", /* Plugin description */ + NULL, /* Initialization */ + vtx_about, /* Show aboutbox */ + vtx_config, /* Show/edit configuration */ + vtx_is_our_file, /* Check file, return 1 if the plugin can handle this file */ + NULL, /* Scan directory */ + vtx_play_file, /* Play given file */ + vtx_stop, /* Stop playing */ + vtx_pause, /* Pause playing */ + vtx_seek, /* Seek time */ + NULL, /* Set equalizer */ + NULL, /* Get playing time (obsoleted by InputPlayback API) */ + NULL, /* Get volume */ + NULL, /* Set volume */ + NULL, /* Cleanup */ + NULL, /* OBSOLETE! */ + NULL, /* Send data to Visualization plugin */ + NULL, NULL, /* FILLED BY XMMS */ + vtx_get_song_info, /* Get song title and length */ + vtx_file_info, /* Show file-information dialog */ + NULL, /* FILLED BY XMMS */ + vtx_get_song_tuple, /* Tuple */ + NULL, /* Tuple */ + NULL, /* Buffer */ + vtx_is_our_fd, /* VFS */ + vtx_fmts /* ext assist */ +}; + +/* called from xmms for plug */ +InputPlugin * +get_iplugin_info (void) +{ + vtx_ip.description = g_strdup (_("VTX Plugin")); + return &vtx_ip; +} +