mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 09:40:51 +01:00
Updated audacious VFS STREAMFILE support
git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@198 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
parent
6fb390ea08
commit
882eaf0814
@ -4,6 +4,6 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
|
||||
AM_MAKEFLAGS=-f Makefile.unix
|
||||
|
||||
liblayout_la_LDFLAGS =
|
||||
liblayout_la_SOURCES = ast_blocked.c blocked.c halpst_blocked.c interleave.c nolayout.c xa_blocked.c
|
||||
liblayout_la_SOURCES = ast_blocked.c blocked.c halpst_blocked.c interleave.c nolayout.c xa_blocked.c xbox_blocked.c
|
||||
|
||||
EXTRA_DIST = layout.h
|
||||
|
@ -4,6 +4,6 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
|
||||
AM_MAKEFLAGS=-f Makefile.unix
|
||||
|
||||
libmeta_la_LDFLAGS =
|
||||
libmeta_la_SOURCES = Cstr.c adx_header.c afc_header.c agsc.c ast.c brstm.c gcsw.c halpst.c nds_strm.c ngc_adpdtk.c ngc_dsp_std.c ps2_ads.c ps2_exst.c ps2_int.c ps2_mib.c ps2_mic.c ps2_npsf.c ps2_rxw.c ps2_str.c ps2_svag.c ps2_vag.c psx_cdxa.c raw.c rs03.c rsf.c rwsd.c psx_gms.c
|
||||
libmeta_la_SOURCES = Cstr.c adx_header.c afc_header.c agsc.c ast.c brstm.c gcsw.c halpst.c nds_strm.c ngc_adpdtk.c ngc_dsp_std.c ps2_ads.c ps2_exst.c ps2_ild.c ps2_int.c ps2_mib.c ps2_mic.c ps2_npsf.c ps2_pnb.c ps2_rxw.c ps2_str.c ps2_svag.c ps2_vag.c psx_cdxa.c raw.c rs03.c rsf.c rwsd.c psx_gms.c xbox_xwav.c xbox_wavm.c
|
||||
|
||||
EXTRA_DIST = meta.h
|
||||
|
@ -7,4 +7,4 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir) -I$(top_builddir)/i
|
||||
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
|
||||
libvgmstream_la_SOURCES = main.c data.c gui.c vfs.c
|
||||
|
91
unix/main.c
91
unix/main.c
@ -11,6 +11,7 @@
|
||||
#include "version.h"
|
||||
#include "../src/vgmstream.h"
|
||||
#include "gui.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#define TM_QUIT 0
|
||||
#define TM_PLAY 1
|
||||
@ -44,27 +45,31 @@ static gint get_ms_position()
|
||||
}
|
||||
*/
|
||||
|
||||
/* TODO -
|
||||
|
||||
Rewrite vgmstream/STREAMFILE so that you can open a VGMSTREAM* by providing
|
||||
a custom implementation of STREAMFILE. Audacious wants you to use the
|
||||
VFS functions to do I/O, but VGMSTREAM only supports fopen/fread/etc.
|
||||
*/
|
||||
|
||||
/* Here's a function to convert file://<whatever> to the actual path */
|
||||
static void get_file_name(char *buffer,const char *pfile)
|
||||
static char *get_title(const char *uri,char *title,size_t sz)
|
||||
{
|
||||
/* unconvert from file:// to regular path */
|
||||
gchar *unescaped = g_uri_unescape_string(pfile,NULL);
|
||||
if (strncmp(unescaped,"file://",7) == 0)
|
||||
gchar *base = aud_uri_to_display_basename(uri);
|
||||
#ifdef INCLUDE_BASE_IN_TITLE
|
||||
size_t len;
|
||||
gchar *dir = aud_uri_to_display_dirname(uri);
|
||||
|
||||
/* first copy the dir */
|
||||
len = strlen(dir);
|
||||
strcpy(title,dir);
|
||||
if (dir[len-1] != '/')
|
||||
{
|
||||
strcpy(buffer,unescaped+7);
|
||||
title[len++] = '/';
|
||||
title[len] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(buffer,unescaped);
|
||||
}
|
||||
g_free(unescaped);
|
||||
/* then the basename */
|
||||
strcat(title,base);
|
||||
|
||||
g_free(dir);
|
||||
#else
|
||||
strcpy(title,base);
|
||||
#endif
|
||||
g_free(base);
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
void vgmstream_mseek(InputPlayback *data,gulong ms);
|
||||
@ -106,19 +111,9 @@ void* vgmstream_play_loop(InputPlayback *playback)
|
||||
if (seek_needed_samples < decode_pos_samples)
|
||||
{
|
||||
/* go back in time, reopen file */
|
||||
CLOSE_STREAM();
|
||||
reset_vgmstream(vgmstream);
|
||||
decode_pos_samples = 0;
|
||||
vgmstream = init_vgmstream(strPlaying);
|
||||
if (vgmstream)
|
||||
{
|
||||
samples_to_do = seek_needed_samples;
|
||||
}
|
||||
else
|
||||
{
|
||||
samples_to_do = -1;
|
||||
// trigger eof
|
||||
playback->eof = 1;
|
||||
}
|
||||
samples_to_do = seek_needed_samples;
|
||||
}
|
||||
else if (decode_pos_samples < seek_needed_samples)
|
||||
{
|
||||
@ -212,7 +207,6 @@ void vgmstream_destroy()
|
||||
|
||||
gboolean vgmstream_is_our_file(char *pFile)
|
||||
{
|
||||
char strFile[260];
|
||||
const char *pExt;
|
||||
gchar **exts;
|
||||
VGMSTREAM *stream;
|
||||
@ -227,13 +221,11 @@ gboolean vgmstream_is_our_file(char *pFile)
|
||||
/* skip past period */
|
||||
++pExt;
|
||||
|
||||
get_file_name(strFile,pFile);
|
||||
|
||||
for (exts = vgmstream_iplug.vfs_extensions;*exts;++exts)
|
||||
{
|
||||
if (strcasecmp(pExt,*exts) == 0)
|
||||
{
|
||||
if ((stream = init_vgmstream(strFile)))
|
||||
if ((stream = init_vgmstream_from_STREAMFILE(open_vfs(pFile))))
|
||||
{
|
||||
close_vgmstream(stream);
|
||||
return TRUE;
|
||||
@ -257,12 +249,9 @@ void vgmstream_mseek(InputPlayback *data,gulong ms)
|
||||
|
||||
void vgmstream_play(InputPlayback *context)
|
||||
{
|
||||
// this is now called in a new thread context
|
||||
char title[260];
|
||||
|
||||
get_file_name(title,context->filename);
|
||||
|
||||
vgmstream = init_vgmstream(title);
|
||||
// this is now called in a new thread context
|
||||
vgmstream = init_vgmstream_from_STREAMFILE(open_vfs(context->filename));
|
||||
if (!vgmstream || vgmstream->channels <= 0 || vgmstream->channels > 2)
|
||||
{
|
||||
CLOSE_STREAM();
|
||||
@ -274,13 +263,14 @@ void vgmstream_play(InputPlayback *context)
|
||||
CLOSE_STREAM();
|
||||
return;
|
||||
}
|
||||
|
||||
/* copy file name */
|
||||
strcpy(strPlaying,title);
|
||||
strcpy(strPlaying,context->filename);
|
||||
// set the info
|
||||
stream_length_samples = get_vgmstream_play_samples(loop_count,fade_seconds,fade_delay_seconds,vgmstream);
|
||||
gint ms = (stream_length_samples * 1000LL) / vgmstream->sample_rate;
|
||||
gint rate = vgmstream->sample_rate * 2 * vgmstream->channels;
|
||||
context->set_params(context,title,
|
||||
context->set_params(context,get_title(context->filename,title,sizeof(title)),
|
||||
/* length */ ms,
|
||||
/* rate */rate,
|
||||
/* freq */vgmstream->sample_rate,
|
||||
@ -331,14 +321,12 @@ int vgmstream_get_time(InputPlayback *context)
|
||||
|
||||
void vgmstream_get_song_info(gchar *pFile,gchar **title,gint *length)
|
||||
{
|
||||
char strTitle[260];
|
||||
VGMSTREAM *infostream;
|
||||
|
||||
get_file_name(strTitle,pFile);
|
||||
|
||||
*title = g_strdup(strTitle);
|
||||
|
||||
if ((infostream = init_vgmstream(strTitle)))
|
||||
char strTitle[260];
|
||||
|
||||
*title = g_strdup(get_title(pFile,strTitle,sizeof(strTitle)));
|
||||
|
||||
if ((infostream = init_vgmstream_from_STREAMFILE(open_vfs(pFile))))
|
||||
{
|
||||
*length = get_vgmstream_play_samples(loop_count,fade_seconds,fade_delay_seconds,infostream) * 1000LL / infostream->sample_rate;
|
||||
close_vgmstream(infostream);
|
||||
@ -352,18 +340,15 @@ void vgmstream_get_song_info(gchar *pFile,gchar **title,gint *length)
|
||||
void vgmstream_file_info_box(gchar *pFile)
|
||||
{
|
||||
char msg[512];
|
||||
char strTitle[260];
|
||||
VGMSTREAM *stream;
|
||||
|
||||
get_file_name(strTitle,pFile);
|
||||
|
||||
if ((stream = init_vgmstream(strTitle)))
|
||||
if ((stream = init_vgmstream_from_STREAMFILE(open_vfs(pFile))))
|
||||
{
|
||||
gint sls = get_vgmstream_play_samples(loop_count,fade_seconds,fade_delay_seconds,stream);
|
||||
gint ms = (sls * 1000LL) / stream->sample_rate;
|
||||
gint rate = stream->sample_rate * 2 * stream->channels;
|
||||
|
||||
sprintf(msg,"%s\nSample rate: %d\nStereo: %s\nTotal samples: %d\nBits per second: %d\nLength: %f seconds",strTitle,stream->sample_rate,(stream->channels >= 2) ? "yes" : "no",sls,rate,(double)ms / 1000.0);
|
||||
sprintf(msg,"%s\nSample rate: %d\nStereo: %s\nTotal samples: %d\nBits per second: %d\nLength: %f seconds",pFile,stream->sample_rate,(stream->channels >= 2) ? "yes" : "no",sls,rate,(double)ms / 1000.0);
|
||||
|
||||
close_vgmstream(stream);
|
||||
|
||||
|
127
unix/vfs.c
Normal file
127
unix/vfs.c
Normal file
@ -0,0 +1,127 @@
|
||||
#include <audacious/util.h>
|
||||
#include <audacious/configdb.h>
|
||||
#include <audacious/plugin.h>
|
||||
#include <audacious/output.h>
|
||||
#include <audacious/i18n.h>
|
||||
#include <audacious/strings.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];
|
||||
} 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)
|
||||
{
|
||||
strcpy(buffer,streamfile->name);
|
||||
}
|
||||
|
||||
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.open = (void*)open_vfs_impl;
|
||||
streamfile->sf.close = (void*)close_vfs;
|
||||
|
||||
streamfile->vfsFile = file;
|
||||
streamfile->offset = 0;
|
||||
strcpy(streamfile->name,path);
|
||||
|
||||
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);
|
||||
}
|
6
unix/vfs.h
Normal file
6
unix/vfs.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef __VFS__
|
||||
#define __VFS__
|
||||
|
||||
STREAMFILE *open_vfs(const char *path);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user