Merge pull request #312 from bnnm/tags-etc

tags etc
This commit is contained in:
Christopher Snowhill 2018-11-05 01:56:59 -08:00 committed by GitHub
commit 7fb4a05b36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 908 additions and 138 deletions

View File

@ -46,25 +46,26 @@ or in a system directory, or any other directory in the PATH variable.
```
Usage: test.exe [-o outfile.wav] [options] infile
Options:
-o outfile.wav: name of output .wav file, default is infile.wav
-o outfile.wav: name of output .wav file, default infile.wav
-l loop count: loop count, default 2.0
-f fade time: fade time (seconds), default 10.0
-d fade delay: fade delay (seconds, default 0.0
-f fade time: fade time in seconds after N loops, default 10.0
-d fade delay: fade delay in seconds, default 0.0
-F: don't fade after N loops and play the rest of the stream
-i: ignore looping information and play the whole stream once
-e: force end-to-end looping
-E: force end-to-end looping even if file has real loop points
-s N: select subsong N, if the format supports multiple subsongs
-m: print metadata only, don't decode
-L: append a smpl chunk and create a looping wav
-2 N: only output the Nth (first is 0) set of stereo channels
-p: output to stdout (for piping into another program)
-P: output to stdout even if stdout is a terminal
-c: loop forever (continuously)
-m: print metadata only, don't decode
-c: loop forever (continuously) to stdout
-x: decode and print adxencd command line to encode as ADX
-g: decode and print oggenc command line to encode as OGG
-b: decode and print batch variable commands
-L: append a smpl chunk and create a looping wav
-e: force end-to-end looping
-E: force end-to-end looping even if file has real loop points
-r outfile2.wav: output a second time after resetting
-2 N: only output the Nth (first is 0) set of stereo channels
-F: don't fade after N loops and play the rest of the stream
-s N: select subsong N, if the format supports multiple subsongs
-r: output a second file after resetting (for testing)
-t file: print if tags are found in file
```
Typical usage would be: ```test -o happy.wav happy.adx``` to decode ```happy.adx``` to ```happy.wav```.
@ -232,6 +233,32 @@ Creation of those files is meant for advanced users, docs can be found in
vgmstream source.
## Tagging
Some of vgmstream's plugins support simple read-only tagging via external files.
Tags are loaded from a text/M3U-like file named _!tags.m3u_ in the song folder.
You don't have to load your songs with that M3U though (but you can, for pre-made
ordering), the file itself just 'looks' like an M3U.
Format is:
```
# ignored comment
# @GLOBAL_TAG value (applies all following tracks)
# %LOCAL_TAG value (applies to next track only)
filename1
# %LOCAL_TAG value (applies to next track only)
filename2
```
Accepted tags depend on the player (foobar: any; winamp: see ATF config),
typically ALBUM/ARTIST/TITLE/DISC/TRACK/COMPOSER/etc, lower or uppercase,
separated by one or multiple spaces. Repeated tags overwrite previous
(ex.- may define @COMPOSER for multiple tracks). It only reads up to current
_filename_ though, so any @TAG below would be ignored.
Playlist formatting should follow player's config. ASCII or UTF-8 tags work.
## Supported codec types
Quick list of codecs vgmstream supports, including many obscure ones that
are used in few games.

View File

