Merge pull request #6 from TricksterGuy/master

Fixes for undefined reference errors when linking / update audacious plugin for audacious 3.5.1
This commit is contained in:
Chris Moeller 2014-09-14 18:52:03 -07:00
commit 716d359865
16 changed files with 442 additions and 807 deletions

View File

@ -1,7 +1,7 @@
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.53)
AC_INIT(audacious-vgmstream,1.0.0)
AM_INIT_AUTOMAKE(audacious-vgmstream, 1.0.0)
AC_INIT(audacious-vgmstream,1.1.0)
AM_INIT_AUTOMAKE(audacious-vgmstream, 1.1.0)
AM_CONFIG_HEADER(unix/config.h)
AM_DISABLE_STATIC
@ -15,7 +15,7 @@ AM_PROG_LIBTOOL
AC_PATH_X
AC_PATH_XTRA
PKG_CHECK_MODULES(AUDACIOUS, [audacious >= 1.4.0],,
PKG_CHECK_MODULES(AUDACIOUS, [audacious >= 3.5.0],,
[AC_MSG_ERROR([Cannot find Audacious, have you installed audacious yet?])]
)

View File

@ -108,6 +108,7 @@ META_OBJS=meta/adx_header.o \
meta/ps2_sl3.o \
meta/ps2_aus.o \
meta/fsb.o \
meta/fsb5.o \
meta/rsd.o \
meta/rwx.o \
meta/xwb.o \
@ -293,7 +294,7 @@ META_OBJS=meta/adx_header.o \
meta/ps2_vbk.o \
meta/otm.o \
meta/bcstm.o \
meta/bfwav.o
meta/bfwav.o
OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS)

View File

@ -1,10 +1,10 @@
noinst_LTLIBRARIES = libmeta.la
AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
AM_MAKEFLAGS=-f Makefile.unix
libmeta_la_LDFLAGS =
libmeta_la_SOURCES =
libmeta_la_LDFLAGS =
libmeta_la_SOURCES =
libmeta_la_SOURCES += Cstr.c
libmeta_la_SOURCES += adx_header.c
libmeta_la_SOURCES += afc_header.c
@ -56,6 +56,7 @@ libmeta_la_SOURCES += xss.c
libmeta_la_SOURCES += ps2_sl3.c
libmeta_la_SOURCES += ps2_aus.c
libmeta_la_SOURCES += fsb.c
libmeta_la_SOURCES += fsb5.c
libmeta_la_SOURCES += rsd.c
libmeta_la_SOURCES += rwx.c
libmeta_la_SOURCES += xwb.c
@ -235,7 +236,9 @@ libmeta_la_SOURCES += ps2_hsf.c
libmeta_la_SOURCES += ps3_ivag.c
libmeta_la_SOURCES += ps2_2pfs.c
libmeta_la_SOURCES += ubi_ckd.c
libmeta_la_SOURCES += otm.c
libmeta_la_SOURCES += bcstm.c
libmeta_la_SOURCES += otm.c
libmeta_la_SOURCES += bcstm.c
libmeta_la_SOURCES += bfwav.c
libmeta_la_SOURCES += ps2_vbk.c
EXTRA_DIST = meta.h

View File

@ -3,8 +3,8 @@ lib_LTLIBRARIES = libvgmstream.la
libdir = @plugindir@/@INPUT_PLUGIN_DIR@
AM_MAKEFLAGS=-f Makefile.unix
AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir) -I$(top_builddir)/in_cube @GTK_CFLAGS@
AM_LIBS =
AM_CXXFLAGS = -Wall -std=c++11 -fpermissive @CXXFLAGS@ -I$(top_builddir) -I$(top_srcdir) -I$(top_builddir)/in_cube @GTK_CFLAGS@
AM_LIBS =
libvgmstream_la_LDFLAGS = -no-undefined -module -avoid-version -export-symbols-regex get_plugin_info ../src/libvgmstream.la
libvgmstream_la_SOURCES = main.c data.c gui.c vfs.c settings.c
libvgmstream_la_SOURCES = exts.cc plugin.cc settings.cc vfs.cc

View File

