mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-14 10:37:38 +01:00
cleanup
This commit is contained in:
parent
33f01354e6
commit
ea630eeead
10
src/Makefile
10
src/Makefile
@ -2,13 +2,15 @@
|
|||||||
# main vgmstream code
|
# main vgmstream code
|
||||||
#
|
#
|
||||||
|
|
||||||
# automatically get all possible .o by finding all .c
|
|
||||||
OBJECTS =
|
|
||||||
|
|
||||||
#SRCS = $(wildcard **/*.c) #GNUMake 3.81?
|
#SRCS = $(wildcard **/*.c) #GNUMake 3.81?
|
||||||
SRCS = $(wildcard *.c) $(wildcard */*.c) $(wildcard */*/*.c)
|
SRCS = $(wildcard *.c) $(wildcard */*.c) $(wildcard */*/*.c)
|
||||||
|
|
||||||
|
# get all possible .o by finding all .c
|
||||||
OBJECTS = $(patsubst %.c,%.o,$(SRCS))
|
OBJECTS = $(patsubst %.c,%.o,$(SRCS))
|
||||||
|
|
||||||
|
# in case of renamed files
|
||||||
|
OBJECTS_CLEAN = $(wildcard *.o) $(wildcard */*.o) $(wildcard */*/*.o)
|
||||||
|
|
||||||
|
|
||||||
libvgmstream.a: $(OBJECTS)
|
libvgmstream.a: $(OBJECTS)
|
||||||
$(AR) crs libvgmstream.a $(OBJECTS)
|
$(AR) crs libvgmstream.a $(OBJECTS)
|
||||||
@ -20,6 +22,6 @@ libvgmstream.so: $(OBJECTS)
|
|||||||
# $(CC) $(CFLAGS) -M -o vgmstream-deps
|
# $(CC) $(CFLAGS) -M -o vgmstream-deps
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RMF) $(OBJECTS) libvgmstream.a
|
$(RMF) $(OBJECTS_CLEAN) libvgmstream.a
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
@ -33,14 +33,14 @@ TARGET_EXT_LIBS += $(LIBS_TARGET_EXT_LIBS)
|
|||||||
|
|
||||||
export CFLAGS LDFLAGS
|
export CFLAGS LDFLAGS
|
||||||
|
|
||||||
#SRC_SRCS = $(wildcard *.c)
|
SRCS = $(wildcard *.c)
|
||||||
SRC_SRCS = in_vgmstream.c in_streamfile.c in_config.c
|
OBJECTS = $(wildcard *.o)
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
### targets
|
### targets
|
||||||
|
|
||||||
in_vgmstream: libvgmstream.a $(TARGET_EXT_LIBS) resource.o
|
in_vgmstream: libvgmstream.a $(TARGET_EXT_LIBS) resource.o
|
||||||
$(CC) -shared -static-libgcc $(CFLAGS) $(SRC_SRCS) resource.o $(LDFLAGS) -o $(OUTPUT_WINAMP)
|
$(CC) -shared -static-libgcc $(CFLAGS) $(SRCS) resource.o $(LDFLAGS) -o $(OUTPUT_WINAMP)
|
||||||
$(STRIP) $(OUTPUT_WINAMP)
|
$(STRIP) $(OUTPUT_WINAMP)
|
||||||
|
|
||||||
resource.o: resource.rc resource.h
|
resource.o: resource.rc resource.h
|
||||||
@ -53,6 +53,6 @@ $(TARGET_EXT_LIBS):
|
|||||||
$(MAKE) -C ../ext_libs $@
|
$(MAKE) -C ../ext_libs $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RMF) $(OUTPUT_WINAMP) resource.o
|
$(RMF) $(OUTPUT_WINAMP) $(OBJECTS) resource.o
|
||||||
|
|
||||||
.PHONY: clean in_vgmstream libvgmstream.a $(TARGET_EXT_LIBS)
|
.PHONY: clean in_vgmstream libvgmstream.a $(TARGET_EXT_LIBS)
|
||||||
|
@ -42,7 +42,7 @@ TCHAR *dlg_replaygain_strings[] = {
|
|||||||
TEXT("Peak")
|
TEXT("Peak")
|
||||||
};
|
};
|
||||||
|
|
||||||
int priority_values[7] = {
|
const int priority_values[7] = {
|
||||||
THREAD_PRIORITY_IDLE,
|
THREAD_PRIORITY_IDLE,
|
||||||
THREAD_PRIORITY_LOWEST,
|
THREAD_PRIORITY_LOWEST,
|
||||||
THREAD_PRIORITY_BELOW_NORMAL,
|
THREAD_PRIORITY_BELOW_NORMAL,
|
||||||
|
120
winamp/in_utils.c
Normal file
120
winamp/in_utils.c
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#include "in_vgmstream.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Adds ext to Winamp's extension list */
|
||||||
|
static int add_extension(char* dst, int dst_len, const char* ext) {
|
||||||
|
int ext_len;
|
||||||
|
|
||||||
|
ext_len = strlen(ext);
|
||||||
|
if (dst_len <= ext_len + 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
strcpy(dst, ext); /* seems winamp uppercases this if needed */
|
||||||
|
dst[ext_len] = ';';
|
||||||
|
|
||||||
|
return ext_len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Creates Winamp's extension list, a single string that ends with \0\0.
|
||||||
|
* Each extension must be in this format: "extensions\0Description\0"
|
||||||
|
*
|
||||||
|
* The list is used to accept extensions by default when IsOurFile returns 0, to register file
|
||||||
|
* types, and in the open dialog's type combo. Format actually can be:
|
||||||
|
* - "ext1;ext2;...\0EXTS Audio Files (*.ext1; *.ext2; *...\0", //single line with all
|
||||||
|
* - "ext1\0EXT1 Audio File (*.ext1)\0ext2\0EXT2 Audio File (*.ext2)\0...", //multiple lines
|
||||||
|
* Open dialog's text (including all plugin's "Description") seems limited to old MAX_PATH 260
|
||||||
|
* (max size for "extensions" checks seems ~0x40000 though). Given vgmstream's huge number
|
||||||
|
* of exts, use single line to (probably) work properly with dialogs (used to be multi line).
|
||||||
|
*/
|
||||||
|
void build_extension_list(char* winamp_list, int winamp_list_size) {
|
||||||
|
const char** ext_list;
|
||||||
|
size_t ext_list_len;
|
||||||
|
int i, written;
|
||||||
|
int description_size = 0x100; /* reserved max at the end */
|
||||||
|
|
||||||
|
winamp_list[0] = '\0';
|
||||||
|
winamp_list[1] = '\0';
|
||||||
|
|
||||||
|
ext_list = vgmstream_get_formats(&ext_list_len);
|
||||||
|
|
||||||
|
for (i = 0; i < ext_list_len; i++) {
|
||||||
|
int used = add_extension(winamp_list, winamp_list_size - description_size, ext_list[i]);
|
||||||
|
if (used <= 0) {
|
||||||
|
vgm_logi("build_extension_list: not enough buf for all exts\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
winamp_list += used;
|
||||||
|
winamp_list_size -= used;
|
||||||
|
}
|
||||||
|
if (i > 0) {
|
||||||
|
winamp_list[-1] = '\0'; /* last "ext;" to "ext\0" */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generic description for the info dialog since we can't really show everything */
|
||||||
|
written = snprintf(winamp_list, winamp_list_size - 2, "vgmstream Audio Files%c", '\0');
|
||||||
|
|
||||||
|
/* should end with double \0 */
|
||||||
|
if (written < 0) {
|
||||||
|
winamp_list[0] = '\0';
|
||||||
|
winamp_list[1] = '\0';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
winamp_list[written + 0] = '\0';
|
||||||
|
winamp_list[written + 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* makes a modified filename, suitable to pass parameters around */
|
||||||
|
static void make_fn_subsong(in_char* dst, int dst_size, const in_char* filename, int subsong_index) {
|
||||||
|
/* Follows "(file)(config)(ext)". Winamp needs to "see" (ext) to validate, and file goes first so relative
|
||||||
|
* files work in M3Us (path is added). Protocols a la "vgmstream://(config)(file)" work but don't get full paths. */
|
||||||
|
wa_snprintf(dst,dst_size, wa_L("%s|$s=%i|.vgmstream"), filename, subsong_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unpacks the subsongs by adding entries to the playlist */
|
||||||
|
bool split_subsongs(const in_char* filename, int subsong_index, VGMSTREAM* vgmstream) {
|
||||||
|
int i, playlist_index;
|
||||||
|
HWND hPlaylistWindow;
|
||||||
|
|
||||||
|
|
||||||
|
if (settings.disable_subsongs || vgmstream->num_streams <= 1)
|
||||||
|
return 0; /* don't split if no subsongs */
|
||||||
|
if (subsong_index > 0 || vgmstream->stream_index > 0)
|
||||||
|
return 0; /* no split if already playing subsong */
|
||||||
|
|
||||||
|
hPlaylistWindow = (HWND)SendMessage(input_module.hMainWindow, WM_WA_IPC, IPC_GETWND_PE, IPC_GETWND);
|
||||||
|
playlist_index = SendMessage(input_module.hMainWindow,WM_WA_IPC,0,IPC_GETLISTPOS);
|
||||||
|
|
||||||
|
/* The only way to pass info around in Winamp is encoding it into the filename, so a fake name
|
||||||
|
* is created with the index. Then, winamp_Play (and related) intercepts and reads the index. */
|
||||||
|
for (i = 0; i < vgmstream->num_streams; i++) {
|
||||||
|
in_char stream_fn[PATH_LIMIT];
|
||||||
|
|
||||||
|
make_fn_subsong(stream_fn,PATH_LIMIT, filename, (i+1)); /* encode index in filename */
|
||||||
|
|
||||||
|
/* insert at index */
|
||||||
|
{
|
||||||
|
COPYDATASTRUCT cds = {0};
|
||||||
|
wa_fileinfo f;
|
||||||
|
|
||||||
|
wa_strncpy(f.file, stream_fn,MAX_PATH-1);
|
||||||
|
f.file[MAX_PATH-1] = '\0';
|
||||||
|
f.index = playlist_index + (i+1);
|
||||||
|
cds.dwData = wa_IPC_PE_INSERTFILENAME;
|
||||||
|
cds.lpData = (void*)&f;
|
||||||
|
cds.cbData = sizeof(wa_fileinfo);
|
||||||
|
SendMessage(hPlaylistWindow,WM_COPYDATA,0,(LPARAM)&cds);
|
||||||
|
}
|
||||||
|
/* IPC_ENQUEUEFILE can pre-set the title without needing the Playlist handle, but can't insert at index */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove current file from the playlist */
|
||||||
|
SendMessage(hPlaylistWindow, WM_WA_IPC, IPC_PE_DELETEINDEX, playlist_index);
|
||||||
|
|
||||||
|
/* autoplay doesn't always advance to the first unpacked track, but manually fails somehow */
|
||||||
|
//SendMessage(input_module.hMainWindow,WM_WA_IPC,playlist_index,IPC_SETPLAYLISTPOS);
|
||||||
|
//SendMessage(input_module.hMainWindow,WM_WA_IPC,0,IPC_STARTPLAY);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
@ -27,7 +27,7 @@ DWORD WINAPI __stdcall decode(void *arg);
|
|||||||
* (older versions of XMPlay also will crash with so many exts but can't autodetect version here) */
|
* (older versions of XMPlay also will crash with so many exts but can't autodetect version here) */
|
||||||
#define EXTENSION_LIST_SIZE (0x2000 * 6)
|
#define EXTENSION_LIST_SIZE (0x2000 * 6)
|
||||||
/* fixed list to simplify but could also malloc/free on init/close */
|
/* fixed list to simplify but could also malloc/free on init/close */
|
||||||
char working_extension_list[EXTENSION_LIST_SIZE] = {0};
|
char extension_list[EXTENSION_LIST_SIZE] = {0};
|
||||||
|
|
||||||
|
|
||||||
/* current play state */
|
/* current play state */
|
||||||
@ -127,61 +127,6 @@ static VGMSTREAM* init_vgmstream_winamp_fileinfo(const in_char* fn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* makes a modified filename, suitable to pass parameters around */
|
|
||||||
static void make_fn_subsong(in_char* dst, int dst_size, const in_char* filename, int stream_index) {
|
|
||||||
/* Follows "(file)(config)(ext)". Winamp needs to "see" (ext) to validate, and file goes first so relative
|
|
||||||
* files work in M3Us (path is added). Protocols a la "vgmstream://(config)(file)" work but don't get full paths. */
|
|
||||||
wa_snprintf(dst,dst_size, wa_L("%s|$s=%i|.vgmstream"), filename, stream_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* unpacks the subsongs by adding entries to the playlist */
|
|
||||||
static int split_subsongs(const in_char* filename, int stream_index, VGMSTREAM *vgmstream) {
|
|
||||||
int i, playlist_index;
|
|
||||||
HWND hPlaylistWindow;
|
|
||||||
|
|
||||||
|
|
||||||
if (settings.disable_subsongs || vgmstream->num_streams <= 1)
|
|
||||||
return 0; /* don't split if no subsongs */
|
|
||||||
if (stream_index > 0 || vgmstream->stream_index > 0)
|
|
||||||
return 0; /* no split if already playing subsong */
|
|
||||||
|
|
||||||
hPlaylistWindow = (HWND)SendMessage(input_module.hMainWindow, WM_WA_IPC, IPC_GETWND_PE, IPC_GETWND);
|
|
||||||
playlist_index = SendMessage(input_module.hMainWindow,WM_WA_IPC,0,IPC_GETLISTPOS);
|
|
||||||
|
|
||||||
/* The only way to pass info around in Winamp is encoding it into the filename, so a fake name
|
|
||||||
* is created with the index. Then, winamp_Play (and related) intercepts and reads the index. */
|
|
||||||
for (i = 0; i < vgmstream->num_streams; i++) {
|
|
||||||
in_char stream_fn[PATH_LIMIT];
|
|
||||||
|
|
||||||
make_fn_subsong(stream_fn,PATH_LIMIT, filename, (i+1)); /* encode index in filename */
|
|
||||||
|
|
||||||
/* insert at index */
|
|
||||||
{
|
|
||||||
COPYDATASTRUCT cds = {0};
|
|
||||||
wa_fileinfo f;
|
|
||||||
|
|
||||||
wa_strncpy(f.file, stream_fn,MAX_PATH-1);
|
|
||||||
f.file[MAX_PATH-1] = '\0';
|
|
||||||
f.index = playlist_index + (i+1);
|
|
||||||
cds.dwData = wa_IPC_PE_INSERTFILENAME;
|
|
||||||
cds.lpData = (void*)&f;
|
|
||||||
cds.cbData = sizeof(wa_fileinfo);
|
|
||||||
SendMessage(hPlaylistWindow,WM_COPYDATA,0,(LPARAM)&cds);
|
|
||||||
}
|
|
||||||
/* IPC_ENQUEUEFILE can pre-set the title without needing the Playlist handle, but can't insert at index */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove current file from the playlist */
|
|
||||||
SendMessage(hPlaylistWindow, WM_WA_IPC, IPC_PE_DELETEINDEX, playlist_index);
|
|
||||||
|
|
||||||
/* autoplay doesn't always advance to the first unpacked track, but manually fails somehow */
|
|
||||||
//SendMessage(input_module.hMainWindow,WM_WA_IPC,playlist_index,IPC_SETPLAYLISTPOS);
|
|
||||||
//SendMessage(input_module.hMainWindow,WM_WA_IPC,0,IPC_STARTPLAY);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* try to detect XMPlay, which can't interact with the playlist = no splitting */
|
/* try to detect XMPlay, which can't interact with the playlist = no splitting */
|
||||||
static int is_xmplay() {
|
static int is_xmplay() {
|
||||||
if (GetModuleHandle( TEXT("xmplay.exe") ))
|
if (GetModuleHandle( TEXT("xmplay.exe") ))
|
||||||
@ -194,70 +139,6 @@ static int is_xmplay() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Adds ext to Winamp's extension list */
|
|
||||||
static int add_extension(char* dst, int dst_len, const char* ext) {
|
|
||||||
int ext_len;
|
|
||||||
|
|
||||||
ext_len = strlen(ext);
|
|
||||||
if (dst_len <= ext_len + 1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
strcpy(dst, ext); /* seems winamp uppercases this if needed */
|
|
||||||
dst[ext_len] = ';';
|
|
||||||
|
|
||||||
return ext_len + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Creates Winamp's extension list, a single string that ends with \0\0.
|
|
||||||
* Each extension must be in this format: "extensions\0Description\0"
|
|
||||||
*
|
|
||||||
* The list is used to accept extensions by default when IsOurFile returns 0, to register file
|
|
||||||
* types, and in the open dialog's type combo. Format actually can be:
|
|
||||||
* - "ext1;ext2;...\0EXTS Audio Files (*.ext1; *.ext2; *...\0", //single line with all
|
|
||||||
* - "ext1\0EXT1 Audio File (*.ext1)\0ext2\0EXT2 Audio File (*.ext2)\0...", //multiple lines
|
|
||||||
* Open dialog's text (including all plugin's "Description") seems limited to old MAX_PATH 260
|
|
||||||
* (max size for "extensions" checks seems ~0x40000 though). Given vgmstream's huge number
|
|
||||||
* of exts, use single line to (probably) work properly with dialogs (used to be multi line).
|
|
||||||
*/
|
|
||||||
static void build_extension_list(char* winamp_list, int winamp_list_size) {
|
|
||||||
const char** ext_list;
|
|
||||||
size_t ext_list_len;
|
|
||||||
int i, written;
|
|
||||||
int description_size = 0x100; /* reserved max at the end */
|
|
||||||
|
|
||||||
winamp_list[0] = '\0';
|
|
||||||
winamp_list[1] = '\0';
|
|
||||||
|
|
||||||
ext_list = vgmstream_get_formats(&ext_list_len);
|
|
||||||
|
|
||||||
for (i = 0; i < ext_list_len; i++) {
|
|
||||||
int used = add_extension(winamp_list, winamp_list_size - description_size, ext_list[i]);
|
|
||||||
if (used <= 0) {
|
|
||||||
vgm_logi("build_extension_list: not enough buf for all exts\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
winamp_list += used;
|
|
||||||
winamp_list_size -= used;
|
|
||||||
}
|
|
||||||
if (i > 0) {
|
|
||||||
winamp_list[-1] = '\0'; /* last "ext;" to "ext\0" */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* generic description for the info dialog since we can't really show everything */
|
|
||||||
written = snprintf(winamp_list, winamp_list_size - 2, "vgmstream Audio Files%c", '\0');
|
|
||||||
|
|
||||||
/* should end with double \0 */
|
|
||||||
if (written < 0) {
|
|
||||||
winamp_list[0] = '\0';
|
|
||||||
winamp_list[1] = '\0';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
winamp_list[written + 0] = '\0';
|
|
||||||
winamp_list[written + 1] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* unicode utils */
|
/* unicode utils */
|
||||||
static void get_title(in_char* dst, int dst_size, const in_char* fn, VGMSTREAM* infostream) {
|
static void get_title(in_char* dst, int dst_size, const in_char* fn, VGMSTREAM* infostream) {
|
||||||
in_char filename[PATH_LIMIT];
|
in_char filename[PATH_LIMIT];
|
||||||
@ -388,7 +269,7 @@ void winamp_Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* dynamically make a list of supported extensions */
|
/* dynamically make a list of supported extensions */
|
||||||
build_extension_list(working_extension_list, sizeof(working_extension_list));
|
build_extension_list(extension_list, sizeof(extension_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called at program quit */
|
/* called at program quit */
|
||||||
@ -872,7 +753,7 @@ In_Module input_module = {
|
|||||||
PLUGIN_NAME,
|
PLUGIN_NAME,
|
||||||
0, /* hMainWindow (filled in by Winamp) */
|
0, /* hMainWindow (filled in by Winamp) */
|
||||||
0, /* hDllInstance (filled in by Winamp) */
|
0, /* hDllInstance (filled in by Winamp) */
|
||||||
working_extension_list,
|
extension_list,
|
||||||
1, /* is_seekable flag */
|
1, /* is_seekable flag */
|
||||||
9, /* UsesOutputPlug flag */
|
9, /* UsesOutputPlug flag */
|
||||||
winamp_Config,
|
winamp_Config,
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
/* ************************************* */
|
/* ************************************* */
|
||||||
|
|
||||||
extern In_Module input_module;
|
extern In_Module input_module;
|
||||||
extern int priority_values[7];
|
extern const int priority_values[7];
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
REPLAYGAIN_NONE,
|
REPLAYGAIN_NONE,
|
||||||
@ -87,8 +87,8 @@ extern winamp_log_t* walog;
|
|||||||
/* ************************************* */
|
/* ************************************* */
|
||||||
/* IN_UNICODE */
|
/* IN_UNICODE */
|
||||||
/* ************************************* */
|
/* ************************************* */
|
||||||
//todo safe ops
|
//TODO safe ops
|
||||||
//todo there must be a better way to handle unicode...
|
//TODO there must be a better way to handle unicode...
|
||||||
#ifdef UNICODE_INPUT_PLUGIN
|
#ifdef UNICODE_INPUT_PLUGIN
|
||||||
#define wa_strcmp wcscmp
|
#define wa_strcmp wcscmp
|
||||||
#define wa_strncmp wcsncmp
|
#define wa_strncmp wcsncmp
|
||||||
@ -190,11 +190,11 @@ static inline void cfg_char_to_wchar(TCHAR *wdst, size_t wdstsize, const char *s
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ************************************* */
|
|
||||||
/* IN_STREAMFILE */
|
|
||||||
/* ************************************* */
|
|
||||||
|
|
||||||
/* in_streamfile.c */
|
/* in_streamfile.c */
|
||||||
STREAMFILE* open_winamp_streamfile_by_ipath(const in_char* wpath);
|
STREAMFILE* open_winamp_streamfile_by_ipath(const in_char* wpath);
|
||||||
|
|
||||||
#endif /*_IN_VGMSTREAM_*/
|
void build_extension_list(char* extension_list, int list_size);
|
||||||
|
|
||||||
|
bool split_subsongs(const in_char* filename, int subsong_index, VGMSTREAM* vgmstream);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -67,10 +67,15 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="in_vgmstream.h" />
|
<ClInclude Include="in_vgmstream.h" />
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
|
<ClInclude Include="sdk\in2.h" />
|
||||||
|
<ClInclude Include="sdk\ipc_pe.h" />
|
||||||
|
<ClInclude Include="sdk\out.h" />
|
||||||
|
<ClInclude Include="sdk\wa_ipc.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="in_config.c" />
|
<ClCompile Include="in_config.c" />
|
||||||
<ClCompile Include="in_streamfile.c" />
|
<ClCompile Include="in_streamfile.c" />
|
||||||
|
<ClCompile Include="in_utils.c" />
|
||||||
<ClCompile Include="in_vgmstream.c" />
|
<ClCompile Include="in_vgmstream.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -21,6 +21,18 @@
|
|||||||
<ClInclude Include="resource.h">
|
<ClInclude Include="resource.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="sdk\in2.h">
|
||||||
|
<Filter>sdk\Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="sdk\ipc_pe.h">
|
||||||
|
<Filter>sdk\Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="sdk\out.h">
|
||||||
|
<Filter>sdk\Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="sdk\wa_ipc.h">
|
||||||
|
<Filter>sdk\Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="resource.rc">
|
<ResourceCompile Include="resource.rc">
|
||||||
@ -34,6 +46,9 @@
|
|||||||
<ClCompile Include="in_streamfile.c">
|
<ClCompile Include="in_streamfile.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="in_utils.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="in_vgmstream.c">
|
<ClCompile Include="in_vgmstream.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -31,12 +31,14 @@ TARGET_EXT_LIBS += $(LIBS_TARGET_EXT_LIBS)
|
|||||||
|
|
||||||
export CFLAGS LDFLAGS
|
export CFLAGS LDFLAGS
|
||||||
|
|
||||||
|
SRCS = $(wildcard *.c)
|
||||||
|
OBJECTS = $(wildcard *.o)
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
### targets
|
### targets
|
||||||
|
|
||||||
xmp_vgmstream: libvgmstream.a $(TARGET_EXT_LIBS)
|
xmp_vgmstream: libvgmstream.a $(TARGET_EXT_LIBS)
|
||||||
$(CC) -shared -static-libgcc $(CFLAGS) xmp_vgmstream.c $(LDFLAGS) -o $(OUTPUT_XMPLAY) xmpin.def
|
$(CC) -shared -static-libgcc $(CFLAGS) $(SRCS) $(LDFLAGS) -o $(OUTPUT_XMPLAY) xmpin.def
|
||||||
$(STRIP) $(OUTPUT_XMPLAY)
|
$(STRIP) $(OUTPUT_XMPLAY)
|
||||||
|
|
||||||
libvgmstream.a:
|
libvgmstream.a:
|
||||||
@ -46,6 +48,6 @@ $(TARGET_EXT_LIBS):
|
|||||||
$(MAKE) -C ../ext_libs $@
|
$(MAKE) -C ../ext_libs $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RMF) $(OUTPUT_XMPLAY)
|
$(RMF) $(OBJECTS) $(OUTPUT_XMPLAY)
|
||||||
|
|
||||||
.PHONY: clean xmp_vgmstream libvgmstream.a $(TARGET_EXT_LIBS)
|
.PHONY: clean xmp_vgmstream libvgmstream.a $(TARGET_EXT_LIBS)
|
||||||
|
@ -69,8 +69,11 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="xmpfunc.h" />
|
<ClInclude Include="xmpfunc.h" />
|
||||||
<ClInclude Include="xmpin.h" />
|
<ClInclude Include="xmpin.h" />
|
||||||
|
<ClInclude Include="xmp_vgmstream.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="xmp_streamfile.c" />
|
||||||
|
<ClCompile Include="xmp_utils.c" />
|
||||||
<ClCompile Include="xmp_vgmstream.c" />
|
<ClCompile Include="xmp_vgmstream.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,11 +1,26 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="xmp_vgmstream.c" />
|
<ClCompile Include="xmp_streamfile.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="xmp_utils.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="xmp_vgmstream.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="xmpfunc.h" />
|
<ClInclude Include="xmpfunc.h">
|
||||||
<ClInclude Include="xmpin.h" />
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="xmpin.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="xmp_vgmstream.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="xmpin.def" />
|
<None Include="xmpin.def" />
|
||||||
|
86
xmplay/xmp_streamfile.c
Normal file
86
xmplay/xmp_streamfile.c
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#include "xmp_vgmstream.h"
|
||||||
|
|
||||||
|
/* a STREAMFILE that operates via XMPlay's XMPFUNC_FILE+XMPFILE */
|
||||||
|
typedef struct _XMPLAY_STREAMFILE {
|
||||||
|
STREAMFILE sf; /* callbacks */
|
||||||
|
XMPFILE infile; /* actual FILE */
|
||||||
|
XMPFUNC_FILE* xmpf_file; /* helper */
|
||||||
|
char name[0x8000]; /* path limit */
|
||||||
|
off_t offset; /* current offset */
|
||||||
|
int internal_xmpfile; /* infile was not supplied externally and can be closed */
|
||||||
|
} XMPLAY_STREAMFILE;
|
||||||
|
|
||||||
|
|
||||||
|
static size_t xmpsf_read(XMPLAY_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) {
|
||||||
|
size_t read;
|
||||||
|
|
||||||
|
if (sf->offset != offset) {
|
||||||
|
if (sf->xmpf_file->Seek(sf->infile, offset))
|
||||||
|
sf->offset = offset;
|
||||||
|
else
|
||||||
|
sf->offset = sf->xmpf_file->Tell(sf->infile);
|
||||||
|
}
|
||||||
|
|
||||||
|
read = sf->xmpf_file->Read(sf->infile, dst, length);
|
||||||
|
if (read > 0)
|
||||||
|
sf->offset += read;
|
||||||
|
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
static off_t xmpsf_get_size(XMPLAY_STREAMFILE* sf) {
|
||||||
|
return sf->xmpf_file->GetSize(sf->infile);
|
||||||
|
}
|
||||||
|
|
||||||
|
static off_t xmpsf_get_offset(XMPLAY_STREAMFILE* sf) {
|
||||||
|
return sf->xmpf_file->Tell(sf->infile);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xmpsf_get_name(XMPLAY_STREAMFILE* sf, char* buffer, size_t length) {
|
||||||
|
snprintf(buffer, length, "%s", sf->name);
|
||||||
|
buffer[length - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static STREAMFILE* xmpsf_open(XMPLAY_STREAMFILE* sf, const char* const filename, size_t buffersize) {
|
||||||
|
XMPFILE newfile;
|
||||||
|
|
||||||
|
if (!filename)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
newfile = sf->xmpf_file->Open(filename);
|
||||||
|
if (!newfile) return NULL;
|
||||||
|
|
||||||
|
return open_xmplay_streamfile_by_xmpfile(newfile, sf->xmpf_file, filename, true); /* internal XMPFILE */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xmpsf_close(XMPLAY_STREAMFILE* sf) {
|
||||||
|
/* Close XMPFILE, but only if we opened it (ex. for subfiles inside metas).
|
||||||
|
* Otherwise must be left open as other parts of XMPlay need it and would crash. */
|
||||||
|
if (sf->internal_xmpfile) {
|
||||||
|
sf->xmpf_file->Close(sf->infile);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(sf);
|
||||||
|
}
|
||||||
|
|
||||||
|
STREAMFILE* open_xmplay_streamfile_by_xmpfile(XMPFILE infile, XMPFUNC_FILE* xmpf_file, const char* path, bool internal) {
|
||||||
|
XMPLAY_STREAMFILE* this_sf = calloc(1, sizeof(XMPLAY_STREAMFILE));
|
||||||
|
if (!this_sf) return NULL;
|
||||||
|
|
||||||
|
this_sf->sf.read = (void*)xmpsf_read;
|
||||||
|
this_sf->sf.get_size = (void*)xmpsf_get_size;
|
||||||
|
this_sf->sf.get_offset = (void*)xmpsf_get_offset;
|
||||||
|
this_sf->sf.get_name = (void*)xmpsf_get_name;
|
||||||
|
this_sf->sf.open = (void*)xmpsf_open;
|
||||||
|
this_sf->sf.close = (void*)xmpsf_close;
|
||||||
|
this_sf->infile = infile;
|
||||||
|
this_sf->offset = 0;
|
||||||
|
|
||||||
|
snprintf(this_sf->name, sizeof(this_sf->name), "%s", path);
|
||||||
|
this_sf->name[sizeof(this_sf->name) - 1] = '\0';
|
||||||
|
|
||||||
|
this_sf->internal_xmpfile = internal;
|
||||||
|
this_sf->xmpf_file = xmpf_file;
|
||||||
|
|
||||||
|
return &this_sf->sf; /* pointer to STREAMFILE start = rest of the custom data follows */
|
||||||
|
}
|
262
xmplay/xmp_utils.c
Normal file
262
xmplay/xmp_utils.c
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
#include "xmp_vgmstream.h"
|
||||||
|
|
||||||
|
/* with <v3.8.5.62, any more than ~1000 will crash XMplay's file list screen. */
|
||||||
|
#define EXTENSION_LIST_SIZE_OLD 1000
|
||||||
|
#define EXTENSION_LIST_SIZE_OLD_VERSION 0x0308053d /* less than v3.8.5.62 */
|
||||||
|
|
||||||
|
|
||||||
|
/* Adds ext to XMPlay's extension list. */
|
||||||
|
static int add_extension(int length, char * dst, const char * ext) {
|
||||||
|
int ext_len;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (length <= 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ext_len = strlen(ext);
|
||||||
|
|
||||||
|
/* check if end reached or not enough room to add */
|
||||||
|
if (ext_len+2 > length-2) {
|
||||||
|
dst[0]='\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy new extension + null terminate */
|
||||||
|
for (i=0; i < ext_len; i++)
|
||||||
|
dst[i] = ext[i];
|
||||||
|
dst[i]='/';
|
||||||
|
dst[i+1]='\0';
|
||||||
|
return i+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Creates XMPlay's extension list, a single string with 2 nulls.
|
||||||
|
* Extensions must be in this format: "Description\0extension1/.../extensionN" */
|
||||||
|
void build_extension_list(char* extension_list, int list_size, DWORD version) {
|
||||||
|
const char ** ext_list;
|
||||||
|
size_t ext_list_len;
|
||||||
|
int i, written;
|
||||||
|
|
||||||
|
int limit_old = EXTENSION_LIST_SIZE_OLD;
|
||||||
|
int limit = list_size;
|
||||||
|
if (limit > limit_old && version <= EXTENSION_LIST_SIZE_OLD_VERSION)
|
||||||
|
limit = limit_old;
|
||||||
|
|
||||||
|
written = sprintf(extension_list, "%s%c", "vgmstream files",'\0');
|
||||||
|
|
||||||
|
ext_list = vgmstream_get_formats(&ext_list_len);
|
||||||
|
|
||||||
|
for (i=0; i < ext_list_len; i++) {
|
||||||
|
written += add_extension(limit-written, extension_list + written, ext_list[i]);
|
||||||
|
}
|
||||||
|
extension_list[written-1] = '\0'; /* remove last "/" */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Get tags as an array of "key\0value\0", NULL-terminated.
|
||||||
|
* Processes tags from the path alone (expects folders to be named in a particular way),
|
||||||
|
* so of limited usefulness. */
|
||||||
|
char* get_tags_from_filepath_info(VGMSTREAM* infostream, XMPFUNC_MISC* xmpf_misc, const char* filepath) {
|
||||||
|
char* tags;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
tags = xmpf_misc->Alloc(1024);
|
||||||
|
memset(tags, 0x00, 1024);
|
||||||
|
|
||||||
|
if (strlen(infostream->stream_name) > 0) {
|
||||||
|
memcpy(tags + pos, "title", 5);
|
||||||
|
pos += 6;
|
||||||
|
memcpy(tags + pos, infostream->stream_name, strlen(infostream->stream_name));
|
||||||
|
pos += strlen(infostream->stream_name) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* end;
|
||||||
|
const char* start = NULL;
|
||||||
|
int j = 2;
|
||||||
|
for (const char* i = filepath + strlen(filepath); i > filepath; i--)
|
||||||
|
{
|
||||||
|
if ((*i == '\\') && (j == 1))
|
||||||
|
{
|
||||||
|
start = i + 1;
|
||||||
|
j--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((*i == '\\') && (j == 2))
|
||||||
|
{
|
||||||
|
end = i;
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//run some sanity checks
|
||||||
|
|
||||||
|
int brace_curly = 0, brace_square = 0;
|
||||||
|
char check_ok = 0;
|
||||||
|
for (const char* i = filepath; *i != 0; i++)
|
||||||
|
{
|
||||||
|
if (*i == '(')
|
||||||
|
brace_curly++;
|
||||||
|
if (*i == ')')
|
||||||
|
brace_curly--;
|
||||||
|
if (*i == '[')
|
||||||
|
brace_square++;
|
||||||
|
if (*i == ']')
|
||||||
|
brace_square--;
|
||||||
|
if (brace_curly > 1 || brace_curly < -1 || brace_square > 1 || brace_square < -1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (brace_square == 0 && brace_curly == 0)
|
||||||
|
check_ok = 1;
|
||||||
|
|
||||||
|
if (start != NULL && strstr(filepath, "\\VGMPP\\") != NULL && check_ok == 1 && strchr(start, '(') != NULL)
|
||||||
|
{
|
||||||
|
char tagline[1024];
|
||||||
|
memset(tagline, 0x00, sizeof(tagline));
|
||||||
|
strncpy(tagline, start, end - start);
|
||||||
|
|
||||||
|
char* alttitle_st;
|
||||||
|
char* alttitle_ed;
|
||||||
|
char* album_st;
|
||||||
|
char* album_ed;
|
||||||
|
char* company_st;
|
||||||
|
char* company_ed;
|
||||||
|
char* company2_st;
|
||||||
|
char* company2_ed;
|
||||||
|
char* date_st;
|
||||||
|
char* date_ed;
|
||||||
|
char* platform_st;
|
||||||
|
char* platform_ed;
|
||||||
|
|
||||||
|
if (strchr(tagline, '[') != NULL) //either alternative title or platform usually
|
||||||
|
{
|
||||||
|
alttitle_st = strchr(tagline, '[') + 1;
|
||||||
|
alttitle_ed = strchr(alttitle_st, ']');
|
||||||
|
if (strchr(alttitle_st, '[') != NULL && strchr(alttitle_st, '[') > strchr(alttitle_st, '(')) //both might be present actually
|
||||||
|
{
|
||||||
|
platform_st = strchr(alttitle_st, '[') + 1;
|
||||||
|
platform_ed = strchr(alttitle_ed + 1, ']');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
platform_st = NULL;
|
||||||
|
platform_ed = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
platform_st = NULL;
|
||||||
|
platform_ed = NULL;
|
||||||
|
alttitle_st = NULL;
|
||||||
|
alttitle_ed = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
album_st = tagline;
|
||||||
|
|
||||||
|
if (strchr(tagline, '(') < alttitle_st && alttitle_st != NULL) //square braces after curly braces -- platform
|
||||||
|
{
|
||||||
|
platform_st = alttitle_st;
|
||||||
|
platform_ed = alttitle_ed;
|
||||||
|
alttitle_st = NULL;
|
||||||
|
alttitle_ed = NULL;
|
||||||
|
album_ed = strchr(tagline, '('); //get normal title for now
|
||||||
|
}
|
||||||
|
else if (alttitle_st != NULL)
|
||||||
|
album_ed = strchr(tagline, '[');
|
||||||
|
else
|
||||||
|
album_ed = strchr(tagline, '(');
|
||||||
|
|
||||||
|
date_st = strchr(album_ed, '(') + 1; //first string in curly braces is usualy release date, I have one package with platform name there
|
||||||
|
if (date_st == NULL)
|
||||||
|
date_ed = NULL;
|
||||||
|
if (date_st[0] >= 0x30 && date_st[0] <= 0x39 && date_st[1] >= 0x30 && date_st[1] <= 0x39) //check if it contains 2 digits
|
||||||
|
{
|
||||||
|
date_ed = strchr(date_st, ')');
|
||||||
|
}
|
||||||
|
else //platform?
|
||||||
|
{
|
||||||
|
platform_st = date_st;
|
||||||
|
platform_ed = strchr(date_st, ')');
|
||||||
|
date_st = strchr(platform_ed, '(') + 1;
|
||||||
|
date_ed = strchr(date_st, ')');
|
||||||
|
}
|
||||||
|
|
||||||
|
company_st = strchr(date_ed, '(') + 1; //company name follows date
|
||||||
|
if (company_st != NULL)
|
||||||
|
{
|
||||||
|
company_ed = strchr(company_st, ')');
|
||||||
|
if (strchr(company_ed, '(') != NULL)
|
||||||
|
{
|
||||||
|
company2_st = strchr(company_ed, '(') + 1;
|
||||||
|
company2_ed = strchr(company2_st, ')');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
company2_st = NULL;
|
||||||
|
company2_ed = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
company_st = NULL;
|
||||||
|
company_ed = NULL;
|
||||||
|
company2_st = NULL;
|
||||||
|
company2_ed = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alttitle_st != NULL) //prefer alternative title, which is usually japanese
|
||||||
|
{
|
||||||
|
memcpy(tags + pos, "album", 5);
|
||||||
|
pos += 6;
|
||||||
|
memcpy(tags + pos, alttitle_st, alttitle_ed - alttitle_st);
|
||||||
|
pos += alttitle_ed - alttitle_st + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(tags + pos, "album", 5);
|
||||||
|
pos += 6;
|
||||||
|
memcpy(tags + pos, album_st, album_ed - album_st);
|
||||||
|
pos += album_ed - album_st + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (date_st != NULL)
|
||||||
|
{
|
||||||
|
memcpy(tags + pos, "date", 4);
|
||||||
|
pos += 5;
|
||||||
|
memcpy(tags + pos, date_st, date_ed - date_st);
|
||||||
|
pos += date_ed - date_st + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (date_st != NULL)
|
||||||
|
{
|
||||||
|
memcpy(tags + pos, "genre", 5);
|
||||||
|
pos += 6;
|
||||||
|
memcpy(tags + pos, platform_st, platform_ed - platform_st);
|
||||||
|
pos += platform_ed - platform_st + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (company_st != NULL)
|
||||||
|
{
|
||||||
|
char combuf[256];
|
||||||
|
memset(combuf, 0x00, sizeof(combuf));
|
||||||
|
char tmp[128];
|
||||||
|
memset(tmp, 0x00, sizeof(tmp));
|
||||||
|
memcpy(tmp, company_st, company_ed - company_st);
|
||||||
|
if (company2_st != NULL)
|
||||||
|
{
|
||||||
|
char tmp2[128];
|
||||||
|
memset(tmp2, 0x00, sizeof(tmp2));
|
||||||
|
memcpy(tmp2, company2_st, company2_ed - company2_st);
|
||||||
|
sprintf(combuf, "\r\n\r\nDeveloper\t%s\r\nPublisher\t%s", tmp, tmp2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sprintf(combuf, "\r\n\r\nDeveloper\t%s", tmp);
|
||||||
|
|
||||||
|
memcpy(tags + pos, "comment", 7);
|
||||||
|
pos += 8;
|
||||||
|
memcpy(tags + pos, combuf, strlen(combuf));
|
||||||
|
pos += strlen(combuf) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags; /* assuming XMPlay free()s this, since it Alloc()s it */
|
||||||
|
}
|
@ -11,10 +11,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "xmpin.h"
|
#include "xmp_vgmstream.h"
|
||||||
#include "../src/vgmstream.h"
|
|
||||||
#include "../src/api.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include "../version.h"
|
#include "../version.h"
|
||||||
#ifndef VGMSTREAM_VERSION
|
#ifndef VGMSTREAM_VERSION
|
||||||
@ -28,20 +25,19 @@
|
|||||||
|
|
||||||
#define SAMPLE_BUFFER_SIZE 1024
|
#define SAMPLE_BUFFER_SIZE 1024
|
||||||
|
|
||||||
/* XMPlay extension list, only needed to associate extensions in Windows */
|
|
||||||
/* with <v3.8.5.62, any more than ~1000 will crash XMplay's file list screen. */
|
|
||||||
#define EXTENSION_LIST_SIZE (0x2000 * 6)
|
|
||||||
#define EXTENSION_LIST_SIZE_OLD 1000
|
|
||||||
#define EXTENSION_LIST_SIZE_OLD_VERSION 0x0308053d /* less than v3.8.5.62 */
|
|
||||||
#define XMPLAY_MAX_PATH 32768
|
#define XMPLAY_MAX_PATH 32768
|
||||||
|
|
||||||
/* XMPlay function library */
|
/* XMPlay function library */
|
||||||
static XMPFUNC_IN *xmpfin;
|
static XMPFUNC_IN* xmpf_in;
|
||||||
static XMPFUNC_MISC *xmpfmisc;
|
static XMPFUNC_MISC* xmpf_misc;
|
||||||
static XMPFUNC_FILE *xmpffile;
|
static XMPFUNC_FILE* xmpf_file;
|
||||||
|
|
||||||
|
/* XMPlay extension list, only needed to associate extensions in Windows */
|
||||||
|
#define EXTENSION_LIST_SIZE (0x2000 * 6)
|
||||||
|
|
||||||
char working_extension_list[EXTENSION_LIST_SIZE] = {0};
|
char working_extension_list[EXTENSION_LIST_SIZE] = {0};
|
||||||
char filepath[MAX_PATH];
|
|
||||||
|
char last_filepath[MAX_PATH] = {0};
|
||||||
|
|
||||||
/* plugin config */
|
/* plugin config */
|
||||||
double fade_seconds = 10.0;
|
double fade_seconds = 10.0;
|
||||||
@ -66,96 +62,11 @@ static int shownerror = 0; /* init error */
|
|||||||
|
|
||||||
/* ************************************* */
|
/* ************************************* */
|
||||||
|
|
||||||
/* a STREAMFILE that operates via XMPlay's XMPFUNC_FILE+XMPFILE */
|
|
||||||
typedef struct _XMPLAY_STREAMFILE {
|
|
||||||
STREAMFILE sf; /* callbacks */
|
|
||||||
XMPFILE infile; /* actual FILE */
|
|
||||||
char name[PATH_LIMIT];
|
|
||||||
off_t offset; /* current offset */
|
|
||||||
int internal_xmpfile; /* infile was not supplied externally and can be closed */
|
|
||||||
} XMPLAY_STREAMFILE;
|
|
||||||
|
|
||||||
static STREAMFILE* open_xmplay_streamfile_by_xmpfile(XMPFILE file, const char* path, int internal);
|
|
||||||
|
|
||||||
static size_t xmpsf_read(XMPLAY_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) {
|
|
||||||
size_t read;
|
|
||||||
|
|
||||||
if (sf->offset != offset) {
|
|
||||||
if (xmpffile->Seek(sf->infile, offset))
|
|
||||||
sf->offset = offset;
|
|
||||||
else
|
|
||||||
sf->offset = xmpffile->Tell(sf->infile);
|
|
||||||
}
|
|
||||||
|
|
||||||
read = xmpffile->Read(sf->infile, dst, length);
|
|
||||||
if (read > 0)
|
|
||||||
sf->offset += read;
|
|
||||||
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static off_t xmpsf_get_size(XMPLAY_STREAMFILE* sf) {
|
|
||||||
return xmpffile->GetSize(sf->infile);
|
|
||||||
}
|
|
||||||
|
|
||||||
static off_t xmpsf_get_offset(XMPLAY_STREAMFILE* sf) {
|
|
||||||
return xmpffile->Tell(sf->infile);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void xmpsf_get_name(XMPLAY_STREAMFILE* sf, char* buffer, size_t length) {
|
|
||||||
strncpy(buffer, sf->name, length);
|
|
||||||
buffer[length-1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static STREAMFILE* xmpsf_open(XMPLAY_STREAMFILE* sf, const char* const filename, size_t buffersize) {
|
|
||||||
XMPFILE newfile;
|
|
||||||
|
|
||||||
if (!filename)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
newfile = xmpffile->Open(filename);
|
|
||||||
if (!newfile) return NULL;
|
|
||||||
|
|
||||||
strncpy(filepath, filename, MAX_PATH);
|
|
||||||
filepath[MAX_PATH - 1] = 0x00;
|
|
||||||
|
|
||||||
return open_xmplay_streamfile_by_xmpfile(newfile, filename, 1); /* internal XMPFILE */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void xmpsf_close(XMPLAY_STREAMFILE* sf) {
|
|
||||||
/* Close XMPFILE, but only if we opened it (ex. for subfiles inside metas).
|
|
||||||
* Otherwise must be left open as other parts of XMPlay need it and would crash. */
|
|
||||||
if (sf->internal_xmpfile) {
|
|
||||||
xmpffile->Close(sf->infile);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(sf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static STREAMFILE* open_xmplay_streamfile_by_xmpfile(XMPFILE infile, const char* path, int internal) {
|
|
||||||
XMPLAY_STREAMFILE* this_sf = calloc(1, sizeof(XMPLAY_STREAMFILE));
|
|
||||||
if (!this_sf) return NULL;
|
|
||||||
|
|
||||||
this_sf->sf.read = (void*)xmpsf_read;
|
|
||||||
this_sf->sf.get_size = (void*)xmpsf_get_size;
|
|
||||||
this_sf->sf.get_offset = (void*)xmpsf_get_offset;
|
|
||||||
this_sf->sf.get_name = (void*)xmpsf_get_name;
|
|
||||||
this_sf->sf.open = (void*)xmpsf_open;
|
|
||||||
this_sf->sf.close = (void*)xmpsf_close;
|
|
||||||
this_sf->infile = infile;
|
|
||||||
this_sf->offset = 0;
|
|
||||||
strncpy(this_sf->name, path, sizeof(this_sf->name));
|
|
||||||
|
|
||||||
this_sf->internal_xmpfile = internal;
|
|
||||||
|
|
||||||
return &this_sf->sf; /* pointer to STREAMFILE start = rest of the custom data follows */
|
|
||||||
}
|
|
||||||
|
|
||||||
VGMSTREAM* init_vgmstream_xmplay(XMPFILE infile, const char* path, int subsong) {
|
VGMSTREAM* init_vgmstream_xmplay(XMPFILE infile, const char* path, int subsong) {
|
||||||
STREAMFILE* sf = NULL;
|
STREAMFILE* sf = NULL;
|
||||||
VGMSTREAM* vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
|
||||||
sf = open_xmplay_streamfile_by_xmpfile(infile, path, 0); /* external XMPFILE */
|
sf = open_xmplay_streamfile_by_xmpfile(infile, xmpf_file, path, false); /* external XMPFILE */
|
||||||
if (!sf) return NULL;
|
if (!sf) return NULL;
|
||||||
|
|
||||||
sf->stream_index = subsong;
|
sf->stream_index = subsong;
|
||||||
@ -184,259 +95,6 @@ static void apply_config(VGMSTREAM* vgmstream) {
|
|||||||
vgmstream_apply_config(vgmstream, &vcfg);
|
vgmstream_apply_config(vgmstream, &vcfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* get the tags as an array of "key\0value\0", NULL-terminated */
|
|
||||||
static char *get_tags(VGMSTREAM * infostream) {
|
|
||||||
char* tags;
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
tags = xmpfmisc->Alloc(1024);
|
|
||||||
memset(tags, 0x00, 1024);
|
|
||||||
|
|
||||||
if (infostream->stream_name != NULL && strlen(infostream->stream_name) > 0)
|
|
||||||
{
|
|
||||||
memcpy(tags + pos, "title", 5);
|
|
||||||
pos += 6;
|
|
||||||
memcpy(tags + pos, infostream->stream_name, strlen(infostream->stream_name));
|
|
||||||
pos += strlen(infostream->stream_name) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* end;
|
|
||||||
char* start = NULL;
|
|
||||||
int j = 2;
|
|
||||||
for (char* i = filepath+strlen(filepath); i > filepath; i--)
|
|
||||||
{
|
|
||||||
if ((*i == '\\') && (j == 1))
|
|
||||||
{
|
|
||||||
start = i + 1;
|
|
||||||
j--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ((*i == '\\') && (j == 2))
|
|
||||||
{
|
|
||||||
end = i;
|
|
||||||
j--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//run some sanity checks
|
|
||||||
|
|
||||||
int brace_curly = 0, brace_square = 0;
|
|
||||||
char check_ok = 0;
|
|
||||||
for (char* i = filepath; *i != 0; i++)
|
|
||||||
{
|
|
||||||
if (*i == '(')
|
|
||||||
brace_curly++;
|
|
||||||
if (*i == ')')
|
|
||||||
brace_curly--;
|
|
||||||
if (*i == '[')
|
|
||||||
brace_square++;
|
|
||||||
if (*i == ']')
|
|
||||||
brace_square--;
|
|
||||||
if (brace_curly > 1 || brace_curly < -1 || brace_square > 1 || brace_square < -1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (brace_square == 0 && brace_curly == 0)
|
|
||||||
check_ok = 1;
|
|
||||||
|
|
||||||
if (start != NULL && strstr(filepath, "\\VGMPP\\") != NULL && check_ok == 1 && strchr(start, '(') != NULL)
|
|
||||||
{
|
|
||||||
char tagline[1024];
|
|
||||||
memset(tagline, 0x00, sizeof(tagline));
|
|
||||||
strncpy(tagline, start, end - start);
|
|
||||||
|
|
||||||
char* alttitle_st;
|
|
||||||
char* alttitle_ed;
|
|
||||||
char* album_st;
|
|
||||||
char* album_ed;
|
|
||||||
char* company_st;
|
|
||||||
char* company_ed;
|
|
||||||
char* company2_st;
|
|
||||||
char* company2_ed;
|
|
||||||
char* date_st;
|
|
||||||
char* date_ed;
|
|
||||||
char* platform_st;
|
|
||||||
char* platform_ed;
|
|
||||||
|
|
||||||
if (strchr(tagline, '[') != NULL) //either alternative title or platform usually
|
|
||||||
{
|
|
||||||
alttitle_st = strchr(tagline, '[') + 1;
|
|
||||||
alttitle_ed = strchr(alttitle_st, ']');
|
|
||||||
if (strchr(alttitle_st, '[') != NULL && strchr(alttitle_st, '[') > strchr(alttitle_st, '(')) //both might be present actually
|
|
||||||
{
|
|
||||||
platform_st = strchr(alttitle_st, '[') + 1;
|
|
||||||
platform_ed = strchr(alttitle_ed + 1, ']');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
platform_st = NULL;
|
|
||||||
platform_ed = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
platform_st = NULL;
|
|
||||||
platform_ed = NULL;
|
|
||||||
alttitle_st = NULL;
|
|
||||||
alttitle_ed = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
album_st = tagline;
|
|
||||||
|
|
||||||
if (strchr(tagline, '(') < alttitle_st && alttitle_st != NULL) //square braces after curly braces -- platform
|
|
||||||
{
|
|
||||||
platform_st = alttitle_st;
|
|
||||||
platform_ed = alttitle_ed;
|
|
||||||
alttitle_st = NULL;
|
|
||||||
alttitle_ed = NULL;
|
|
||||||
album_ed = strchr(tagline, '('); //get normal title for now
|
|
||||||
}
|
|
||||||
else if (alttitle_st != NULL)
|
|
||||||
album_ed = strchr(tagline, '[');
|
|
||||||
else
|
|
||||||
album_ed = strchr(tagline, '(');
|
|
||||||
|
|
||||||
date_st = strchr(album_ed, '(') + 1; //first string in curly braces is usualy release date, I have one package with platform name there
|
|
||||||
if (date_st == NULL)
|
|
||||||
date_ed = NULL;
|
|
||||||
if (date_st[0] >= 0x30 && date_st[0] <= 0x39 && date_st[1] >= 0x30 && date_st[1] <= 0x39) //check if it contains 2 digits
|
|
||||||
{
|
|
||||||
date_ed = strchr(date_st, ')');
|
|
||||||
}
|
|
||||||
else //platform?
|
|
||||||
{
|
|
||||||
platform_st = date_st;
|
|
||||||
platform_ed = strchr(date_st, ')');
|
|
||||||
date_st = strchr(platform_ed, '(') + 1;
|
|
||||||
date_ed = strchr(date_st, ')');
|
|
||||||
}
|
|
||||||
|
|
||||||
company_st = strchr(date_ed, '(') + 1; //company name follows date
|
|
||||||
if (company_st != NULL)
|
|
||||||
{
|
|
||||||
company_ed = strchr(company_st, ')');
|
|
||||||
if (strchr(company_ed, '(') != NULL)
|
|
||||||
{
|
|
||||||
company2_st = strchr(company_ed, '(') + 1;
|
|
||||||
company2_ed = strchr(company2_st, ')');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
company2_st = NULL;
|
|
||||||
company2_ed = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
company_st = NULL;
|
|
||||||
company_ed = NULL;
|
|
||||||
company2_st = NULL;
|
|
||||||
company2_ed = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alttitle_st != NULL) //prefer alternative title, which is usually japanese
|
|
||||||
{
|
|
||||||
memcpy(tags + pos, "album", 5);
|
|
||||||
pos += 6;
|
|
||||||
memcpy(tags + pos, alttitle_st, alttitle_ed - alttitle_st);
|
|
||||||
pos += alttitle_ed - alttitle_st + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(tags + pos, "album", 5);
|
|
||||||
pos += 6;
|
|
||||||
memcpy(tags + pos, album_st, album_ed - album_st);
|
|
||||||
pos += album_ed - album_st + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (date_st != NULL)
|
|
||||||
{
|
|
||||||
memcpy(tags + pos, "date", 4);
|
|
||||||
pos += 5;
|
|
||||||
memcpy(tags + pos, date_st, date_ed - date_st);
|
|
||||||
pos += date_ed - date_st + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (date_st != NULL)
|
|
||||||
{
|
|
||||||
memcpy(tags + pos, "genre", 5);
|
|
||||||
pos += 6;
|
|
||||||
memcpy(tags + pos, platform_st, platform_ed - platform_st);
|
|
||||||
pos += platform_ed - platform_st + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (company_st != NULL)
|
|
||||||
{
|
|
||||||
char combuf[256];
|
|
||||||
memset(combuf, 0x00, sizeof(combuf));
|
|
||||||
char tmp[128];
|
|
||||||
memset(tmp, 0x00, sizeof(tmp));
|
|
||||||
memcpy(tmp, company_st, company_ed - company_st);
|
|
||||||
if (company2_st != NULL)
|
|
||||||
{
|
|
||||||
char tmp2[128];
|
|
||||||
memset(tmp2, 0x00, sizeof(tmp2));
|
|
||||||
memcpy(tmp2, company2_st, company2_ed - company2_st);
|
|
||||||
sprintf(combuf, "\r\n\r\nDeveloper\t%s\r\nPublisher\t%s", tmp, tmp2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
sprintf(combuf, "\r\n\r\nDeveloper\t%s", tmp);
|
|
||||||
|
|
||||||
memcpy(tags + pos, "comment", 7);
|
|
||||||
pos += 8;
|
|
||||||
memcpy(tags + pos, combuf, strlen(combuf));
|
|
||||||
pos += strlen(combuf) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tags; /* assuming XMPlay free()s this, since it Alloc()s it */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Adds ext to XMPlay's extension list. */
|
|
||||||
static int add_extension(int length, char * dst, const char * ext) {
|
|
||||||
int ext_len;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (length <= 1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ext_len = strlen(ext);
|
|
||||||
|
|
||||||
/* check if end reached or not enough room to add */
|
|
||||||
if (ext_len+2 > length-2) {
|
|
||||||
dst[0]='\0';
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy new extension + null terminate */
|
|
||||||
for (i=0; i < ext_len; i++)
|
|
||||||
dst[i] = ext[i];
|
|
||||||
dst[i]='/';
|
|
||||||
dst[i+1]='\0';
|
|
||||||
return i+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Creates XMPlay's extension list, a single string with 2 nulls.
|
|
||||||
* Extensions must be in this format: "Description\0extension1/.../extensionN" */
|
|
||||||
static void build_extension_list() {
|
|
||||||
const char ** ext_list;
|
|
||||||
size_t ext_list_len;
|
|
||||||
int i, written;
|
|
||||||
|
|
||||||
int limit = EXTENSION_LIST_SIZE;
|
|
||||||
if (xmpfmisc->GetVersion() <= EXTENSION_LIST_SIZE_OLD_VERSION)
|
|
||||||
limit = EXTENSION_LIST_SIZE_OLD;
|
|
||||||
|
|
||||||
written = sprintf(working_extension_list, "%s%c", "vgmstream files",'\0');
|
|
||||||
|
|
||||||
ext_list = vgmstream_get_formats(&ext_list_len);
|
|
||||||
|
|
||||||
for (i=0; i < ext_list_len; i++) {
|
|
||||||
written += add_extension(limit-written, working_extension_list + written, ext_list[i]);
|
|
||||||
}
|
|
||||||
working_extension_list[written-1] = '\0'; /* remove last "/" */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ************************************* */
|
/* ************************************* */
|
||||||
|
|
||||||
/* info for the "about" button in plugin options */
|
/* info for the "about" button in plugin options */
|
||||||
@ -487,6 +145,11 @@ DWORD WINAPI xmplay_GetFileInfo(const char *filename, XMPFILE file, float **leng
|
|||||||
if (!infostream)
|
if (!infostream)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
char temp_filepath[MAX_PATH];
|
||||||
|
|
||||||
|
snprintf(temp_filepath, sizeof(temp_filepath), "%s", filename);
|
||||||
|
temp_filepath[sizeof(temp_filepath) - 1] = '\0';
|
||||||
|
|
||||||
apply_config(infostream);
|
apply_config(infostream);
|
||||||
|
|
||||||
//vgmstream_mixing_autodownmix(infostream, downmix_channels);
|
//vgmstream_mixing_autodownmix(infostream, downmix_channels);
|
||||||
@ -494,7 +157,7 @@ DWORD WINAPI xmplay_GetFileInfo(const char *filename, XMPFILE file, float **leng
|
|||||||
|
|
||||||
if (length && infostream->sample_rate) {
|
if (length && infostream->sample_rate) {
|
||||||
int length_samples = vgmstream_get_samples(infostream);
|
int length_samples = vgmstream_get_samples(infostream);
|
||||||
float *lens = (float*)xmpfmisc->Alloc(sizeof(float));
|
float *lens = (float*)xmpf_misc->Alloc(sizeof(float));
|
||||||
lens[0] = (float)length_samples / (float)infostream->sample_rate;
|
lens[0] = (float)length_samples / (float)infostream->sample_rate;
|
||||||
*length = lens;
|
*length = lens;
|
||||||
}
|
}
|
||||||
@ -503,7 +166,7 @@ DWORD WINAPI xmplay_GetFileInfo(const char *filename, XMPFILE file, float **leng
|
|||||||
if (disable_subsongs || subsong_count == 0)
|
if (disable_subsongs || subsong_count == 0)
|
||||||
subsong_count = 1;
|
subsong_count = 1;
|
||||||
|
|
||||||
*tags = get_tags(infostream);
|
*tags = get_tags_from_filepath_info(infostream, xmpf_misc, temp_filepath);
|
||||||
close_vgmstream(infostream);
|
close_vgmstream(infostream);
|
||||||
|
|
||||||
return subsong_count;
|
return subsong_count;
|
||||||
@ -518,6 +181,9 @@ DWORD WINAPI xmplay_Open(const char *filename, XMPFILE file) {
|
|||||||
if (!vgmstream)
|
if (!vgmstream)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
snprintf(last_filepath, sizeof(last_filepath), "%s", filename);
|
||||||
|
last_filepath[sizeof(last_filepath) - 1] = '\0';
|
||||||
|
|
||||||
apply_config(vgmstream);
|
apply_config(vgmstream);
|
||||||
|
|
||||||
//vgmstream_mixing_autodownmix(vgmstream, downmix_channels);
|
//vgmstream_mixing_autodownmix(vgmstream, downmix_channels);
|
||||||
@ -533,7 +199,7 @@ DWORD WINAPI xmplay_Open(const char *filename, XMPFILE file) {
|
|||||||
|
|
||||||
if (length_samples) {
|
if (length_samples) {
|
||||||
float length = (float)length_samples / (float)vgmstream->sample_rate;
|
float length = (float)length_samples / (float)vgmstream->sample_rate;
|
||||||
xmpfin->SetLength(length, TRUE);
|
xmpf_in->SetLength(length, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -554,7 +220,7 @@ void WINAPI xmplay_SetFormat(XMPFORMAT *form) {
|
|||||||
|
|
||||||
/* get tags, return NULL to delay title update (OPTIONAL) */
|
/* get tags, return NULL to delay title update (OPTIONAL) */
|
||||||
char* WINAPI xmplay_GetTags() {
|
char* WINAPI xmplay_GetTags() {
|
||||||
return get_tags(vgmstream);
|
return get_tags_from_filepath_info(vgmstream, xmpf_misc, last_filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* main panel info text (short file info) */
|
/* main panel info text (short file info) */
|
||||||
@ -677,7 +343,7 @@ double WINAPI xmplay_SetPosition(DWORD pos) {
|
|||||||
/* decode some sample data */
|
/* decode some sample data */
|
||||||
DWORD WINAPI xmplay_Process(float* buf, DWORD bufsize) {
|
DWORD WINAPI xmplay_Process(float* buf, DWORD bufsize) {
|
||||||
int32_t i, done, samples_to_do;
|
int32_t i, done, samples_to_do;
|
||||||
BOOL do_loop = xmpfin->GetLooping();
|
BOOL do_loop = xmpf_in->GetLooping();
|
||||||
float *sbuf = buf;
|
float *sbuf = buf;
|
||||||
|
|
||||||
|
|
||||||
@ -794,11 +460,12 @@ __declspec(dllexport) XMPIN* WINAPI XMPIN_GetInterface(UINT32 face, InterfacePr
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
xmpfin = (XMPFUNC_IN*)faceproc(XMPFUNC_IN_FACE);
|
/* retrieval of xmp helpers */
|
||||||
xmpfmisc = (XMPFUNC_MISC*)faceproc(XMPFUNC_MISC_FACE);
|
xmpf_in = (XMPFUNC_IN*)faceproc(XMPFUNC_IN_FACE);
|
||||||
xmpffile = (XMPFUNC_FILE*)faceproc(XMPFUNC_FILE_FACE);
|
xmpf_misc = (XMPFUNC_MISC*)faceproc(XMPFUNC_MISC_FACE);
|
||||||
|
xmpf_file = (XMPFUNC_FILE*)faceproc(XMPFUNC_FILE_FACE);
|
||||||
|
|
||||||
build_extension_list();
|
build_extension_list(working_extension_list, sizeof(working_extension_list), xmpf_misc->GetVersion());
|
||||||
|
|
||||||
return &vgmstream_xmpin;
|
return &vgmstream_xmpin;
|
||||||
}
|
}
|
||||||
|
16
xmplay/xmp_vgmstream.h
Normal file
16
xmplay/xmp_vgmstream.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef _XMP_VGMSTREAM_
|
||||||
|
#define _XMP_VGMSTREAM_
|
||||||
|
|
||||||
|
#include "xmpin.h"
|
||||||
|
#include "xmpfunc.h"
|
||||||
|
#include "../src/vgmstream.h"
|
||||||
|
#include "../src/api.h"
|
||||||
|
|
||||||
|
|
||||||
|
STREAMFILE* open_xmplay_streamfile_by_xmpfile(XMPFILE infile, XMPFUNC_FILE* xmpf_file, const char* path, bool internal);
|
||||||
|
|
||||||
|
char* get_tags_from_filepath_info(VGMSTREAM* infostream, XMPFUNC_MISC* xmpf_misc, const char* filepath);
|
||||||
|
|
||||||
|
void build_extension_list(char* extension_list, int list_size, DWORD version);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user