@ -1,6 +1,7 @@
#define POSIXLY_CORRECT
#include <getopt.h>
#include "../src/vgmstream.h"
#include "../src/plugins.h"
#include "../src/util.h"
#ifdef WIN32
#include <io.h>
@ -52,6 +53,7 @@ static void usage(const char * name) {
" -g: decode and print oggenc command line to encode as OGG\n"
" -b: decode and print batch variable commands\n"
" -r: output a second file after resetting (for testing)\n"
" -t file: print if tags are found in file\n"
, name);
}
@ -59,6 +61,7 @@ static void usage(const char * name) {
typedef struct {
char * infilename;
char * outfilename;
char * tag_filename;
int ignore_loop;
int force_loop;
int really_force_loop;
@ -96,7 +99,7 @@ static int parse_config(cli_config *cfg, int argc, char ** argv) {
opterr = 0;
/* read config */
while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEFrgb2:s:")) != -1) {
while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEFrgb2:s:t:")) != -1) {
switch (opt) {
case 'o':
cfg->outfilename = optarg;
@ -156,6 +159,9 @@ static int parse_config(cli_config *cfg, int argc, char ** argv) {
case 's':
cfg->stream_index = atoi(optarg);
break;
case 't':
cfg->tag_filename= optarg;
break;
case '?':
fprintf(stderr, "Unknown option -%c found\n", optopt);
goto fail;
@ -323,6 +329,8 @@ void apply_fade(sample * buf, VGMSTREAM * vgmstream, int to_get, int i, int len_
}
}
/* ************************************************************ */
int main(int argc, char ** argv) {
VGMSTREAM * vgmstream = NULL;
FILE * outfile = NULL;
@ -403,6 +411,27 @@ int main(int argc, char ** argv) {
/* print file info (or batch commands, depending on config) */
print_info(vgmstream, &cfg);
/* print tags info */
if (cfg.tag_filename) {
VGMSTREAM_TAGS tag;
STREAMFILE *tagFile = open_stdio_streamfile(cfg.tag_filename);
if (!tagFile) {
fprintf(stderr,"tag file %s not found\n",cfg.tag_filename);
goto fail;
}
printf("tags:\n");
vgmstream_tags_reset(&tag, cfg.infilename);
while ( vgmstream_tags_next_tag(&tag, tagFile)) {
printf("- '%s'='%s'\n", tag.key, tag.val);
}
close_streamfile(tagFile);
}
/* prints done */
if (cfg.print_metaonly) {
if (!cfg.play_sdtout)
fclose(outfile);

View File

@ -102,7 +102,7 @@ file2.ext#m2-3,4-5,4-6 # ogg "FL CN FR BL BR SB" to wav "FL FR CN SB BL BR"
Those setting should override player's defaults if set (except "loop forever"). They are equivalent to some test.exe options.
- __God Hand (PS2)__: _boss2_3ningumi_ver6.txtp_ (each line is a separate TXTP)
<EFBFBD><EFBFBD><EFBFBD>
```
# set number of loops
boss2_3ningumi_ver6.adx#l3
@ -128,7 +128,7 @@ boss2_3ningumi_ver6.adx#l2#F # 2 loops + ending
boss2_3ningumi_ver6.adx#l1.5#d1#f5
# boss2_3ningumi_ver6.adx#l1.0#F # this is equivalent to #i
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
```
For segments and layers the first file defines looping options.

View File

@ -3,13 +3,13 @@
* BSD License:
****************************************************************************
*
* Copyright (c) 2005-2007 Paul Hsieh
* Copyright (c) 2005-2016 Paul Hsieh
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
@ -17,7 +17,7 @@
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
@ -31,30 +31,28 @@
*
****************************************************************************
*
* Version 0.1.10
* Version 0.1.16.0
*
* The ANSI C standard committee, for the C99 standard, specified the
* inclusion of a new standard include file called stdint.h. This is
* a very useful and long desired include file which contains several
* very precise definitions for integer scalar types that is
* critically important for making portable several classes of
* applications including cryptography, hashing, variable length
* integer libraries and so on. But for most developers its likely
* useful just for programming sanity.
* very precise definitions for integer scalar types that is critically
* important for making several classes of applications portable
* including cryptography, hashing, variable length integer libraries
* and so on. But for most developers its likely useful just for
* programming sanity.
*
* The problem is that most compiler vendors have decided not to
* implement the C99 standard, and the next C++ language standard
* (which has a lot more mindshare these days) will be a long time in
* coming and its unknown whether or not it will include stdint.h or
* how much adoption it will have. Either way, it will be a long time
* before all compilers come with a stdint.h and it also does nothing
* for the extremely large number of compilers available today which
* do not include this file, or anything comparable to it.
* The problem is that some compiler vendors chose to ignore the C99
* standard and some older compilers have no opportunity to be updated.
* Because of this situation, simply including stdint.h in your code
* makes it unportable.
*
* So that's what this file is all about. Its an attempt to build a
* So that's what this file is all about. It's an attempt to build a
* single universal include file that works on as many platforms as
* possible to deliver what stdint.h is supposed to. A few things
* that should be noted about this file:
* possible to deliver what stdint.h is supposed to. Even compilers
* that already come with stdint.h can use this file instead without
* any loss of functionality. A few things that should be noted about
* this file:
*
* 1) It is not guaranteed to be portable and/or present an identical
* interface on all platforms. The extreme variability of the
@ -73,7 +71,7 @@
* include stdint.h. The hope is that one or the other can be
* used with no real difference.
*
* 5) In the current verison, if your platform can't represent
* 5) In the current version, if your platform can't represent
* int32_t, int16_t and int8_t, it just dumps out with a compiler
* error.
*
@ -154,7 +152,12 @@
* PRINTF_INT64_DEC_WIDTH
* PRINTF_INT32_DEC_WIDTH
* PRINTF_INT16_DEC_WIDTH
* PRINTF_INT8_DEC_WIDTH
* PRINTF_UINT8_DEC_WIDTH
* PRINTF_UINTMAX_DEC_WIDTH
* PRINTF_UINT64_DEC_WIDTH
* PRINTF_UINT32_DEC_WIDTH
* PRINTF_UINT16_DEC_WIDTH
* PRINTF_UINT8_DEC_WIDTH
*
* Which specifies the maximum number of characters required to
* print the number of that type in either hexadecimal or decimal.
@ -178,6 +181,10 @@
* Chris Howie
* John Steele Scott
* Dave Thorup
* John Dill
* Florian Wobbe
* Christopher Sean Morrison
* Mikkel Fahnoe Jorgensen
*
*/
@ -190,14 +197,27 @@
* do nothing else. On the Mac OS X version of gcc this is _STDINT_H_.
*/
#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) )) && !defined (_PSTDINT_H_INCLUDED)
#if ((defined(__SUNPRO_C) && __SUNPRO_C >= 0x570) || (defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (__GNUC__ > 3 || defined(_STDINT_H) || defined(_STDINT_H_) || defined (__UINT_FAST64_TYPE__)) )) && !defined (_PSTDINT_H_INCLUDED)
#include <stdint.h>
#define _PSTDINT_H_INCLUDED
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER "l"
# if defined(__GNUC__) && (defined(__x86_64__) || defined(__ppc64__)) && !(defined(__APPLE__) && defined(__MACH__))
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "l"
# endif
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
# else
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# ifndef PRINTF_INT32_MODIFIER
# if (UINT_MAX == UINT32_MAX)
# define PRINTF_INT32_MODIFIER ""
# else
# define PRINTF_INT32_MODIFIER "l"
# endif
# endif
# endif
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER "h"
@ -208,32 +228,62 @@
# ifndef PRINTF_INT64_HEX_WIDTH
# define PRINTF_INT64_HEX_WIDTH "16"
# endif
# ifndef PRINTF_UINT64_HEX_WIDTH
# define PRINTF_UINT64_HEX_WIDTH "16"
# endif
# ifndef PRINTF_INT32_HEX_WIDTH
# define PRINTF_INT32_HEX_WIDTH "8"
# endif
# ifndef PRINTF_UINT32_HEX_WIDTH
# define PRINTF_UINT32_HEX_WIDTH "8"
# endif
# ifndef PRINTF_INT16_HEX_WIDTH
# define PRINTF_INT16_HEX_WIDTH "4"
# endif
# ifndef PRINTF_UINT16_HEX_WIDTH
# define PRINTF_UINT16_HEX_WIDTH "4"
# endif
# ifndef PRINTF_INT8_HEX_WIDTH
# define PRINTF_INT8_HEX_WIDTH "2"
# endif
# ifndef PRINTF_UINT8_HEX_WIDTH
# define PRINTF_UINT8_HEX_WIDTH "2"
# endif
# ifndef PRINTF_INT64_DEC_WIDTH
# define PRINTF_INT64_DEC_WIDTH "20"
# define PRINTF_INT64_DEC_WIDTH "19"
# endif
# ifndef PRINTF_UINT64_DEC_WIDTH
# define PRINTF_UINT64_DEC_WIDTH "20"
# endif
# ifndef PRINTF_INT32_DEC_WIDTH
# define PRINTF_INT32_DEC_WIDTH "10"
# endif
# ifndef PRINTF_UINT32_DEC_WIDTH
# define PRINTF_UINT32_DEC_WIDTH "10"
# endif
# ifndef PRINTF_INT16_DEC_WIDTH
# define PRINTF_INT16_DEC_WIDTH "5"
# endif
# ifndef PRINTF_UINT16_DEC_WIDTH
# define PRINTF_UINT16_DEC_WIDTH "5"
# endif
# ifndef PRINTF_INT8_DEC_WIDTH
# define PRINTF_INT8_DEC_WIDTH "3"
# endif
# ifndef PRINTF_UINT8_DEC_WIDTH
# define PRINTF_UINT8_DEC_WIDTH "3"
# endif
# ifndef PRINTF_INTMAX_HEX_WIDTH
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_UINT64_HEX_WIDTH
# endif
# ifndef PRINTF_UINTMAX_HEX_WIDTH
# define PRINTF_UINTMAX_HEX_WIDTH PRINTF_UINT64_HEX_WIDTH
# endif
# ifndef PRINTF_INTMAX_DEC_WIDTH
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_UINT64_DEC_WIDTH
# endif
# ifndef PRINTF_UINTMAX_DEC_WIDTH
# define PRINTF_UINTMAX_DEC_WIDTH PRINTF_UINT64_DEC_WIDTH
# endif
/*
@ -287,11 +337,25 @@
# endif
#endif
/*
* I have no idea what is the truly correct thing to do on older Solaris.
* From some online discussions, this seems to be what is being
* recommended. For people who actually are developing on older Solaris,
* what I would like to know is, does this define all of the relevant
* macros of a complete stdint.h? Remember, in pstdint.h 64 bit is
* considered optional.
*/
#if (defined(__SUNPRO_C) && __SUNPRO_C >= 0x420) && !defined(_PSTDINT_H_INCLUDED)
#include <sys/inttypes.h>
#define _PSTDINT_H_INCLUDED
#endif
#ifndef _PSTDINT_H_INCLUDED
#define _PSTDINT_H_INCLUDED
#ifndef SIZE_MAX
# define SIZE_MAX (~(size_t)0)
# define SIZE_MAX ((size_t)-1)
#endif
/*
@ -303,7 +367,7 @@
#ifndef UINT8_MAX
# define UINT8_MAX 0xff
#endif
#ifndef uint8_t
#if !defined(uint8_t) && !defined(_UINT8_T) && !defined(vxWorks)
# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S)
typedef unsigned char uint8_t;
# define UINT8_C(v) ((uint8_t) v)
@ -318,7 +382,7 @@
#ifndef INT8_MIN
# define INT8_MIN INT8_C(0x80)
#endif
#ifndef int8_t
#if !defined(int8_t) && !defined(_INT8_T) && !defined(vxWorks)
# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S)
typedef signed char int8_t;
# define INT8_C(v) ((int8_t) v)
@ -330,7 +394,7 @@
#ifndef UINT16_MAX
# define UINT16_MAX 0xffff
#endif
#ifndef uint16_t
#if !defined(uint16_t) && !defined(_UINT16_T) && !defined(vxWorks)
#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S)
typedef unsigned int uint16_t;
# ifndef PRINTF_INT16_MODIFIER
@ -354,7 +418,7 @@
#ifndef INT16_MIN
# define INT16_MIN INT16_C(0x8000)
#endif
#ifndef int16_t
#if !defined(int16_t) && !defined(_INT16_T) && !defined(vxWorks)
#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S)
typedef signed int int16_t;
# define INT16_C(v) ((int16_t) (v))
@ -375,7 +439,7 @@
#ifndef UINT32_MAX
# define UINT32_MAX (0xffffffffUL)
#endif
#ifndef uint32_t
#if !defined(uint32_t) && !defined(_UINT32_T) && !defined(vxWorks)
#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S)
typedef unsigned long uint32_t;
# define UINT32_C(v) v ## UL
@ -405,7 +469,7 @@
#ifndef INT32_MIN
# define INT32_MIN INT32_C(0x80000000)
#endif
#ifndef int32_t
#if !defined(int32_t) && !defined(_INT32_T) && !defined(vxWorks)
#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S)
typedef signed long int32_t;
# define INT32_C(v) v ## L
@ -438,7 +502,7 @@
#undef stdint_int64_defined
#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S)
# if (__STDC__ && __STDC_VERSION >= 199901L) || defined (S_SPLINT_S)
# if (__STDC__ && __STDC_VERSION__ >= 199901L) || defined (S_SPLINT_S)
# define stdint_int64_defined
typedef long long int64_t;
typedef unsigned long long uint64_t;
@ -451,7 +515,7 @@
#endif
#if !defined (stdint_int64_defined)
# if defined(__GNUC__)
# if defined(__GNUC__) && !defined(vxWorks)
# define stdint_int64_defined
__extension__ typedef long long int64_t;
__extension__ typedef unsigned long long uint64_t;
@ -514,9 +578,8 @@
#ifndef PRINTF_INT8_HEX_WIDTH
# define PRINTF_INT8_HEX_WIDTH "2"
#endif
#ifndef PRINTF_INT64_DEC_WIDTH
# define PRINTF_INT64_DEC_WIDTH "20"
# define PRINTF_INT64_DEC_WIDTH "19"
#endif
#ifndef PRINTF_INT32_DEC_WIDTH
# define PRINTF_INT32_DEC_WIDTH "10"
@ -527,6 +590,18 @@
#ifndef PRINTF_INT8_DEC_WIDTH
# define PRINTF_INT8_DEC_WIDTH "3"
#endif
#ifndef PRINTF_UINT64_DEC_WIDTH
# define PRINTF_UINT64_DEC_WIDTH "20"
#endif
#ifndef PRINTF_UINT32_DEC_WIDTH
# define PRINTF_UINT32_DEC_WIDTH "10"
#endif
#ifndef PRINTF_UINT16_DEC_WIDTH
# define PRINTF_UINT16_DEC_WIDTH "5"
#endif
#ifndef PRINTF_UINT8_DEC_WIDTH
# define PRINTF_UINT8_DEC_WIDTH "3"
#endif
/*
* Ok, lets not worry about 128 bit integers for now. Moore's law says
@ -606,14 +681,12 @@
#undef stdint_least_defined
/*
* The ANSI C committee pretending to know or specify anything about
* performance is the epitome of misguided arrogance. The mandate of
* this file is to *ONLY* ever support that absolute minimum
* definition of the fast integer types, for compatibility purposes.
* No extensions, and no attempt to suggest what may or may not be a
* faster integer type will ever be made in this file. Developers are
* warned to stay away from these types when using this or any other
* stdint.h.
* The ANSI C committee has defined *int*_fast*_t types as well. This,
* of course, defies rationality -- you can't know what will be fast
* just from the type itself. Even for a given architecture, compatible
* implementations might have different performance characteristics.
* Developers are warned to stay away from these types when using this
* or any other stdint.h.
*/
typedef int_least8_t int_fast8_t;
@ -646,7 +719,7 @@ typedef uint_least32_t uint_fast32_t;
* type limits.
*/
#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__)
#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__) && !defined(vxWorks)
# include <wchar.h>
# ifndef WCHAR_MIN
# define WCHAR_MIN 0
@ -661,12 +734,12 @@ typedef uint_least32_t uint_fast32_t;
* (u)intptr_t types and limits.
*/
#if defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED)
#if (defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED)) || defined (_UINTPTR_T)
# define STDINT_H_UINTPTR_T_DEFINED
#endif
#ifndef STDINT_H_UINTPTR_T_DEFINED
# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64)
# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64) || defined (__ppc64__)
# define stdint_intptr_bits 64
# elif defined (__WATCOMC__) || defined (__TURBOC__)
# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
@ -674,10 +747,12 @@ typedef uint_least32_t uint_fast32_t;
# else
# define stdint_intptr_bits 32
# endif
# elif defined (__i386__) || defined (_WIN32) || defined (WIN32)
# elif defined (__i386__) || defined (_WIN32) || defined (WIN32) || defined (__ppc64__)
# define stdint_intptr_bits 32
# elif defined (__INTEL_COMPILER)
/* TODO -- what will Intel do about x86-64? */
/* TODO -- what did Intel do about x86-64? */
# else
/* #error "This platform might not be supported yet" */
# endif
# ifdef stdint_intptr_bits
@ -726,3 +801,119 @@ typedef uint_least32_t uint_fast32_t;
#endif
#endif
#if defined (__TEST_PSTDINT_FOR_CORRECTNESS)
/*
* Please compile with the maximum warning settings to make sure macros are
* not defined more than once.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define glue3_aux(x,y,z) x ## y ## z
#define glue3(x,y,z) glue3_aux(x,y,z)
#define DECLU(bits) glue3(uint,bits,_t) glue3(u,bits,) = glue3(UINT,bits,_C) (0);
#define DECLI(bits) glue3(int,bits,_t) glue3(i,bits,) = glue3(INT,bits,_C) (0);
#define DECL(us,bits) glue3(DECL,us,) (bits)
#define TESTUMAX(bits) glue3(u,bits,) = ~glue3(u,bits,); if (glue3(UINT,bits,_MAX) != glue3(u,bits,)) printf ("Something wrong with UINT%d_MAX\n", bits)
#define REPORTERROR(msg) { err_n++; if (err_first <= 0) err_first = __LINE__; printf msg; }
#define X_SIZE_MAX ((size_t)-1)
int main () {
int err_n = 0;
int err_first = 0;
DECL(I,8)
DECL(U,8)
DECL(I,16)
DECL(U,16)
DECL(I,32)
DECL(U,32)
#ifdef INT64_MAX
DECL(I,64)
DECL(U,64)
#endif
intmax_t imax = INTMAX_C(0);
uintmax_t umax = UINTMAX_C(0);
char str0[256], str1[256];
sprintf (str0, "%" PRINTF_INT32_MODIFIER "d", INT32_C(2147483647));
if (0 != strcmp (str0, "2147483647")) REPORTERROR (("Something wrong with PRINTF_INT32_MODIFIER : %s\n", str0));
if (atoi(PRINTF_INT32_DEC_WIDTH) != (int) strlen(str0)) REPORTERROR (("Something wrong with PRINTF_INT32_DEC_WIDTH : %s\n", PRINTF_INT32_DEC_WIDTH));
sprintf (str0, "%" PRINTF_INT32_MODIFIER "u", UINT32_C(4294967295));
if (0 != strcmp (str0, "4294967295")) REPORTERROR (("Something wrong with PRINTF_INT32_MODIFIER : %s\n", str0));
if (atoi(PRINTF_UINT32_DEC_WIDTH) != (int) strlen(str0)) REPORTERROR (("Something wrong with PRINTF_UINT32_DEC_WIDTH : %s\n", PRINTF_UINT32_DEC_WIDTH));
#ifdef INT64_MAX
sprintf (str1, "%" PRINTF_INT64_MODIFIER "d", INT64_C(9223372036854775807));
if (0 != strcmp (str1, "9223372036854775807")) REPORTERROR (("Something wrong with PRINTF_INT32_MODIFIER : %s\n", str1));
if (atoi(PRINTF_INT64_DEC_WIDTH) != (int) strlen(str1)) REPORTERROR (("Something wrong with PRINTF_INT64_DEC_WIDTH : %s, %d\n", PRINTF_INT64_DEC_WIDTH, (int) strlen(str1)));
sprintf (str1, "%" PRINTF_INT64_MODIFIER "u", UINT64_C(18446744073709550591));
if (0 != strcmp (str1, "18446744073709550591")) REPORTERROR (("Something wrong with PRINTF_INT32_MODIFIER : %s\n", str1));
if (atoi(PRINTF_UINT64_DEC_WIDTH) != (int) strlen(str1)) REPORTERROR (("Something wrong with PRINTF_UINT64_DEC_WIDTH : %s, %d\n", PRINTF_UINT64_DEC_WIDTH, (int) strlen(str1)));
#endif
sprintf (str0, "%d %x\n", 0, ~0);
sprintf (str1, "%d %x\n", i8, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with i8 : %s\n", str1));
sprintf (str1, "%u %x\n", u8, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with u8 : %s\n", str1));
sprintf (str1, "%d %x\n", i16, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with i16 : %s\n", str1));
sprintf (str1, "%u %x\n", u16, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with u16 : %s\n", str1));
sprintf (str1, "%" PRINTF_INT32_MODIFIER "d %x\n", i32, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with i32 : %s\n", str1));
sprintf (str1, "%" PRINTF_INT32_MODIFIER "u %x\n", u32, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with u32 : %s\n", str1));
#ifdef INT64_MAX
sprintf (str1, "%" PRINTF_INT64_MODIFIER "d %x\n", i64, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with i64 : %s\n", str1));
#endif
sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "d %x\n", imax, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with imax : %s\n", str1));
sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "u %x\n", umax, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with umax : %s\n", str1));
TESTUMAX(8);
TESTUMAX(16);
TESTUMAX(32);
#ifdef INT64_MAX
TESTUMAX(64);
#endif
#define STR(v) #v
#define Q(v) printf ("sizeof " STR(v) " = %u\n", (unsigned) sizeof (v));
if (err_n) {
printf ("pstdint.h is not correct. Please use sizes below to correct it:\n");
}
Q(int)
Q(unsigned)
Q(long int)
Q(short int)
Q(int8_t)
Q(int16_t)
Q(int32_t)
#ifdef INT64_MAX
Q(int64_t)
#endif
#if UINT_MAX < X_SIZE_MAX
printf ("UINT_MAX < X_SIZE_MAX\n");
#else
printf ("UINT_MAX >= X_SIZE_MAX\n");
#endif
printf ("%" PRINTF_INT64_MODIFIER "u vs %" PRINTF_INT64_MODIFIER "u\n", UINT_MAX, X_SIZE_MAX);
return EXIT_SUCCESS;
}
#endif

Binary file not shown.

View File

@ -31,18 +31,27 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x0
BEGIN
LTEXT "Loop Count",IDC_STATIC,7,10,44,12
EDITTEXT IDC_LOOP_COUNT,52,7,39,14,ES_AUTOHSCROLL
LTEXT "Fade Length",IDC_STATIC,7,25,41,8
EDITTEXT IDC_FADE_SECONDS,52,23,39,14,ES_AUTOHSCROLL
LTEXT "seconds",IDC_STATIC,93,25,29,11
LTEXT "Fade Delay",IDC_STATIC,7,40,41,8
EDITTEXT IDC_FADE_DELAY_SECONDS,52,38,39,14,ES_AUTOHSCROLL
LTEXT "seconds",IDC_STATIC,93,40,29,11
CONTROL "Loop normally",IDC_LOOP_NORMALLY,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,57,77,10
CONTROL "Loop forever",IDC_LOOP_FOREVER,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,70,77,10
CONTROL "Ignore looping",IDC_IGNORE_LOOP,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,83,77,10
CONTROL "Disable subsongs",IDC_DISABLE_SUBSONGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,99,87,10
LTEXT "Downmix",IDC_STATIC,7,115,48,12
EDITTEXT IDC_DOWNMIX_CHANNELS,52,112,37,14,ES_AUTOHSCROLL
CONTROL "Disable tagfile",IDC_TAGFILE_DISABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,131,87,10
CONTROL "Override title",IDC_OVERRIDE_TITLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,147,97,10
END

View File

@ -21,6 +21,8 @@ static const GUID guid_cfg_FadeLength = { 0x61da7ef1, 0x56a5, 0x4368, { 0xae, 0x
static const GUID guid_cfg_FadeDelay = { 0x73907787, 0xaf49, 0x4659, { 0x96, 0x8e, 0x9f, 0x70, 0xa1, 0x62, 0x49, 0xc4 } };
static const GUID guid_cfg_DisableSubsongs = { 0xa8cdd664, 0xb32b, 0x4a36, { 0x83, 0x07, 0xa0, 0x4c, 0xcd, 0x52, 0xa3, 0x7c } };
static const GUID guid_cfg_DownmixChannels = { 0x5a0e65dd, 0xeb37, 0x4c67, { 0x9a, 0xb1, 0x3f, 0xb0, 0xc9, 0x7e, 0xb0, 0xe0 } };
static const GUID guid_cfg_TagfileDisable = { 0xc1971eb7, 0xa930, 0x4bae, { 0x9e, 0x7f, 0xa9, 0x50, 0x36, 0x32, 0x41, 0xb3 } };
static const GUID guid_cfg_OverrideTitle = { 0xe794831f, 0xd067, 0x4337, { 0x97, 0x85, 0x10, 0x57, 0x39, 0x4b, 0x1b, 0x97 } };
static cfg_bool cfg_LoopForever(guid_cfg_LoopForever, DEFAULT_LOOP_FOREVER);
static cfg_bool cfg_IgnoreLoop(guid_cfg_IgnoreLoop, DEFAULT_IGNORE_LOOP);
@ -29,6 +31,8 @@ static cfg_string cfg_FadeLength(guid_cfg_FadeLength, DEFAULT_FADE_SECONDS);
static cfg_string cfg_FadeDelay(guid_cfg_FadeDelay, DEFAULT_FADE_DELAY_SECONDS);
static cfg_bool cfg_DisableSubsongs(guid_cfg_DisableSubsongs, DEFAULT_DISABLE_SUBSONGS);
static cfg_string cfg_DownmixChannels(guid_cfg_DownmixChannels, DEFAULT_DOWNMIX_CHANNELS);
static cfg_bool cfg_TagfileDisable(guid_cfg_TagfileDisable, DEFAULT_TAGFILE_DISABLE);
static cfg_bool cfg_OverrideTitle(guid_cfg_OverrideTitle, DEFAULT_OVERRIDE_TITLE);
// Needs to be here in rder to access the static config
void input_vgmstream::load_settings()
@ -41,6 +45,8 @@ void input_vgmstream::load_settings()
ignore_loop = cfg_IgnoreLoop;
disable_subsongs = cfg_DisableSubsongs;
sscanf(cfg_DownmixChannels.get_ptr(),"%d",&downmix_channels);
tagfile_disable = cfg_TagfileDisable;
override_title = cfg_OverrideTitle;
}
const char * vgmstream_prefs::get_name()
@ -75,6 +81,9 @@ BOOL vgmstreamPreferences::OnInitDialog(CWindow, LPARAM)
uSetDlgItemText(m_hWnd, IDC_DOWNMIX_CHANNELS, cfg_DownmixChannels);
CheckDlgButton(IDC_TAGFILE_DISABLE, cfg_TagfileDisable?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_OVERRIDE_TITLE, cfg_OverrideTitle?BST_CHECKED:BST_UNCHECKED);
return TRUE;
}
@ -100,6 +109,9 @@ void vgmstreamPreferences::reset()
CheckDlgButton(IDC_DISABLE_SUBSONGS, DEFAULT_DISABLE_SUBSONGS?BST_CHECKED:BST_UNCHECKED);
uSetDlgItemText(m_hWnd, IDC_DOWNMIX_CHANNELS, DEFAULT_DOWNMIX_CHANNELS);
CheckDlgButton(IDC_TAGFILE_DISABLE, DEFAULT_TAGFILE_DISABLE?BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(IDC_OVERRIDE_TITLE, DEFAULT_OVERRIDE_TITLE?BST_CHECKED:BST_UNCHECKED);
}
@ -109,6 +121,8 @@ void vgmstreamPreferences::apply()
cfg_LoopForever = IsDlgButtonChecked(IDC_LOOP_FOREVER)?true:false;
cfg_IgnoreLoop = IsDlgButtonChecked(IDC_IGNORE_LOOP)?true:false;
cfg_DisableSubsongs = IsDlgButtonChecked(IDC_DISABLE_SUBSONGS)?true:false;
cfg_TagfileDisable = IsDlgButtonChecked(IDC_TAGFILE_DISABLE)?true:false;
cfg_OverrideTitle = IsDlgButtonChecked(IDC_OVERRIDE_TITLE)?true:false;
double temp_fade_seconds;
double temp_fade_delay_seconds;
@ -178,6 +192,12 @@ bool vgmstreamPreferences::HasChanged()
bool current_cfg_DisableSubsongs = IsDlgButtonChecked(IDC_DISABLE_SUBSONGS)?true:false;
if(cfg_DisableSubsongs != current_cfg_DisableSubsongs) return true;
bool current_cfg_TagfileDisable = IsDlgButtonChecked(IDC_TAGFILE_DISABLE)?true:false;
if(cfg_TagfileDisable != current_cfg_TagfileDisable) return true;
bool current_cfg_OverrideTitle = IsDlgButtonChecked(IDC_OVERRIDE_TITLE)?true:false;
if(cfg_OverrideTitle != current_cfg_OverrideTitle) return true;
pfc::string FadeLength(cfg_FadeLength);
pfc::string FadeDelay(cfg_FadeDelay);
pfc::string LoopCount(cfg_LoopCount);

View File

@ -16,6 +16,8 @@
#define DEFAULT_IGNORE_LOOP false
#define DEFAULT_DISABLE_SUBSONGS false
#define DEFAULT_DOWNMIX_CHANNELS "8"
#define DEFAULT_TAGFILE_DISABLE false
#define DEFAULT_OVERRIDE_TITLE false
class vgmstreamPreferences : public CDialogImpl<vgmstreamPreferences>, public preferences_page_instance {
public:
@ -44,6 +46,8 @@ public:
COMMAND_HANDLER_EX(IDC_LOOP_COUNT, EN_CHANGE, OnEditChange)
COMMAND_HANDLER_EX(IDC_DISABLE_SUBSONGS, BN_CLICKED, OnEditChange)
COMMAND_HANDLER_EX(IDC_DOWNMIX_CHANNELS, EN_CHANGE, OnEditChange)
COMMAND_HANDLER_EX(IDC_TAGFILE_DISABLE, BN_CLICKED, OnEditChange)
COMMAND_HANDLER_EX(IDC_OVERRIDE_TITLE, BN_CLICKED, OnEditChange)
END_MSG_MAP()
private:
BOOL OnInitDialog(CWindow, LPARAM);

View File

@ -14,6 +14,7 @@
extern "C" {
#include "../src/vgmstream.h"
#include "../src/plugins.h"
}
#include "foo_vgmstream.h"
#include "foo_filetypes.h"
@ -58,6 +59,9 @@ input_vgmstream::input_vgmstream() {
ignore_loop = 0;
disable_subsongs = false;
downmix_channels = 0;
tagfile_disable = false;
tagfile_name = "!tags.m3u"; //todo make configurable
override_title = false;
load_settings();
}
@ -77,15 +81,6 @@ void input_vgmstream::open(service_ptr_t<file> p_filehint,const char * p_path,t_
filename = p_path;
/* KLUDGE */
if ( !pfc::stricmp_ascii( pfc::string_extension(filename), "MUS" ) )
{
unsigned char buffer[ 4 ];
if ( p_filehint.is_empty() ) input_open_file_helper( p_filehint, filename, p_reason, p_abort );
p_filehint->read_object_t( buffer, p_abort );
if ( !memcmp( buffer, "MUS\x1A", 4 ) ) throw exception_io_unsupported_format();
}
// keep file stats around (timestamp, filesize)
if ( p_filehint.is_empty() )
@ -142,18 +137,59 @@ void input_vgmstream::get_info(t_uint32 p_subsong, file_info & p_info, abort_cal
get_subsong_info(p_subsong, temp, &length_in_ms, &total_samples, &loop_start, &loop_end, &samplerate, &channels, &bitrate, description, p_abort);
if (get_subsong_count() > 1) {
/* set tag info (metadata tab in file properties) */
/* Shows a custom subsong title by default with subsong name, to simplify for average users.
* This can be overriden and extended and using the exported STREAM_x below and foobar's formatting.
* foobar defaults to filename minus extension if there is no meta "title" value. */
if (!override_title && get_subsong_count() > 1) {
p_info.meta_set("TITLE",temp);
}
if (get_description_tag(temp,description,"stream count: ")) p_info.meta_set("stream_count",temp);
if (get_description_tag(temp,description,"stream index: ")) p_info.meta_set("stream_index",temp);
if (get_description_tag(temp,description,"stream name: ")) p_info.meta_set("stream_name",temp);
p_info.info_set("vgmstream version",PLUGIN_VERSION);
/* get external file tags */
//todo optimize and don't parse tags again for this session (not sure how), seems foobar
// calls get_info on every play even if the file hasn't changes, and won't refresh "meta"
// unless forced or closing playlist+exe
if (!tagfile_disable) {
//todo use foobar's fancy-but-arcane string functions
char tagfile_path[PATH_LIMIT];
strcpy(tagfile_path, filename);
char *path = strrchr(tagfile_path,'\\');
if (path!=NULL) {
path[1] = '\0'; /* includes "\", remove after that from tagfile_path */
strcat(tagfile_path,tagfile_name);
}
else { /* ??? */
strcpy(tagfile_path,tagfile_name);
}
STREAMFILE *tagFile = open_foo_streamfile(tagfile_path, &p_abort, &stats);
if (tagFile != NULL) {
VGMSTREAM_TAGS tag;
vgmstream_tags_reset(&tag, filename);
while (vgmstream_tags_next_tag(&tag, tagFile)) {
p_info.meta_set(tag.key,tag.val);
}
close_streamfile(tagFile);
}
}
/* set technical info (details tab in file properties) */
p_info.info_set("vgmstream_version",PLUGIN_VERSION);
p_info.info_set_int("samplerate", samplerate);
p_info.info_set_int("channels", channels);
p_info.info_set_int("bitspersample",16);
/* not quite accurate but some people are confused by this
/* not quite accurate but some people are confused by "lossless"
* (could set lossless if PCM, but then again PCMFloat or PCM8 are converted/"lossy" in vgmstream) */
p_info.info_set("encoding","lossy");
p_info.info_set("encoding","lossy/lossless");
p_info.info_set_bitrate(bitrate / 1000);
if (total_samples > 0)
p_info.info_set_int("stream_total_samples", total_samples);
@ -344,8 +380,8 @@ bool input_vgmstream::g_is_our_path(const char * p_path,const char * p_extension
return 1;
}
/* some extensionless files can be handled by vgmstream, try to play */
if (strlen(p_extension) <= 0) {
// Last Of Us speech files have no file extension
return 1;
}

View File

@ -65,7 +65,7 @@ class input_vgmstream : public input_stubs {
int seek_pos_samples;
short sample_buffer[SAMPLE_BUFFER_SIZE];
/* config */
/* settings */
double fade_seconds;
double fade_delay_seconds;
double loop_count;
@ -74,7 +74,11 @@ class input_vgmstream : public input_stubs {
int ignore_loop;
bool disable_subsongs;
int downmix_channels;
bool tagfile_disable;
pfc::string8 tagfile_name;
bool override_title;
/* song config */
foobar_song_config config;
/* helpers */

View File

@ -15,6 +15,8 @@
#define IDC_DEFAULT_BUTTON 1008
#define IDC_DISABLE_SUBSONGS 1009
#define IDC_DOWNMIX_CHANNELS 1010
#define IDC_TAGFILE_DISABLE 1011
#define IDC_OVERRIDE_TITLE 1012
// Next default values for new objects
//

View File

@ -147,10 +147,14 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\streamfile.h"
>
</File>
<File
RelativePath=".\plugins.h"
>
</File>
<File
RelativePath=".\streamfile.h"
>
</File>
<File
RelativePath=".\streamtypes.h"
>
@ -172,6 +176,10 @@
<File
RelativePath=".\formats.c"
>
</File>
<File
RelativePath=".\plugins.c"
>
</File>
<File
RelativePath=".\streamfile.c"

View File

@ -89,6 +89,7 @@
<ClInclude Include="coding\vorbis_custom_data_fsb.h" />
<ClInclude Include="coding\vorbis_custom_data_wwise.h" />
<ClInclude Include="coding\vorbis_custom_decoder.h" />
<ClInclude Include="plugins.h" />
<ClInclude Include="streamfile.h" />
<ClInclude Include="streamtypes.h" />
<ClInclude Include="util.h" />
@ -189,6 +190,7 @@
<ClCompile Include="meta\x360_cxs.c" />
<ClCompile Include="meta\x360_tra.c" />
<ClCompile Include="formats.c" />
<ClCompile Include="plugins.c" />
<ClCompile Include="meta\ps2_va3.c" />
<ClCompile Include="streamfile.c" />
<ClCompile Include="util.c" />

View File

@ -47,6 +47,9 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="plugins.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="streamfile.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -160,6 +163,9 @@
<ClCompile Include="formats.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="plugins.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="streamfile.c">
<Filter>Source Files</Filter>
</ClCompile>

View File

@ -185,6 +185,9 @@ static const adxkey_info adxkey8_list[] = {
/* Tensei Hakkenshi - Fuumaroku (PS2) */
{0x5761,0x6283,0x4531, "HAKKEN",0},
/* Lucky Star - Ryouou Gakuen Outousai (PS2) */
{0x481D,0x44F9,0x4E35, "LSTARPS2",0},
};
static const adxkey_info adxkey9_list[] = {

View File

@ -32,7 +32,7 @@ VGMSTREAM * init_vgmstream_svs(STREAMFILE *streamFile) {
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_SVS;
vgmstream->sample_rate = (48000 * pitch) / 4096; /* music = ~44100, ambience = 48000 */
vgmstream->sample_rate = round10((48000 * pitch) / 4096); /* music = ~44100, ambience = 48000 (rounding makes more sense but not sure) */
vgmstream->num_samples = ps_bytes_to_samples(get_streamfile_size(streamFile) - start_offset, channel_count);
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile) * 28; /* frame count (0x10*ch) */

View File

@ -35,7 +35,7 @@ VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE *streamFile) {
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VS_FFX;
vgmstream->sample_rate = (48000 * pitch) / 4096; /* verified, needed for rare files */
vgmstream->sample_rate = round10((48000 * pitch) / 4096); /* needed for rare files */
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_vs_ffx;

129
src/plugins.c Normal file
View File

@ -0,0 +1,129 @@
#include "vgmstream.h"
#include "plugins.h"
static void tags_clean(VGMSTREAM_TAGS* tag) {
int i;
int val_len = strlen(tag->val);
/* remove trailing spaces */
for (i = val_len - 1; i > 0; i--) {
if (tag->val[i] != ' ')
break;
tag->val[i] = '\0';
}
}
/* Tags are divided in two: "global" @TAGS and "file" %TAGS for target filename. To extract both
* we find the filename's tag "section": (other_filename) ..(#tag section).. (target_filename).
* When a new "other_filename" is found that offset is marked as section_start, and when target_filename
* is found it's marked as section_end. Then we can begin extracting tags within that section, until
* all tags are exhausted. Global tags are extracted while searching, so they always go first, and
* also meaning any tags after the section is found are ignored. */
int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tag, STREAMFILE* tagfile) {
off_t file_size = get_streamfile_size(tagfile);
char currentname[TAG_LINE_MAX] = {0};
char line[TAG_LINE_MAX] = {0};
int ok, bytes_read, line_done;
/* prepare file start and skip BOM if needed */
if (tag->offset == 0) {
if ((uint16_t)read_16bitLE(0x00, tagfile) == 0xFFFE ||
(uint16_t)read_16bitLE(0x00, tagfile) == 0xFEFF) {
tag->offset = 0x02;
if (tag->section_start == 0)
tag->section_start = 0x02;
}
else if (((uint32_t)read_32bitBE(0x00, tagfile) & 0xFFFFFF00) == 0xEFBBBF00) {
tag->offset = 0x03;
if (tag->section_start == 0)
tag->section_start = 0x03;
}
}
/* read lines */
while (tag->offset < file_size) {
/* no more tags to extract */
if (tag->section_found && tag->offset >= tag->section_end) {
goto fail;
}
bytes_read = get_streamfile_text_line(TAG_LINE_MAX,line, tag->offset,tagfile, &line_done);
if (!line_done) goto fail;
tag->offset += bytes_read;
if (tag->section_found) {
/* find possible file tag */
ok = sscanf(line, "# %%%[^ \t] %[^\r\n] ", tag->key,tag->val);
if (ok == 2) {
tags_clean(tag);
return 1;
}
}
else {
/* find possible global tag */
if (line[0] == '#') {
ok = sscanf(line, "# @%[^ \t] %[^\r\n]", tag->key,tag->val);
if (ok == 2) {
tags_clean(tag);
return 1;
}
continue; /* next line */
}
/* find possible filename and section start/end */
ok = sscanf(line, " %[^\r\n] ", currentname);
if (ok == 1) {
if (strcasecmp(tag->targetname,currentname) == 0) { /* looks ok even for UTF-8 */
/* section ok, start would be set before this (or be 0) */
tag->section_end = tag->offset;
tag->section_found = 1;
tag->offset = tag->section_start;
}
else {
/* mark new possible section */
tag->section_start = tag->offset;
}
continue;
}
/* empty/bad line, probably */
}
}
/* may reach here if read up to file_size but no section was found */
fail:
tag->key[0] = '\0';
tag->val[0] = '\0';
return 0;
}
void vgmstream_tags_reset(VGMSTREAM_TAGS* tag, const char* target_filename) {
const char *path;
memset(tag, 0, sizeof(VGMSTREAM_TAGS));
/* get base name */
//todo Windows CMD accepts both \\ and /, better way to handle this?
path = strrchr(target_filename,'\\');
if (!path)
path = strrchr(target_filename,'/');
if (path != NULL)
path = path+1;
//todo validate sizes and copy sensible max
if (path) {
strcpy(tag->targetname, path);
} else {
strcpy(tag->targetname, target_filename);
}
}

36
src/plugins.h Normal file
View File

@ -0,0 +1,36 @@
/*
* plugins.h - helper for plugins
*/
#ifndef _PLUGINS_H_
#define _PLUGINS_H_
#include "streamfile.h"
#define TAG_LINE_MAX 2048
//todo improve API and make opaque
//typedef struct VGMSTREAM_TAGS VGMSTREAM_TAGS;
typedef struct {
/* extracted output */
char key[TAG_LINE_MAX];
char val[TAG_LINE_MAX];
/* file to find tags for */
char targetname[TAG_LINE_MAX];
/* tag section for filename (see comments below) */
int section_found;
off_t section_start;
off_t section_end;
off_t offset;
} VGMSTREAM_TAGS;
/* Extracts next valid tag in tagfile to *tag. Returns 0 if no more tags are found (meant to be
* called repeatedly until 0). Key are lowercase and values can be treated as UTF-8. */
int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tag, STREAMFILE* tagfile);
/* resets tagfile to restart reading from the beginning for a new filename */
void vgmstream_tags_reset(VGMSTREAM_TAGS* tag, const char* target_filename);
#endif /* _PLUGINS_H_ */

View File

@ -14,7 +14,10 @@
#include <pstdint.h>
#endif /* (_MSC_VER >= 1600) */
#ifndef inline /* (_MSC_VER < 1900)? */
#define inline _inline
#endif
#define strcasecmp _stricmp
#define strncasecmp _strnicmp

View File

@ -67,6 +67,14 @@ static inline int clamp16(int32_t val) {
return val;
}
static inline int round10(int val) {
int round_val = val % 10;
if (round_val < 5) /* half-down rounding */
return val - round_val;
else
return val + (10 - round_val);
}
/* return a file's extension (a pointer to the first character of the
* extension in the original filename or the ending null byte if no extension */
const char * filename_extension(const char * filename);

View File

@ -2322,12 +2322,13 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
concatn(length,desc,temp);
}
if (vgmstream->num_streams > 1 && vgmstream->stream_index > 0) {
if (vgmstream->num_streams > 1) {
snprintf(temp,TEMPSIZE,
"\nstream index: %d",
vgmstream->stream_index);
vgmstream->stream_index == 0 ? 1 : vgmstream->stream_index);
concatn(length,desc,temp);
}
if (vgmstream->stream_name[0] != '\0') {
snprintf(temp,TEMPSIZE,
"\nstream name: %s",

View File

@ -12,6 +12,7 @@
#ifdef _MSC_VER
#define _CRT_SECURE_NO_DEPRECATE
#endif
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
@ -21,9 +22,10 @@
#include <ctype.h>
#include "../src/vgmstream.h"
#include "in2.h"
#include "wa_ipc.h"
#include "ipc_pe.h"
#include "../src/plugins.h"
#include "sdk/in2.h"
#include "sdk/wa_ipc.h"
#include "sdk/ipc_pe.h"
#include "resource.h"
@ -39,13 +41,14 @@
/* ************************************* */
/* plugin main (declared at the bottom of this file) */
/* plugin module (declared at the bottom of this file) */
In_Module input_module;
DWORD WINAPI __stdcall decode(void *arg);
/* Winamp Play extension list, to accept and associate extensions in Windows */
#define EXTENSION_LIST_SIZE (0x2000 * 6)
#define EXT_BUFFER_SIZE 200
/* fixed list to simplify but could also malloc/free on init/close */
char working_extension_list[EXTENSION_LIST_SIZE] = {0};
/* defaults */
@ -58,6 +61,7 @@ typedef struct {
int thread_priority;
int disable_subsongs;
int downmix_channels;
int tagfile_disable;
} winamp_settings;
/* current song settings */
@ -89,13 +93,18 @@ int stream_length_samples = 0;
int fade_samples = 0;
int output_channels = 0;
const char* tagfile_name = "!tags.m3u"; //todo make configurable
in_char lastfn[PATH_LIMIT] = {0}; /* name of the currently playing file */
/* ************************************* */
/* IN_UNICODE */
/* ************************************* */
//todo safe ops
//todo there must be a better way to handle unicode...
#ifdef UNICODE_INPUT_PLUGIN
#define wa_strcmp wcscmp
#define wa_strcpy wcscpy
#define wa_strncpy wcsncpy
#define wa_strcat wcscat
@ -108,6 +117,7 @@ in_char lastfn[PATH_LIMIT] = {0}; /* name of the currently playing file */
#define wa_IPC_PE_INSERTFILENAME IPC_PE_INSERTFILENAMEW
#define wa_L(x) L ##x
#else
#define wa_strcmp strcmp
#define wa_strcpy strcpy
#define wa_strncpy strncpy
#define wa_strcat strcat
@ -121,8 +131,8 @@ in_char lastfn[PATH_LIMIT] = {0}; /* name of the currently playing file */
#define wa_L(x) x
#endif
/* converts from utf16 to utf8 (if unicode is active) */
static void wa_wchar_to_char(char *dst, size_t dstsize, const in_char *wsrc) {
/* converts from utf16 to utf8 (if unicode is on) */
static void wa_ichar_to_char(char *dst, size_t dstsize, const in_char *wsrc) {
#ifdef UNICODE_INPUT_PLUGIN
/* converto to UTF8 codepage, default separate bytes, source wstr, wstr lenght, */
//int size_needed = WideCharToMultiByte(CP_UTF8,0, src,-1, NULL,0, NULL, NULL);
@ -132,8 +142,8 @@ static void wa_wchar_to_char(char *dst, size_t dstsize, const in_char *wsrc) {
#endif
}
/* converts from utf8 to utf16 (if unicode is active) */
static void wa_char_to_wchar(in_char *wdst, size_t wdstsize, const char *src) {
/* converts from utf8 to utf16 (if unicode is on) */
static void wa_char_to_ichar(in_char *wdst, size_t wdstsize, const char *src) {
#ifdef UNICODE_INPUT_PLUGIN
//int size_needed = MultiByteToWideChar(CP_UTF8,0, src,-1, NULL,0);
MultiByteToWideChar(CP_UTF8,0, src,-1, wdst,wdstsize);
@ -142,6 +152,24 @@ static void wa_char_to_wchar(in_char *wdst, size_t wdstsize, const char *src) {
#endif
}
/* copies from utf16 to utf16 (if unicode is active) */
static void wa_wchar_to_ichar(in_char *wdst, size_t wdstsize, const wchar_t *src) {
#ifdef UNICODE_INPUT_PLUGIN
wcscpy(wdst,src);
#else
strcpy(wdst,src); //todo ???
#endif
}
/* copies from utf16 to utf16 */
static void wa_char_to_wchar(wchar_t *wdst, size_t wdstsize, const char *src) {
#ifdef UNICODE_INPUT_PLUGIN
MultiByteToWideChar(CP_UTF8,0, src,-1, wdst,wdstsize);
#else
strcpy(wdst,src); //todo ???
#endif
}
/* opens a utf16 (unicode) path */
static FILE* wa_fopen(const in_char *wpath) {
#ifdef UNICODE_INPUT_PLUGIN
@ -172,7 +200,7 @@ typedef struct {
} WINAMP_STREAMFILE;
static STREAMFILE *open_winamp_streamfile_by_file(FILE *infile, const char * path);
static STREAMFILE *open_winamp_streamfile_by_wpath(const in_char *wpath);
static STREAMFILE *open_winamp_streamfile_by_ipath(const in_char *wpath);
static size_t wasf_read(WINAMP_STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) {
return streamfile->stdiosf->read(streamfile->stdiosf,dest,offset,length);
@ -216,8 +244,8 @@ static STREAMFILE *wasf_open(WINAMP_STREAMFILE *streamFile, const char *const fi
}
/* STREAMFILEs carry char/UTF8 names, convert to wchar for Winamp */
wa_char_to_wchar(wpath,PATH_LIMIT, filename);
return open_winamp_streamfile_by_wpath(wpath);
wa_char_to_ichar(wpath,PATH_LIMIT, filename);
return open_winamp_streamfile_by_ipath(wpath);
}
static void wasf_close(WINAMP_STREAMFILE *streamfile) {
@ -255,7 +283,7 @@ fail:
}
static STREAMFILE *open_winamp_streamfile_by_wpath(const in_char *wpath) {
static STREAMFILE *open_winamp_streamfile_by_ipath(const in_char *wpath) {
FILE *infile = NULL;
STREAMFILE *streamFile;
char path[PATH_LIMIT];
@ -265,7 +293,7 @@ static STREAMFILE *open_winamp_streamfile_by_wpath(const in_char *wpath) {
if (!infile) return NULL;
/* convert to UTF-8 if needed for internal use */
wa_wchar_to_char(path,PATH_LIMIT, wpath);
wa_ichar_to_char(path,PATH_LIMIT, wpath);
streamFile = open_winamp_streamfile_by_file(infile,path);
if (!streamFile) {
@ -282,7 +310,7 @@ static VGMSTREAM* init_vgmstream_winamp(const in_char *fn, int stream_index) {
//return init_vgmstream(fn);
/* manually init streamfile to pass the stream index */
STREAMFILE *streamFile = open_winamp_streamfile_by_wpath(fn); //open_stdio_streamfile(fn);
STREAMFILE *streamFile = open_winamp_streamfile_by_ipath(fn); //open_stdio_streamfile(fn);
if (streamFile) {
streamFile->stream_index = stream_index;
vgmstream = init_vgmstream_from_STREAMFILE(streamFile);
@ -336,6 +364,7 @@ static void cfg_char_to_wchar(TCHAR *wdst, size_t wdstsize, const char *src) {
#define DEFAULT_IGNORE_LOOP 0
#define DEFAULT_DISABLE_SUBSONGS 0
#define DEFAULT_DOWNMIX_CHANNELS 0
#define DEFAULT_TAGFILE_DISABLE 0
#define INI_ENTRY_FADE_SECONDS TEXT("fade_seconds")
#define INI_ENTRY_FADE_DELAY_SECONDS TEXT("fade_delay")
@ -345,6 +374,7 @@ static void cfg_char_to_wchar(TCHAR *wdst, size_t wdstsize, const char *src) {
#define INI_ENTRY_IGNORE_LOOP TEXT("ignore_loop")
#define INI_ENTRY_DISABLE_SUBSONGS TEXT("disable_subsongs")
#define INI_ENTRY_DOWNMIX_CHANNELS TEXT("downmix_channels")
#define INI_ENTRY_TAGFILE_DISABLE TEXT("tagfile_disable")
TCHAR *priority_strings[] = {
TEXT("Idle"),
@ -458,6 +488,7 @@ static void load_config() {
settings.downmix_channels = DEFAULT_DOWNMIX_CHANNELS;
}
settings.tagfile_disable = GetPrivateProfileInt(CONFIG_APP_NAME,INI_ENTRY_TAGFILE_DISABLE,DEFAULT_TAGFILE_DISABLE,iniFile);
}
/* config dialog handler */
@ -508,6 +539,9 @@ INT_PTR CALLBACK configDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
cfg_sprintf(buf, TEXT("%d"),settings.downmix_channels);
SetDlgItemText(hDlg,IDC_DOWNMIX_CHANNELS,buf);
if (settings.tagfile_disable)
CheckDlgButton(hDlg,IDC_TAGFILE_DISABLE,BST_CHECKED);
break;
case WM_COMMAND: /* button presses */
@ -598,6 +632,10 @@ INT_PTR CALLBACK configDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
settings.downmix_channels = temp_downmix_channels;
cfg_sprintf(buf, TEXT("%d"),settings.downmix_channels);
WritePrivateProfileString(CONFIG_APP_NAME,INI_ENTRY_DOWNMIX_CHANNELS,buf,iniFile);
settings.tagfile_disable = (IsDlgButtonChecked(hDlg,IDC_TAGFILE_DISABLE) == BST_CHECKED);
cfg_sprintf(buf, TEXT("%d"),settings.tagfile_disable);
WritePrivateProfileString(CONFIG_APP_NAME,INI_ENTRY_TAGFILE_DISABLE,buf,iniFile);
}
EndDialog(hDlg,TRUE);
@ -628,6 +666,7 @@ INT_PTR CALLBACK configDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
CheckDlgButton(hDlg,IDC_DISABLE_SUBSONGS,BST_UNCHECKED);
SetDlgItemText(hDlg,IDC_DOWNMIX_CHANNELS,DEFAULT_DOWNMIX_CHANNELS);
CheckDlgButton(hDlg,IDC_TAGFILE_DISABLE,BST_UNCHECKED);
break;
default:
@ -706,19 +745,17 @@ static int split_subsongs(const in_char * filename, int stream_index, VGMSTREAM
/* 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, manually fails too */
/* 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;
}
/* parses a modified filename ('fakename') extracting tags parameters (NULL tag for first = filename) */
static int parse_fn_string(const in_char * fn, const in_char * tag, in_char * dst, int dst_size) {
in_char *end;
const in_char *end = wa_strchr(fn,'|');
end = wa_strchr(fn,'|');
if (tag==NULL) {
wa_strcpy(dst,fn);
if (end)
@ -726,14 +763,12 @@ static int parse_fn_string(const in_char * fn, const in_char * tag, in_char * ds
return 1;
}
//todo actually find + read tags
dst[0] = '\0';
return 0;
}
static int parse_fn_int(const in_char * fn, const in_char * tag, int * num) {
in_char * start = wa_strchr(fn,'|');
const in_char * start = wa_strchr(fn,'|');
//todo actually find + read tags
if (start > 0) {
wa_sscanf(start+1, wa_L("$s=%i "), num);
return 1;
@ -767,13 +802,13 @@ static void add_extension(int length, char * dst, const char * ext) {
ext_len = strlen(ext);
/* find end of dst (double \0), saved in i */
for (i=0; i<length-2 && (dst[i] || dst[i+1]); i++)
for (i = 0; i < length-2 && (dst[i] || dst[i+1]); i++)
;
/* check if end reached or not enough room to add */
if (i == length-2 || i + EXT_BUFFER_SIZE+2 > length-2 || ext_len * 3 + 20+2 > EXT_BUFFER_SIZE) {
dst[i]='\0';
dst[i+1]='\0';
dst[i] = '\0';
dst[i+1] = '\0';
return;
}
@ -781,16 +816,17 @@ static void add_extension(int length, char * dst, const char * ext) {
i++;
/* uppercase ext */
for (j=0; j < ext_len; j++)
for (j = 0; j < ext_len; j++)
ext_upp[j] = toupper(ext[j]);
ext_upp[j] = '\0';
/* copy new extension + double null terminate */
written = sprintf(buf, "%s%c%s Audio File (*.%s)%c", ext,'\0',ext_upp,ext_upp,'\0'); /*ex: "vgmstream\0vgmstream Audio File (*.VGMSTREAM)\0" */
for (j=0; j < written; i++,j++)
/* ex: "vgmstream\0vgmstream Audio File (*.VGMSTREAM)\0" */
written = sprintf(buf, "%s%c%s Audio File (*.%s)%c", ext,'\0',ext_upp,ext_upp,'\0');
for (j = 0; j < written; i++,j++)
dst[i] = buf[j];
dst[i]='\0';
dst[i+1]='\0';
dst[i] = '\0';
dst[i+1] = '\0';
}
/* Creates Winamp's extension list, a single string that ends with \0\0.
@ -837,7 +873,7 @@ static void get_title(in_char * dst, int dst_size, const in_char * fn, VGMSTREAM
/* show name, but not for the base stream */
if (infostream && infostream->stream_name[0] != '\0' && stream_index > 0) {
in_char stream_name[PATH_LIMIT];
wa_char_to_wchar(stream_name, PATH_LIMIT, infostream->stream_name);
wa_char_to_ichar(stream_name, PATH_LIMIT, infostream->stream_name);
wa_snprintf(buffer,PATH_LIMIT, wa_L(" (%s)"), stream_name);
wa_strcat(dst,buffer);
}
@ -1198,7 +1234,8 @@ void winamp_GetFileInfo(const in_char *fn, in_char *title, int *length_in_ms) {
if (length_in_ms) {
*length_in_ms = -1000;
if (infostream) {
int num_samples = get_vgmstream_play_samples(infoconfig.song_loop_count,infoconfig.song_fade_time,infoconfig.song_fade_delay,infostream);
const int num_samples = get_vgmstream_play_samples(
infoconfig.song_loop_count,infoconfig.song_fade_time,infoconfig.song_fade_delay,infostream);
*length_in_ms = num_samples * 1000LL /infostream->sample_rate;
}
}
@ -1214,8 +1251,8 @@ void winamp_EQSet(int on, char data[10], int preamp) {
/* the decode thread */
DWORD WINAPI __stdcall decode(void *arg) {
int max_buffer_samples = sizeof(sample_buffer) / sizeof(sample_buffer[0]) / 2 / vgmstream->channels;
int max_samples = stream_length_samples;
const int max_buffer_samples = sizeof(sample_buffer) / sizeof(sample_buffer[0]) / 2 / vgmstream->channels;
const int max_samples = stream_length_samples;
while (!decode_abort) {
int samples_to_do;
@ -1284,11 +1321,11 @@ DWORD WINAPI __stdcall decode(void *arg) {
if (vgmstream->loop_flag && fade_samples > 0 && !settings.loop_forever) {
int samples_into_fade = decode_pos_samples - (stream_length_samples - fade_samples);
if (samples_into_fade + samples_to_do > 0) {
int j,k;
for (j=0; j < samples_to_do; j++, samples_into_fade++) {
int j, k;
for (j = 0; j < samples_to_do; j++, samples_into_fade++) {
if (samples_into_fade > 0) {
double fadedness = (double)(fade_samples-samples_into_fade)/fade_samples;
for (k=0; k < vgmstream->channels; k++) {
const double fadedness = (double)(fade_samples-samples_into_fade)/fade_samples;
for (k = 0; k < vgmstream->channels; k++) {
sample_buffer[j*vgmstream->channels+k] =
(short)(sample_buffer[j*vgmstream->channels+k]*fadedness);
}
@ -1385,6 +1422,210 @@ In_Module input_module = {
0 /* outMod */
};
__declspec( dllexport ) In_Module * winampGetInModule2() {
__declspec(dllexport) In_Module * winampGetInModule2() {
return &input_module;
}
/* ************************************* */
/* IN_TAGS */
/* ************************************* */
/* could malloc and stuff but totals aren't much bigger than PATH_LIMITs anyway */
#define WINAMP_TAGS_ENTRY_MAX 30
#define WINAMP_TAGS_ENTRY_SIZE 2048
typedef struct {
in_char filename[PATH_LIMIT]; /* tags are loaded for this file */
int tag_count;
char keys[WINAMP_TAGS_ENTRY_MAX][WINAMP_TAGS_ENTRY_SIZE+1];
char vals[WINAMP_TAGS_ENTRY_MAX][WINAMP_TAGS_ENTRY_SIZE+1];
} winamp_tags;
winamp_tags last_tags;
/* Loads all tags for a filename in a temp struct to improve performance, as
* Winamp requests one tag at a time and may reask for the same tag several times */
static void load_tagfile_info(in_char* filename) {
STREAMFILE *tagFile = NULL;
char filename_utf8[PATH_LIMIT];
char tagfile_path_utf8[PATH_LIMIT];
in_char tagfile_path_i[PATH_LIMIT];
char *path;
if (settings.tagfile_disable) {
last_tags.tag_count = 0; /* maybe helps if setting changes during play */
return;
}
if (wa_strcmp(last_tags.filename, filename) == 0) {
return; /* not changed, tags still apply */
}
/* tags are now for this filename, find tagfile path */
wa_ichar_to_char(filename_utf8, PATH_LIMIT, filename);
strcpy(tagfile_path_utf8,filename_utf8);
path = strrchr(tagfile_path_utf8,'\\');
if (path != NULL) {
path[1] = '\0'; /* includes "\", remove after that from tagfile_path */
strcat(tagfile_path_utf8,tagfile_name);
}
else { /* ??? */
strcpy(tagfile_path_utf8,tagfile_name);
}
wa_char_to_ichar(tagfile_path_i, PATH_LIMIT, tagfile_path_utf8);
wa_strcpy(last_tags.filename, filename);
last_tags.tag_count = 0;
/* load all tags from tagfile */
tagFile = open_winamp_streamfile_by_ipath(tagfile_path_i);
if (tagFile != NULL) {
VGMSTREAM_TAGS tag;
int i;
vgmstream_tags_reset(&tag, filename_utf8);
while (vgmstream_tags_next_tag(&tag, tagFile)) {
int repeated_tag = 0;
int current_tag = last_tags.tag_count;
if (current_tag >= WINAMP_TAGS_ENTRY_MAX)
continue;
/* should overwrite repeated tags as global tags may appear multiple times */
for (i = 0; i < current_tag; i++) {
if (strcmp(last_tags.keys[i], tag.key) == 0) {
current_tag = i;
repeated_tag = 1;
break;
}
}
last_tags.keys[current_tag][0] = '\0';
strncat(last_tags.keys[current_tag], tag.key, WINAMP_TAGS_ENTRY_SIZE);
last_tags.vals[current_tag][0] = '\0';
strncat(last_tags.vals[current_tag], tag.val, WINAMP_TAGS_ENTRY_SIZE);
if (!repeated_tag)
last_tags.tag_count++;
}
close_streamfile(tagFile);
}
}
/* Winamp repeatedly calls this for every known tag currently used in the Advanced Title Formatting (ATF)
* config, 'metadata' being the requested tag. Returns 0 on failure/tag not found.
* May be called again after certain actions (adding file to playlist, Play, GetFileInfo, etc), and
* doesn't seem the plugin can tell Winamp all tags it supports at once or use custom tags. */
//todo unicode stuff could be improved... probably
static int winampGetExtendedFileInfo_common(in_char* filename, char *metadata, char* ret, int retlen) {
int i, tag_found;
int max_len;
/* always called (value in ms), must return ok so other tags get called */
if (strcasecmp(metadata, "length") == 0) {
strcpy(ret, "0");//todo should export but shows GetFileInfo's ms if not provided
return 1;
}
/* load list current tags, if necessary */
load_tagfile_info(filename);
#if 0
/* special case to fill WA5's unified dialog */
if (strcasecmp(metadata, "formatinformation") == 0) {
generate_format_string(...);
}
#endif
/* find requested tag */
tag_found = 0;
max_len = (retlen > 0) ? retlen-1 : retlen;
for (i = 0; i < last_tags.tag_count; i++) {
if (strcasecmp(metadata,last_tags.keys[i]) == 0) {
ret[0] = '\0';
strncat(ret, last_tags.vals[i], max_len);
tag_found = 1;
break;
}
}
if (!tag_found)
goto fail;
return 1;
fail:
return 0;
}
/* for Winamp 5.24 */
__declspec (dllexport) int winampGetExtendedFileInfo(char *filename, char *metadata, char *ret, int retlen) {
in_char filename_wchar[PATH_LIMIT];
int ok;
if (settings.tagfile_disable)
return 0;
wa_char_to_ichar(filename_wchar,PATH_LIMIT, filename);
ok = winampGetExtendedFileInfo_common(filename_wchar, metadata, ret, retlen);
if (ok == 0)
return 0;
return 1;
}
/* for Winamp 5.3+ */
__declspec (dllexport) int winampGetExtendedFileInfoW(wchar_t *filename, char *metadata, wchar_t *ret, int retlen) {
in_char filename_ichar[PATH_LIMIT];
char ret_utf8[2048];
int ok;
if (settings.tagfile_disable)
return 0;
wa_wchar_to_ichar(filename_ichar,PATH_LIMIT, filename);
ok = winampGetExtendedFileInfo_common(filename_ichar, metadata, ret_utf8,2048);
if (ok == 0)
return 0;
wa_char_to_wchar(ret,retlen, ret_utf8);
return 1;
}
/* return 1 if you want winamp to show it's own file info dialogue, 0 if you want to show your own (via In_Module.InfoBox)
* if returning 1, remember to implement winampGetExtendedFileInfo("formatinformation")! */
__declspec(dllexport) int winampUseUnifiedFileInfoDlg(const wchar_t * fn) {
return 0;
}
__declspec(dllexport) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) {
/* may uninstall without restart as we aren't subclassing */
return IN_PLUGIN_UNINSTALL_NOW;
}
/* winamp sekrit exports: */
/*
EXPORTS
winampGetInModule2 @1
winampGetExtendedFileInfo @2
winampGetExtendedFileInfoW @3
winampAddUnifiedFileInfoPane @4
winampUseUnifiedFileInfoDlg @5
winampGetExtendedRead_close @6
winampGetExtendedRead_getData @7
winampGetExtendedRead_open @8
winampGetExtendedRead_openW @9
winampGetExtendedRead_setTime @10
winampUninstallPlugin @11
*/

View File

@ -71,7 +71,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;VGM_WINAMP_UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -99,7 +99,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;VGM_WINAMP_UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>

View File

@ -10,3 +10,4 @@
#define IDC_DEFAULT_BUTTON 1008
#define IDC_DISABLE_SUBSONGS 1009
#define IDC_DOWNMIX_CHANNELS 1011
#define IDC_TAGFILE_DISABLE 1012

View File

@ -9,25 +9,35 @@ STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "in_vgmstream configuration"
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
// right column
DEFPUSHBUTTON "OK",IDOK,129,7,50,14
PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14
PUSHBUTTON "Default",IDC_DEFAULT_BUTTON,129,41,50,14
LTEXT "Thread Priority",IDC_STATIC,110,60,46,8
CONTROL "Slider1",IDC_THREAD_PRIORITY_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,96,76,77,10
CTEXT "DATARIFIC",IDC_THREAD_PRIORITY_TEXT,96,92,77,18
// left column
LTEXT "Loop Count",IDC_STATIC,7,10,44,12
EDITTEXT IDC_LOOP_COUNT,52,7,39,14,ES_AUTOHSCROLL
LTEXT "Fade Length",IDC_STATIC,7,25,41,8
EDITTEXT IDC_FADE_SECONDS,52,23,39,14,ES_AUTOHSCROLL
LTEXT "seconds",IDC_STATIC,93,25,29,11
LTEXT "Fade Delay",IDC_STATIC,7,40,41,8
EDITTEXT IDC_FADE_DELAY_SECONDS,52,38,39,14,ES_AUTOHSCROLL
LTEXT "seconds",IDC_STATIC,93,40,29,11
CONTROL "Loop normally",IDC_LOOP_NORMALLY,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,57,77,10
CONTROL "Loop forever",IDC_LOOP_FOREVER,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,70,77,10
CONTROL "Ignore looping",IDC_IGNORE_LOOP,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,83,77,10
CONTROL "Disable subsongs",IDC_DISABLE_SUBSONGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,99,87,10
LTEXT "Downmix",IDC_STATIC,7,115,48,12
EDITTEXT IDC_DOWNMIX_CHANNELS,52,112,37,14,ES_AUTOHSCROLL
LTEXT "Thread Priority",IDC_STATIC,21,132,46,8
CONTROL "Slider1",IDC_THREAD_PRIORITY_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,7,140,77,10
CTEXT "DATARIFIC",IDC_THREAD_PRIORITY_TEXT,7,153,77,18
CONTROL "Disable tagfile",IDC_TAGFILE_DISABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,131,87,10
END