@ -1,19 +1,9 @@
#include <audacious/util.h>
#include <cstdlib>
void vgmstream_init();
void vgmstream_about();
void vgmstream_configure();
void vgmstream_destroy();
void vgmstream_play(InputPlayback *context);
void vgmstream_stop(InputPlayback *context);
void vgmstream_pause(InputPlayback *context,gshort paused);
void vgmstream_seek(InputPlayback *context,gint time);
int vgmstream_get_time(InputPlayback *context);
void vgmstream_mseek(InputPlayback *context,gulong ms);
void vgmstream_file_info_box(const gchar *pFile);
Tuple * vgmstream_probe_for_tuple(const gchar *uri, VFSFile *fd);
#include "exts.h"
gchar *vgmstream_exts [] = {
const char *vgmstream_exts[] =
{
"2dx9",
"2pfs",
@ -288,22 +278,3 @@ gchar *vgmstream_exts [] = {
/* terminator */
NULL
};
InputPlugin vgmstream_iplug = {
.description = "VGMStream Decoder",
.init = vgmstream_init,
.about = vgmstream_about,
.configure = vgmstream_configure,
.cleanup = vgmstream_destroy,
.probe_for_tuple = vgmstream_probe_for_tuple,
.play_file = vgmstream_play,
.stop = vgmstream_stop,
.pause = vgmstream_pause,
.seek = vgmstream_seek,
.vfs_extensions = vgmstream_exts,
.mseek = vgmstream_mseek,
.file_info_box = vgmstream_file_info_box,
};

6
unix/exts.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef __EXTS__
#define __EXTS__
extern const char *vgmstream_exts[];
#endif

View File

@ -1,224 +0,0 @@
#include <audacious/util.h>
#include <audacious/configdb.h>
#include <glib.h>
#include <gtk/gtk.h>
#include "gui.h"
#include "version.h"
#include "settings.h"
#include <stdio.h>
#include <stdarg.h>
extern SETTINGS settings;
static GtkWidget *about_box;
static GtkWidget *config_win;
static GtkWidget *loopcount_win;
static GtkWidget *fadeseconds_win;
static GtkWidget *fadedelayseconds_win;
void DisplayError(char *pMsg,...)
{
GtkWidget *mbox_win,
*mbox_vbox1,
*mbox_vbox2,
*mbox_frame,
*mbox_label,
*mbox_bbox,
*mbox_ok;
va_list vlist;
char message[1024];
va_start(vlist,pMsg);
vsnprintf(message,sizeof(message),pMsg,vlist);
va_end(vlist);
mbox_win = gtk_window_new( GTK_WINDOW_TOPLEVEL );
gtk_window_set_type_hint( GTK_WINDOW(mbox_win), GDK_WINDOW_TYPE_HINT_DIALOG );
gtk_signal_connect(GTK_OBJECT(mbox_win), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &mbox_win);
gtk_window_set_title(GTK_WINDOW(mbox_win), (gchar *)"vgmstream file information");
gtk_window_set_policy(GTK_WINDOW(mbox_win), FALSE, FALSE, FALSE);
gtk_container_border_width(GTK_CONTAINER(mbox_win), 10);
mbox_vbox1 = gtk_vbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(mbox_win), mbox_vbox1);
mbox_frame = gtk_frame_new((gchar *)" vgmstream error ");
gtk_container_set_border_width(GTK_CONTAINER(mbox_frame), 5);
gtk_box_pack_start(GTK_BOX(mbox_vbox1), mbox_frame, FALSE, FALSE, 0);
mbox_vbox2 = gtk_vbox_new(FALSE, 10);
gtk_container_set_border_width(GTK_CONTAINER(mbox_vbox2), 5);
gtk_container_add(GTK_CONTAINER(mbox_frame), mbox_vbox2);
mbox_label = gtk_label_new((gchar *)message);
gtk_misc_set_alignment(GTK_MISC(mbox_label), 0, 0);
gtk_label_set_justify(GTK_LABEL(mbox_label), GTK_JUSTIFY_LEFT);
gtk_box_pack_start(GTK_BOX(mbox_vbox2), mbox_label, TRUE, TRUE, 0);
gtk_widget_show(mbox_label);
mbox_bbox = gtk_hbutton_box_new();
gtk_button_box_set_layout(GTK_BUTTON_BOX(mbox_bbox), GTK_BUTTONBOX_SPREAD);
gtk_button_box_set_spacing(GTK_BUTTON_BOX(mbox_bbox), 5);
gtk_box_pack_start(GTK_BOX(mbox_vbox2), mbox_bbox, FALSE, FALSE, 0);
mbox_ok = gtk_button_new_with_label((gchar *)"OK");
gtk_signal_connect_object(GTK_OBJECT(mbox_ok), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(mbox_win));
GTK_WIDGET_SET_FLAGS(mbox_ok, GTK_CAN_DEFAULT);
gtk_box_pack_start(GTK_BOX(mbox_bbox), mbox_ok, TRUE, TRUE, 0);
gtk_widget_show(mbox_ok);
gtk_widget_grab_default(mbox_ok);
gtk_widget_show(mbox_bbox);
gtk_widget_show(mbox_vbox2);
gtk_widget_show(mbox_frame);
gtk_widget_show(mbox_vbox1);
gtk_widget_show(mbox_win);
}
static int ToInt(const char *pText,int *val)
{
char *end;
if (!pText) return 0;
*val = strtol(pText,&end,10);
if (!end || *end)
return 0;
return 1;
}
static void OnOK()
{
SETTINGS s;
// update my variables
if (!ToInt(gtk_entry_get_text(GTK_ENTRY(loopcount_win)),&s.loopcount))
{
DisplayError("Invalid loop times entry.");
return;
}
if (!ToInt(gtk_entry_get_text(GTK_ENTRY(fadeseconds_win)),&s.fadeseconds))
{
DisplayError("Invalid fade delay entry.");
return;
}
if (!ToInt(gtk_entry_get_text(GTK_ENTRY(fadedelayseconds_win)),&s.fadedelayseconds))
{
DisplayError("Invalid fade length entry.");
return;
}
if (SaveSettings(&s))
{
settings = s; /* update local copy */
gtk_widget_destroy(config_win);
}
else
{
DisplayError("Unable to save settings\n");
}
}
void vgmstream_gui_about()
{
if (about_box)
{
gdk_window_raise(about_box->window);
return;
}
about_box = audacious_info_dialog(
(gchar *) "About VGMStream Decoder",
(gchar *) "[ VGMStream Decoder ]\n\n"
"audacious-vgmstream version: " AUDACIOUSVGMSTREAM_VERSION "\n\n"
"audacious-vgmstream written by Todd Jeffreys (http://voidpointer.org/)\n"
"vgmstream written by hcs, FastElbja, manakoAT, and bxaimc (http://www.sf.net/projects/vgmstream)",
(gchar *) "OK",
FALSE, NULL, NULL);
gtk_signal_connect(GTK_OBJECT(about_box), "destroy",
GTK_SIGNAL_FUNC(gtk_widget_destroyed), &about_box);
}
void vgmstream_gui_configure()
{
GtkWidget *hbox;
GtkWidget *tmp;
GtkWidget *vbox;
GtkWidget *ok;
GtkWidget *cancel;
GtkWidget *bbox;
char buf[8];
if (config_win)
{
gdk_window_raise(config_win->window);
return;
}
config_win = gtk_window_new( GTK_WINDOW_TOPLEVEL );
gtk_window_set_type_hint( GTK_WINDOW(config_win), GDK_WINDOW_TYPE_HINT_DIALOG );
gtk_signal_connect(GTK_OBJECT(config_win), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &config_win);
gtk_window_set_title(GTK_WINDOW(config_win), (gchar *)"vgmstream file configuration");
gtk_window_set_policy(GTK_WINDOW(config_win), FALSE, FALSE, FALSE);
gtk_container_border_width(GTK_CONTAINER(config_win), 10);
vbox = gtk_vbox_new(FALSE,5);
// loop count
hbox = gtk_hbox_new(FALSE,5);
tmp = gtk_label_new("Loop count");
gtk_box_pack_start(GTK_BOX(hbox),tmp,FALSE,FALSE,0);
loopcount_win = gtk_entry_new_with_max_length(3);
gtk_editable_set_editable(GTK_EDITABLE(loopcount_win),TRUE);
sprintf(buf,"%i",settings.loopcount);
gtk_entry_set_text(GTK_ENTRY(loopcount_win),buf);
gtk_box_pack_start(GTK_BOX(hbox),loopcount_win,FALSE,FALSE,0);
gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);
// fade length
hbox = gtk_hbox_new(FALSE,5);
tmp = gtk_label_new("Fade length");
gtk_box_pack_start(GTK_BOX(hbox),tmp,FALSE,FALSE,0);
fadeseconds_win = gtk_entry_new_with_max_length(3);
gtk_editable_set_editable(GTK_EDITABLE(fadeseconds_win),TRUE);
sprintf(buf,"%i",settings.fadeseconds);
gtk_entry_set_text(GTK_ENTRY(fadeseconds_win),buf);
gtk_box_pack_start(GTK_BOX(hbox),fadeseconds_win,FALSE,FALSE,0);
gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);
// fade delay
hbox = gtk_hbox_new(FALSE,5);
tmp = gtk_label_new("Fade delay");
gtk_box_pack_start(GTK_BOX(hbox),tmp,FALSE,FALSE,0);
fadedelayseconds_win = gtk_entry_new_with_max_length(3);
gtk_editable_set_editable(GTK_EDITABLE(fadedelayseconds_win),TRUE);
sprintf(buf,"%i",settings.fadedelayseconds);
gtk_entry_set_text(GTK_ENTRY(fadedelayseconds_win),buf);
gtk_box_pack_start(GTK_BOX(hbox),fadedelayseconds_win,FALSE,FALSE,0);
gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);
/* buttons on bottom */
bbox = gtk_hbutton_box_new();
gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox),GTK_BUTTONBOX_END);
gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox),5);
ok = gtk_button_new_with_label((gchar *)"OK");
gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(OnOK), NULL);
GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT);
gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
gtk_widget_grab_default(ok);
cancel = gtk_button_new_with_label((gchar *)"Cancel");
gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(config_win));
GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox),bbox,FALSE,FALSE,0);
gtk_container_add(GTK_CONTAINER(config_win),vbox);
gtk_widget_show_all(config_win);
gtk_widget_grab_default(ok);
}

View File

@ -1,7 +0,0 @@
#ifndef __GUI__
#define __GUI__
void vgmstream_gui_about();
void vgmstream_gui_configure();
#endif

View File

@ -1,320 +0,0 @@
#include <audacious/util.h>
#include <audacious/configdb.h>
#include <audacious/plugin.h>
#include <audacious/output.h>
#include <audacious/i18n.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include "version.h"
#include "../src/vgmstream.h"
#include "gui.h"
#include "vfs.h"
#include "settings.h"
#define TM_QUIT 0
#define TM_PLAY 1
#define TM_SEEK 2
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
extern InputPlugin vgmstream_iplug;
//static CDecoder decoder;
static volatile long decode_seek;
static GThread *decode_thread;
static GCond *ctrl_cond = NULL;
static GMutex *ctrl_mutex = NULL;
static gint stream_length_samples;
static gint fade_length_samples;
SETTINGS settings;
static gint decode_pos_samples = 0;
static VGMSTREAM *vgmstream = NULL;
static gchar strPlaying[260];
static InputPlugin *vgmstream_iplist[] = { &vgmstream_iplug, NULL };
static gint loop_forever = 0;
void vgmstream_mseek(InputPlayback *data,gulong ms);
#define CLOSE_STREAM() do { \
if (vgmstream) close_vgmstream(vgmstream); \
vgmstream = NULL; } while (0)
SIMPLE_INPUT_PLUGIN(vgmstream,vgmstream_iplist);
#define DS_EXIT -2
void* vgmstream_play_loop(InputPlayback *playback)
{
int16_t buffer[576*vgmstream->channels];
long l;
gint seek_needed_samples;
gint samples_to_do;
decode_seek = -1;
playback->playing = 1;
playback->eof = 0;
decode_pos_samples = 0;
while (playback->playing)
{
// ******************************************
// Seeking
// ******************************************
// check thread flags, not my favorite method
if (decode_seek == DS_EXIT)
{
goto exit_thread;
}
else if (decode_seek >= 0)
{
/* compute from ms to samples */
seek_needed_samples = (long long)decode_seek * vgmstream->sample_rate / 1000L;
if (seek_needed_samples < decode_pos_samples)
{
/* go back in time, reopen file */
reset_vgmstream(vgmstream);
decode_pos_samples = 0;
samples_to_do = seek_needed_samples;
}
else if (decode_pos_samples < seek_needed_samples)
{
/* go forward in time */
samples_to_do = seek_needed_samples - decode_pos_samples;
}
else
{
/* seek to where we are, how convenient */
samples_to_do = -1;
}
/* do the actual seeking */
if (samples_to_do >= 0)
{
while (samples_to_do > 0)
{
l = min(576,samples_to_do);
render_vgmstream(buffer,l,vgmstream);
samples_to_do -= l;
decode_pos_samples += l;
}
playback->output->flush(decode_seek);
// reset eof flag
playback->eof = 0;
}
// reset decode_seek
decode_seek = -1;
}
// ******************************************
// Playback
// ******************************************
if (!playback->eof)
{
// read data and pass onward
samples_to_do = min(576,stream_length_samples - (decode_pos_samples + 576));
l = (samples_to_do * vgmstream->channels*2);
if (!l)
{
playback->eof = 1;
// will trigger on next run through
}
else
{
// ok we read stuff
render_vgmstream(buffer,samples_to_do,vgmstream);
// fade!
if (vgmstream->loop_flag && fade_length_samples > 0 && !loop_forever) {
int samples_into_fade = decode_pos_samples - (stream_length_samples - fade_length_samples);
if (samples_into_fade + samples_to_do > 0) {
int j,k;
for (j=0;j<samples_to_do;j++,samples_into_fade++) {
if (samples_into_fade > 0) {
double fadedness = (double)(fade_length_samples-samples_into_fade)/fade_length_samples;
for (k=0;k<vgmstream->channels;k++) {
buffer[j*vgmstream->channels+k] =
(short)(buffer[j*vgmstream->channels+k]*fadedness);
}
}
}
}
}
// pass it on
playback->pass_audio(playback,FMT_S16_LE,vgmstream->channels , l , buffer , &playback->playing );
decode_pos_samples += samples_to_do;
}
}
else
{
// at EOF
while (playback->output->buffer_playing())
g_usleep(10000);
playback->playing = 0;
// this effectively ends the loop
}
}
exit_thread:
decode_seek = -1;
playback->playing = 0;
decode_pos_samples = 0;
CLOSE_STREAM();
return 0;
}
void vgmstream_about()
{
vgmstream_gui_about();
}
void vgmstream_configure()
{
vgmstream_gui_configure();
}
void vgmstream_init()
{
LoadSettings(&settings);
ctrl_cond = g_cond_new();
ctrl_mutex = g_mutex_new();
}
void vgmstream_destroy()
{
g_cond_free(ctrl_cond);
ctrl_cond = NULL;
g_mutex_free(ctrl_mutex);
ctrl_mutex = NULL;
}
void vgmstream_mseek(InputPlayback *data,gulong ms)
{
if (vgmstream)
{
decode_seek = ms;
data->eof = 0;
while (decode_seek != -1)
g_usleep(10000);
}
}
void vgmstream_play(InputPlayback *context)
{
// this is now called in a new thread context
vgmstream = init_vgmstream_from_STREAMFILE(open_vfs(context->filename));
if (!vgmstream || vgmstream->channels <= 0)
{
CLOSE_STREAM();
goto end_thread;
}
// open the audio device
if (context->output->open_audio(FMT_S16_LE,vgmstream->sample_rate,vgmstream->channels) == 0)
{
CLOSE_STREAM();
goto end_thread;
}
/* copy file name */
strcpy(strPlaying,context->filename);
// set the info
stream_length_samples = get_vgmstream_play_samples(settings.loopcount,settings.fadeseconds,settings.fadedelayseconds,vgmstream);
if (vgmstream->loop_flag)
{
fade_length_samples = settings.fadeseconds * vgmstream->sample_rate;
} else {
fade_length_samples = -1;
}
gint ms = (stream_length_samples * 1000LL) / vgmstream->sample_rate;
gint rate = vgmstream->sample_rate * 2 * vgmstream->channels;
Tuple * tuple = tuple_new_from_filename(context->filename);
tuple_associate_int(tuple, FIELD_LENGTH, NULL, ms);
tuple_associate_int(tuple, FIELD_BITRATE, NULL, rate);
context->set_tuple(context, tuple);
decode_thread = g_thread_self();
context->set_pb_ready(context);
vgmstream_play_loop(context);
end_thread:
g_mutex_lock(ctrl_mutex);
g_cond_signal(ctrl_cond);
g_mutex_unlock(ctrl_mutex);
}
void vgmstream_stop(InputPlayback *context)
{
if (vgmstream)
{
// kill thread
decode_seek = DS_EXIT;
// wait for it to die
g_mutex_lock(ctrl_mutex);
g_cond_wait(ctrl_cond, ctrl_mutex);
g_mutex_unlock(ctrl_mutex);
// close audio output
}
context->output->close_audio();
// cleanup
CLOSE_STREAM();
}
void vgmstream_pause(InputPlayback *context,gshort paused)
{
context->output->pause(paused);
}
void vgmstream_seek(InputPlayback *context,gint time)
{
vgmstream_mseek(context,time * 1000);
}
Tuple * vgmstream_probe_for_tuple(const gchar * filename, VFSFile * file)
{
VGMSTREAM *infostream = NULL;
Tuple * tuple = NULL;
long length;
infostream = init_vgmstream_from_STREAMFILE(open_vfs(filename));
if (!infostream)
goto fail;
tuple = tuple_new_from_filename (filename);
length = get_vgmstream_play_samples(settings.loopcount,settings.fadeseconds,settings.fadedelayseconds,infostream) * 1000LL / infostream->sample_rate;
tuple_associate_int(tuple, FIELD_LENGTH, NULL, length);
close_vgmstream(infostream);
return tuple;
fail:
if (tuple) {
tuple_free(tuple);
}
if (infostream)
{
close_vgmstream(infostream);
}
return NULL;
}
void vgmstream_file_info_box(const gchar *pFile)
{
char msg[1024] = {0};
VGMSTREAM *stream;
if ((stream = init_vgmstream_from_STREAMFILE(open_vfs(pFile))))
{
describe_vgmstream(stream,msg,sizeof(msg));
close_vgmstream(stream);
audacious_info_dialog("File information",msg,"OK",FALSE,NULL,NULL);
}
}

216
unix/plugin.cc Normal file
View File

@ -0,0 +1,216 @@
#include <cstdlib>
#include <algorithm>
#include <libaudcore/input.h>
#include <libaudcore/plugin.h>
#include <libaudcore/runtime.h>
extern "C" {
#include "../src/vgmstream.h"
}
#include "version.h"
#include "vfs.h"
#include "settings.h"
VGMSTREAM *vgmstream = NULL;
#define CFG_ID "vgmstream" //ID for storing in audacious
// //default-values for Settings
#define DEFAULT_LOOP_FOREVER "1"
#define DEFAULT_FADE_LENGTH "3"
#define DEFAULT_FADE_DELAY "3"
#define DEFAULT_LOOP_COUNT "2"
static const char* const defaults[] =
{
"loop_forever", DEFAULT_LOOP_FOREVER,
"loop_count", DEFAULT_LOOP_COUNT,
"fade_length", DEFAULT_FADE_LENGTH,
"fade_delay", DEFAULT_FADE_DELAY,
NULL
};
bool vgmstream_init()
{
debugMessage("init");
vgmstream_cfg_load();
debugMessage("after load cfg");
return true;
}
void vgmstream_cleanup()
{
debugMessage("cleanup");
vgmstream_cfg_save();
}
void vgmstream_seek(int seek_value, int& current_sample_pos)
{
debugMessage("seeking");
// compute from ms to samples
int seek_needed_samples = (long long)seek_value * vgmstream->sample_rate / 1000L;
short buffer[576 * vgmstream->channels];
int max_buffer_samples = sizeof(buffer) / sizeof(buffer[0]) / vgmstream->channels;
int samples_to_do = 0;
if (seek_needed_samples < current_sample_pos)
{
// go back in time, reopen file
debugMessage("reopen file to seek backward");
reset_vgmstream(vgmstream);
current_sample_pos = 0;
samples_to_do = seek_needed_samples;
}
else if (current_sample_pos < seek_needed_samples)
{
// go forward in time
samples_to_do = seek_needed_samples - current_sample_pos;
}
// do the actual seeking
if (samples_to_do >= 0)
{
debugMessage("render forward");
//render till seeked sample
while (samples_to_do >0)
{
int seek_samples = std::min(max_buffer_samples, samples_to_do);
current_sample_pos += seek_samples;
samples_to_do -= seek_samples;
render_vgmstream(buffer, seek_samples, vgmstream);
}
debugMessage("after render vgmstream");
}
}
bool vgmstream_play(const char * filename, VFSFile * file)
{
int current_sample_pos = 0;
int rate;
debugMessage("start play");
STREAMFILE* streamfile = open_vfs(filename);
if (!streamfile)
{
printf("failed opening %s\n", filename);
return false;
}
vgmstream = init_vgmstream_from_STREAMFILE(streamfile);
close_streamfile(streamfile);
if (!vgmstream || vgmstream->channels <= 0)
{
printf("Error::Channels are zero or couldn't init plugin\n");
if (vgmstream)
close_vgmstream(vgmstream);
vgmstream = NULL;
return false;
}
short buffer[576 * vgmstream->channels];
int max_buffer_samples = sizeof(buffer) / sizeof(buffer[0]) / vgmstream->channels;
int stream_samples_amount = get_vgmstream_play_samples(vgmstream_cfg.loop_count, vgmstream_cfg.fade_length, vgmstream_cfg.fade_delay, vgmstream);
rate = vgmstream->sample_rate * 2 * vgmstream->channels;
aud_input_set_bitrate(rate);
if (!aud_input_open_audio(FMT_S16_LE, vgmstream->sample_rate, 2))
return false;
int fade_samples = vgmstream_cfg.fade_length * vgmstream->sample_rate;
while (!aud_input_check_stop())
{
int toget = max_buffer_samples;
int seek_value = aud_input_check_seek();
if (seek_value > 0)
vgmstream_seek(seek_value, current_sample_pos);
// If we haven't configured the plugin to play forever
// or the current song is not loopable.
if (!vgmstream_cfg.loop_forever || !vgmstream->loop_flag)
{
if (current_sample_pos >= stream_samples_amount)
break;
if (current_sample_pos + toget > stream_samples_amount)
toget = stream_samples_amount - current_sample_pos;
}
render_vgmstream(buffer, toget, vgmstream);
if (vgmstream->loop_flag && fade_samples > 0 && !vgmstream_cfg.loop_forever)
{
int samples_into_fade = current_sample_pos - (stream_samples_amount - fade_samples);
if (samples_into_fade + toget > 0)
{
for (int j = 0; j < toget; j++, samples_into_fade++)
{
if (samples_into_fade > 0)
{
double fadedness = (double)(fade_samples - samples_into_fade) / fade_samples;
for (int k = 0; k < vgmstream->channels; k++)
buffer[j * vgmstream->channels + k] *= fadedness;
}
}
}
}
aud_input_write_audio(buffer, toget * sizeof(short) * vgmstream->channels);
current_sample_pos += toget;
}
debugMessage("finished");
if (vgmstream)
close_vgmstream(vgmstream);
vgmstream = NULL;
return true;
}
// called every time the user adds a new file to playlist
Tuple vgmstream_probe_for_tuple(const char *filename, VFSFile *file)
{
debugMessage("probe for tuple");
Tuple tuple;
int ms;
int rate;
VGMSTREAM* vgmstream = NULL;
STREAMFILE* streamfile = NULL;
streamfile = open_vfs(filename);
vgmstream = init_vgmstream_from_STREAMFILE(streamfile);
tuple.set_filename(filename);
rate = vgmstream->sample_rate * 2 * vgmstream->channels;
tuple.set_int(FIELD_BITRATE, rate);
ms = get_vgmstream_play_samples(vgmstream_cfg.loop_count, vgmstream_cfg.fade_length, vgmstream_cfg.fade_delay, vgmstream) * 1000LL / vgmstream->sample_rate;
tuple.set_int(FIELD_LENGTH, ms);
close_streamfile(streamfile);
close_vgmstream(vgmstream);
return tuple;
}
void vgmstream_cfg_load()
{
debugMessage("cfg_load called");
aud_config_set_defaults(CFG_ID, defaults);
vgmstream_cfg.loop_forever = aud_get_bool(CFG_ID, "loop_forever");
vgmstream_cfg.loop_count = aud_get_int(CFG_ID, "loop_count");
vgmstream_cfg.fade_length = aud_get_double(CFG_ID, "fade_length");
vgmstream_cfg.fade_delay = aud_get_double(CFG_ID, "fade_delay");
}
void vgmstream_cfg_save()
{
debugMessage("cfg_save called");
aud_set_bool(CFG_ID, "loop_forever", vgmstream_cfg.loop_forever);
aud_set_int(CFG_ID, "loop_count", vgmstream_cfg.loop_count);
aud_set_double(CFG_ID, "fade_length", vgmstream_cfg.fade_length);
aud_set_double(CFG_ID, "fade_delay", vgmstream_cfg.fade_delay);
}

View File

@ -1,59 +0,0 @@
#include "settings.h"
#include <audacious/plugin.h>
#define CUBE_CONFIG_TAG "vgmstream"
static ConfigDb *GetConfigFile( void )
{
ConfigDb *cfg = aud_cfg_db_open();
return cfg;
}
void DefaultSettings(LPSETTINGS pSettings)
{
memset(pSettings,0,sizeof(SETTINGS));
pSettings->loopcount = 1;
pSettings->fadeseconds = 0;
pSettings->fadedelayseconds = 0;
}
#define LOOPCOUNT_NAME "loopcount"
#define FADESECOND_NAME "fadeseconds"
#define FADEDELAYSECOND_NAME "fadedelayseconds"
int LoadSettings(LPSETTINGS pSettings)
{
ConfigDb *cfg = GetConfigFile();
if (!cfg)
{
DefaultSettings(pSettings);
}
else
{
int bRet = (aud_cfg_db_get_int(cfg,CUBE_CONFIG_TAG,LOOPCOUNT_NAME,&pSettings->loopcount) &&
aud_cfg_db_get_int(cfg,CUBE_CONFIG_TAG,FADESECOND_NAME,&pSettings->fadeseconds) &&
aud_cfg_db_get_int(cfg,CUBE_CONFIG_TAG,FADEDELAYSECOND_NAME,&pSettings->fadedelayseconds));
aud_cfg_db_close(cfg);
// check if reading one value failed. If so, then use defaults
if (!bRet)
DefaultSettings(pSettings);
}
return 1;
}
int SaveSettings(LPSETTINGS pSettings)
{
ConfigDb *cfg = GetConfigFile();
if (!cfg)
return 0;
aud_cfg_db_set_int(cfg,CUBE_CONFIG_TAG,LOOPCOUNT_NAME,pSettings->loopcount);
aud_cfg_db_set_int(cfg,CUBE_CONFIG_TAG,FADESECOND_NAME,pSettings->fadeseconds);
aud_cfg_db_set_int(cfg,CUBE_CONFIG_TAG,FADEDELAYSECOND_NAME,pSettings->fadedelayseconds);
aud_cfg_db_close(cfg);
return 1;
}

75
unix/settings.cc Normal file
View File

@ -0,0 +1,75 @@
#include "settings.h"
#include <ctime>
#include <sys/time.h>
#include <libaudcore/plugin.h>
#include <libaudcore/i18n.h>
#include <libaudcore/preferences.h>
#include "../src/vgmstream.h"
#include "exts.h"
#include "version.h"
#include "vfs.h"
void debugMessage(const char *str)
{
#ifdef DEBUG
timeval curTime;
gettimeofday(&curTime, NULL);
int milli = curTime.tv_usec / 1000;
char buffer [80];
strftime(buffer, 80, "%H:%M:%S", localtime(&curTime.tv_sec));
char currentTime[84] = "";
sprintf(currentTime, "%s:%d", buffer, milli);
printf("[%s] Debug: %s\n", currentTime, str);
#endif
}
Settings vgmstream_cfg;
bool vgmstream_init();
void vgmstream_cleanup();
Tuple vgmstream_probe_for_tuple(const char *uri, VFSFile *fd);
void vgmstream_play(const char *filename, VFSFile * file);
const char vgmstream_about[] =
{
"audacious-vgmstream version: " AUDACIOUSVGMSTREAM_VERSION "\n\n"
"ported to audacious 3.5.1 by Brandon Whitehead\n"
"adopted from audacious 3 port by Thomas Eppers\n"
"originally written by Todd Jeffreys (http://voidpointer.org/)\n"
"vgmstream written by hcs, FastElbja, manakoAT, and bxaimc (http://www.sf.net/projects/vgmstream)"
};
static const PreferencesWidget vgmstream_widgets[] = {
WidgetLabel(N_("<b>VGMStream Config</b>")),
WidgetCheck(N_("Loop Forever:"), WidgetBool(vgmstream_cfg.loop_forever)),
WidgetSpin(N_("Loop Count:"), WidgetInt(vgmstream_cfg.loop_count), {1, 20, 1}),
WidgetSpin(N_("Fade Length:"), WidgetFloat(vgmstream_cfg.fade_length), {0, 60, 0.1}),
WidgetSpin(N_("Fade Delay:"), WidgetFloat(vgmstream_cfg.fade_delay), {0, 60, 0.1}),
};
static const PluginPreferences vgmstream_prefs = {
{vgmstream_widgets},
vgmstream_cfg_load,
vgmstream_cfg_save
};
#define AUD_PLUGIN_NAME N_("VGMStream Decoder")
#define AUD_PLUGIN_DOMAIN "vgmstream"
#define AUD_PLUGIN_ABOUT vgmstream_about
#define AUD_PLUGIN_INIT vgmstream_init
#define AUD_PLUGIN_CLEANUP vgmstream_cleanup
#define AUD_PLUGIN_PREFS & vgmstream_prefs
#define AUD_INPUT_IS_OUR_FILE nullptr
#define AUD_INPUT_PLAY vgmstream_play
#define AUD_INPUT_READ_TUPLE vgmstream_probe_for_tuple
#define AUD_INPUT_EXTS vgmstream_exts
#define AUD_DECLARE_INPUT
#include <libaudcore/plugin-declare.h>

View File

@ -1,16 +1,18 @@
#ifndef __SETTINGS__
#define __SETTINGS__
typedef struct _SETTINGS
typedef struct
{
int loopcount;
int fadeseconds;
int fadedelayseconds;
} SETTINGS,*PSETTINGS,*LPSETTINGS;
bool loop_forever;
int loop_count;
double fade_length;
double fade_delay;
} Settings;
void DefaultSettings(LPSETTINGS pSettings);
int LoadSettings(LPSETTINGS pSettings);
int SaveSettings(LPSETTINGS pSettings);
extern Settings vgmstream_cfg;
void debugMessage(const char *str);
void vgmstream_cfg_load();
void vgmstream_cfg_save();
#endif

View File

@ -1,6 +1,6 @@
#ifndef __VERSION_H__
#define __VERSION_H__
#define AUDACIOUSVGMSTREAM_VERSION "1.0.0"
#define AUDACIOUSVGMSTREAM_VERSION "1.1.0"
#endif

View File

@ -1,143 +0,0 @@
#include <audacious/util.h>
#include <audacious/configdb.h>
#include <audacious/plugin.h>
#include <audacious/output.h>
#include <audacious/i18n.h>
#include <glib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include "version.h"
#include "../src/vgmstream.h"
#include "vfs.h"
/* vfs_dup doesn't actually work, it just returns us the same pointer
as the one we pass in. Therefore, the offset optimization doesn't work.
So by not defining SUPPORT_DUP, we end up with two VFS handles with
unique offsets.
*/
//#define SUPPORT_DUP 1
typedef struct _VFSSTREAMFILE
{
STREAMFILE sf;
VFSFile *vfsFile;
off_t offset;
char name[260];
char realname[260];
} VFSSTREAMFILE;
static size_t read_vfs(VFSSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length)
{
size_t sz;
/* if the offsets don't match, then we need to perform a seek */
if (streamfile->offset != offset)
{
aud_vfs_fseek(streamfile->vfsFile,offset,SEEK_SET);
streamfile->offset = offset;
}
sz = aud_vfs_fread(dest,1,length,streamfile->vfsFile);
/* increment our current offset */
if (sz >= 0)
streamfile->offset += sz;
return sz;
}
static void close_vfs(VFSSTREAMFILE *streamfile)
{
aud_vfs_fclose(streamfile->vfsFile);
free(streamfile);
}
static size_t get_size_vfs(VFSSTREAMFILE *streamfile)
{
return aud_vfs_fsize(streamfile->vfsFile);
}
static size_t get_offset_vfs(VFSSTREAMFILE *streamfile)
{
//return aud_vfs_ftell(streamfile->vfsFile);
return streamfile->offset;
}
static void get_name_vfs(VFSSTREAMFILE *streamfile,char *buffer,size_t length)
{
strncpy(buffer,streamfile->name,length);
buffer[length-1]='\0';
}
static void get_realname_vfs(VFSSTREAMFILE *streamfile,char *buffer,size_t length)
{
strncpy(buffer,streamfile->realname,length);
buffer[length-1]='\0';
}
static STREAMFILE *open_vfs_by_VFSFILE(VFSFile *file,const char *path);
static STREAMFILE *open_vfs_impl(VFSSTREAMFILE *streamfile,const char * const filename,size_t buffersize)
{
#ifdef SUPPORT_DUP
VFSFile *newfile;
STREAMFILE *newstreamFile;
#endif
if (!filename)
return NULL;
// if same name, duplicate the file pointer we already have open
#ifdef SUPPORT_DUP
if (!strcmp(streamfile->name,filename)) {
if ((newfile = aud_vfs_dup(streamfile->vfsFile)))
{
newstreamFile = open_vfs_by_VFSFILE(newfile,filename);
if (newstreamFile) {
return newstreamFile;
}
// failure, close it and try the default path (which will probably fail a second time)
aud_vfs_fclose(newfile);
}
}
#endif
return open_vfs(filename);
}
static STREAMFILE *open_vfs_by_VFSFILE(VFSFile *file,const char *path)
{
VFSSTREAMFILE *streamfile = malloc(sizeof(VFSSTREAMFILE));
if (!streamfile)
return NULL;
/* success, set our pointers */
memset(streamfile,0,sizeof(VFSSTREAMFILE));
streamfile->sf.read = (void*)read_vfs;
streamfile->sf.get_size = (void*)get_size_vfs;
streamfile->sf.get_offset = (void*)get_offset_vfs;
streamfile->sf.get_name = (void*)get_name_vfs;
streamfile->sf.get_realname = (void*)get_realname_vfs;
streamfile->sf.open = (void*)open_vfs_impl;
streamfile->sf.close = (void*)close_vfs;
streamfile->vfsFile = file;
streamfile->offset = 0;
strncpy(streamfile->name,path,sizeof(streamfile->name));
streamfile->name[sizeof(streamfile->name)-1] = '\0';
{
gchar* realname = g_filename_from_uri(path,NULL,NULL);
strncpy(streamfile->realname,realname,sizeof(streamfile->realname));
streamfile->realname[sizeof(streamfile->realname)-1] = '\0';
g_free(realname);
}
return &streamfile->sf;
}
STREAMFILE *open_vfs(const char *path)
{
VFSFile *vfsFile = aud_vfs_fopen(path,"rb");
if (!vfsFile)
return NULL;
return open_vfs_by_VFSFILE(vfsFile,path);
}

114
unix/vfs.cc Normal file
View File

@ -0,0 +1,114 @@
#include <glib.h>
#include <cstdlib>
#include <libaudcore/plugin.h>
#include "../src/vgmstream.h"
#include "version.h"
#include "vfs.h"
#include "settings.h"
typedef struct _VFSSTREAMFILE
{
STREAMFILE sf;
VFSFile *vfsFile;
off_t offset;
char name[260];
char realname[260];
} VFSSTREAMFILE;
static STREAMFILE *open_vfs_by_VFSFILE(VFSFile *file, const char *path);
static size_t read_vfs(VFSSTREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length)
{
size_t sz;
// if the offsets don't match, then we need to perform a seek
if (streamfile->offset != offset)
{
vfs_fseek(streamfile->vfsFile, offset, SEEK_SET);
streamfile->offset = offset;
}
sz = vfs_fread(dest, 1, length, streamfile->vfsFile);
// increment our current offset
streamfile->offset += sz;
return sz;
}
static void close_vfs(VFSSTREAMFILE *streamfile)
{
debugMessage("close_vfs");
vfs_fclose(streamfile->vfsFile);
free(streamfile);
}
static size_t get_size_vfs(VFSSTREAMFILE *streamfile)
{
return vfs_fsize(streamfile->vfsFile);
}
static size_t get_offset_vfs(VFSSTREAMFILE *streamfile)
{
return streamfile->offset;
}
static void get_name_vfs(VFSSTREAMFILE *streamfile, char *buffer, size_t length)
{
strncpy(buffer, streamfile->name, length);
buffer[length-1] = '\0';
}
static void get_realname_vfs(VFSSTREAMFILE *streamfile, char *buffer, size_t length)
{
strncpy(buffer, streamfile->realname, length);
buffer[length-1]='\0';
}
static STREAMFILE *open_vfs_impl(VFSSTREAMFILE *streamfile, const char * const filename, size_t buffersize)
{
if (!filename)
return NULL;
return open_vfs(filename);
}
static STREAMFILE *open_vfs_by_VFSFILE(VFSFile *file, const char *path)
{
VFSSTREAMFILE *streamfile = (VFSSTREAMFILE*)malloc(sizeof(VFSSTREAMFILE));
if (!streamfile)
return NULL;
// success, set our pointers
memset(streamfile, 0, sizeof(VFSSTREAMFILE));
streamfile->sf.read = read_vfs;
streamfile->sf.get_size = get_size_vfs;
streamfile->sf.get_offset = get_offset_vfs;
streamfile->sf.get_name = get_name_vfs;
streamfile->sf.get_realname = get_realname_vfs;
streamfile->sf.open = open_vfs_impl;
streamfile->sf.close = close_vfs;
streamfile->vfsFile = file;
streamfile->offset = 0;
strncpy(streamfile->name, path, sizeof(streamfile->name));
streamfile->name[sizeof(streamfile->name)-1] = '\0';
{
gchar* realname = g_filename_from_uri(path, NULL, NULL);
strncpy(streamfile->realname, realname, sizeof(streamfile->realname));
streamfile->realname[sizeof(streamfile->realname)-1] = '\0';
g_free(realname);
}
return &streamfile->sf;
}
STREAMFILE *open_vfs(const char *path)
{
VFSFile *vfsFile = vfs_fopen(path, "rb");
if (!vfsFile)
return NULL;
return open_vfs_by_VFSFILE(vfsFile, path);
}