From fa829d49f72b6c86c2fa30ecd274c83a4baf1fdb Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 28 Apr 2017 16:10:16 +0200 Subject: [PATCH 01/16] Relax XWB size checks for padded files [BlazBlue Centralfiction PC] --- src/meta/xwb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/meta/xwb.c b/src/meta/xwb.c index 834f65da..5cf0c58f 100644 --- a/src/meta/xwb.c +++ b/src/meta/xwb.c @@ -117,7 +117,8 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { /* for Techland's XWB with no data */ if (xwb.base_offset == 0) goto fail; - if (xwb.data_offset + xwb.data_size != get_streamfile_size(streamFile)) goto fail; + /* some BlazBlue Centralfiction songs have padding after data size */ + if (xwb.data_offset + xwb.data_size > get_streamfile_size(streamFile)) goto fail; /* read base entry (WAVEBANKDATA) */ off = xwb.base_offset; From 3fc6db041452d2278dc64c7011703abb51d7eb51 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 28 Apr 2017 16:15:32 +0200 Subject: [PATCH 02/16] Update Winamp plugin with the "latest" (2008) SDK defs [unicode preps] --- winamp/in2.h | 172 +++--- winamp/in_vgmstream.c | 298 +++++----- winamp/out.h | 85 +-- winamp/wa_ipc.h | 1256 ++++++++++++++++++++++++++++++++++------- 4 files changed, 1388 insertions(+), 423 deletions(-) diff --git a/winamp/in2.h b/winamp/in2.h index 9a2bd083..a9416d6c 100644 --- a/winamp/in2.h +++ b/winamp/in2.h @@ -1,103 +1,137 @@ +#ifndef NULLSOFT_WINAMP_IN2H +#define NULLSOFT_WINAMP_IN2H #include "out.h" // note: exported symbol is now winampGetInModule2. -#define IN_VER 0x100 +#define IN_UNICODE 0x0F000000 +#ifdef UNICODE_INPUT_PLUGIN +#define in_char wchar_t +#define IN_VER (IN_UNICODE | 0x100) +#else +#define in_char char +#define IN_VER 0x100 +#endif + +#define IN_MODULE_FLAG_USES_OUTPUT_PLUGIN 1 +// By default, Winamp assumes that your input plugin wants to use Winamp's EQ, and doesn't do replay gain +// if you handle any of these yourself (EQ, Replay Gain adjustments), then set these flags accordingly +#define IN_MODULE_FLAG_EQ 2 // set this if you do your own EQ +#define IN_MODULE_FLAG_REPLAYGAIN 8 // set this if you adjusted volume for replay gain + // for tracks with no replay gain metadata, you should clear this flag + // UNLESS you handle "non_replaygain" gain adjustment yourself +#define IN_MODULE_FLAG_REPLAYGAIN_PREAMP 16 // use this if you queried for the replay gain preamp parameter and used it + // this parameter is new to 5.54 typedef struct { - int version; // module type (IN_VER) - char *description; // description of module, with version string + int version; // module type (IN_VER) + char *description; // description of module, with version string - HWND hMainWindow; // winamp's main window (filled in by winamp) - HINSTANCE hDllInstance; // DLL instance handle (Also filled in by winamp) + HWND hMainWindow; // winamp's main window (filled in by winamp) + HINSTANCE hDllInstance; // DLL instance handle (Also filled in by winamp) - char *FileExtensions; // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0" - // May be altered from Config, so the user can select what they want - - int is_seekable; // is this stream seekable? - int UsesOutputPlug; // does this plug-in use the output plug-ins? (musn't ever change, ever :) + char *FileExtensions; // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0" + // May be altered from Config, so the user can select what they want - void (*Config)(HWND hwndParent); // configuration dialog - void (*About)(HWND hwndParent); // about dialog + int is_seekable; // is this stream seekable? + int UsesOutputPlug; // does this plug-in use the output plug-ins? (musn't ever change, ever :) + // note that this has turned into a "flags" field + // see IN_MODULE_FLAG_* - void (*Init)(); // called at program init - void (*Quit)(); // called at program quit + void (*Config)(HWND hwndParent); // configuration dialog + void (*About)(HWND hwndParent); // about dialog - void (*GetFileInfo)(char *file, char *title, int *length_in_ms); // if file == NULL, current playing is used - int (*InfoBox)(char *file, HWND hwndParent); - - int (*IsOurFile)(char *fn); // called before extension checks, to allow detection of mms://, etc - // playback stuff - int (*Play)(char *fn); // return zero on success, -1 on file-not-found, some other value on other (stopping winamp) error - void (*Pause)(); // pause stream - void (*UnPause)(); // unpause stream - int (*IsPaused)(); // ispaused? return 1 if paused, 0 if not - void (*Stop)(); // stop (unload) stream + void (*Init)(); // called at program init + void (*Quit)(); // called at program quit - // time stuff - int (*GetLength)(); // get length in ms - int (*GetOutputTime)(); // returns current output time in ms. (usually returns outMod->GetOutputTime() - void (*SetOutputTime)(int time_in_ms); // seeks to point in stream (in ms). Usually you signal yoru thread to seek, which seeks and calls outMod->Flush().. +#define GETFILEINFO_TITLE_LENGTH 2048 + void (*GetFileInfo)(const in_char *file, in_char *title, int *length_in_ms); // if file == NULL, current playing is used - // volume stuff - void (*SetVolume)(int volume); // from 0 to 255.. usually just call outMod->SetVolume - void (*SetPan)(int pan); // from -127 to 127.. usually just call outMod->SetPan - - // in-window builtin vis stuff +#define INFOBOX_EDITED 0 +#define INFOBOX_UNCHANGED 1 + int (*InfoBox)(const in_char *file, HWND hwndParent); - void (*SAVSAInit)(int maxlatency_in_ms, int srate); // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open() - // call after opening audio device with max latency in ms and samplerate - void (*SAVSADeInit)(); // call in Stop() + int (*IsOurFile)(const in_char *fn); // called before extension checks, to allow detection of mms://, etc + // playback stuff + int (*Play)(const in_char *fn); // return zero on success, -1 on file-not-found, some other value on other (stopping winamp) error + void (*Pause)(); // pause stream + void (*UnPause)(); // unpause stream + int (*IsPaused)(); // ispaused? return 1 if paused, 0 if not + void (*Stop)(); // stop (unload) stream + + // time stuff + int (*GetLength)(); // get length in ms + int (*GetOutputTime)(); // returns current output time in ms. (usually returns outMod->GetOutputTime() + void (*SetOutputTime)(int time_in_ms); // seeks to point in stream (in ms). Usually you signal your thread to seek, which seeks and calls outMod->Flush().. + + // volume stuff + void (*SetVolume)(int volume); // from 0 to 255.. usually just call outMod->SetVolume + void (*SetPan)(int pan); // from -127 to 127.. usually just call outMod->SetPan + + // in-window builtin vis stuff + + void (*SAVSAInit)(int maxlatency_in_ms, int srate); // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open() + // call after opening audio device with max latency in ms and samplerate + void (*SAVSADeInit)(); // call in Stop() - // simple vis supplying mode - void (*SAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); - // sets the spec data directly from PCM data - // quick and easy way to get vis working :) - // needs at least 576 samples :) + // simple vis supplying mode + void (*SAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); + // sets the spec data directly from PCM data + // quick and easy way to get vis working :) + // needs at least 576 samples :) - // advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff. - int (*SAGetMode)(); // gets csa (the current type (4=ws,2=osc,1=spec)) - // use when calling SAAdd() - void (*SAAdd)(void *data, int timestamp, int csa); // sets the spec data, filled in by winamp + // advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff. + int (*SAGetMode)(); // gets csa (the current type (4=ws,2=osc,1=spec)) + // use when calling SAAdd() + int (*SAAdd)(void *data, int timestamp, int csa); // sets the spec data, filled in by winamp - // vis stuff (plug-in) - // simple vis supplying mode - void (*VSAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data - // quick and easy way to get vis working :) - // needs at least 576 samples :) + // vis stuff (plug-in) + // simple vis supplying mode + void (*VSAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data + // quick and easy way to get vis working :) + // needs at least 576 samples :) - // advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff. - int (*VSAGetMode)(int *specNch, int *waveNch); // use to figure out what to give to VSAAdd - void (*VSAAdd)(void *data, int timestamp); // filled in by winamp, called by plug-in + // advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff. + int (*VSAGetMode)(int *specNch, int *waveNch); // use to figure out what to give to VSAAdd + int (*VSAAdd)(void *data, int timestamp); // filled in by winamp, called by plug-in - // call this in Play() to tell the vis plug-ins the current output params. - void (*VSASetInfo)(int nch, int srate); + // call this in Play() to tell the vis plug-ins the current output params. + void (*VSASetInfo)(int srate, int nch); // <-- Correct (benski, dec 2005).. old declaration had the params backwards - // dsp plug-in processing: - // (filled in by winamp, called by input plug) + // dsp plug-in processing: + // (filled in by winamp, calld by input plug) - // returns 1 if active (which means that the number of samples returned by dsp_dosamples - // could be greater than went in.. Use it to estimate if you'll have enough room in the - // output buffer - int (*dsp_isactive)(); + // returns 1 if active (which means that the number of samples returned by dsp_dosamples + // could be greater than went in.. Use it to estimate if you'll have enough room in the + // output buffer + int (*dsp_isactive)(); - // returns number of samples to output. This can be as much as twice numsamples. - // be sure to allocate enough buffer for samples, then. - int (*dsp_dosamples)(short int *samples, int numsamples, int bps, int nch, int srate); + // returns number of samples to output. This can be as much as twice numsamples. + // be sure to allocate enough buffer for samples, then. + int (*dsp_dosamples)(short int *samples, int numsamples, int bps, int nch, int srate); - // eq stuff - void (*EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore. + // eq stuff + void (*EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore. - // info setting (filled in by winamp) - void (*SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :) + // info setting (filled in by winamp) + void (*SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :) - Out_Module *outMod; // filled in by winamp, optionally used :) + Out_Module *outMod; // filled in by winamp, optionally used :) } In_Module; +// return values from the winampUninstallPlugin(HINSTANCE hdll, HWND parent, int param) +// which determine if we can uninstall the plugin immediately or on winamp restart +// +// uninstall support was added from 5.0+ and uninstall now support from 5.5+ +// it is down to you to ensure that if uninstall now is returned that it will not cause a crash +// (ie don't use if you've been subclassing the main window) +#define IN_PLUGIN_UNINSTALL_NOW 0x1 +#define IN_PLUGIN_UNINSTALL_REBOOT 0x0 +#endif diff --git a/winamp/in_vgmstream.c b/winamp/in_vgmstream.c index 356759fa..8d6fda52 100644 --- a/winamp/in_vgmstream.c +++ b/winamp/in_vgmstream.c @@ -5,6 +5,10 @@ ** Copyright (c) 1998, Justin Frankel/Nullsoft Inc. */ +/* Winamp uses wchar_t when this is on, so extra steps are needed */ +//#define UNICODE_INPUT_PLUGIN + + #ifdef _MSC_VER #define _CRT_SECURE_NO_DEPRECATE #endif @@ -22,6 +26,7 @@ #include "wa_ipc.h" #include "resource.h" + #ifndef VERSION #include "../version.h" #endif @@ -33,14 +38,16 @@ #define PLUGIN_DESCRIPTION "vgmstream plugin " VERSION " " __DATE__ #define INI_NAME "plugin.ini" + /* post when playback stops */ #define WM_WA_MPEG_EOF WM_USER+2 In_Module input_module; /* the input module, declared at the bottom of this file */ DWORD WINAPI __stdcall decode(void *arg); -char lastfn[MAX_PATH+1] = {0}; /* name of the currently playing file */ -short sample_buffer[576*2*2]; /* 576 16-bit samples, stereo, possibly doubled in size for DSP */ +#define WINAMP_MAX_PATH 32768 /* originally 260+1 */ +char lastfn[WINAMP_MAX_PATH] = {0}; /* name of the currently playing file */ + #define DEFAULT_FADE_SECONDS "10.00" #define DEFAULT_FADE_DELAY_SECONDS "0.00" @@ -56,6 +63,16 @@ short sample_buffer[576*2*2]; /* 576 16-bit samples, stereo, possibly doubled in #define LOOP_FOREVER_INI_ENTRY "loop_forever" #define IGNORE_LOOP_INI_ENTRY "ignore_loop" +char *priority_strings[] = {"Idle","Lowest","Below Normal","Normal","Above Normal","Highest (not recommended)","Time Critical (not recommended)"}; +int priority_values[] = {THREAD_PRIORITY_IDLE,THREAD_PRIORITY_LOWEST,THREAD_PRIORITY_BELOW_NORMAL,THREAD_PRIORITY_NORMAL,THREAD_PRIORITY_ABOVE_NORMAL,THREAD_PRIORITY_HIGHEST,THREAD_PRIORITY_TIME_CRITICAL}; + + +/* Winamp Play extension list, needed to accept/play and associate extensions in Windows */ +#define EXTENSION_LIST_SIZE VGM_EXTENSION_LIST_CHAR_SIZE * 6 +#define EXT_BUFFER_SIZE 200 +char working_extension_list[EXTENSION_LIST_SIZE] = {0}; + +/* plugin config */ double fade_seconds; double fade_delay_seconds; double loop_count; @@ -63,11 +80,11 @@ int thread_priority; int loop_forever; int ignore_loop; -char *priority_strings[] = {"Idle","Lowest","Below Normal","Normal","Above Normal","Highest (not recommended)","Time Critical (not recommended)"}; -int priority_values[] = {THREAD_PRIORITY_IDLE,THREAD_PRIORITY_LOWEST,THREAD_PRIORITY_BELOW_NORMAL,THREAD_PRIORITY_NORMAL,THREAD_PRIORITY_ABOVE_NORMAL,THREAD_PRIORITY_HIGHEST,THREAD_PRIORITY_TIME_CRITICAL}; - +/* plugin state */ VGMSTREAM * vgmstream = NULL; HANDLE decode_thread_handle = INVALID_HANDLE_VALUE; +short sample_buffer[576*2*2]; /* 576 16-bit samples, stereo, possibly doubled in size for DSP */ + int paused = 0; int decode_abort = 0; int seek_needed_samples = -1; @@ -76,15 +93,93 @@ int decode_pos_samples = 0; int stream_length_samples = 0; int fade_samples = 0; -/* Winamp Play extension list, needed to accept/play and associate extensions in Windows */ -#define EXTENSION_LIST_SIZE VGM_EXTENSION_LIST_CHAR_SIZE * 6 -char working_extension_list[EXTENSION_LIST_SIZE] = {0}; -#define EXT_BUFFER_SIZE 200 +/* ***************************************** */ -static void add_extension(int length, char * dst, const char * src); -static void build_extension_list(); +/* Winamp INI reader */ +static void GetINIFileName(char * iniFile) { + /* if we're running on a newer winamp version that better supports + * saving of settings to a per-user directory, use that directory - if not + * then just revert to the old behaviour */ + if(IsWindow(input_module.hMainWindow) && SendMessage(input_module.hMainWindow, WM_WA_IPC,0,IPC_GETVERSION) >= 0x5000) { + char * iniDir = (char *)SendMessage(input_module.hMainWindow, WM_WA_IPC, 0, IPC_GETINIDIRECTORY); + strncpy(iniFile, iniDir, WINAMP_MAX_PATH); + strncat(iniFile, "\\Plugins\\", WINAMP_MAX_PATH); + /* can't be certain that \Plugins already exists in the user dir */ + CreateDirectory(iniFile,NULL); + strncat(iniFile, INI_NAME, WINAMP_MAX_PATH); + } + else { + char * lastSlash; + + GetModuleFileName(NULL, iniFile, WINAMP_MAX_PATH); + lastSlash = strrchr(iniFile, '\\'); + + *(lastSlash + 1) = 0; + strncat(iniFile, "Plugins\\" INI_NAME,WINAMP_MAX_PATH); + } +} + +/* Adds ext to Winamp's extension list */ +static void add_extension(int length, char * dst, const char * ext) { + char buf[EXT_BUFFER_SIZE]; + char ext_upp[EXT_BUFFER_SIZE]; + int ext_len, written; + int i,j; + if (length <= 1) + return; + + ext_len = strlen(ext); + + /* find end of dst (double \0), saved in i */ + for (i=0; i length-2 || ext_len * 3 + 20+2 > EXT_BUFFER_SIZE) { + dst[i]='\0'; + dst[i+1]='\0'; + return; + } + + if (i > 0) + i++; + + /* uppercase ext */ + 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++) + dst[i] = buf[j]; + dst[i]='\0'; + dst[i+1]='\0'; +} + +/* Creates Winamp's extension list, a single string that ends with \0\0. + * Each extension must be in this format: "extension\0Description\0" */ +static void build_extension_list() { + const char ** ext_list; + int ext_list_len; + int i; + + working_extension_list[0]='\0'; + working_extension_list[1]='\0'; + + ext_list = vgmstream_get_formats(); + ext_list_len = vgmstream_get_formats_length(); + + for (i=0; i < ext_list_len; i++) { + add_extension(EXTENSION_LIST_SIZE, working_extension_list, ext_list[i]); + } +} + +/* ***************************************** */ + +/* about dialog */ void about(HWND hwndParent) { MessageBox(hwndParent, PLUGIN_DESCRIPTION "\n" @@ -92,36 +187,10 @@ void about(HWND hwndParent) { "http://sourceforge.net/projects/vgmstream" ,"about in_vgmstream",MB_OK); } -void quit() {} - -void GetINIFileName(char * iniFile) { - /* if we're running on a newer winamp version that better supports - * saving of settings to a per-user directory, use that directory - if not - * then just revert to the old behaviour */ - - if(IsWindow(input_module.hMainWindow) && SendMessage(input_module.hMainWindow, WM_WA_IPC,0,IPC_GETVERSION) >= 0x5000) { - char * iniDir = (char *)SendMessage(input_module.hMainWindow, WM_WA_IPC, 0, IPC_GETINIDIRECTORY); - strncpy(iniFile, iniDir, MAX_PATH); - - strncat(iniFile, "\\Plugins\\", MAX_PATH); - /* can't be certain that \Plugins already exists in the user dir */ - CreateDirectory(iniFile,NULL); - strncat(iniFile, INI_NAME, MAX_PATH); - - } - else { - char * lastSlash; - - GetModuleFileName(NULL, iniFile, MAX_PATH); - lastSlash = strrchr(iniFile, '\\'); - - *(lastSlash + 1) = 0; - strncat(iniFile, "Plugins\\" INI_NAME,MAX_PATH); - } -} +/* called at program init */ void init() { - char iniFile[MAX_PATH+1]; + char iniFile[WINAMP_MAX_PATH]; char buf[256]; int consumed; @@ -167,18 +236,23 @@ void init() { build_extension_list(); } -/* we don't recognize protocols */ -int isourfile(char *fn) { return 0; } +/* called at program quit */ +void quit() { +} + +/* called before extension checks, to allow detection of mms://, etc */ +int isourfile(const in_char *fn) { + return 0; /* we don't recognize protocols */ +} /* request to start playing a file */ -int play(char *fn) -{ +int play(const in_char *fn) { int max_latency; /* don't lose a pointer! */ if (vgmstream) { /* TODO: this should either pop up an error box or close the file */ - return 1; + return 1; /* error */ } /* open the stream, set up */ vgmstream = init_vgmstream(fn); @@ -191,11 +265,11 @@ int play(char *fn) if (vgmstream->channels <= 0) { close_vgmstream(vgmstream); vgmstream=NULL; - return 1; + return 1; /* error */ } /* Remember that name, friends! */ - strncpy(lastfn,fn,MAX_PATH); + strncpy(lastfn,fn,WINAMP_MAX_PATH); /* open the output plugin */ max_latency = input_module.outMod->Open(vgmstream->sample_rate,vgmstream->channels, @@ -204,7 +278,7 @@ int play(char *fn) if (max_latency < 0) { close_vgmstream(vgmstream); vgmstream=NULL; - return 1; + return 1; /* error */ } /* Set info display */ @@ -234,15 +308,27 @@ int play(char *fn) SetThreadPriority(decode_thread_handle,priority_values[thread_priority]); - return 0; + return 0; /* success */ } -/* pausing... */ -void pause() { paused=1; input_module.outMod->Pause(1); } -void unpause() {paused=0; input_module.outMod->Pause(0); } -int ispaused() { return paused; } +/* pause stream */ +void pause() { + paused=1; + input_module.outMod->Pause(1); +} -/* stop playback */ +/* unpause stream */ +void unpause() { + paused=0; + input_module.outMod->Pause(0); +} + +/* ispaused? return 1 if paused, 0 if not */ +int ispaused() { + return paused; +} + +/* stop (unload) stream */ void stop() { if (decode_thread_handle != INVALID_HANDLE_VALUE) { decode_abort=1; @@ -265,28 +351,32 @@ void stop() { input_module.SAVSADeInit(); } -/* get current stream length */ +/* get length in ms */ int getlength() { return stream_length_samples*1000LL/vgmstream->sample_rate; } -/* get current output time */ +/* current output time in ms */ int getoutputtime() { return decode_pos_ms+(input_module.outMod->GetOutputTime()-input_module.outMod->GetWrittenTime()); } -/* seek */ +/* seeks to point in stream (in ms) */ void setoutputtime(int t) { if (vgmstream) seek_needed_samples = (long long)t * vgmstream->sample_rate / 1000LL; } /* pass these commands through */ -void setvolume(int volume) { input_module.outMod->SetVolume(volume); } -void setpan(int pan) { input_module.outMod->SetPan(pan); } +void setvolume(int volume) { + input_module.outMod->SetVolume(volume); +} +void setpan(int pan) { + input_module.outMod->SetPan(pan); +} /* display information */ -int infoDlg(char *fn, HWND hwnd) { +int infoDlg(const in_char *fn, HWND hwnd) { VGMSTREAM * infostream = NULL; char description[1024]; description[0]='\0'; @@ -297,7 +387,7 @@ int infoDlg(char *fn, HWND hwnd) { if (!vgmstream) return 0; describe_vgmstream(vgmstream,description,sizeof(description)); } else { - infostream = init_vgmstream(fn); + infostream = init_vgmstream((char*)fn); if (!infostream) return 0; describe_vgmstream(infostream,description,sizeof(description)); close_vgmstream(infostream); @@ -309,7 +399,7 @@ int infoDlg(char *fn, HWND hwnd) { } /* retrieve information on this or possibly another file */ -void getfileinfo(char *filename, char *title, int *length_in_ms) { +void getfileinfo(const in_char *filename, in_char *title, int *length_in_ms) { if (!filename || !*filename) /* currently playing file*/ { if (!vgmstream) return; @@ -318,7 +408,7 @@ void getfileinfo(char *filename, char *title, int *length_in_ms) { { char *p=lastfn+strlen(lastfn); while (*p != '\\' && p >= lastfn) p--; - strcpy(title,++p); + strcpy((char*)title,++p); } } else /* some other file */ @@ -337,15 +427,17 @@ void getfileinfo(char *filename, char *title, int *length_in_ms) { } if (title) { - char *p=filename+strlen(filename); + const char *p = filename + strlen(filename); while (*p != '\\' && p >= filename) p--; - strcpy(title,++p); + strcpy((char*)title,++p); } } } -/* nothin' */ -void eq_set(int on, char data[10], int preamp) {} +/* eq stuff */ +void eq_set(int on, char data[10], int preamp) { + /* nothin' */ +} /* the decode thread */ DWORD WINAPI __stdcall decode(void *arg) { @@ -439,7 +531,7 @@ DWORD WINAPI __stdcall decode(void *arg) { INT_PTR CALLBACK configDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { char buf[256]; - char iniFile[MAX_PATH+1]; + char iniFile[WINAMP_MAX_PATH]; static int mypri; HANDLE hSlider; @@ -587,12 +679,16 @@ INT_PTR CALLBACK configDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara return TRUE; } +/* configuration dialog */ void config(HWND hwndParent) { + /* defined in resource.rc */ DialogBox(input_module.hDllInstance, (const char *)IDD_CONFIG, hwndParent, configDlgProc); } -In_Module input_module = -{ +/* *********************************** */ + +/* main plugin def */ +In_Module input_module = { IN_VER, PLUGIN_DESCRIPTION, 0, /* hMainWindow */ @@ -624,68 +720,6 @@ In_Module input_module = 0 // out_mod }; -__declspec( dllexport ) In_Module * winampGetInModule2() -{ +__declspec( dllexport ) In_Module * winampGetInModule2() { return &input_module; } - - -/** - * Creates Winamp's extension list, a single string that ends with \0\0. - * Each extension must be in this format: "extension\0Description\0" - */ -static void build_extension_list() { - const char ** ext_list; - int ext_list_len; - int i; - - working_extension_list[0]='\0'; - working_extension_list[1]='\0'; - - ext_list = vgmstream_get_formats(); - ext_list_len = vgmstream_get_formats_length(); - - for (i=0; i < ext_list_len; i++) { - add_extension(EXTENSION_LIST_SIZE, working_extension_list, ext_list[i]); - } -} - -/** - * Adds ext to Winamp's extension list. - */ -static void add_extension(int length, char * dst, const char * ext) { - char buf[EXT_BUFFER_SIZE]; - char ext_upp[EXT_BUFFER_SIZE]; - int ext_len, written; - int i,j; - if (length <= 1) - return; - - ext_len = strlen(ext); - - /* find end of dst (double \0), saved in i */ - for (i=0; i length-2 || ext_len * 3 + 20+2 > EXT_BUFFER_SIZE) { - dst[i]='\0'; - dst[i+1]='\0'; - return; - } - - if (i > 0) - i++; - - /* uppercase ext */ - 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++) - dst[i] = buf[j]; - dst[i]='\0'; - dst[i+1]='\0'; -} diff --git a/winamp/out.h b/winamp/out.h index 5c853e6b..0adfab9a 100644 --- a/winamp/out.h +++ b/winamp/out.h @@ -1,52 +1,73 @@ +#ifndef NULLSOFT_OUTH +#define NULLSOFT_OUTH +#include +#include +// ids: +// waveout: 32 +// gapless: 64 +// xfade: 63 +// disk: 33 +// dsound: 38 +// NULL: 65 +// mm2: 69 + +#if (_MSC_VER <= 1200) +typedef int intptr_t; +#endif + #define OUT_VER 0x10 typedef struct { - int version; // module version (OUT_VER) - char *description; // description of module, with version string - int id; // module id. each input module gets its own. non-nullsoft modules should - // be >= 65536. + int version; // module version (OUT_VER) + char *description; // description of module, with version string + intptr_t id; // module id. each input module gets its own. non-nullsoft modules should + // be >= 65536. - HWND hMainWindow; // winamp's main window (filled in by winamp) - HINSTANCE hDllInstance; // DLL instance handle (filled in by winamp) + HWND hMainWindow; // winamp's main window (filled in by winamp) + HINSTANCE hDllInstance; // DLL instance handle (filled in by winamp) - void (*Config)(HWND hwndParent); // configuration dialog - void (*About)(HWND hwndParent); // about dialog + void (*Config)(HWND hwndParent); // configuration dialog + void (*About)(HWND hwndParent); // about dialog - void (*Init)(); // called when loaded - void (*Quit)(); // called when unloaded + void (*Init)(); // called when loaded + void (*Quit)(); // called when unloaded - int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms); - // returns >=0 on success, <0 on failure - // NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins. - // ... so don't expect the max latency returned to be what you asked for. - // returns max latency in ms (0 for diskwriters, etc) - // bufferlenms and prebufferms must be in ms. 0 to use defaults. - // prebufferms must be <= bufferlenms + int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms); + // returns >=0 on success, <0 on failure - void (*Close)(); // close the ol' output device. + // NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins. + // ... so don't expect the max latency returned to be what you asked for. + // returns max latency in ms (0 for diskwriters, etc) + // bufferlenms and prebufferms must be in ms. 0 to use defaults. + // prebufferms must be <= bufferlenms + // pass bufferlenms==-666 to tell the output plugin that it's clock is going to be used to sync video + // out_ds turns off silence-eating when -666 is passed - int (*Write)(char *buf, int len); - // 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data. - // 1 returns not able to write (yet). Non-blocking, always. + void (*Close)(); // close the ol' output device. - int (*CanWrite)(); // returns number of bytes possible to write at a given time. - // Never will decrease unless you call Write (or Close, heh) + int (*Write)(char *buf, int len); + // 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data. + // 1 returns not able to write (yet). Non-blocking, always. - int (*IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be - // written (i.e. closing while IsPlaying() returns 1 would truncate the song + int (*CanWrite)(); // returns number of bytes possible to write at a given time. + // Never will decrease unless you call Write (or Close, heh) - int (*Pause)(int pause); // returns previous pause state + int (*IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be + // written (i.e. closing while IsPlaying() returns 1 would truncate the song - void (*SetVolume)(int volume); // volume is 0-255 - void (*SetPan)(int pan); // pan is -128 to 128 + int (*Pause)(int pause); // returns previous pause state - void (*Flush)(int t); // flushes buffers and restarts output at time t (in ms) - // (used for seeking) + void (*SetVolume)(int volume); // volume is 0-255 + void (*SetPan)(int pan); // pan is -128 to 128 - int (*GetOutputTime)(); // returns played time in MS - int (*GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff) + void (*Flush)(int t); // flushes buffers and restarts output at time t (in ms) + // (used for seeking) + + int (*GetOutputTime)(); // returns played time in MS + int (*GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff) } Out_Module; +#endif diff --git a/winamp/wa_ipc.h b/winamp/wa_ipc.h index 0094b81c..bf434e00 100644 --- a/winamp/wa_ipc.h +++ b/winamp/wa_ipc.h @@ -1,5 +1,5 @@ /* -** Copyright (C) 2006 Nullsoft, Inc. +** Copyright (C) 1997-2008 Nullsoft, Inc. ** ** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held ** liable for any damages arising from the use of this software. @@ -30,22 +30,22 @@ typedef int intptr_t; ** */ -/* message used to sent many messages to winamp's main window. -** most all of the IPC_* messages involve sending the message in the form of: -** result = SendMessage(hwnd_winamp,WM_WA_IPC,(parameter),IPC_*); +/* Most of the IPC_* messages involve sending the message in the form of: +** result = SendMessage(hwnd_winamp,WM_WA_IPC,(parameter),IPC_*); +** Where different then this is specified (typically with WM_COPYDATA variants) ** ** When you use SendMessage(hwnd_winamp,WM_WA_IPC,(parameter),IPC_*) and specify a IPC_* ** which is not currently implemented/supported by the Winamp version being used then it ** will return 1 for 'result'. This is a good way of helping to check if an api being ** used which returns a function pointer, etc is even going to be valid. */ + #define WM_WA_IPC WM_USER -/* but some of them use WM_COPYDATA. be afraid. -*/ #define WINAMP_VERSION_MAJOR(winampVersion) ((winampVersion & 0x0000FF00) >> 12) #define WINAMP_VERSION_MINOR(winampVersion) (winampVersion & 0x000000FF) // returns, i.e. 0x12 for 5.12 and 0x10 for 5.1... + #define IPC_GETVERSION 0 /* int version = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION); ** @@ -61,9 +61,17 @@ typedef int intptr_t; ** Notes: For 5.02 this api will return the same value as for a 5.01 build. ** For 5.07 this api will return the same value as for a 5.06 build. */ + + #define IPC_GETVERSIONSTRING 1 + #define IPC_GETREGISTEREDVERSION 770 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETREGISTEREDVERSION); +** +** This will open the Winamp Preferences and show the Winamp Pro page. +*/ typedef struct { @@ -83,6 +91,7 @@ typedef struct { #define IPC_PLAYFILE 100 // dont be fooled, this is really the same as enqueufile #define IPC_ENQUEUEFILE 100 #define IPC_PLAYFILEW 1100 +#define IPC_ENQUEUEFILEW 1100 /* This is sent as a WM_COPYDATA with IPC_PLAYFILE as the dwData member and the string ** of the file / playlist to be enqueued into the playlist editor as the lpData member. ** This will just enqueue the file or files since you can use this to enqueue a playlist. @@ -125,6 +134,7 @@ typedef struct { ** since it won't be any fun. */ + #define IPC_CHDIR 103 /* This is sent as a WM_COPYDATA type message with IPC_CHDIR as the dwData value and the ** directory you want to change to as the lpData member. @@ -157,10 +167,12 @@ typedef struct { ** ** If mode = 1 then it will return the current track length (in seconds). ** Will return -1 if there are no tracks (or possibly if Winamp cannot get the length). +** +** If mode = 2 then it will return the current track length (in milliseconds). +** Will return -1 if there are no tracks (or possibly if Winamp cannot get the length). */ - #define IPC_JUMPTOTIME 106 /* (requires Winamp 1.60+) ** SendMessage(hwnd_winamp,WM_WA_IPC,ms,IPC_JUMPTOTIME); @@ -170,6 +182,7 @@ typedef struct { ** This returns -1 if Winamp is not playing, 1 on end of file, or 0 if it was successful. */ + #define IPC_GETMODULENAME 109 #define IPC_EX_ISRIGHTEXE 666 /* usually shouldnt bother using these, but here goes: @@ -179,6 +192,7 @@ typedef struct { ** matches. lame, I know. */ + #define IPC_WRITEPLAYLIST 120 /* (requires Winamp 1.666+) ** int cur = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_WRITEPLAYLIST); @@ -219,6 +233,13 @@ typedef struct { */ +#define IPC_GETVOLUME(hwnd_winamp) SendMessage(hwnd_winamp,WM_WA_IPC,-666,IPC_SETVOLUME) +/* (requires Winamp 2.0+) +** int curvol = IPC_GETVOLUME(hwnd_winamp); +** This will return the current volume of Winamp or +*/ + + #define IPC_SETPANNING 123 /* (requires Winamp 2.0+) ** SendMessage(hwnd_winamp,WM_WA_IPC,panning,IPC_SETPANNING); @@ -293,6 +314,7 @@ typedef struct { which band, and the bottom word specifies the value. */ + #define IPC_ADDBOOKMARK 129 #define IPC_ADDBOOKMARKW 131 /* (requires Winamp 2.4+) @@ -347,6 +369,8 @@ typedef struct { ** This is useful for when you're an output plugin and you want to see if the stop/close ** happening is a full stop or if you are just between tracks. This returns non zero if ** it is a full stop or zero if it is just a new track. +** benski> i think it's actually the other way around - +** !0 for EOF and 0 for user pressing stop */ @@ -374,8 +398,8 @@ typedef struct { ** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_REFRESHPLCACHE); ** IPC_REFRESHPLCACHE will flush the playlist cache buffer and you send this if you want ** Winamp to go refetch the titles for all of the entries in the current playlist. - -5.3+: pass a wchar_t * string in wParam, and it'll do a strnicmp() before clearing the cache +** +** 5.3+: pass a wchar_t * string in wParam, and it'll do a strnicmp() before clearing the cache */ @@ -435,8 +459,6 @@ typedef struct { #define IPC_ISWNDVISIBLE 261 // same param as IPC_GETWND - - /************************************************************************ ***************** in-process only (WE LOVE PLUGINS) ************************************************************************/ @@ -453,6 +475,7 @@ typedef struct { #define IPC_GETSKIN 201 +#define IPC_GETSKINW 1201 /* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) ** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)skinname_buffer,IPC_GETSKIN); ** IPC_GETSKIN puts the directory where skin bitmaps can be found @@ -503,6 +526,10 @@ typedef struct { */ +#define IPC_GETHTTPGETTERW 1240 +/* int (*httpRetrieveFileW)(HWND hwnd, char *url, wchar_t *file, wchar_t *dlgtitle); */ + + #define IPC_MBOPEN 241 /* (requires Winamp 2.05+) ** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_MBOPEN); @@ -511,15 +538,15 @@ typedef struct { */ - #define IPC_CHANGECURRENTFILE 245 /* (requires Winamp 2.05+) ** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_CHANGECURRENTFILE); ** IPC_CHANGECURRENTFILE will set the current playlist item. */ + #define IPC_CHANGECURRENTFILEW 1245 -/* (requires Winamp 2.05+) +/* (requires Winamp 5.3+) ** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_CHANGECURRENTFILEW); ** IPC_CHANGECURRENTFILEW will set the current playlist item. */ @@ -541,6 +568,7 @@ typedef struct { ** IPC_MBBLOCK will block the Minibrowser from updates if value is set to 1 */ + #define IPC_MBOPENREAL 249 /* (requires Winamp 2.4+) ** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPENREAL); @@ -549,6 +577,7 @@ typedef struct { ** IPC_MBBLOCK has been set to 1 */ + #define IPC_ADJUST_OPTIONSMENUPOS 280 /* (requires Winamp 2.9+) ** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_OPTIONSMENUPOS); @@ -556,6 +585,7 @@ typedef struct { ** menu item above the options/skins/vis menus. */ + #define IPC_GET_HMENU 281 /* (requires Winamp 2.9+) ** HMENU hMenu=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)0,IPC_GET_HMENU); @@ -568,6 +598,7 @@ typedef struct { ** other values will return NULL. */ + #define IPC_GET_EXTENDED_FILE_INFO 290 //pass a pointer to the following struct in wParam #define IPC_GET_EXTENDED_FILE_INFO_HOOKABLE 296 /* (requires Winamp 2.9+) @@ -581,7 +612,7 @@ typedef struct { const char *filename; const char *metadata; char *ret; - int retlen; + size_t retlen; } extendedFileInfoStruct; @@ -597,6 +628,7 @@ typedef struct { int titlelen; } basicFileInfoStruct; + #define IPC_GET_BASIC_FILE_INFOW 1291 //pass a pointer to the following struct in wParam typedef struct { const wchar_t *filename; @@ -613,18 +645,21 @@ typedef struct { #define IPC_GET_EXTLIST 292 //returns doublenull delimited. GlobalFree() it when done. if data is 0, returns raw extlist, if 1, returns something suitable for getopenfilename #define IPC_GET_EXTLISTW 1292 // wide char version of above + #define IPC_INFOBOX 293 typedef struct { HWND parent; char *filename; } infoBoxParam; + #define IPC_INFOBOXW 1293 typedef struct { HWND parent; const wchar_t *filename; } infoBoxParamW; + #define IPC_SET_EXTENDED_FILE_INFO 294 //pass a pointer to the a extendedFileInfoStruct in wParam /* (requires Winamp 2.9+) ** to use, create an extendedFileInfoStruct, point the values filename and metadata to the @@ -634,12 +669,14 @@ typedef struct { ** Call IPC_WRITE_EXTENDED_FILE_INFO once you're done setting all the metadata you want to update */ + #define IPC_WRITE_EXTENDED_FILE_INFO 295 /* (requires Winamp 2.9+) ** writes all the metadata set thru IPC_SET_EXTENDED_FILE_INFO to the file ** returns 1 if the file has been successfully updated, 0 if error */ + #define IPC_FORMAT_TITLE 297 typedef struct { @@ -653,11 +690,12 @@ typedef struct void (*TAGFREEFUNC)(char * tag,void * p); } waFormatTitle; + #define IPC_FORMAT_TITLE_EXTENDED 298 // similiar to IPC_FORMAT_TITLE, but falls back to Winamp's %tags% if your passed tag function doesn't handle it typedef struct { - const wchar_t *filename; - int useExtendedInfo; // set to 1 if you want the Title Formatter to query the input plugins for any tags that your tag function fails on + const wchar_t *filename; + int useExtendedInfo; // set to 1 if you want the Title Formatter to query the input plugins for any tags that your tag function fails on const wchar_t *spec; // NULL=default winamp spec void *p; @@ -668,12 +706,22 @@ typedef struct void (*TAGFREEFUNC)(wchar_t *tag, void *p); } waFormatTitleExtended; -#define IPC_GETUNCOMPRESSINTERFACE 331 -/* returns a function pointer to uncompress(). -** int (*uncompress)(unsigned char *dest, unsigned long *destLen, const unsigned char *source, unsigned long sourceLen); -** right out of zlib, useful for decompressing zlibbed data. -** if you pass the parm of 0x10100000, it will return a wa_inflate_struct * to an inflate API. -*/ + +#define IPC_COPY_EXTENDED_FILE_INFO 299 +typedef struct +{ + const char *source; + const char *dest; +} copyFileInfoStruct; + + +#define IPC_COPY_EXTENDED_FILE_INFOW 1299 +typedef struct +{ + const wchar_t *source; + const wchar_t *dest; +} copyFileInfoStructW; + typedef struct { int (*inflateReset)(void *strm); @@ -683,43 +731,205 @@ typedef struct { unsigned long (*crc32)(unsigned long crc, const unsigned char *buf, unsigned int len); } wa_inflate_struct; - -#define IPC_ADD_PREFS_DLG 332 -#define IPC_REMOVE_PREFS_DLG 333 -/* (requires Winamp 2.9+) -** to use, allocate a prefsDlgRec structure (either on the heap or some global -** data, but NOT on the stack), initialze the members: -** hInst to the DLL instance where the resource is located -** dlgID to the ID of the dialog, -** proc to the window procedure for the dialog -** name to the name of the prefs page in the prefs. -** where to 0 (eventually we may add more options) -** then, SendMessage(hwnd_winamp,WM_WA_IPC,&prefsRec,IPC_ADD_PREFS_DLG); -** -** you can also IPC_REMOVE_PREFS_DLG with the address of the same prefsRec, -** but you shouldn't really ever have to. -** +#define IPC_GETUNCOMPRESSINTERFACE 331 +/* returns a function pointer to uncompress(). +** int (*uncompress)(unsigned char *dest, unsigned long *destLen, const unsigned char *source, unsigned long sourceLen); +** right out of zlib, useful for decompressing zlibbed data. +** if you pass the parm of 0x10100000, it will return a wa_inflate_struct * to an inflate API. */ -#define IPC_OPENPREFSTOPAGE 380 // pass an id of a builtin page, or a &prefsDlgRec of prefs page to open + typedef struct _prefsDlgRec { - HINSTANCE hInst; - int dlgID; - void *proc; + HINSTANCE hInst; // dll instance containing the dialog resource + int dlgID; // resource identifier of the dialog + void *proc; // window proceedure for handling the dialog defined as + // LRESULT CALLBACK PrefsPage(HWND,UINT,WPARAM,LPARAM) - char *name; - intptr_t where; // 0 for options, 1 for plugins, 2 for skins, 3 for bookmarks, 4 for prefs + char *name; // name shown for the prefs page in the treelist + intptr_t where; // section in the treelist the prefs page is to be added to + // 0 for General Preferences + // 1 for Plugins + // 2 for Skins + // 3 for Bookmarks (no longer in the 5.0+ prefs) + // 4 for Prefs (the old 'Setup' section - no longer in 5.0+) intptr_t _id; - struct _prefsDlgRec *next; + struct _prefsDlgRec *next; // no longer implemented as a linked list, now used by Winamp for other means } prefsDlgRec; +typedef struct _prefsDlgRecW { + HINSTANCE hInst; // dll instance containing the dialog resource + int dlgID; // resource identifier of the dialog + void *proc; // window proceedure for handling the dialog defined as + // LRESULT CALLBACK PrefsPage(HWND,UINT,WPARAM,LPARAM) + + wchar_t *name; // name shown for the prefs page in the treelist + intptr_t where; // section in the treelist the prefs page is to be added to + // 0 for General Preferences + // 1 for Plugins + // 2 for Skins + // 3 for Bookmarks (no longer in the 5.0+ prefs) + // 4 for Prefs (the old 'Setup' section - no longer in 5.0+) + + intptr_t _id; + struct _prefsDlgRec *next; // no longer implemented as a linked list, now used by Winamp for other means +} prefsDlgRecW; + +#define IPC_ADD_PREFS_DLG 332 +#define IPC_ADD_PREFS_DLGW 1332 +#define IPC_REMOVE_PREFS_DLG 333 +/* (requires Winamp 2.9+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_ADD_PREFS_DLG); +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_REMOVE_PREFS_DLG); +** +** IPC_ADD_PREFS_DLG: +** To use this you need to allocate a prefsDlgRec structure (either on the heap or with +** some global data but NOT on the stack) and then initialise the members of the structure +** (see the definition of the prefsDlgRec structure above). +** +** hInst - dll instance of where the dialog resource is located. +** dlgID - id of the dialog resource. +** proc - dialog window procedure for the prefs dialog. +** name - name of the prefs page as shown in the preferences list. +** where - see above for the valid locations the page can be added. +** +** Then you do SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_ADD_PREFS_DLG); +** +** example: +** +** prefsDlgRec* prefsRec = 0; +** prefsRec = GlobalAlloc(GPTR,sizeof(prefsDlgRec)); +** prefsRec->hInst = hInst; +** prefsRec->dlgID = IDD_PREFDIALOG; +** prefsRec->name = "Pref Page"; +** prefsRec->where = 0; +** prefsRec->proc = PrefsPage; +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_ADD_PREFS_DLG); +** +** +** IPC_REMOVE_PREFS_DLG: +** To use you pass the address of the same prefsRec you used when adding the prefs page +** though you shouldn't really ever have to do this but it's good to clean up after you +** when you're plugin is being unloaded. +** +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_REMOVE_PREFS_DLG); +** +** IPC_ADD_PREFS_DLGW +** requires Winamp 5.53+ +*/ + + +#define IPC_OPENPREFSTOPAGE 380 +/* SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_OPENPREFSTOPAGE); +** +** There are two ways of opening a preferences page. +** +** The first is to pass an id of a builtin preferences page (see below for ids) or a +** &prefsDlgRec of the preferences page to open and this is normally done if you are +** opening a prefs page you added yourself. +** +** If the page id does not or the &prefsRec is not valid then the prefs dialog will be +** opened to the first page available (usually the Winamp Pro page). +** +** (requires Winamp 5.04+) +** Passing -1 for param will open the preferences dialog to the last page viewed. +** +** Note: v5.0 to 5.03 had a bug in this api +** +** On the first call then the correct prefs page would be opened to but on the next call +** the prefs dialog would be brought to the front but the page would not be changed to the +** specified. +** In 5.04+ it will change to the prefs page specified if the prefs dialog is already open. +*/ + +/* Builtin Preference page ids (valid for 5.0+) +** (stored in the lParam member of the TVITEM structure from the tree item) +** +** These can be useful if you want to detect a specific prefs page and add things to it +** yourself or something like that ;) +** +** Winamp Pro 20 +** General Preferences 0 +** File Types 1 +** Playlist 23 +** Titles 21 +** Playback 42 (added in 5.25) +** Station Info 41 (added in 5.11 & removed in 5.5) +** Video 24 +** Localization 25 (added in 5.5) +** Skins 40 +** Classic Skins 22 +** Plugins 30 +** Input 31 +** Output 32 +** Visualisation 33 +** DSP/Effect 34 +** General Purpose 35 +** +** Note: +** Custom page ids begin from 60 +** The value of the normal custom pages (Global Hotkeys, Jump To File, etc) is not +** guaranteed since it depends on the order in which the plugins are loaded which can +** change on different systems. +** +** Global Hotkeys, Jump To File, Media Library (under General Preferences and child pages), +** Media Library (under Plugins), Portables, CD Ripping and Modern Skins are custom pages +** created by the plugins shipped with Winamp. +*/ + + +#define IPC_GETINIFILE 334 +/* (requires Winamp 2.9+) +** char *ini=(char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIFILE); +** This returns a pointer to the full file path of winamp.ini. +** +** char ini_path[MAX_PATH] = {0}; +** +** void GetIniFilePath(HWND hwnd){ +** if(SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION) >= 0x2900){ +** // this gets the string of the full ini file path +** lstrcpyn(ini_path,(char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIFILE),sizeof(ini_path)); +** } +** else{ +** char* p = ini_path; +** p += GetModuleFileName(0,ini_path,sizeof(ini_path)) - 1; +** while(p && *p != '.'){p--;} +** lstrcpyn(p+1,"ini",sizeof(ini_path)); +** } +** } +*/ + + +#define IPC_GETINIDIRECTORY 335 +/* (requires Winamp 2.9+) +** char *dir=(char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIDIRECTORY); +** This returns a pointer to the directory where winamp.ini can be found and is +** useful if you want store config files but you don't want to use winamp.ini. +*/ + -#define IPC_GETINIFILE 334 // returns a pointer to winamp.ini -#define IPC_GETINIDIRECTORY 335 // returns a pointer to the directory to put config files in (if you dont want to use winamp.ini) #define IPC_GETPLUGINDIRECTORY 336 -#define IPC_GETM3UDIRECTORY 337 // returns a char pointer to the directory where winamp.m3u is stored in. -#define IPC_GETM3UDIRECTORYW 338 // returns a wchar_t pointer to the directory where winamp.m3u is stored in. +/* (requires Winamp 5.11+) +** char *plugdir=(char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETPLUGINDIRECTORY); +** This returns a pointer to the directory where Winamp has its plugins stored and is +** useful if you want store config files in plugins.ini in the plugins folder or for +** accessing any local files in the plugins folder. +*/ + + +#define IPC_GETM3UDIRECTORY 337 +/* (requires Winamp 5.11+) +** char *m3udir=(char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETM3UDIRECTORY); +** This returns a pointer to the directory where winamp.m3u (and winamp.m3u8 if supported) is stored in. +*/ + + +#define IPC_GETM3UDIRECTORYW 338 +/* (requires Winamp 5.3+) +** wchar_t *m3udirW=(wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETM3UDIRECTORYW); +** This returns a pointer to the directory where winamp.m3u (and winamp.m3u8 if supported) is stored in. +*/ + #define IPC_SPAWNBUTTONPOPUP 361 // param = // 0 = eject @@ -729,15 +939,49 @@ typedef struct _prefsDlgRec { // 4 = play // 5 = stop -#define IPC_OPENURLBOX 360 // pass a HWND to a parent, returns a HGLOBAL that needs to be freed with GlobalFree(), if successful -#define IPC_OPENFILEBOX 362 // pass a HWND to a parent -#define IPC_OPENDIRBOX 363 // pass a HWND to a parent -// pass an HWND to a parent. call this if you take over the whole UI so that the dialogs are not appearing on the -// bottom right of the screen since the main winamp window is at 3000x3000, call again with NULL to reset +#define IPC_OPENURLBOX 360 +/* (requires Winamp 5.0+) +** HGLOBAL hglobal = (HGLOBAL)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_OPENURLBOX); +** You pass a hwnd for the dialog to be parented to (which modern skin support uses). +** This will return a HGLOBAL that needs to be freed with GlobalFree() if this worked. +*/ + + +#define IPC_OPENFILEBOX 362 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_OPENFILEBOX); +** You pass a hwnd for the dialog to be parented to (which modern skin support uses). +*/ + + +#define IPC_OPENDIRBOX 363 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_OPENDIRBOX); +** You pass a hwnd for the dialog to be parented to (which modern skin support uses). +*/ + + #define IPC_SETDIALOGBOXPARENT 364 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_SETDIALOGBOXPARENT); +** Pass 'parent' as the window which will be used as the parent for a number of the built +** in Winamp dialogs and is useful when you are taking over the whole of the UI so that +** the dialogs will not appear at the bottom right of the screen since the main winamp +** window is located at 3000x3000 by gen_ff when this is used. Call this again with +** parent = null to reset the parent back to the orginal Winamp window. +*/ +#define IPC_GETDIALOGBOXPARENT 365 +/* (requires Winamp 5.51+) +** HWND hwndParent = SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)0, IPC_GETDIALOGBOXPARENT); +** hwndParent can/must be passed to all modal dialogs (including MessageBox) thats uses winamp as a parent +*/ +#define IPC_UPDATEDIALOGBOXPARENT 366 +/* (requires Winamp 5.53+) +** if you previous called IPC_SETDIALOGBOXPARENT, call this every time your window resizes +*/ #define IPC_DRO_MIN 401 // reserved for DrO #define IPC_SET_JTF_COMPARATOR 409 @@ -756,28 +1000,56 @@ typedef struct _prefsDlgRec { #define IPC_GET_GENSKINBITMAP 503 -#define IPC_GET_EMBEDIF 505 // pass an embedWindowState -// returns an HWND embedWindow(embedWindowState *); if the data is NULL, otherwise returns the HWND directly typedef struct { HWND me; //hwnd of the window - int flags; + #define EMBED_FLAGS_NORESIZE 0x1 + // set this bit to keep window from being resizable + + #define EMBED_FLAGS_NOTRANSPARENCY 0x2 + // set this bit to make gen_ff turn transparency off for this window + + #define EMBED_FLAGS_NOWINDOWMENU 0x4 + // set this bit to prevent gen_ff from automatically adding your window to the right-click menu + + #define EMBED_FLAGS_GUID 0x8 + // (5.31+) call SET_EMBED_GUID(yourEmbedWindowStateStruct, GUID) to define a GUID for this window + + #define SET_EMBED_GUID(windowState, windowGUID) { windowState->flags |= EMBED_FLAGS_GUID; *((GUID *)&windowState->extra_data[4])=windowGUID; } + #define GET_EMBED_GUID(windowState) (*((GUID *)&windowState->extra_data[4])) + + int flags; // see above RECT r; - - void *user_ptr; // for application use - - intptr_t extra_data[64]; // for internal winamp use + void *user_ptr; // for application use + int extra_data[64]; // for internal winamp use } embedWindowState; -#define EMBED_FLAGS_NORESIZE 0x1 // set this bit in embedWindowState.flags to keep window from being resizable -#define EMBED_FLAGS_NOTRANSPARENCY 0x2 // set this bit in embedWindowState.flags to make gen_ff turn transparency off for this wnd -#define EMBED_FLAGS_NOWINDOWMENU 0x4 // set this bit to prevent gen_ff from automatically adding your window to the right-click menu -#define EMBED_FLAGS_GUID 0x8 // call SET_EMBED_GUID(yourEmbedWindowStateStruct, GUID) to define a GUID for this window +#define IPC_GET_EMBEDIF 505 +/* (requires Winamp 2.9+) +** HWND myframe = (HWND)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&wa_wnd,IPC_GET_EMBEDIF); +** +** or +** +** HWND myframe = 0; +** HWND (*embed)(embedWindowState *params)=0; +** *(void**)&embed = (void*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_EMBEDIF); +** myframe = embed(&wa_wnd); +** +** You pass an embedWindowState* and it will return a hwnd for the frame window or if you +** pass wParam as null then it will return a HWND embedWindow(embedWindowState *); +*/ + +#define IPC_SKINWINDOW 534 + +typedef struct __SKINWINDOWPARAM +{ + HWND hwndToSkin; + GUID windowGuid; +} SKINWINDOWPARAM; + -#define SET_EMBED_GUID(windowState, windowGUID) { windowState->flags |= EMBED_FLAGS_GUID; *((GUID *)&windowState->extra_data[4])=windowGUID; } -#define GET_EMBED_GUID(windowState) (*((GUID *)&windowState->extra_data[4])) #define IPC_EMBED_ENUM 532 typedef struct embedEnumStruct @@ -787,7 +1059,13 @@ typedef struct embedEnumStruct } embedEnumStruct; // pass + #define IPC_EMBED_ISVALID 533 +/* (requires Winamp 2.9+) +** int valid = SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)embedhwnd,IPC_EMBED_ISVALID); +** Pass a hwnd in the wParam to this to check if the hwnd is a valid embed window or not. +*/ + #define IPC_CONVERTFILE 506 /* (requires Winamp 2.92+) @@ -808,7 +1086,7 @@ typedef struct { char *sourcefile; // "c:\\source.mp3" char *destfile; // "c:\\dest.pcm" - int destformat[8]; // like 'PCM ',srate,nch,bps. + intptr_t destformat[8]; // like 'PCM ',srate,nch,bps. //hack alert! you can set destformat[6]=mmioFOURCC('I','N','I',' '); and destformat[7]=(int)my_ini_file; (where my_ini_file is a char*) HWND callbackhwnd; // window that will receive the IPC_CB_CONVERT notification messages @@ -823,6 +1101,29 @@ typedef struct intptr_t extra_data[64]; // for internal winamp use } convertFileStruct; + +#define IPC_CONVERTFILEW 515 +// (requires Winamp 5.36+) +typedef struct +{ + wchar_t *sourcefile; // "c:\\source.mp3" + wchar_t *destfile; // "c:\\dest.pcm" + intptr_t destformat[8]; // like 'PCM ',srate,nch,bps. + //hack alert! you can set destformat[6]=mmioFOURCC('I','N','I',' '); and destformat[7]=(int)my_ini_file; (where my_ini_file is a char*) + HWND callbackhwnd; // window that will receive the IPC_CB_CONVERT notification messages + + //filled in by winamp.exe + wchar_t *error; //if IPC_CONVERTFILE returns 0, the reason will be here + + int bytes_done; //you can look at both of these values for speed statistics + int bytes_total; + int bytes_out; + + int killswitch; // don't set it manually, use IPC_CONVERTFILE_END + intptr_t extra_data[64]; // for internal winamp use +} convertFileStructW; + + #define IPC_CONVERTFILE_END 507 /* (requires Winamp 2.92+) ** Stop/ends a convert process started from IPC_CONVERTFILE @@ -834,6 +1135,10 @@ typedef struct ** No return value */ + +#define IPC_CONVERTFILEW_END 516 +// (requires Winamp 5.36+) + typedef struct { HWND hwndParent; int format; @@ -843,6 +1148,8 @@ typedef struct { int extra_data[8]; //hack alert! you can set extra_data[6]=mmioFOURCC('I','N','I',' '); and extra_data[7]=(int)my_ini_file; (where my_ini_file is a char*) } convertConfigStruct; + + #define IPC_CONVERT_CONFIG 508 #define IPC_CONVERT_CONFIG_END 509 @@ -873,8 +1180,20 @@ typedef struct convertFileStruct *cfs; int priority; } convertSetPriority; + + #define IPC_CONVERT_SET_PRIORITY 512 +typedef struct +{ + convertFileStructW *cfs; + int priority; +} convertSetPriorityW; + + +#define IPC_CONVERT_SET_PRIORITYW 517 +// (requires Winamp 5.36+) + typedef struct { unsigned int format; //fourcc value @@ -884,9 +1203,11 @@ typedef struct char *configfile; // config file to read from } convertConfigItem; + #define IPC_CONVERT_CONFIG_SET_ITEM 513 // returns TRUE if successful #define IPC_CONVERT_CONFIG_GET_ITEM 514 // returns TRUE if successful + typedef struct { const char *filename; @@ -894,30 +1215,57 @@ typedef struct int length; int force_useformatting; // can set this to 1 if you want to force a url to use title formatting shit } waHookTitleStruct; -// return TRUE if you hook this + #define IPC_HOOK_TITLES 850 +/* (requires Winamp 5.0+) +** If you hook this message and modify the information then make sure to return TRUE. +** If you don't hook the message then make sure you pass it on through the subclass chain. +** +** LRESULT CALLBACK WinampWndProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) +** { +** LRESULT ret = CallWindowProc((WNDPROC)WinampProc,hwnd,umsg,wParam,lParam); +** +** if(message==WM_WA_IPC && lParam==IPC_HOOK_TITLES) +** { +** waHookTitleStruct *ht = (waHookTitleStruct *) wParam; +** // Doing ATF stuff with ht->title, whatever... +** return TRUE; +** } +** return ret; +** } +*/ typedef struct { const wchar_t *filename; - wchar_t *title; // 2048 bytes + wchar_t *title; // 2048 characters int length; int force_useformatting; // can set this to 1 if you want to force a url to use title formatting shit } waHookTitleStructW; -// return TRUE if you hook this #define IPC_HOOK_TITLESW 851 +/* (requires Winamp 5.3+) +** See information on IPC_HOOK_TITLES for how to process this. +*/ + #define IPC_GETSADATAFUNC 800 // 0: returns a char *export_sa_get() that returns 150 bytes of data // 1: returns a export_sa_setreq(int want); + #define IPC_GETVUDATAFUNC 801 // 0: returns a int export_vu_get(int channel) that returns 0-255 (or -1 for bad channel) + #define IPC_ISMAINWNDVISIBLE 900 +/* (requires Winamp 5.0+) +** int visible=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISMAINWNDVISIBLE); +** You send this to Winamp to query if the main window is visible or not such as by +** unchecking the option in the main right-click menu. If the main window is visible then +** this will return 1 otherwise it returns 0. +*/ -#define IPC_SETPLEDITCOLORS 920 typedef struct { int numElems; @@ -925,22 +1273,30 @@ typedef struct HBITMAP bm; // set if you want to override } waSetPlColorsStruct; +#define IPC_SETPLEDITCOLORS 920 +/* (requires Winamp 5.0+) +** This is sent by gen_ff when a modern skin is being loaded to set the colour scheme for +** the playlist editor. When sent numElems is usually 6 and matches with the 6 possible +** colours which are provided be pledit.txt from the classic skins. The elems array is +** defined as follows: +** +** elems = 0 => normal text +** elems = 1 => current text +** elems = 2 => normal background +** elems = 3 => selected background +** elems = 4 => minibroswer foreground +** elems = 5 => minibroswer background +** +** if(uMsg == WM_WA_IPC && lParam == IPC_SETPLEDITCOLORS) +** { +** waSetPlColorsStruct* colStr = (waSetPlColorsStruct*)wp; +** if(colStr) +** { +** // set or inspect the colours being used (basically for gen_ff's benefit) +** } +** } +*/ -// the following IPC use waSpawnMenuParms as parameter -#define IPC_SPAWNEQPRESETMENU 933 -#define IPC_SPAWNFILEMENU 934 //menubar -#define IPC_SPAWNOPTIONSMENU 935 //menubar -#define IPC_SPAWNWINDOWSMENU 936 //menubar -#define IPC_SPAWNHELPMENU 937 //menubar -#define IPC_SPAWNPLAYMENU 938 //menubar -#define IPC_SPAWNPEFILEMENU 939 //menubar -#define IPC_SPAWNPEPLAYLISTMENU 940 //menubar -#define IPC_SPAWNPESORTMENU 941 //menubar -#define IPC_SPAWNPEHELPMENU 942 //menubar -#define IPC_SPAWNMLFILEMENU 943 //menubar -#define IPC_SPAWNMLVIEWMENU 944 //menubar -#define IPC_SPAWNMLHELPMENU 945 //menubar -#define IPC_SPAWNPELISTOFPLAYLISTS 946 typedef struct { @@ -959,13 +1315,45 @@ typedef struct int height; } waSpawnMenuParms2; +// the following IPC use waSpawnMenuParms as parameter +#define IPC_SPAWNEQPRESETMENU 933 +#define IPC_SPAWNFILEMENU 934 //menubar +#define IPC_SPAWNOPTIONSMENU 935 //menubar +#define IPC_SPAWNWINDOWSMENU 936 //menubar +#define IPC_SPAWNHELPMENU 937 //menubar +#define IPC_SPAWNPLAYMENU 938 //menubar +#define IPC_SPAWNPEFILEMENU 939 //menubar +#define IPC_SPAWNPEPLAYLISTMENU 940 //menubar +#define IPC_SPAWNPESORTMENU 941 //menubar +#define IPC_SPAWNPEHELPMENU 942 //menubar +#define IPC_SPAWNMLFILEMENU 943 //menubar +#define IPC_SPAWNMLVIEWMENU 944 //menubar +#define IPC_SPAWNMLHELPMENU 945 //menubar +#define IPC_SPAWNPELISTOFPLAYLISTS 946 + -// system tray sends this (you might want to simulate it) #define WM_WA_SYSTRAY WM_USER+1 +/* This is sent by the system tray when an event happens (you might want to simulate it). +** +** if(uMsg == WM_WA_SYSTRAY) +** { +** switch(lParam) +** { +** // process the messages sent from the tray +** } +** } +*/ + -// input plugins send this when they are done playing back #define WM_WA_MPEG_EOF WM_USER+2 - +/* Input plugins send this when they are done playing back the current file to inform +** Winamp or anyother installed plugins that the current +** +** if(uMsg == WM_WA_MPEG_EOF) +** { +** // do what is needed here +** } +*/ //// video stuff @@ -980,14 +1368,15 @@ typedef struct #define VIDUSER_OPENVIDEORENDERER 0x1004 #define VIDUSER_CLOSEVIDEORENDERER 0x1005 #define VIDUSER_GETPOPUPMENU 0x1006 +#define VIDUSER_SET_INFOSTRINGW 0x1007 typedef struct { - int w; - int h; - int vflip; - double aspectratio; - unsigned int fmt; + int w; + int h; + int vflip; + double aspectratio; + unsigned int fmt; } VideoOpenStruct; #ifndef NO_IVIDEO_DECLARE @@ -996,31 +1385,32 @@ typedef struct class VideoOutput; class SubsItem; -typedef struct { - unsigned char* baseAddr; - long rowBytes; -} YV12_PLANE; +#ifndef _NSV_DEC_IF_H_ +struct YV12_PLANE { + unsigned char* baseAddr; + long rowBytes; +} ; -typedef struct { - YV12_PLANE y; - YV12_PLANE u; - YV12_PLANE v; -} YV12_PLANES; +struct YV12_PLANES { + YV12_PLANE y; + YV12_PLANE u; + YV12_PLANE v; +}; +#endif class IVideoOutput { public: virtual ~IVideoOutput() { } virtual int open(int w, int h, int vflip, double aspectratio, unsigned int fmt)=0; - virtual void setcallback(LRESULT (*msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam), void *token) { (void)token; (void)msgcallback; /* to eliminate warning C4100 */ } + virtual void setcallback(LRESULT (*msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam), void *token) { (void)token; (void)msgcallback; /* to eliminate warning C4100 */ } virtual void close()=0; virtual void draw(void *frame)=0; - virtual void drawSubtitle(SubsItem *item) { } - virtual void showStatusMsg(const char *text) { } + virtual void drawSubtitle(SubsItem *item) {UNREFERENCED_PARAMETER(item); } + virtual void showStatusMsg(const char *text) {UNREFERENCED_PARAMETER(text); } virtual int get_latency() { return 0; } - virtual void notifyBufferState(int bufferstate) { } /* 0-255*/ - - virtual INT_PTR extended(INT_PTR param1, INT_PTR param2, INT_PTR param3) { return 0; } // Dispatchable, eat this! + virtual void notifyBufferState(int bufferstate) { UNREFERENCED_PARAMETER(bufferstate); } /* 0-255*/ + virtual INT_PTR extended(INT_PTR param1, INT_PTR param2, INT_PTR param3) { UNREFERENCED_PARAMETER(param1); UNREFERENCED_PARAMETER(param2); UNREFERENCED_PARAMETER(param3); return 0; } // Dispatchable, eat this! }; class ITrackSelector @@ -1055,35 +1445,88 @@ class ITrackSelector #define IPC_CB_GETTOOLTIP 602 #define IPC_CB_MISC 603 - #define IPC_CB_MISC_TITLE 0 + #define IPC_CB_MISC_TITLE 0 // start of playing/stop/pause #define IPC_CB_MISC_VOLUME 1 // volume/pan - #define IPC_CB_MISC_STATUS 2 + #define IPC_CB_MISC_STATUS 2 // start playing/stop/pause/ffwd/rwd #define IPC_CB_MISC_EQ 3 #define IPC_CB_MISC_INFO 4 #define IPC_CB_MISC_VIDEOINFO 5 + #define IPC_CB_MISC_TITLE_RATING 6 // (5.5+ for when the rating is changed via the songticker menu on current file) + +/* Example of using IPC_CB_MISC_STATUS to detect the start of track playback with 5.x +** +** if(lParam == IPC_CB_MISC && wParam == IPC_CB_MISC_STATUS) +** { +** if(SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISPLAYING) == 1 && +** !SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETOUTPUTTIME)) +** { +** char* file = (char*)SendMessage(hwnd_winamp,WM_WA_IPC, +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS),IPC_GETPLAYLISTFILE); +** // only output if a valid file was found +** if(file) +** { +** MessageBox(hwnd_winamp,file,"starting",0); +** // or do something else that you need to do +** } +** } +** } +*/ + #define IPC_CB_CONVERT_STATUS 604 // param value goes from 0 to 100 (percent) #define IPC_CB_CONVERT_DONE 605 + #define IPC_ADJUST_FFWINDOWSMENUPOS 606 /* (requires Winamp 2.9+) ** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFWINDOWSMENUPOS); -** moves where winamp expects the freeform windows in the menubar windows main menu. Useful if you wish to insert a -** menu item above extra freeform windows. +** This will move where Winamp expects the freeform windows in the menubar windows main +** menu. This is useful if you wish to insert a menu item above extra freeform windows. */ + #define IPC_ISDOUBLESIZE 608 +/* (requires Winamp 5.0+) +** int dsize=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISDOUBLESIZE); +** You send this to Winamp to query if the double size mode is enabled or not. +** If it is on then this will return 1 otherwise it will return 0. +*/ + #define IPC_ADJUST_FFOPTIONSMENUPOS 609 /* (requires Winamp 2.9+) ** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFOPTIONSMENUPOS); -** moves where winamp expects the freeform preferences item in the menubar windows main menu. Useful if you wish to insert a -** menu item above preferences item. +** moves where winamp expects the freeform preferences item in the menubar windows main +** menu. This is useful if you wish to insert a menu item above the preferences item. +** +** Note: This setting was ignored by gen_ff until it was fixed in 5.1 +** gen_ff would assume thatthe menu position was 11 in all cases and so when you +** had two plugins attempting to add entries into the main right click menu it +** would cause the 'colour themes' submenu to either be incorrectly duplicated or +** to just disappear.instead. */ -#define IPC_GETTIMEDISPLAYMODE 610 // returns 0 if displaying elapsed time or 1 if displaying remaining time -#define IPC_SETVISWND 611 // param is hwnd, setting this allows you to receive ID_VIS_NEXT/PREVOUS/RANDOM/FS wm_commands +#define IPC_GETTIMEDISPLAYMODE 610 +/* (requires Winamp 5.0+) +** int mode=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETTIMEDISPLAYMODE); +** This will return the status of the time display i.e. shows time elapsed or remaining. +** This returns 0 if Winamp is displaying time elapsed or 1 for the time remaining. +*/ + + +#define IPC_SETVISWND 611 +/* (requires Winamp 5.0+) +** int viswnd=(HWND)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)viswnd,IPC_SETVISWND); +** This allows you to set a window to receive the following message commands (which are +** used as part of the modern skin integration). +** When you have finished or your visualisation is closed then send wParam as zero to +** ensure that things are correctly tidied up. +*/ + +/* The following messages are received as the LOWORD(wParam) of the WM_COMMAND message. +** See %SDK%\winamp\wa5vis.txt for more info about visualisation integration in Winamp. +*/ #define ID_VIS_NEXT 40382 #define ID_VIS_PREV 40383 #define ID_VIS_RANDOM 40384 @@ -1091,14 +1534,50 @@ class ITrackSelector #define ID_VIS_CFG 40390 #define ID_VIS_MENU 40391 -#define IPC_GETVISWND 612 // returns the vis cmd handler hwnd + +#define IPC_GETVISWND 612 +/* (requires Winamp 5.0+) +** int viswnd=(HWND)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVISWND); +** This returns a HWND to the visualisation command handler window if set by IPC_SETVISWND. +*/ + + #define IPC_ISVISRUNNING 613 +/* (requires Winamp 5.0+) +** int visrunning=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISVISRUNNING); +** This will return 1 if a visualisation is currently running and 0 if one is not running. +*/ + + #define IPC_CB_VISRANDOM 628 // param is status of random -#define IPC_SETIDEALVIDEOSIZE 614 // sent by winamp to winamp, trap it if you need it. width=HIWORD(param), height=LOWORD(param) + +#define IPC_SETIDEALVIDEOSIZE 614 +/* (requires Winamp 5.0+) +** This is sent by Winamp back to itself so it can be trapped and adjusted as needed with +** the desired width in HIWORD(wParam) and the desired height in LOWORD(wParam). +** +** if(uMsg == WM_WA_IPC){ +** if(lParam == IPC_SETIDEALVIDEOSIZE){ +** wParam = MAKEWPARAM(height,width); +** } +** } +*/ + #define IPC_GETSTOPONVIDEOCLOSE 615 +/* (requires Winamp 5.0+) +** int sovc=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETSTOPONVIDEOCLOSE); +** This will return 1 if 'stop on video close' is enabled and 0 if it is disabled. +*/ + + #define IPC_SETSTOPONVIDEOCLOSE 616 +/* (requires Winamp 5.0+) +** int sovc=SendMessage(hwnd_winamp,WM_WA_IPC,enabled,IPC_SETSTOPONVIDEOCLOSE); +** Set enabled to 1 to enable and 0 to disable the 'stop on video close' option. +*/ + typedef struct { HWND hwnd; @@ -1108,6 +1587,9 @@ typedef struct { } transAccelStruct; #define IPC_TRANSLATEACCELERATOR 617 +/* (requires Winamp 5.0+) +** (deprecated as of 5.53x+) +*/ typedef struct { int cmd; @@ -1116,163 +1598,361 @@ typedef struct { int align; } windowCommand; // send this as param to an IPC_PLCMD, IPC_MBCMD, IPC_VIDCMD + #define IPC_CB_ONTOGGLEAOT 618 -#define IPC_GETPREFSWND 619 -#define IPC_SET_PE_WIDTHHEIGHT 620 // data is a pointer to a POINT structure that holds width & height +#define IPC_GETPREFSWND 619 +/* (requires Winamp 5.0+) +** HWND prefs = (HWND)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETPREFSWND); +** This will return a handle to the preferences dialog if it is open otherwise it will +** return zero. A simple check with the OS api IsWindow(..) is a good test if it's valid. +** +** e.g. this will open (or close if already open) the preferences dialog and show if we +** managed to get a valid +** SendMessage(hwnd_winamp,WM_COMMAND,MAKEWPARAM(WINAMP_OPTIONS_PREFS,0),0); +** MessageBox(hwnd_winamp,(IsWindow((HWND)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETPREFSWND))?"Valid":"Not Open"),0,MB_OK); +*/ + + +#define IPC_SET_PE_WIDTHHEIGHT 620 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&point,IPC_SET_PE_WIDTHHEIGHT); +** You pass a pointer to a POINT structure which holds the width and height and Winamp +** will set the playlist editor to that size (this is used by gen_ff on skin changes). +** There does not appear to be any bounds limiting with this so it is possible to create +** a zero size playlist editor window (which is a pretty silly thing to do). +*/ + #define IPC_GETLANGUAGEPACKINSTANCE 621 +/* (requires Winamp 5.0+) +** HINSTANCE hInst = (HINSTANCE)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLANGUAGEPACKINSTANCE); +** This will return the HINSTANCE to the currently used language pack file for winamp.exe +** +** (5.5+) +** If you pass 1 in wParam then you will have zero returned if a language pack is in use. +** if(!SendMessage(hwnd_winamp,WM_WA_IPC,1,IPC_GETLANGUAGEPACKINSTANCE)){ +** // winamp is currently using a language pack +** } +** +** If you pass 2 in wParam then you will get the path to the language pack folder. +** wchar_t* lngpackfolder = (wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,2,IPC_GETLANGUAGEPACKINSTANCE); +** +** If you pass 3 in wParam then you will get the path to the currently extracted language pack. +** wchar_t* lngpack = (wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,3,IPC_GETLANGUAGEPACKINSTANCE); +** +** If you pass 4 in wParam then you will get the name of the currently used language pack. +** wchar_t* lngname = (char*)SendMessage(hwnd_winamp,WM_WA_IPC,4,IPC_GETLANGUAGEPACKINSTANCE); +*/ +#define LANG_IDENT_STR 0 +#define LANG_LANG_CODE 1 +#define LANG_COUNTRY_CODE 2 +/* +** (5.51+) +** If you pass 5 in LOWORD(wParam) then you will get the ident string/code string +** (based on the param passed in the HIWORD(wParam) of the currently used language pack. +** The string returned with LANG_IDENT_STR is used to represent the language that the +** language pack is intended for following ISO naming conventions for consistancy. +** +** wchar_t* ident_str = (wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,MAKEWPARAM(5,LANG_XXX),IPC_GETLANGUAGEPACKINSTANCE); +** +** e.g. +** For the default language it will return the following for the different LANG_XXX codes +** LANG_IDENT_STR -> "en-US" (max buffer size of this is 9 wchar_t) +** LANG_LANG_CODE -> "en" (language code) +** LANG_COUNTRY_CODE -> "US" (country code) +** +** On pre 5.51 installs you can get LANG_IDENT_STR using the following method +** (you'll have to custom process the string returned if you want the langugage or country but that's easy ;) ) +** +** #define LANG_PACK_LANG_ID 65534 (if you don't have lang.h) +** HINSTANCE hInst = (HINSTANCE)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLANGUAGEPACKINSTANCE); +** TCHAR buffer[9] = {0}; +** LoadString(hInst,LANG_PACK_LANG_ID,buffer,sizeof(buffer)); +** +** +** +** The following example shows how using the basic api will allow you to load the playlist +** context menu resource from the currently loaded language pack or it will fallback to +** the default winamp.exe instance. +** +** HINSTANCE lang = (HINSTANCE)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLANGUAGEPACKINSTANCE); +** HMENU popup = GetSubMenu(GetSubMenu((LoadMenu(lang?lang:GetModuleHandle(0),MAKEINTRESOURCE(101))),2),5); +** // do processing as needed on the menu before displaying it +** TrackPopupMenuEx(orig,TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,rc.left,rc.bottom,hwnd_owner,0); +** DestroyMenu(popup); +** +** If you need a specific menu handle then look at IPC_GET_HMENU for more information. +*/ + #define IPC_CB_PEINFOTEXT 622 // data is a string, ie: "04:21/45:02" + #define IPC_CB_OUTPUTCHANGED 623 // output plugin was changed in config + #define IPC_GETOUTPUTPLUGIN 625 +/* (requires Winamp 5.0+) +** char* outdll = (char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETOUTPUTPLUGIN); +** This returns a string of the current output plugin's dll name. +** e.g. if the directsound plugin was selected then this would return 'out_ds.dll'. +*/ + #define IPC_SETDRAWBORDERS 626 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,enabled,IPC_SETDRAWBORDERS); +** Set enabled to 1 to enable and 0 to disable drawing of the playlist editor and winamp +** gen class windows (used by gen_ff to allow it to draw its own window borders). +*/ + + #define IPC_DISABLESKINCURSORS 627 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,enabled,IPC_DISABLESKINCURSORS); +** Set enabled to 1 to enable and 0 to disable the use of skinned cursors. +*/ + + +#define IPC_GETSKINCURSORS 628 +/* (requires Winamp 5.36+) +** data = (WACURSOR)cursorId. (check wa_dlg.h for values) +*/ + + #define IPC_CB_RESETFONT 629 -#define IPC_IS_FULLSCREEN 630 // returns 1 if video or vis is in fullscreen mode -#define IPC_SET_VIS_FS_FLAG 631 // a vis should send this message with 1/as param to notify winamp that it has gone to or has come back from fullscreen mode + +#define IPC_IS_FULLSCREEN 630 +/* (requires Winamp 5.0+) +** int val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_IS_FULLSCREEN); +** This will return 1 if the video or visualisation is in fullscreen mode or 0 otherwise. +*/ + + +#define IPC_SET_VIS_FS_FLAG 631 +/* (requires Winamp 5.0+) +** A vis should send this message with 1/as param to notify winamp that it has gone to or has come back from fullscreen mode +*/ + #define IPC_SHOW_NOTIFICATION 632 + #define IPC_GETSKININFO 633 +#define IPC_GETSKININFOW 1633 +/* (requires Winamp 5.0+) +** This is a notification message sent to the main Winamp window by itself whenever it +** needs to get information to be shown about the current skin in the 'Current skin +** information' box on the main Skins page in the Winamp preferences. +** +** When this notification is received and the current skin is one you are providing the +** support for then you return a valid buffer for Winamp to be able to read from with +** information about it such as the name of the skin file. +** +** if(uMsg == WM_WA_IPC && lParam == IPC_GETSKININFO){ +** if(is_our_skin()){ +** return is_our_skin_name(); +** } +** } +*/ + #define IPC_GET_MANUALPLADVANCE 634 /* (requires Winamp 5.03+) -** val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_MANUALPLADVANCE); -** -** IPC_GET_MANUALPLADVANCE returns the status of the Manual Playlist Advance (1 if set) +** int val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_MANUALPLADVANCE); +** IPC_GET_MANUALPLADVANCE returns the status of the Manual Playlist Advance. +** If enabled this will return 1 otherwise it will return 0. */ + #define IPC_SET_MANUALPLADVANCE 635 /* (requires Winamp 5.03+) ** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_MANUALPLADVANCE); -** -** IPC_SET_MANUALPLADVANCE sets the status of the Manual Playlist Advance option (1 to turn it on) +** IPC_SET_MANUALPLADVANCE sets the status of the Manual Playlist Advance option. +** Set value = 1 to turn it on and value = 0 to turn it off. */ + #define IPC_GET_NEXT_PLITEM 636 /* (requires Winamp 5.04+) ** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_EOF_GET_NEXT_PLITEM); ** -** Sent to Winamp's main window when an item has just finished playback or the next button has been pressed and -** requesting the new playlist item number to go to. -** Mainly used by gen_jumpex. Subclass this message in your application to return the new item number. -** -1 for normal winamp operation (default) or the new item number in the playlist to play. +** Sent to Winamp's main window when an item has just finished playback or the next +** button has been pressed and requesting the new playlist item number to go to. +** +** Subclass this message in your application to return the new item number. +** Return -1 for normal Winamp operation (default) or the new item number in +** the playlist to be played instead of the originally selected next track. +** +** This is primarily provided for the JTFE plugin (gen_jumpex.dll). */ + #define IPC_GET_PREVIOUS_PLITEM 637 /* (requires Winamp 5.04+) ** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_EOF_GET_PREVIOUS_PLITEM); ** -** Sent to Winamp's main window when the previous button has been pressed and Winamp is requesting the new playlist item number to go to. -** Mainly used by gen_jumpex. Subclass this message in your application to return the new item number. -** -1 for normal winamp operation (default) or the new item number in the playlist to play. +** Sent to Winamp's main window when the previous button has been pressed and Winamp is +** requesting the new playlist item number to go to. +** +** Return -1 for normal Winamp operation (default) or the new item number in +** the playlist to be played instead of the originally selected previous track. +** +** This is primarily provided for the JTFE plugin (gen_jumpex.dll). */ -#define IPC_IS_WNDSHADE 638 + +#define IPC_IS_WNDSHADE 638 /* (requires Winamp 5.04+) -** SendMessage(hwnd_winamp,WM_WA_IPC,wnd,IPC_IS_WNDSHADE); -** -** 'wnd' is window id as defined for IPC_GETWND, or -1 for main window -** Returns 1 if wnd is set to winshade mode, or 0 if it is not +** int is_shaded=SendMessage(hwnd_winamp,WM_WA_IPC,wnd,IPC_IS_WNDSHADE); +** Pass 'wnd' as an id as defined for IPC_GETWND or pass -1 to query the status of the +** main window. This returns 1 if the window is in winshade mode and 0 if it is not. +** Make sure you only test for this on a 5.04+ install otherwise you get a false result. +** (See the notes about unhandled WM_WA_IPC messages). */ + #define IPC_SETRATING 639 /* (requires Winamp 5.04+ with ML) -** SendMessage(hwnd_winamp,WM_WA_IPC,rating,IPC_SETRATING); -** 'rating' is an int value from 0 (no rating) to 5 +** int rating=SendMessage(hwnd_winamp,WM_WA_IPC,rating,IPC_SETRATING); +** This will allow you to set the 'rating' on the current playlist entry where 'rating' +** is an integer value from 0 (no rating) to 5 (5 stars). +** +** The following example should correctly allow you to set the rating for any specified +** playlist entry assuming of course that you're trying to get a valid playlist entry. +** +** void SetPlaylistItemRating(int item_to_set, int rating_to_set){ +** int cur_pos=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS); +** SendMessage(hwnd_winamp,WM_WA_IPC,item_to_set,IPC_SETPLAYLISTPOS); +** SendMessage(hwnd_winamp,WM_WA_IPC,rating_to_set,IPC_SETRATING); +** SendMessage(hwnd_winamp,WM_WA_IPC,cur_pos,IPC_SETPLAYLISTPOS); +** } */ + #define IPC_GETRATING 640 /* (requires Winamp 5.04+ with ML) -** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETRATING); -** returns the current item's rating +** int rating=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETRATING); +** This returns the current playlist entry's rating between 0 (no rating) to 5 (5 stars). +** +** The following example should correctly allow you to get the rating for any specified +** playlist entry assuming of course that you're trying to get a valid playlist entry. +** +** int GetPlaylistItemRating(int item_to_get, int rating_to_set){ +** int cur_pos=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS), rating = 0; +** SendMessage(hwnd_winamp,WM_WA_IPC,item_to_get,IPC_SETPLAYLISTPOS); +** rating = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETRATING); +** SendMessage(hwnd_winamp,WM_WA_IPC,cur_pos,IPC_SETPLAYLISTPOS); +** return rating; +** } */ + #define IPC_GETNUMAUDIOTRACKS 641 /* (requires Winamp 5.04+) ** int n = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETNUMAUDIOTRACKS); -** returns the number of audio tracks for the currently playing item +** This will return the number of audio tracks available from the currently playing item. */ + #define IPC_GETNUMVIDEOTRACKS 642 /* (requires Winamp 5.04+) ** int n = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETNUMVIDEOTRACKS); -** returns the number of video tracks for the currently playing item +** This will return the number of video tracks available from the currently playing item. */ + #define IPC_GETAUDIOTRACK 643 /* (requires Winamp 5.04+) ** int cur = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETAUDIOTRACK); -** returns the id of the current audio track for the currently playing item +** This will return the id of the current audio track for the currently playing item. */ + #define IPC_GETVIDEOTRACK 644 /* (requires Winamp 5.04+) ** int cur = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVIDEOTRACK); -** returns the id of the current video track for the currently playing item +** This will return the id of the current video track for the currently playing item. */ + #define IPC_SETAUDIOTRACK 645 /* (requires Winamp 5.04+) ** SendMessage(hwnd_winamp,WM_WA_IPC,track,IPC_SETAUDIOTRACK); -** switch the currently playing item to a new audio track +** This allows you to switch to a new audio track (if supported) in the current playing file. */ + #define IPC_SETVIDEOTRACK 646 /* (requires Winamp 5.04+) ** SendMessage(hwnd_winamp,WM_WA_IPC,track,IPC_SETVIDEOTRACK); -** switch the currently playing item to a new video track +** This allows you to switch to a new video track (if supported) in the current playing file. */ + #define IPC_PUSH_DISABLE_EXIT 647 /* (requires Winamp 5.04+) -** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_PUSH_DISABLE_EXIT ); -** lets you disable or re-enable the UI exit functions (close button, -** context menu, alt-f4). -** call IPC_POP_DISABLE_EXIT when you are done doing whatever required -** preventing exit +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_PUSH_DISABLE_EXIT); +** This will let you disable or re-enable the UI exit functions (close button, context +** menu, alt-f4). Remember to call IPC_POP_DISABLE_EXIT when you are done doing whatever +** was required that needed to prevent exit otherwise you have to kill the Winamp process. */ + #define IPC_POP_DISABLE_EXIT 648 /* (requires Winamp 5.04+) -** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_POP_DISABLE_EXIT ); -** see IPC_PUSH_DISABLE_EXIT +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_POP_DISABLE_EXIT); +** See IPC_PUSH_DISABLE_EXIT */ + #define IPC_IS_EXIT_ENABLED 649 /* (requires Winamp 5.04+) ** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_IS_EXIT_ENABLED); -** returns 0 if exit is disabled, 1 otherwise +** This will return 0 if the 'exit' option of Winamp's menu is disabled and 1 otherwise. */ + #define IPC_IS_AOT 650 /* (requires Winamp 5.04+) ** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_IS_AOT); -** returns status of always on top flag. note: this may not match the actual -** TOPMOST window flag while another fullscreen application is focused +** This will return the status of the always on top flag. +** Note: This may not match the actual TOPMOST window flag while another fullscreen +** application is focused if the user has the 'Disable always on top while fullscreen +** applications are focused' option under the General Preferences page is checked. */ + #define IPC_USES_RECYCLEBIN 651 -/* -** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_USES_RECYCLEBIN); -** returns 1 if deleted files should be sent to the recycle bin. -** returns 0 if deleted files should be deleted permanently. -** -** You should check for this option if your plugin deletes files -** so that your setting matches the winamp setting +/* (requires Winamp 5.09+) +** int use_bin=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_USES_RECYCLEBIN); +** This will return 1 if the deleted file should be sent to the recycle bin or +** 0 if deleted files should be deleted permanently (default action for < 5.09). +** +** Note: if you use this on pre 5.09 installs of Winamp then it will return 1 which is +** not correct but is due to the way that SendMessage(..) handles un-processed messages. +** Below is a quick case for checking if the returned value is correct. +** +** if(SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_USES_RECYCLEBIN) && +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION)>=0x5009) +** { +** // can safely follow the option to recycle the file +** } +** else +* { +** // need to do a permanent delete of the file +** } */ + #define IPC_FLUSHAUDITS 652 /* ** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_FLUSHAUDITS); ** -** Will flush any pending audits in the global audits que +** Will flush any pending audits in the global audits queue ** */ @@ -1280,7 +1960,27 @@ typedef struct { #define IPC_GETPLAYITEM_END 654 -// >>>>>>>>>>> Next is 655 +#define IPC_GETVIDEORESIZE 655 +#define IPC_SETVIDEORESIZE 656 + + +#define IPC_INITIAL_SHOW_STATE 657 +/* (requires Winamp 5.36+) +** int show_state = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_INITIAL_SHOW_STATE); +** returns the processed value of nCmdShow when Winamp was started +** (see MSDN documentation the values passed to WinMain(..) for what this should be) +** +** e.g. +** if(SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_INITIAL_SHOW_STATE) == SW_SHOWMINIMIZED){ +** // we are starting minimised so process as needed (keep our window hidden) +** } +** +** Useful for seeing if winamp was run minimised on startup so you can act accordingly. +** On pre-5.36 versions this will effectively return SW_NORMAL/SW_SHOWNORMAL due to the +** handling of unknown apis returning 1 from Winamp. +*/ + +// >>>>>>>>>>> Next is 658 #define IPC_PLCMD 1000 @@ -1315,8 +2015,83 @@ typedef struct { #define IPC_STATS_LIBRARY_ITEMCNT 1300 // updates library count status -// IPC 2000-3000 reserved for freeform messages, see gen_ff/ff_ipc.h +/* +** IPC's in the message range 2000 - 3000 are reserved internally for freeform messages. +** These messages are taken from ff_ipc.h which is part of the Modern skin integration. +*/ + #define IPC_FF_FIRST 2000 + +#define IPC_FF_COLOURTHEME_CHANGE IPC_FF_ONCOLORTHEMECHANGED +#define IPC_FF_ONCOLORTHEMECHANGED IPC_FF_FIRST + 3 +/* +** This is a notification message sent when the user changes the colour theme in a Modern +** skin and can also be detected when the Modern skin is first loaded as the gen_ff plugin +** applies relevant settings and styles (like the colour theme). +** +** The value of wParam is the name of the new color theme being switched to. +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(const char*)colour_theme_name,IPC_FF_ONCOLORTHEMECHANGED); +** +** (IPC_FF_COLOURTHEME_CHANGE is the name i (DrO) was using before getting a copy of +** ff_ipc.h with the proper name in it). +*/ + + +#define IPC_FF_ISMAINWND IPC_FF_FIRST + 4 +/* +** int ismainwnd = (HWND)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)test_wnd,IPC_FF_ISMAINWND); +** +** This allows you to determine if the window handle passed to it is a modern skin main +** window or not. If it is a main window or any of its windowshade variants then it will +** return 1. +** +** Because of the way modern skins are implemented, it is possible for this message to +** return a positive test result for a number of window handles within the current Winamp +** process. This appears to be because you can have a visible main window, a compact main +** window and also a winshaded version. +** +** The following code example below is one way of seeing how this api works since it will +** enumerate all windows related to Winamp at the time and allows you to process as +** required when a detection happens. +** +** +** EnumThreadWindows(GetCurrentThreadId(),enumWndProc,0); +** +** BOOL CALLBACK enumWndProc(HWND hwnd, LPARAM lParam){ +** +** if(SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)hwnd,IPC_FF_ISMAINWND)){ +** // do processing in here +** // or continue the enum for other main windows (if they exist) +** // and just comment out the line below +** return 0; +** } +** return 1; +** } +*/ + + +#define IPC_FF_GETCONTENTWND IPC_FF_FIRST + 5 +/* +** HWND wa2embed = (HWND)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)test_wnd,IPC_FF_GETCONTENTWND); +** +** This will return the Winamp 2 window that is embedded in the window's container +** i.e. if hwnd is the playlist editor windowshade hwnd then it will return the Winamp 2 +** playlist editor hwnd. +** +** If no content is found such as the window has nothing embedded then this will return +** the hwnd passed to it. +*/ + + +#define IPC_FF_NOTIFYHOTKEY IPC_FF_FIRST + 6 +/* +** This is a notification message sent when the user uses a global hotkey combination +** which had been registered with the gen_hotkeys plugin. +** +** The value of wParam is the description of the hotkey as passed to gen_hotkeys. +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(const char*)hotkey_desc,IPC_FF_NOTIFYHOTKEY); +*/ + #define IPC_FF_LAST 3000 @@ -1339,6 +2114,7 @@ typedef struct { ** what's needed to handle it in your own instance. */ + #define IPC_PLAYLIST_MODIFIED 3002 /* (requires Winamp 5.0+) ** This is a notification message sent to the main Winamp window whenever the playlist is @@ -1348,52 +2124,62 @@ typedef struct { ** will slow down Winamp as playlist entries are modified (especially when you're adding ** in a large playlist). ** -** if(uMsg == WM_WA_IPC && lParam == IPC_PLAYLIST_MODIFIED){ +** if(uMsg == WM_WA_IPC && lParam == IPC_PLAYLIST_MODIFIED) +** { ** // do what you need to do here ** } */ + #define IPC_PLAYING_FILE 3003 /* (requires Winamp 5.0+) ** This is a notification message sent to the main Winamp window when playback begins for ** a file. This passes the full filepath in the wParam of the message received. ** -** if(uMsg == WM_WA_IPC && lParam == IPC_PLAYING_FILE){ +** if(uMsg == WM_WA_IPC && lParam == IPC_PLAYING_FILE) +** { ** // do what you need to do here, e.g. ** process_file((char*)wParam); ** } */ + #define IPC_PLAYING_FILEW 13003 /* (requires Winamp 5.0+) ** This is a notification message sent to the main Winamp window when playback begins for ** a file. This passes the full filepath in the wParam of the message received. ** -** if(uMsg == WM_WA_IPC && lParam == IPC_PLAYING_FILEW){ +** if(uMsg == WM_WA_IPC && lParam == IPC_PLAYING_FILEW) +** { ** // do what you need to do here, e.g. ** process_file((wchar_t*)wParam); ** } */ -#define IPC_FILE_TAG_MAY_HAVE_UPDATED 3004 // sent to main wnd with the file as parm whenever a file tag might be updated + +#define IPC_FILE_TAG_MAY_HAVE_UPDATED 3004 +#define IPC_FILE_TAG_MAY_HAVE_UPDATEDW 3005 /* (requires Winamp 5.0+) ** This is a notification message sent to the main Winamp window when a file's tag ** (e.g. id3) may have been updated. This appears to be sent when the InfoBox(..) function ** of the associated input plugin returns a 1 (which is the file information dialog/editor ** call normally). ** -** if(uMsg == WM_WA_IPC && lParam == IPC_FILE_TAG_MAY_HAVE_UPDATED){ +** if(uMsg == WM_WA_IPC && lParam == IPC_FILE_TAG_MAY_HAVE_UPDATED) +** { ** // do what you need to do here, e.g. ** update_info_on_file_update((char*)wParam); ** } */ + #define IPC_ALLOW_PLAYTRACKING 3007 /* (requires Winamp 5.0+) ** SendMessage(hwnd_winamp,WM_WA_IPC,allow,IPC_ALLOW_PLAYTRACKING); ** Send allow as nonzero to allow play tracking and zero to disable the mode. */ + #define IPC_HOOK_OKTOQUIT 3010 /* (requires Winamp 5.0+) ** This is a notification message sent to the main Winamp window asking if it's okay to @@ -1404,14 +2190,17 @@ typedef struct { ** original window proceedure since another plugin may want to have a say in the matter ** with regards to Winamp closing. ** -** if(uMsg == WM_WA_IPC && lParam == IPC_HOOK_OKTOQUIT){ +** if(uMsg == WM_WA_IPC && lParam == IPC_HOOK_OKTOQUIT) +** { ** // do what you need to do here, e.g. -** if(no_shut_down()){ +** if(no_shut_down()) +** { ** return 1; ** } ** } */ + #define IPC_WRITECONFIG 3011 /* (requires Winamp 5.0+) ** SendMessage(hwnd_winamp,WM_WA_IPC,write_type,IPC_WRITECONFIG); @@ -1432,10 +2221,10 @@ typedef struct { ** Send write_type as 0 to write the common and less common settings and no playlist. */ -#define IPC_UPDATE_URL 3012 // pass the URL (char *) in lparam, will be free()'d on done. -// pass a string to be the name to register, and returns a value > 65536, which is a unique value you can use -// for custom WM_WA_IPC messages. +#define IPC_UPDATE_URL 3012 +// pass the URL (char *) in lparam, will be free()'d on done. + #define IPC_GET_RANDFUNC 3015 // returns a function to get a random number /* (requires Winamp 5.1+) @@ -1449,6 +2238,7 @@ typedef struct { ** SendMessage(..) when it is not handled so is good to check for it in this situation. */ + #define IPC_METADATA_CHANGED 3017 /* (requires Winamp 5.1+) ** int changed=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(char*)field,IPC_METADATA_CHANGED); @@ -1467,16 +2257,19 @@ typedef struct { ** Winamp for it at the moment. */ + #define IPC_SKIN_CHANGED 3018 /* (requires Winamp 5.1+) ** This is a notification message sent to the main Winamp window by itself whenever ** the skin in use is changed. There is no information sent by the wParam for this. ** -** if(message == WM_WA_IPC && lparam == IPC_SKIN_CHANGED){ +** if(message == WM_WA_IPC && lparam == IPC_SKIN_CHANGED) +** { ** // do what you need to do to handle skin changes, e.g. call WADlg_init(hwnd_winamp); ** } */ + #define IPC_REGISTER_LOWORD_COMMAND 3019 /* (requires Winamp 5.1+) ** WORD id = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_REGISTER_LOWORD_COMMAND); @@ -1484,26 +2277,32 @@ typedef struct { ** entries. The starting value returned by this message will potentially change as and ** when the main resource file of Winamp is updated with extra data so assumptions cannot ** be made on what will be returned and plugin loading order will affect things as well. + +** 5.33+ +** If you want to reserve more than one id, you can pass the number of ids required in wParam */ + #define IPC_GET_DISPATCH_OBJECT 3020 // gets winamp main IDispatch * (for embedded webpages) #define IPC_GET_UNIQUE_DISPATCH_ID 3021 // gives you a unique dispatch ID that won't conflict with anything in winamp's IDispatch * - #define IPC_ADD_DISPATCH_OBJECT 3022 // add your own dispatch object into winamp's. This lets embedded webpages access your functions // pass a pointer to DispatchInfo (see below). Winamp makes a copy of all this data so you can safely delete it later typedef struct { - wchar_t *name; // filled in by plugin, make sure it's a unicode string!! (i.e. L"myObject" instead of "myObject). - struct IDispatch *dispatch; // filled in by plugin - DWORD id; // filled in by winamp on return + wchar_t *name; // filled in by plugin, make sure it's a unicode string!! (i.e. L"myObject" instead of "myObject). + struct IDispatch *dispatch; // filled in by plugin + DWORD id; // filled in by winamp on return } DispatchInfo; +// see IPC_JSAPI2_GET_DISPATCH_OBJECT for version 2 of the Dispatchable scripting interface + #define IPC_GET_PROXY_STRING 3023 /* (requires Winamp 5.11+) ** char* proxy_string=(char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_PROXY_STRING); ** This will return the same string as is shown on the General Preferences page. */ + #define IPC_USE_REGISTRY 3024 /* (requires Winamp 5.11+) ** int reg_enabled=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_USE_REGISTRY); @@ -1512,6 +2311,7 @@ typedef struct ** system settings, etc. */ + #define IPC_GET_API_SERVICE 3025 /* (requires Winamp 5.12+) ** api_service* api_service = (api_service)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_API_SERVICE); @@ -1528,24 +2328,26 @@ typedef struct */ - typedef struct { const wchar_t *filename; const wchar_t *metadata; wchar_t *ret; - int retlen; + size_t retlen; } extendedFileInfoStructW; #define IPC_GET_EXTENDED_FILE_INFOW 3026 /* (requires Winamp 5.13+) ** Pass a pointer to the above struct in wParam */ + + #define IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE 3027 #define IPC_SET_EXTENDED_FILE_INFOW 3028 /* (requires Winamp 5.13+) ** Pass a pointer to the above struct in wParam */ + #define IPC_PLAYLIST_GET_NEXT_SELECTED 3029 /* (requires 5.2+) ** int pl_item = SendMessage(hwnd_winamp,WM_WA_IPC,start,IPC_PLAYLIST_GET_NEXT_SELECTED); @@ -1567,13 +2369,87 @@ typedef struct { ** } */ + #define IPC_PLAYLIST_GET_SELECTED_COUNT 3030 /* (requires 5.2+) ** int selcnt = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_PLAYLIST_GET_SELECTED_COUNT); ** This will return the number of selected playlist entries. */ -#define IPC_GET_PLAYING_FILENAME 3031 // returns wchar_t * of the currently playing filename + +#define IPC_GET_PLAYING_FILENAME 3031 +// returns wchar_t * of the currently playing filename + +#define IPC_OPEN_URL 3032 +// send either ANSI or Unicode string (it'll figure it out, but it MUST start with "h"!, so don't send ftp:// or anything funny) +// you can also send this one from another process via WM_COPYDATA (unicode only) + + +#define IPC_USE_UXTHEME_FUNC 3033 +/* (requires Winamp 5.35+) +** int ret = SendMessage(hwnd_winamp,WM_WA_IPC,param,IPC_USE_UXTHEME_FUNC); +** param can be IPC_ISWINTHEMEPRESENT or IPC_ISAEROCOMPOSITIONACTIVE or a valid hwnd. +** +** If you pass a hwnd then it will apply EnableThemeDialogTexture(ETDT_ENABLETAB) +** so your tabbed dialogs can use the correct theme (on supporting OSes ie XP+). +** +** Otherwise this will return a value based on the param passed (as defined below). +** For compatability, the return value will be zero on success (as 1 is returned +** for unsupported ipc calls on older Winamp versions) +*/ + #define IPC_ISWINTHEMEPRESENT 0 +/* This will return 0 if uxtheme.dll is present +** int isthemethere = !SendMessage(hwnd_winamp,WM_WA_IPC,IPC_ISWINTHEMEPRESENT,IPC_USE_UXTHEME_FUNC); +*/ + #define IPC_ISAEROCOMPOSITIONACTIVE 1 +/* This will return 0 if aero composition is active +** int isaero = !SendMessage(hwnd_winamp,WM_WA_IPC,IPC_ISAEROCOMPOSITIONACTIVE,IPC_USE_UXTHEME_FUNC); +*/ + + +#define IPC_GET_PLAYING_TITLE 3034 +// returns wchar_t * of the current title + + +#define IPC_CANPLAY 3035 +// pass const wchar_t *, returns an in_mod * or 0 + + +typedef struct { + // fill these in... + size_t size; // init to sizeof(artFetchData) + HWND parent; // parent window of the dialogue + + // fill as much of these in as you can, otherwise leave them 0 + const wchar_t *artist; + const wchar_t *album; + int year, amgArtistId, amgAlbumId; + + int showCancelAll; // if set to 1, this shows a "Cancel All" button on the dialogue + + // winamp will fill these in if the call returns successfully: + void* imgData; // a buffer filled with compressed image data. free with WASABI_API_MEMMGR->sysFree() + int imgDataLen; // the size of the buffer + wchar_t type[10]; // eg: "jpg" + const wchar_t *gracenoteFileId; // if you know it +} artFetchData; + +#define IPC_FETCH_ALBUMART 3036 +/* pass an artFetchData*. This will show a dialog guiding the use through choosing art, and return when it's finished +** return values: +** 1: error showing dialog +** 0: success +** -1: cancel was pressed +** -2: cancel all was pressed +*/ + +#define IPC_JSAPI2_GET_DISPATCH_OBJECT 3037 +/* pass your service's unique ID, as a wchar_t * string, in wParam +** Winamp will copy the string, so don't worry about keeping it around +** An IDispatch * object will be returned (cast the return value from SendMessage) +** This IDispatch can be used for scripting/automation/VB interaction +** Pass to IE via IDocHostUIHandler::GetExternal and it will become window.external in javscript +*/ #define IPC_REGISTER_WINAMP_IPCMESSAGE 65536 /* (requires Winamp 5.0+) @@ -1591,4 +2467,4 @@ typedef struct { ** } */ -#endif//_WA_IPC_H_ +#endif//_WA_IPC_H_ From c630f14ce3117fe2a792645a94ac0b3f1ce109cb Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 28 Apr 2017 16:16:10 +0200 Subject: [PATCH 03/16] Fix some "short" MPDS --- src/meta/ngc_dsp_mpds.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/meta/ngc_dsp_mpds.c b/src/meta/ngc_dsp_mpds.c index 109e0346..68e43df8 100644 --- a/src/meta/ngc_dsp_mpds.c +++ b/src/meta/ngc_dsp_mpds.c @@ -10,7 +10,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_mpds(STREAMFILE *streamFile) { /* check extension, case insensitive */ - /* .adp: Big Air Freestyle */ + /* .dsp: Big Air Freestyle */ /* .mds: Terminator 3 The Redemption, Mission Impossible: Operation Surma */ if (!check_extensions(streamFile, "dsp,mds")) goto fail; @@ -18,7 +18,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_mpds(STREAMFILE *streamFile) { if (read_32bitBE(0x00,streamFile) != 0x4D504453) /* "MPDS" */ goto fail; - short_mpds = read_32bitBE(0x04,streamFile) != 0x00010000 && read_32bitBE(0x0c,streamFile) == 0x00000002; /* version byte? */ + short_mpds = read_32bitBE(0x04,streamFile) != 0x00010000 && check_extensions(streamFile, "mds"); /* version byte? */ channel_count = short_mpds ? read_16bitBE(0x0a, streamFile) : @@ -51,12 +51,13 @@ VGMSTREAM * init_vgmstream_ngc_dsp_mpds(STREAMFILE *streamFile) { vgmstream->sample_rate = (uint16_t)read_16bitBE(0x08,streamFile); vgmstream->interleave_block_size = channel_count==1 ? 0 : 0x200; -#if 0 //todo unknown coeffs, maybe depends on stuff @ 0x10? (but looks like some kind of size) +#if 0 //unknown coeffs/hist, related to data after 0x0c? (only coefs 0..7 seem to be needed) { + off_t offset = 0x0c; int i,ch; for (ch=0; ch < vgmstream->channels; ch++) { for (i=0; i < 16; i++) - vgmstream->ch[ch].adpcm_coef[i] = mpds_coefs[i]; + vgmstream->ch[ch].adpcm_coef[i] = read_16bitBE(offset + i*2); } } #endif From 4a83de7dae282213f854f21d04d4f6096d8d717f Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 28 Apr 2017 17:26:25 +0200 Subject: [PATCH 04/16] Added MC3 decoder/meta [MX Rider, Spy Hunter, T3] (thanks to daemon1) --- fb2k/in_vgmstream.cpp | 1 + src/Makefile | 6 +- src/coding/Makefile.unix.am | 1 + src/coding/coding.h | 3 + src/coding/mc3_decoder.c | 183 +++++++++++++++++++++++++++++++ src/formats.c | 4 + src/libvgmstream.vcproj | 8 ++ src/libvgmstream.vcxproj | 2 + src/libvgmstream.vcxproj.filters | 6 + src/meta/Makefile.unix.am | 1 + src/meta/mc3.c | 46 ++++++++ src/meta/meta.h | 2 + src/vgmstream.c | 12 ++ src/vgmstream.h | 2 + 14 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 src/coding/mc3_decoder.c create mode 100644 src/meta/mc3.c diff --git a/fb2k/in_vgmstream.cpp b/fb2k/in_vgmstream.cpp index a3495bd2..6b76a545 100644 --- a/fb2k/in_vgmstream.cpp +++ b/fb2k/in_vgmstream.cpp @@ -536,6 +536,7 @@ DECLARE_MULTIPLE_FILE_TYPE("LSF Audio File (*.LSF)", lsf); DECLARE_MULTIPLE_FILE_TYPE("LWAV Audio File (*.LWAV)", lwav); DECLARE_MULTIPLE_FILE_TYPE("MATX Audio File (*.MATX)", matx); +DECLARE_MULTIPLE_FILE_TYPE("MC3 Audio File (*.MC3)", mc3); DECLARE_MULTIPLE_FILE_TYPE("MCA Audio File (*.MCA)", mca); DECLARE_MULTIPLE_FILE_TYPE("MCG Audio File (*.MCG)", mcg); DECLARE_MULTIPLE_FILE_TYPE("MDS Audio File (*.MDS)", mds); diff --git a/src/Makefile b/src/Makefile index 3243eb87..b80ef1fb 100644 --- a/src/Makefile +++ b/src/Makefile @@ -30,7 +30,8 @@ CODING_OBJS=coding/adx_decoder.o \ coding/fsb_vorbis_decoder.o \ coding/wwise_vorbis_decoder.o \ coding/wwise_vorbis_utils.o \ - coding/ogl_vorbis_decoder.o + coding/ogl_vorbis_decoder.o \ + coding/mc3_decoder.o LAYOUT_OBJS=layout/ast_blocked.o \ layout/blocked.o \ @@ -324,7 +325,8 @@ META_OBJS=meta/adx.o \ meta/x360_nub.o \ meta/x360_pasx.o \ meta/sxd.o \ - meta/ogl.o + meta/ogl.o \ + meta/mc3.o EXT_LIBS = ../ext_libs/clHCA.o diff --git a/src/coding/Makefile.unix.am b/src/coding/Makefile.unix.am index ac92886e..04cb6338 100644 --- a/src/coding/Makefile.unix.am +++ b/src/coding/Makefile.unix.am @@ -35,5 +35,6 @@ libcoding_la_SOURCES += fsb_vorbis_decoder.c libcoding_la_SOURCES += wwise_vorbis_decoder.c libcoding_la_SOURCES += wwise_vorbis_utils.c libcoding_la_SOURCES += ogl_vorbis_decoder.c +libcoding_la_SOURCES += mc3_decoder.c EXTRA_DIST = coding.h g72x_state.h clHCA.h diff --git a/src/coding/coding.h b/src/coding/coding.h index cb3a992a..780f2239 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -113,6 +113,9 @@ void decode_lsf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, /* mtaf_decoder */ void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int channels); +/* mc3_decoder */ +void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); + /* hca_decoder */ void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels); diff --git a/src/coding/mc3_decoder.c b/src/coding/mc3_decoder.c new file mode 100644 index 00000000..64e6bb17 --- /dev/null +++ b/src/coding/mc3_decoder.c @@ -0,0 +1,183 @@ +#include "coding.h" +#include "../util.h" + + +static const int step_table[4] = { + 5, 1, -1, -3 +}; + +static const int mc3_table[4][4][64] = { + { + { + 2, 2, 3, 7, 15, 27, 45, 70, 104, 148, 202, 268, 347, 441, 551, 677, + 821, 984, 1168, 1374, 1602, 1854, 2131, 2435, 2767, 3127, 3517, 3938, 4392, 4880, 5402, 5960, + 6555, 7189, 7862, 8577, 9333, 10132, 10976, 11865, 12802, 13786, 14819, 15903, 17038, 18226, 19469, 20766, + 22120, 23531, 25001, 26531, 28123, 29776, 31494, 33276, 35124, 37039, 39023, 41076, 43201, 45397, 47666, 50010 + }, + { + 1, 1, 2, 5, 10, 18, 31, 48, 72, 101, 139, 184, 239, 303, 378, 465, + 564, 677, 803, 944, 1101, 1274, 1465, 1674, 1902, 2150, 2418, 2707, 3019, 3355, 3714, 4097, + 4507, 4942, 5405, 5896, 6416, 6966, 7546, 8157, 8801, 9477, 10188, 10933, 11714, 12530, 13384, 14276, + 15207, 16177, 17188, 18240, 19334, 20471, 21652, 22877, 24148, 25464, 26828, 28240, 29700, 31210, 32770, 34382 + }, + { + 0, 0, 1, 2, 4, 8, 14, 22, 32, 46, 63, 83, 108, 138, 172, 211, + 256, 307, 365, 429, 500, 579, 666, 761, 864, 977, 1099, 1230, 1372, 1525, 1688, 1862, + 2048, 2246, 2457, 2680, 2916, 3166, 3430, 3708, 4000, 4308, 4631, 4969, 5324, 5695, 6084, 6489, + 6912, 7353, 7813, 8291, 8788, 9305, 9841, 10398, 10976, 11574, 12194, 12836, 13500, 14186, 14895, 15628 + }, + { + 0, 0, 0, 0, 1, 3, 5, 8, 13, 18, 25, 33, 43, 55, 68, 84, + 102, 123, 146, 171, 200, 231, 266, 304, 345, 390, 439, 492, 549, 610, 675, 745, + 819, 898, 982, 1072, 1166, 1266, 1372, 1483, 1600, 1723, 1852, 1987, 2129, 2278, 2433, 2595, + 2765, 2941, 3125, 3316, 3515, 3722, 3936, 4159, 4390, 4629, 4877, 5134, 5400, 5674, 5958, 6251 + }, + }, + { + { + 1, 1, 2, 4, 9, 17, 28, 44, 65, 92, 126, 167, 217, 276, 344, 423, + 513, 615, 730, 858, 1001, 1159, 1332, 1522, 1729, 1954, 2198, 2461, 2745, 3050, 3376, 3725, + 4097, 4493, 4914, 5360, 5833, 6332, 6860, 7416, 8001, 8616, 9262, 9939, 10649, 11391, 12168, 12978, + 13825, 14707, 15626, 16582, 17576, 18610, 19683, 20797, 21952, 23149, 24389, 25673, 27000, 28373, 29791, 31256 + }, + { + 0, 0, 1, 2, 5, 10, 17, 26, 39, 55, 75, 100, 130, 165, 206, 254, + 308, 369, 438, 515, 600, 695, 799, 913, 1037, 1172, 1319, 1477, 1647, 1830, 2025, 2235, + 2458, 2696, 2948, 3216, 3499, 3799, 4116, 4449, 4800, 5169, 5557, 5963, 6389, 6835, 7300, 7787, + 8295, 8824, 9375, 9949, 10546, 11166, 11810, 12478, 13171, 13889, 14633, 15403, 16200, 17023, 17874, 18753 + }, + { + 0, 0, 0, 1, 3, 6, 11, 17, 26, 37, 50, 67, 86, 110, 137, 169, + 205, 246, 292, 343, 400, 463, 532, 608, 691, 781, 879, 984, 1098, 1220, 1350, 1490, + 1638, 1797, 1965, 2144, 2333, 2533, 2744, 2966, 3200, 3446, 3704, 3975, 4259, 4556, 4867, 5191, + 5530, 5882, 6250, 6632, 7030, 7444, 7873, 8319, 8781, 9259, 9755, 10269, 10800, 11349, 11916, 12502 + }, + { + 0, 0, 0, 0, 0, 1, 2, 4, 6, 9, 12, 16, 21, 27, 34, 42, + 51, 61, 73, 85, 100, 115, 133, 152, 172, 195, 219, 246, 274, 305, 337, 372, + 409, 449, 491, 536, 583, 633, 686, 741, 800, 861, 926, 993, 1064, 1139, 1216, 1297, + 1382, 1470, 1562, 1658, 1757, 1861, 1968, 2079, 2195, 2314, 2438, 2567, 2700, 2837, 2979, 3125 + }, + }, + { + { + 1, 1, 2, 5, 10, 18, 31, 48, 72, 101, 139, 184, 239, 303, 378, 465, + 564, 677, 803, 944, 1101, 1274, 1465, 1674, 1902, 2150, 2418, 2707, 3019, 3355, 3714, 4097, + 4507, 4942, 5405, 5896, 6416, 6966, 7546, 8157, 8801, 9477, 10188, 10933, 11714, 12530, 13384, 14276, + 15207, 16177, 17188, 18240, 19334, 20471, 21652, 22877, 24148, 25464, 26828, 28240, 29700, 31210, 32770, 34382 + }, + { + 1, 1, 1, 3, 7, 13, 22, 35, 52, 74, 101, 134, 173, 220, 275, 338, + 410, 492, 584, 687, 801, 927, 1065, 1217, 1383, 1563, 1758, 1969, 2196, 2440, 2701, 2980, + 3277, 3594, 3931, 4288, 4666, 5066, 5488, 5932, 6401, 6893, 7409, 7951, 8519, 9113, 9734, 10383, + 11060, 11765, 12500, 13265, 14061, 14888, 15747, 16638, 17562, 18519, 19511, 20538, 21600, 22698, 23833, 25005 + }, + { + 0, 0, 1, 2, 4, 8, 14, 22, 32, 46, 63, 83, 108, 138, 172, 211, + 256, 307, 365, 429, 500, 579, 666, 761, 864, 977, 1099, 1230, 1372, 1525, 1688, 1862, + 2048, 2246, 2457, 2680, 2916, 3166, 3430, 3708, 4000, 4308, 4631, 4969, 5324, 5695, 6084, 6489, + 6912, 7353, 7813, 8291, 8788, 9305, 9841, 10398, 10976, 11574, 12194, 12836, 13500, 14186, 14895, 15628 + }, + { + 0, 0, 0, 1, 2, 5, 8, 13, 19, 27, 37, 50, 65, 82, 103, 127, + 154, 184, 219, 257, 300, 347, 399, 456, 518, 586, 659, 738, 823, 915, 1012, 1117, + 1229, 1348, 1474, 1608, 1749, 1899, 2058, 2224, 2400, 2584, 2778, 2981, 3194, 3417, 3650, 3893, + 4147, 4412, 4687, 4974, 5273, 5583, 5905, 6239, 6585, 6944, 7316, 7701, 8100, 8511, 8937, 9376 + }, + }, + { + { + 1, 1, 2, 5, 11, 20, 34, 53, 78, 111, 151, 201, 260, 331, 413, 508, + 616, 738, 876, 1030, 1201, 1390, 1598, 1826, 2075, 2345, 2638, 2954, 3294, 3660, 4051, 4470, + 4916, 5392, 5897, 6432, 6999, 7599, 8232, 8899, 9601, 10339, 11114, 11927, 12779, 13670, 14601, 15574, + 16590, 17648, 18751, 19898, 21092, 22332, 23620, 24957, 26343, 27779, 29267, 30807, 32400, 34047, 35749, 37507 + }, + { + 1, 1, 1, 3, 6, 11, 19, 31, 45, 64, 88, 117, 152, 193, 241, 296, + 359, 430, 511, 601, 701, 811, 932, 1065, 1210, 1368, 1538, 1723, 1921, 2135, 2363, 2607, + 2868, 3145, 3440, 3752, 4083, 4433, 4802, 5191, 5600, 6031, 6483, 6957, 7454, 7974, 8517, 9085, + 9677, 10295, 10938, 11607, 12303, 13027, 13778, 14558, 15366, 16204, 17072, 17971, 18900, 19861, 20854, 21879 + }, + { + 0, 0, 0, 1, 2, 5, 8, 13, 19, 27, 37, 50, 65, 82, 103, 127, + 154, 184, 219, 257, 300, 347, 399, 456, 518, 586, 659, 738, 823, 915, 1012, 1117, + 1229, 1348, 1474, 1608, 1749, 1899, 2058, 2224, 2400, 2584, 2778, 2981, 3194, 3417, 3650, 3893, + 4147, 4412, 4687, 4974, 5273, 5583, 5905, 6239, 6585, 6944, 7316, 7701, 8100, 8511, 8937, 9376 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + } +}; + + +/* MC3 3-bit ADPCM (Paradigm Entertainment games). + * + * Layout: blocks with 32b header + 32b ch1, 32b ch2, 32b ch1... + * Each 32b is a sub-block with 10 samples (3b x10) sharing a 'mode' of sorts. + * More than one block is rarely used though. + * + * Tables and original algorithm by daemon1 + */ +void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { + int i, sample_count = 0; + + int32_t hist = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + /* internal interleave */ + int block_samples = (vgmstream->interleave_block_size - 4) / 4 / vgmstream->channels * 10; + first_sample = first_sample % block_samples; + + + /* block header */ + if (first_sample == 0) { + uint32_t header = (uint32_t)read_32bitLE(stream->offset, stream->streamfile); + header = (header >> channel*16); /* lower 16=ch1, upper 16b=ch2 */ + step_index = header & 0x3f; /* 6b */ + hist = header & 0xffc0; /* 16b sans 6b */ + if (hist > 0x7fff) hist -= 0x10000; /* sign extend */ + } + + + /* block samples */ + for (i = first_sample; i < first_sample + samples_to_do; i++) { + uint32_t subblock, mode, samples, index, sign, diff; + + /* header + ch shift + sub-block number (ex. ch0 i=10: sub-block 1, ch0 i=23: sub-block 2) */ + off_t subblock_offset = stream->offset + 4 + 4*channel + (i/10)*(4*vgmstream->channels); + int sample_shift = (i%10)*3; + + /* expand 3b */ + subblock = (uint32_t)read_32bitLE(subblock_offset, stream->streamfile); + mode = (subblock >> 30) & 0x3; /* upper 2b */ + samples = (subblock) & 0x3FFFFFFF; /* lower 3b*10 */ + + index = (samples >> sample_shift) & 3; /* lower 2b */ + sign = (samples >> sample_shift) & 4; /* upper 1b */ + diff = mc3_table[mode][index][step_index]; + if (sign == 0) + hist += (- 1 - diff); + else + hist += diff; + + /* new step + clamp */ + step_index += step_table[index]; + if (step_index < 0) step_index = 0; + else if (step_index > 63) step_index = 63; + + /* output */ + outbuf[sample_count] = hist; + sample_count += channelspacing; + } + + + /* internal interleave: increment offset on complete frame */ + if (i == block_samples) stream->offset += vgmstream->interleave_block_size; + + stream->adpcm_history1_32 = hist; + stream->adpcm_step_index = step_index; +} diff --git a/src/formats.c b/src/formats.c index 19bce9ea..99cc2852 100644 --- a/src/formats.c +++ b/src/formats.c @@ -149,6 +149,7 @@ static const char* extension_list[] = { "lwav", //fake extension, for looping "matx", + "mc3", "mca", "mcg", "mds", @@ -439,6 +440,8 @@ static const coding_info coding_info_list[] = { {coding_SASSC, "Activision / EXAKT SASSC 8-bit DPCM"}, {coding_LSF, "lsf 4-bit ADPCM"}, {coding_MTAF, "Konami MTAF 4-bit ADPCM"}, + {coding_MC3, "Paradigm MC3 3-bit ADPCM"}, + #ifdef VGM_USE_VORBIS {coding_ogg_vorbis, "Ogg Vorbis"}, {coding_fsb_vorbis, "FSB Vorbis"}, @@ -847,6 +850,7 @@ static const meta_info meta_info_list[] = { {meta_UBI_RAKI, "Ubisoft RAKI header"}, {meta_SXD, "Sony SXD header"}, {meta_OGL, "Shin'en OGL header"}, + {meta_MC3, "Paradigm MC3 header"}, #ifdef VGM_USE_VORBIS {meta_OGG_VORBIS, "Ogg Vorbis"}, diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 081185ff..5951a0f5 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -444,6 +444,10 @@ RelativePath=".\meta\maxis_xa.c" > + + @@ -1330,6 +1334,10 @@ RelativePath=".\coding\lsf_decoder.c" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index f81e14fa..87aeeb85 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -225,6 +225,7 @@ + @@ -412,6 +413,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 3e488f85..24deac16 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -247,6 +247,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files @@ -781,6 +784,9 @@ coding\Source Files + + coding\Source Files + coding\Source Files diff --git a/src/meta/Makefile.unix.am b/src/meta/Makefile.unix.am index 722c6f4b..6604fad1 100644 --- a/src/meta/Makefile.unix.am +++ b/src/meta/Makefile.unix.am @@ -260,5 +260,6 @@ libmeta_la_SOURCES += x360_pasx.c libmeta_la_SOURCES += x360_nub.c libmeta_la_SOURCES += sxd.c libmeta_la_SOURCES += ogl.c +libmeta_la_SOURCES += mc3.c EXTRA_DIST = meta.h diff --git a/src/meta/mc3.c b/src/meta/mc3.c new file mode 100644 index 00000000..bd990406 --- /dev/null +++ b/src/meta/mc3.c @@ -0,0 +1,46 @@ +#include "meta.h" + + +/* MC3 - from Paradigm games [Spy Hunter, MX Rider, Terminator 3] */ +VGMSTREAM * init_vgmstream_mc3(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count; + + /* check extension, case insensitive */ + if ( !check_extensions(streamFile,"mc3")) + goto fail; + + if (read_32bitBE(0x00,streamFile) != 0x4D504333) /* "MPC3" */ + goto fail; + if (read_32bitBE(0x04,streamFile) != 0x00011400) /* version? */ + goto fail; + + start_offset = 0x1c; + loop_flag = 0; + channel_count = read_32bitLE(0x08, streamFile); + if (channel_count > 2) goto fail; /* not seen, decoder must be adapted */ + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + vgmstream->coding_type = coding_MC3; + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_MC3; + + vgmstream->sample_rate = read_32bitLE(0x0c, streamFile); + vgmstream->num_samples = read_32bitLE(0x10, streamFile) * 10; /* sizes in sub-blocks of 10 samples (without headers) */ + vgmstream->interleave_block_size = (read_32bitLE(0x14, streamFile) * 4 * channel_count) + 4; + if (read_32bitLE(0x18, streamFile) + start_offset != get_streamfile_size(streamFile)) + goto fail; + + + /* open the file for reading */ + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/meta/meta.h b/src/meta/meta.h index 2e83b419..7c8d09ba 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -686,4 +686,6 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ogl(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_mc3(STREAMFILE *streamFile); + #endif /*_META_H*/ diff --git a/src/vgmstream.c b/src/vgmstream.c index e4d4eeec..1d4ab085 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -354,6 +354,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_xma, init_vgmstream_sxd, init_vgmstream_ogl, + init_vgmstream_mc3, #ifdef VGM_USE_FFMPEG init_vgmstream_mp4_aac_ffmpeg, @@ -1135,6 +1136,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { return 54; case coding_MTAF: return 0x80*2; + case coding_MC3: + return 10; case coding_CRI_HCA: return clHCA_samplesPerBlock; #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) @@ -1255,6 +1258,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_MSADPCM: case coding_MTAF: return vgmstream->interleave_block_size; + case coding_MC3: + return 4; default: return 0; } @@ -1777,6 +1782,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to chan, vgmstream->channels); } break; + case coding_MC3: + for (chan=0;chanchannels;chan++) { + decode_mc3(vgmstream, &vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels, vgmstream->samples_into_block, samples_to_do, + chan); + } + break; } } diff --git a/src/vgmstream.h b/src/vgmstream.h index 83974f89..5c586b64 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -130,6 +130,7 @@ typedef enum { coding_SASSC, /* Activision EXAKT SASSC DPCM */ coding_LSF, /* lsf ADPCM (Fastlane Street Racing iPhone)*/ coding_MTAF, /* Konami MTAF ADPCM (IMA-derived) */ + coding_MC3, /* Paradigm MC3 3-bit ADPCM */ /* others */ coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression DPCM */ @@ -605,6 +606,7 @@ typedef enum { meta_UBI_RAKI, /* Ubisoft RAKI header (Rayman Legends, Just Dance 2017) */ meta_SXD, /* Sony SXD (Gravity Rush, Freedom Wars PSV) */ meta_OGL, /* Shin'en Wii/WiiU (Jett Rocket (Wii), FAST Racing NEO (WiiU)) */ + meta_MC3, /* Paradigm games (T3 PS2, MX Rider PS2, MI: Operation Surma PS2) */ #ifdef VGM_USE_VORBIS meta_OGG_VORBIS, /* Ogg Vorbis */ From 63894939929055af0faecefc5bc82c0e8e1c5a54 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 28 Apr 2017 18:33:33 +0200 Subject: [PATCH 05/16] Build object list automatically using a make wildcard --- src/Makefile | 342 ++------------------------------------------------- 1 file changed, 13 insertions(+), 329 deletions(-) diff --git a/src/Makefile b/src/Makefile index b80ef1fb..3dda5b10 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,336 +1,20 @@ -CODING_OBJS=coding/adx_decoder.o \ - coding/g721_decoder.o \ - coding/ima_decoder.o \ - coding/ngc_afc_decoder.o \ - coding/ngc_dsp_decoder.o \ - coding/ngc_dtk_decoder.o \ - coding/pcm_decoder.o \ - coding/psx_decoder.o \ - coding/xa_decoder.o \ - coding/eaxa_decoder.o \ - coding/ogg_vorbis_decoder.o \ - coding/sdx2_decoder.o \ - coding/ws_decoder.o \ - coding/mpeg_decoder.o \ - coding/acm_decoder.o \ - coding/nwa_decoder.o \ - coding/msadpcm_decoder.o \ - coding/aica_decoder.o \ - coding/nds_procyon_decoder.o \ - coding/l5_555_decoder.o \ - coding/SASSC_decoder.o \ - coding/g7221_decoder.o \ - coding/lsf_decoder.o \ - coding/mtaf_decoder.o \ - coding/at3_decoder.o \ - coding/g719_decoder.o \ - coding/hca_decoder.o \ - coding/ffmpeg_decoder.o \ - coding/coding_utils.o \ - coding/fsb_vorbis_decoder.o \ - coding/wwise_vorbis_decoder.o \ - coding/wwise_vorbis_utils.o \ - coding/ogl_vorbis_decoder.o \ - coding/mc3_decoder.o +# get all .c to find all possible .o +SRC_SRCS = $(wildcard *.c) +SRC_OBJS = $(patsubst %.c,%.o,$(SRC_SRCS)) -LAYOUT_OBJS=layout/ast_blocked.o \ - layout/blocked.o \ - layout/halpst_blocked.o \ - layout/interleave.o \ - layout/nolayout.o \ - layout/xa_blocked.o \ - layout/caf_blocked.o \ - layout/ea_block.o \ - layout/wsi_blocked.o \ - layout/str_snds_blocked.o \ - layout/ws_aud_blocked.o \ - layout/interleave_byte.o \ - layout/mus_acm_layout.o \ - layout/aix_layout.o \ - layout/ims_block.o \ - layout/de2_blocked.o \ - layout/xvas_block.o \ - layout/vs_blocked.o \ - layout/emff_blocked.o \ - layout/thp_blocked.o \ - layout/gsb_blocked.o \ - layout/filp_blocked.o \ - layout/aax_layout.o \ - layout/ivaud_layout.o \ - layout/mxch_blocked.o \ - layout/psx_mgav_blocked.o \ - layout/ps2_adm_blocked.o \ - layout/bdsp_blocked.o \ - layout/tra_blocked.o \ - layout/ps2_iab_blocked.o \ - layout/ps2_strlr_blocked.o \ - layout/scd_int_layout.o +CODING_SRCS = $(wildcard coding/*.c) +CODING_OBJS = $(patsubst %.c,%.o,$(CODING_SRCS)) -META_OBJS=meta/adx.o \ - meta/afc_header.o \ - meta/agsc.o \ - meta/ast.o \ - meta/brstm.o \ - meta/halpst.o \ - meta/nds_strm.o \ - meta/ngc_adpdtk.o \ - meta/rsf.o \ - meta/rs03.o \ - meta/ngc_dsp_std.o \ - meta/Cstr.o \ - meta/gcsw.o \ - meta/ps2_ads.o \ - meta/ps2_npsf.o \ - meta/rwsd.o \ - meta/psx_cdxa.o \ - meta/ps2_rxw.o \ - meta/ps2_int.o \ - meta/ps2_exst.o \ - meta/ps2_svag.o \ - meta/ps2_mib.o \ - meta/ps2_mic.o \ - meta/raw.o \ - meta/ps2_vag.o \ - meta/psx_gms.o \ - meta/ps2_str.o \ - meta/ps2_ild.o \ - meta/ps2_pnb.o \ - meta/xbox_wavm.o \ - meta/xbox_xwav.o \ - meta/ea_header.o \ - meta/ngc_caf.o \ - meta/ps2_vpk.o \ - meta/genh.o \ - meta/ogg_vorbis_file.o \ - meta/ps2_bmdx.o \ - meta/aifc.o \ - meta/str_snds.o \ - meta/ws_aud.o \ - meta/ahx.o \ - meta/ivb.o \ - meta/svs.o \ - meta/riff.o \ - meta/pos.o \ - meta/nwa.o \ - meta/ps2_rws.o \ - meta/ps2_hgc1.o \ - meta/xss.o \ - meta/ps2_sl3.o \ - meta/ps2_aus.o \ - meta/fsb.o \ - meta/fsb5.o \ - meta/rsd.o \ - meta/rwx.o \ - meta/xwb.o \ - meta/ea_old.o \ - meta/ps2_xa30.o \ - meta/musc.o \ - meta/musx.o \ - meta/ps2_leg.o \ - meta/ps2_filp.o \ - meta/ps2_ikm.o \ - meta/ps2_sfs.o \ - meta/sat_dvi.o \ - meta/ps2_bg00.o \ - meta/dc_kcey.o \ - meta/ps2_rstm.o \ - meta/acm.o \ - meta/mus_acm.o \ - meta/ps2_kces.o \ - meta/ps2_dxh.o \ - meta/ps2_psh.o \ - meta/sli.o \ - meta/sfl.o \ - meta/pcm.o \ - meta/ps2_psw.o \ - meta/rkv.o \ - meta/ps2_vas.o \ - meta/ps2_tec.o \ - meta/ps2_enth.o \ - meta/sdt.o \ - meta/aix.o \ - meta/ngc_tydsp.o \ - meta/wvs.o \ - meta/xbox_ims.o \ - meta/xbox_stma.o \ - meta/de2.o \ - meta/dc_str.o \ - meta/xbox_xmu.o \ - meta/ngc_bh2pcm.o \ - meta/xbox_xvas.o \ - meta/sat_sap.o \ - meta/sat_sap.o \ - meta/dc_idvi.o \ - meta/ps2_rnd.o \ - meta/kraw.o \ - meta/ps2_xa2.o \ - meta/idsp.o \ - meta/ngc_ymf.o \ - meta/nds_sad.o \ - meta/ps2_ccc.o \ - meta/psx_fag.o \ - meta/ps2_mihb.o \ - meta/ngc_pdt.o \ - meta/wii_mus.o \ - meta/dc_asd.o \ - meta/naomi_spsd.o \ - meta/bgw.o \ - meta/ps2_ass.o \ - meta/ngc_waa_wac_wad_wam.o \ - meta/seg.o \ - meta/str_asr.o \ - meta/zwdsp.o \ - meta/gca.o \ - meta/ish_isd.o \ - meta/spt_spd.o \ - meta/ydsp.o \ - meta/gsp_gsb.o \ - meta/ngc_ssm.o \ - meta/msvp.o \ - meta/ps2_joe.o \ - meta/vgs.o \ - meta/vs.o \ - meta/dc_dcsw_dcs.o \ - meta/wii_smp.o \ - meta/ss_stream.o \ - meta/emff.o \ - meta/thp.o \ - meta/wii_sts.o \ - meta/capdsp.o \ - meta/wii_sng.o \ - meta/aax.o \ - meta/ps2_p2bt.o \ - meta/ps2_gbts.o \ - meta/ngc_ffcc_str.o \ - meta/sat_baka.o \ - meta/nds_swav.o \ - meta/vsf.o \ - meta/nds_rrds.o \ - meta/ps2_tk5.o \ - meta/ads.o \ - meta/wii_str.o \ - meta/zsd.o \ - meta/ps2_mcg.o \ - meta/redspark.o \ - meta/ps2_vgs.o \ - meta/ivaud.o \ - meta/ps2_sps.o \ - meta/nds_hwas.o \ - meta/ngc_lps.o \ - meta/ps2_snd.o \ - meta/naomi_adpcm.o \ - meta/sd9.o \ - meta/2dx9.o \ - meta/ngc_dsp_ygo.o \ - meta/ps2_vgv.o \ - meta/ngc_gcub.o \ - meta/maxis_xa.o \ - meta/ngc_sck_dsp.o \ - meta/apple_caff.o \ - meta/pc_mxst.o \ - meta/pc_sob.o \ - meta/exakt_sc.o \ - meta/wii_bns.o \ - meta/pona.o \ - meta/xbox_hlwav.o \ - meta/stx.o \ - meta/ps2_stm.o \ - meta/myspd.o \ - meta/his.o \ - meta/ps2_ast.o \ - meta/dmsg_segh.o \ - meta/ngc_dsp_konami.o \ - meta/ps2_ster.o \ - meta/ps2_wb.o \ - meta/bnsf.o \ - meta/s14_sss.o \ - meta/ps2_gcm.o \ - meta/ps2_smpl.o \ - meta/ps2_msa.o \ - meta/pc_smp.o \ - meta/p3d.o \ - meta/ps2_adsc.o \ - meta/psx_str_mgav.o \ - meta/ngc_bo2.o \ - meta/ngc_dsp_mpds.o \ - meta/ps2_khv.o \ - meta/ps2_voi.o \ - meta/dsp_sth_str.o \ - meta/ps2_b1s.o \ - meta/ps2_wad.o \ - meta/ps2_voi.o \ - meta/ps2_lpcm.o \ - meta/ps2_adm.o \ - meta/dsp_bdsp.o \ - meta/ps2_vms.o \ - meta/ps2_xau.o \ - meta/gh3_bar.o \ - meta/ffw.o \ - meta/ps2_jstm.o \ - meta/ps3_xvag.o \ - meta/ps3_cps.o \ - meta/sqex_scd.o \ - meta/ngc_nst_dsp.o \ - meta/baf.o \ - meta/ps3_msf.o \ - meta/nub_vag.o \ - meta/ps3_past.o \ - meta/sgxd.o \ - meta/ngca.o \ - meta/wii_ras.o \ - meta/ps2_spm.o \ - meta/ps2_mtaf.o \ - meta/x360_tra.o \ - meta/ps2_iab.o \ - meta/ps2_strlr.o \ - meta/lsf.o \ - meta/vawx.o \ - meta/pc_snds.o \ - meta/ps2_wmus.o \ - meta/mattel_hyperscan.o \ - meta/ios_psnd.o \ - meta/pc_adp.o \ - meta/excitebots.o \ - meta/ps3_klbs.o \ - meta/ps2_mtaf.o \ - meta/tun.o \ - meta/wpd.o \ - meta/mn_str.o \ - meta/ps2_mss.o \ - meta/ps2_hsf.o \ - meta/ps3_ivag.o \ - meta/ps2_2pfs.o \ - meta/ubi_ckd.o \ - meta/ps2_vbk.o \ - meta/otm.o \ - meta/bcstm.o \ - meta/bfstm.o \ - meta/bfwav.o \ - meta/g1l.o \ - meta/mca.o \ - meta/btsnd.o \ - meta/hca.o \ - meta/ps2_svag_snk.o \ - meta/ffmpeg.o \ - meta/mp4.o \ - meta/xma.o \ - meta/ps2_vds_vdm.o \ - meta/x360_cxs.o \ - meta/dsp_adx.o \ - meta/bik.o \ - meta/akb.o \ - meta/x360_ast.o \ - meta/wwise.o \ - meta/ubi_raki.o \ - meta/x360_nub.o \ - meta/x360_pasx.o \ - meta/sxd.o \ - meta/ogl.o \ - meta/mc3.o +LAYOUT_SRCS = $(wildcard layout/*.c) +LAYOUT_OBJS = $(patsubst %.c,%.o,$(LAYOUT_SRCS)) -EXT_LIBS = ../ext_libs/clHCA.o +META_SRCS = $(wildcard meta/*.c) +META_OBJS = $(patsubst %.c,%.o,$(META_SRCS)) -OBJECTS=vgmstream.o streamfile.o util.o formats.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS) $(EXT_LIBS) +EXT_LIBS_SRCS = $(wildcard ../ext_libs/*.c) +EXT_LIBS_OBJS = $(patsubst %.c,%.o,$(EXT_LIBS_SRCS)) + +OBJECTS = $(SRC_OBJS) $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS) $(EXT_LIBS_OBJS) libvgmstream.a: $(OBJECTS) $(AR) crs libvgmstream.a $(OBJECTS) From d364cf5a8d3438f207ded452cb043ac914c1c962 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 28 Apr 2017 20:10:18 +0200 Subject: [PATCH 06/16] Add AKB MSADPCM [various SFX]; improve AKB header parsing --- src/meta/akb.c | 50 +++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/meta/akb.c b/src/meta/akb.c index d8318047..40c8224c 100644 --- a/src/meta/akb.c +++ b/src/meta/akb.c @@ -36,11 +36,12 @@ fail: /* AKB - found in SQEX iOS games */ VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - off_t start_offset; - size_t filesize; + off_t start_offset, extra_data_offset = 0; + size_t file_size, header_size, extra_header_size = 0, extra_data_size = 0; int loop_flag = 0, channel_count, codec; /* check extensions */ + /* .akb.bytes is the usual extension in later games */ if ( !check_extensions(streamFile, "akb") ) goto fail; @@ -55,35 +56,47 @@ VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) { vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* 0x04: version? (iPad/IPhone?) 0x24: file_id? */ - filesize = read_32bitLE(0x08,streamFile); + /* 0x04 (2): version (iPad/IPhone?) */ + header_size = read_16bitLE(0x06,streamFile); + file_size = read_32bitLE(0x08,streamFile); codec = read_8bit(0x0c,streamFile); vgmstream->sample_rate = (uint16_t)read_16bitLE(0x0e,streamFile); vgmstream->num_samples = read_32bitLE(0x10,streamFile); vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile); - vgmstream->loop_end_sample = read_32bitLE(0x18,streamFile); - /* 0x0c: some size based on codec 0x10+: unk stuff? 0xc0+: data stuff? */ + vgmstream->loop_end_sample = read_32bitLE(0x18,streamFile); vgmstream->meta_type = meta_AKB; + /* should be ok but not exact (probably more complex, see AKB2) */ + if ( header_size >= 0x44) { /* v2 */ + /* 0x10+: config? (pan, volume), 0x24: file_id? */ + extra_data_size = read_16bitLE(0x1c,streamFile); + extra_header_size = read_16bitLE(0x28,streamFile); + extra_data_offset = header_size + extra_header_size; + start_offset = extra_data_offset + extra_data_size; + /* ~num_samples at extra_data_offset + 0x04/0x0c? */ + } + else { /* v0 */ + start_offset = header_size; + } + + switch (codec) { -#if 0 - case 0x02: { /* some kind of ADPCM or PCM [various SFX] */ - start_offset = 0xC4; - vgmstream->coding_type = coding_APPLE_IMA4; - vgmstream->layout_type = channel_count==1 ? layout_none : layout_interleave; - vgmstream->interleave_block_size = 0x100; + case 0x02: { /* MSAPDCM [various SFX] */ + vgmstream->coding_type = coding_MSADPCM; + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = read_16bitLE(extra_data_offset + 0x02,streamFile); + + vgmstream->num_samples = read_32bitLE(extra_data_offset + 0x04, streamFile); /* lower than header num_samples */ break; } -#endif #ifdef VGM_USE_FFMPEG case 0x05: { /* ogg vorbis [Final Fantasy VI, Dragon Quest II-VI] */ /* Starting from an offset in the current libvorbis code is a bit hard so just use FFmpeg. - * Decoding seems to produce the same output with (inaudible) +-1 lower byte differences here and there. */ + * Decoding seems to produce the same output with (inaudible) +-1 lower byte differences due to rounding. */ ffmpeg_codec_data *ffmpeg_data; - start_offset = 0xCC; - ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,filesize-start_offset); + ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,file_size-start_offset); if ( !ffmpeg_data ) goto fail; vgmstream->codec_data = ffmpeg_data; @@ -98,8 +111,7 @@ VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) { /* init_vgmstream_akb above has priority, but this works fine too */ ffmpeg_codec_data *ffmpeg_data; - start_offset = 0x20; - ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,filesize-start_offset); + ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,file_size-start_offset); if ( !ffmpeg_data ) goto fail; vgmstream->codec_data = ffmpeg_data; @@ -115,7 +127,6 @@ VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) { } #endif - /* AAC @20 in some cases? (see above) */ default: goto fail; } @@ -141,6 +152,7 @@ VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile) { int akb_header_size, sound_index = 0, sound_offset_data, sound, sound_header_size, material_offset_data, material_index = 0, material, extradata, encryption_flag; /* check extensions */ + /* .akb.bytes is the usual extension in later games */ if ( !check_extensions(streamFile, "akb") ) goto fail; From 3d9e48a03f8074baef38d1b61dafa9b5021d6caf Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 29 Apr 2017 02:04:10 +0200 Subject: [PATCH 07/16] Remove unused 2dx.c, 2dx9 is used instead --- src/meta/2dx.c | 69 -------------------------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 src/meta/2dx.c diff --git a/src/meta/2dx.c b/src/meta/2dx.c deleted file mode 100644 index 3993fa39..00000000 --- a/src/meta/2dx.c +++ /dev/null @@ -1,69 +0,0 @@ -#include "meta.h" -#include "../util.h" - -/* 2DX (found in beatmaniaIIDX16 - EMPRESS (Arcade) */ -VGMSTREAM * init_vgmstream_2dx(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("2dx",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x32445839) /* 2DX9 */ - goto fail; - if (read_32bitBE(0x18,streamFile) != 0x52494646) /* RIFF */ - goto fail; - if (read_32bitBE(0x20,streamFile) != 0x57415645) /* WAVE */ - goto fail; - if (read_32bitBE(0x24,streamFile) != 0x666D7420) /* fmt */ - goto fail; - if (read_32bitBE(0x6a,streamFile) != 0x64617461) /* data */ - goto fail; - - loop_flag = 0; - channel_count = read_16bitLE(0x2e,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x72; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x30,streamFile); - vgmstream->coding_type = coding_MSADPCM; - vgmstream->num_samples = read_32bitLE(0x66,streamFile); - vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = read_16bitLE(0x38,streamFile); - vgmstream->meta_type = meta_2DX9; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} From 75d079f3894b581b0a8f77b471cc322bd9fe324a Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 29 Apr 2017 02:19:27 +0200 Subject: [PATCH 08/16] Add block size (interleave) description for MSAPDCM/MS-IMA/etc --- src/vgmstream.c | 55 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/src/vgmstream.c b/src/vgmstream.c index 1d4ab085..2a20524a 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1955,18 +1955,22 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { const char* description; if (!vgmstream) { - snprintf(temp,TEMPSIZE,"NULL VGMSTREAM"); + snprintf(temp,TEMPSIZE, + "NULL VGMSTREAM"); concatn(length,desc,temp); return; } - snprintf(temp,TEMPSIZE,"sample rate: %d Hz\n" + snprintf(temp,TEMPSIZE, + "sample rate: %d Hz\n" "channels: %d\n", - vgmstream->sample_rate,vgmstream->channels); + vgmstream->sample_rate, + vgmstream->channels); concatn(length,desc,temp); if (vgmstream->loop_flag) { - snprintf(temp,TEMPSIZE,"loop start: %d samples (%.4f seconds)\n" + snprintf(temp,TEMPSIZE, + "loop start: %d samples (%.4f seconds)\n" "loop end: %d samples (%.4f seconds)\n", vgmstream->loop_start_sample, (double)vgmstream->loop_start_sample/vgmstream->sample_rate, @@ -1975,12 +1979,14 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { concatn(length,desc,temp); } - snprintf(temp,TEMPSIZE,"stream total samples: %d (%.4f seconds)\n", + snprintf(temp,TEMPSIZE, + "stream total samples: %d (%.4f seconds)\n", vgmstream->num_samples, (double)vgmstream->num_samples/vgmstream->sample_rate); concatn(length,desc,temp); - snprintf(temp,TEMPSIZE,"encoding: "); + snprintf(temp,TEMPSIZE, + "encoding: "); concatn(length,desc,temp); switch (vgmstream->coding_type) { #ifdef VGM_USE_FFMPEG @@ -2009,7 +2015,8 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { } concatn(length,desc,temp); - snprintf(temp,TEMPSIZE,"\nlayout: "); + snprintf(temp,TEMPSIZE, + "\nlayout: "); concatn(length,desc,temp); switch (vgmstream->layout_type) { default: @@ -2021,26 +2028,46 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { } concatn(length,desc,temp); - snprintf(temp,TEMPSIZE,"\n"); + snprintf(temp,TEMPSIZE, + "\n"); concatn(length,desc,temp); if (vgmstream->layout_type == layout_interleave || vgmstream->layout_type == layout_interleave_shortblock || vgmstream->layout_type == layout_interleave_byte) { - snprintf(temp,TEMPSIZE,"interleave: %#x bytes\n", + snprintf(temp,TEMPSIZE, + "interleave: %#x bytes\n", (int32_t)vgmstream->interleave_block_size); concatn(length,desc,temp); if (vgmstream->layout_type == layout_interleave_shortblock) { - snprintf(temp,TEMPSIZE,"last block interleave: %#x bytes\n", + snprintf(temp,TEMPSIZE, + "last block interleave: %#x bytes\n", (int32_t)vgmstream->interleave_smallblock_size); concatn(length,desc,temp); } } - snprintf(temp,TEMPSIZE,"metadata from: "); - concatn(length,desc,temp); + /* codecs with blocks + headers (there are more, this is a start) */ + if (vgmstream->layout_type == layout_none && vgmstream->interleave_block_size > 0) { + switch (vgmstream->coding_type) { + case coding_MSADPCM: + case coding_MS_IMA: + case coding_MC3: + case coding_WWISE_IMA: + snprintf(temp,TEMPSIZE, + "block size: %#x bytes\n", + (int32_t)vgmstream->interleave_block_size); + concatn(length,desc,temp); + break; + default: + break; + } + } + snprintf(temp,TEMPSIZE, + "metadata from: "); + concatn(length,desc,temp); switch (vgmstream->meta_type) { default: description = get_vgmstream_meta_description(vgmstream->meta_type); @@ -2053,7 +2080,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { /* only interesting if more than one */ if (vgmstream->num_streams > 1) { - snprintf(temp,TEMPSIZE,"\nnumber of streams: %d",vgmstream->num_streams); + snprintf(temp,TEMPSIZE, + "\nnumber of streams: %d", + vgmstream->num_streams); concatn(length,desc,temp); } } From 086a47cd76517ff4411419945197e545dcbd2cf1 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 29 Apr 2017 02:20:24 +0200 Subject: [PATCH 09/16] Add compiler flag VGM_DISABLE_VORBIS (as Vorbis is enabled by default) --- src/vgmstream.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vgmstream.h b/src/vgmstream.h index 5c586b64..c1a5180c 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -13,9 +13,10 @@ enum { PATH_LIMIT = 32768 }; * done by external libraries. * If someone wants to do a standalone build, they can do it by simply * removing these defines (and the references to the libraries in the Makefile) */ +#ifndef VGM_DISABLE_VORBIS #define VGM_USE_VORBIS +#endif -/* can be disabled to decode with FFmpeg instead */ #ifndef VGM_DISABLE_MPEG #define VGM_USE_MPEG #endif From d5aee307f0cab66c31b47b48db699c696d0fd02a Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 29 Apr 2017 02:53:36 +0200 Subject: [PATCH 10/16] Rename coding_INT_X to coding_X_int for consistency with other codecs --- src/formats.c | 14 +++++++------- src/meta/ads.c | 2 +- src/meta/bcstm.c | 2 +- src/meta/dc_idvi.c | 2 +- src/meta/genh.c | 4 ++-- src/meta/ivaud.c | 2 +- src/meta/nds_hwas.c | 2 +- src/meta/nds_sad.c | 6 +++--- src/meta/nds_strm.c | 2 +- src/meta/nds_swav.c | 4 ++-- src/meta/ps2_snd.c | 2 +- src/meta/ps2_stm.c | 2 +- src/meta/sat_dvi.c | 2 +- src/meta/xbox_stma.c | 2 +- src/vgmstream.c | 18 +++++++++--------- src/vgmstream.h | 10 +++++----- 16 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/formats.c b/src/formats.c index 99cc2852..11776810 100644 --- a/src/formats.c +++ b/src/formats.c @@ -404,7 +404,7 @@ static const coding_info coding_info_list[] = { {coding_HEVAG, "Playstation Vita HEVAG 4-bit ADPCM"}, {coding_XA, "CD-ROM XA 4-bit ADPCM"}, {coding_XBOX, "XBOX 4-bit IMA ADPCM"}, - {coding_INT_XBOX, "XBOX 4-bit IMA ADPCM (interleaved)"}, + {coding_XBOX_int, "XBOX 4-bit IMA ADPCM (interleaved)"}, {coding_EA_XA, "Electronic Arts 4-bit ADPCM (XA based)"}, {coding_EA_ADPCM, "Electronic Arts R1 4-bit ADPCM (XA based)"}, {coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"}, @@ -412,20 +412,20 @@ static const coding_info coding_info_list[] = { {coding_CBD2, "Cuberoot-delta-exact (CBD2) 8-bit DPCM"}, {coding_CBD2_int, "Cuberoot-delta-exact (CBD2) 8-bit DPCM with 1 byte interleave"}, {coding_DVI_IMA, "Intel DVI 4-bit IMA ADPCM"}, - {coding_INT_DVI_IMA, "Interleaved Intel DVI 4-bit IMA ADPCM"}, + {coding_DVI_IMA_int, "Intel DVI 4-bit IMA ADPCM (interleaved)"}, {coding_EACS_IMA, "EACS 4-bit IMA ADPCM"}, {coding_MAXIS_ADPCM, "Maxis XA (EA ADPCM Variant)"}, - {coding_INT_IMA, "Interleaved 4-bit IMA ADPCM"}, - {coding_IMA, "4-bit IMA ADPCM"}, + {coding_IMA_int, "IMA 4-bit ADPCM (interleaved)"}, + {coding_IMA, "IMA 4-bit ADPCM"}, {coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"}, - {coding_RAD_IMA, "'Radical' 4-bit IMA ADPCM"}, - {coding_RAD_IMA_mono, "'Radical' 4-bit IMA ADPCM (mono)"}, + {coding_RAD_IMA, "Radical 4-bit IMA ADPCM"}, + {coding_RAD_IMA_mono, "Radical 4-bit IMA ADPCM (mono)"}, {coding_APPLE_IMA4, "Apple Quicktime 4-bit IMA ADPCM"}, {coding_SNDS_IMA, "Heavy Iron .snds 4-bit IMA ADPCM"}, {coding_OTNS_IMA, "Omikron: The Nomad Soul 4-bit IMA ADPCM"}, {coding_FSB_IMA, "FSB multichannel 4-bit IMA ADPCM"}, {coding_WWISE_IMA, "Audiokinetic Wwise 4-bit IMA ADPCM"}, - {coding_WS, "Westwood Studios ADPCM"}, + {coding_WS, "Westwood Studios VBR ADPCM"}, {coding_ACM, "InterPlay ACM"}, {coding_NWA0, "NWA DPCM Level 0"}, {coding_NWA1, "NWA DPCM Level 1"}, diff --git a/src/meta/ads.c b/src/meta/ads.c index f555b87d..f3a8c091 100644 --- a/src/meta/ads.c +++ b/src/meta/ads.c @@ -59,7 +59,7 @@ VGMSTREAM * init_vgmstream_ads(STREAMFILE *streamFile) { start_offset = 0x28; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitBE(0x0c,streamFile); - vgmstream->coding_type = coding_INT_XBOX; + vgmstream->coding_type = coding_XBOX_int; vgmstream->num_samples = (read_32bitBE(0x24,streamFile) / 36 *64 / vgmstream->channels)-64; // to avoid the "pop" at the loop point vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave; vgmstream->interleave_block_size = 0x24; diff --git a/src/meta/bcstm.c b/src/meta/bcstm.c index 66fdab2f..93bb1d3e 100644 --- a/src/meta/bcstm.c +++ b/src/meta/bcstm.c @@ -75,7 +75,7 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) { if (seek_offset == 0) goto fail; if ((uint32_t)read_32bitBE(seek_offset, streamFile) != 0x5345454B) { /* "SEEK" If this header doesn't exist, assuming that the file is IMA */ ima = 1; - coding_type = coding_INT_IMA; + coding_type = coding_IMA_int; } else coding_type = coding_NGC_DSP; diff --git a/src/meta/dc_idvi.c b/src/meta/dc_idvi.c index 60df792a..a3962d5f 100644 --- a/src/meta/dc_idvi.c +++ b/src/meta/dc_idvi.c @@ -29,7 +29,7 @@ VGMSTREAM * init_vgmstream_dc_idvi(STREAMFILE *streamFile) { vgmstream->channels = channel_count; start_offset = 0x800; vgmstream->sample_rate = read_32bitLE(0x08,streamFile); - vgmstream->coding_type = coding_INT_DVI_IMA; + vgmstream->coding_type = coding_DVI_IMA_int; vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset); if (loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x0C,streamFile); diff --git a/src/meta/genh.c b/src/meta/genh.c index 6285a64a..ad6a59be 100644 --- a/src/meta/genh.c +++ b/src/meta/genh.c @@ -173,9 +173,9 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { else { vgmstream->layout_type = layout_interleave; if(coding==coding_DVI_IMA) - coding=coding_INT_DVI_IMA; + coding=coding_DVI_IMA_int; if(coding==coding_IMA) - coding=coding_INT_IMA; + coding=coding_IMA_int; } } else { vgmstream->layout_type = layout_none; diff --git a/src/meta/ivaud.c b/src/meta/ivaud.c index 84d52c62..0d585207 100644 --- a/src/meta/ivaud.c +++ b/src/meta/ivaud.c @@ -36,7 +36,7 @@ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) { block_table_offset = read_32bitLE(0,streamFile); vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(block_table_offset + 0x04,streamFile); - vgmstream->coding_type = coding_INT_IMA; + vgmstream->coding_type = coding_IMA_int; vgmstream->layout_type = layout_ivaud_blocked; vgmstream->meta_type = meta_PC_IVAUD; diff --git a/src/meta/nds_hwas.c b/src/meta/nds_hwas.c index 7774f6d8..da727ea8 100644 --- a/src/meta/nds_hwas.c +++ b/src/meta/nds_hwas.c @@ -28,7 +28,7 @@ VGMSTREAM * init_vgmstream_nds_hwas(STREAMFILE *streamFile) { start_offset = 0x200; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x08,streamFile); - vgmstream->coding_type = coding_INT_IMA; + vgmstream->coding_type = coding_IMA_int; vgmstream->num_samples = read_32bitLE(0x14,streamFile); if (loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x10,streamFile); diff --git a/src/meta/nds_sad.c b/src/meta/nds_sad.c index b49f91d4..af3c7262 100644 --- a/src/meta/nds_sad.c +++ b/src/meta/nds_sad.c @@ -27,7 +27,7 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) { switch (read_8bit(0x33,streamFile)&0xf0) { case 0x70: - coding_type = coding_INT_IMA; + coding_type = coding_IMA_int; break; case 0xb0: coding_type = coding_NDS_PROCYON; @@ -61,7 +61,7 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) { vgmstream->coding_type = coding_type; - if (coding_type == coding_INT_IMA) + if (coding_type == coding_IMA_int) vgmstream->num_samples = (read_32bitLE(0x40,streamFile)-start_offset)/channel_count*2; else if (coding_type == coding_NDS_PROCYON) @@ -72,7 +72,7 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) { if (loop_flag) { - if (coding_type == coding_INT_IMA) + if (coding_type == coding_IMA_int) vgmstream->loop_start_sample = (read_32bitLE(0x54,streamFile)-start_offset)/channel_count*2; else vgmstream->loop_start_sample = (read_32bitLE(0x54,streamFile)-start_offset)/channel_count/16*30; diff --git a/src/meta/nds_strm.c b/src/meta/nds_strm.c index 74907203..74b9c7d2 100644 --- a/src/meta/nds_strm.c +++ b/src/meta/nds_strm.c @@ -134,7 +134,7 @@ VGMSTREAM * init_vgmstream_nds_strm_ffta2(STREAMFILE *streamFile) { start_offset = 0x2C; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x0C,streamFile); - vgmstream->coding_type = coding_INT_IMA; + vgmstream->coding_type = coding_IMA_int; vgmstream->num_samples = (read_32bitLE(0x04,streamFile)-start_offset); if (loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile); diff --git a/src/meta/nds_swav.c b/src/meta/nds_swav.c index b3ded873..2840641c 100644 --- a/src/meta/nds_swav.c +++ b/src/meta/nds_swav.c @@ -49,7 +49,7 @@ VGMSTREAM * init_vgmstream_nds_swav(STREAMFILE *streamFile) { bits_per_sample = 16; break; case 2: - coding_type = coding_INT_IMA; + coding_type = coding_IMA_int; bits_per_sample = 4; break; default: @@ -74,7 +74,7 @@ VGMSTREAM * init_vgmstream_nds_swav(STREAMFILE *streamFile) { vgmstream->loop_start_sample; } - if (coding_type == coding_INT_IMA) { + if (coding_type == coding_IMA_int) { /* handle IMA frame header */ vgmstream->loop_start_sample -= 32 / bits_per_sample; vgmstream->loop_end_sample -= 32 / bits_per_sample; diff --git a/src/meta/ps2_snd.c b/src/meta/ps2_snd.c index 5990a7b3..e1be6525 100644 --- a/src/meta/ps2_snd.c +++ b/src/meta/ps2_snd.c @@ -31,7 +31,7 @@ VGMSTREAM * init_vgmstream_ps2_snd(STREAMFILE *streamFile) { vgmstream->sample_rate = (uint16_t)read_16bitLE(0xe,streamFile); if(read_8bit(0x08,streamFile)==1) { - vgmstream->coding_type = coding_INT_DVI_IMA; + vgmstream->coding_type = coding_DVI_IMA_int; } else vgmstream->coding_type = coding_PCM16LE; diff --git a/src/meta/ps2_stm.c b/src/meta/ps2_stm.c index 5e391dba..eb03761f 100644 --- a/src/meta/ps2_stm.c +++ b/src/meta/ps2_stm.c @@ -33,7 +33,7 @@ VGMSTREAM * init_vgmstream_ps2_stm(STREAMFILE *streamFile) { start_offset = 0x800; vgmstream->sample_rate = (uint16_t)read_32bitLE(0xc,streamFile); - vgmstream->coding_type = coding_INT_DVI_IMA; + vgmstream->coding_type = coding_DVI_IMA_int; vgmstream->num_samples = read_32bitLE(0x18,streamFile); diff --git a/src/meta/sat_dvi.c b/src/meta/sat_dvi.c index 83e019c9..4c5f4529 100644 --- a/src/meta/sat_dvi.c +++ b/src/meta/sat_dvi.c @@ -29,7 +29,7 @@ VGMSTREAM * init_vgmstream_dvi(STREAMFILE *streamFile) { vgmstream->channels = channel_count; start_offset = read_32bitBE(0x04,streamFile); vgmstream->sample_rate = 44100; - vgmstream->coding_type = coding_INT_DVI_IMA; + vgmstream->coding_type = coding_DVI_IMA_int; vgmstream->num_samples = read_32bitBE(0x08,streamFile); diff --git a/src/meta/xbox_stma.c b/src/meta/xbox_stma.c index fb329334..a9675095 100644 --- a/src/meta/xbox_stma.c +++ b/src/meta/xbox_stma.c @@ -34,7 +34,7 @@ VGMSTREAM * init_vgmstream_xbox_stma(STREAMFILE *streamFile) { /* fill in the vital statistics */ vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x0C,streamFile); - vgmstream->coding_type = coding_INT_DVI_IMA; + vgmstream->coding_type = coding_DVI_IMA_int; vgmstream->num_samples = read_32bitLE(0x18,streamFile)*2/vgmstream->channels; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size=0x40; diff --git a/src/vgmstream.c b/src/vgmstream.c index 2a20524a..67e3ea16 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1071,8 +1071,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_IMA: case coding_OTNS_IMA: return 1; - case coding_INT_IMA: - case coding_INT_DVI_IMA: + case coding_IMA_int: + case coding_DVI_IMA_int: case coding_AICA: return 2; case coding_NGC_AFC: @@ -1086,7 +1086,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_PSX_cfg: return (vgmstream->interleave_block_size - 1) * 2; /* decodes 1 byte into 2 bytes */ case coding_XBOX: - case coding_INT_XBOX: + case coding_XBOX_int: case coding_FSB_IMA: return 64; case coding_EA_XA: @@ -1223,7 +1223,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_XA: return 14*vgmstream->channels; case coding_XBOX: - case coding_INT_XBOX: + case coding_XBOX_int: case coding_FSB_IMA: return 36; case coding_MAXIS_ADPCM: @@ -1234,8 +1234,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { return 1; // the frame is variant in size case coding_WS: return vgmstream->current_block_size; - case coding_INT_IMA: - case coding_INT_DVI_IMA: + case coding_IMA_int: + case coding_DVI_IMA_int: case coding_AICA: return 1; case coding_APPLE_IMA4: @@ -1400,7 +1400,7 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do,chan); } break; - case coding_INT_XBOX: + case coding_XBOX_int: for (chan=0;chanchannels;chan++) { decode_int_xbox_ima(vgmstream,&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, vgmstream->channels,vgmstream->samples_into_block, @@ -1586,7 +1586,7 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to } break; case coding_DVI_IMA: - case coding_INT_DVI_IMA: + case coding_DVI_IMA_int: for (chan=0;chanchannels;chan++) { decode_dvi_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, vgmstream->channels,vgmstream->samples_into_block, @@ -1601,7 +1601,7 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to } break; case coding_IMA: - case coding_INT_IMA: + case coding_IMA_int: for (chan=0;chanchannels;chan++) { decode_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, vgmstream->channels,vgmstream->samples_into_block, diff --git a/src/vgmstream.h b/src/vgmstream.h index c1a5180c..42dd5ae2 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -107,16 +107,16 @@ typedef enum { coding_NDS_PROCYON, /* Procyon Studio ADPCM */ coding_XBOX, /* XBOX IMA ADPCM */ - coding_INT_XBOX, /* XBOX IMA ADPCM (interleaved) */ + coding_XBOX_int, /* XBOX IMA ADPCM (interleaved) */ coding_IMA, /* IMA ADPCM (low nibble first) */ - coding_INT_IMA, /* IMA ADPCM (interleaved) */ + coding_IMA_int, /* IMA ADPCM (interleaved) */ coding_DVI_IMA, /* DVI IMA ADPCM (high nibble first), aka ADP4 */ - coding_INT_DVI_IMA, /* DVI IMA ADPCM (Interleaved) */ + coding_DVI_IMA_int, /* DVI IMA ADPCM (Interleaved) */ coding_NDS_IMA, /* IMA ADPCM w/ NDS layout */ coding_EACS_IMA, coding_MS_IMA, /* Microsoft IMA */ - coding_RAD_IMA, /* "Radical ADPCM" IMA */ - coding_RAD_IMA_mono, /* "Radical ADPCM" IMA, mono (for interleave) */ + coding_RAD_IMA, /* Radical IMA ADPCM */ + coding_RAD_IMA_mono, /* Radical IMA ADPCM, mono (for interleave) */ coding_APPLE_IMA4, /* Apple Quicktime IMA4 */ coding_DAT4_IMA, /* Eurocom 'DAT4' IMA ADPCM */ coding_SNDS_IMA, /* Heavy Iron Studios .snds IMA ADPCM */ From fd72f6120a1b7ddaaf5b7801ca4b5e63c13ff288 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 29 Apr 2017 16:03:11 +0200 Subject: [PATCH 11/16] Adjust EOF reads; minor cleanup When reading over filesize (buggy metas that request more samples than possible) it returned inconsistent results under some conditions/interleave sizes (the effect was minimal though) --- fb2k/foostream.cpp | 96 ++++++++++++++++++++++------------- src/streamfile.c | 121 +++++++++++++++++++++++++++------------------ 2 files changed, 135 insertions(+), 82 deletions(-) diff --git a/fb2k/foostream.cpp b/fb2k/foostream.cpp index d9d03602..9d3430d8 100644 --- a/fb2k/foostream.cpp +++ b/fb2k/foostream.cpp @@ -18,23 +18,29 @@ extern "C" { } #include "foo_vgmstream.h" +/* On EOF reads we can return length 0, or ignore and return the requested length + 0-set the buffer. + * Some decoders don't check for EOF and may decode garbage if returned 0, as read_Nbit() funcs return -1. + * Only matters for metas that get num_samples wrong (bigger than total data). */ +#define STREAMFILE_IGNORE_EOF 0 + static size_t read_the_rest_foo(uint8_t * dest, off_t offset, size_t length, FOO_STREAMFILE * streamfile) { size_t length_read_total=0; - /* is the beginning at least there? */ - if (offset >= streamfile->offset && offset < streamfile->offset+streamfile->validsize) { + /* is the part of the requested length in the buffer? */ + if (offset >= streamfile->offset && offset < streamfile->offset + streamfile->validsize) { size_t length_read; - off_t offset_into_buffer = offset-streamfile->offset; - length_read = streamfile->validsize-offset_into_buffer; - memcpy(dest,streamfile->buffer+offset_into_buffer,length_read); + off_t offset_into_buffer = offset - streamfile->offset; + length_read = streamfile->validsize - offset_into_buffer; + + memcpy(dest,streamfile->buffer + offset_into_buffer,length_read); length_read_total += length_read; length -= length_read; offset += length_read; dest += length_read; } - /* TODO: What would make more sense here is to read the whole request + /* What would make more sense here is to read the whole request * at once into the dest buffer, as it must be large enough, and then * copy some part of that into our own buffer. * The destination buffer is supposed to be much smaller than the @@ -42,17 +48,22 @@ static size_t read_the_rest_foo(uint8_t * dest, off_t offset, size_t length, FOO * to the buffer size to avoid having to deal with things like this * which are outside of my intended use. */ - /* read as much of the beginning of the request as possible, proceed */ - while (length>0) { + /* read the rest of the requested length */ + while (length > 0) { size_t length_to_read; size_t length_read; - streamfile->validsize=0; + streamfile->validsize = 0; /* buffer is empty now */ /* request outside file: ignore to avoid seek/read */ if (offset > streamfile->filesize) { streamfile->offset = streamfile->filesize; - memset(dest,0,length); - return length; /* return partially-read buffer and 0-set the rest */ + +#if STREAMFILE_IGNORE_EOF + memset(dest,0,length); /* dest is already shifted */ + return length_read_total + length; /* partially-read + 0-set buffer */ +#else + return length_read_total; /* partially-read buffer */ +#endif } /* position to new offset */ @@ -65,43 +76,49 @@ static size_t read_the_rest_foo(uint8_t * dest, off_t offset, size_t length, FOO #ifdef PROFILE_STREAMFILE streamfile->error_count++; #endif - return 0; //fail miserably + return 0; /* fail miserably (fseek shouldn't fail and reach this) */ } - - streamfile->offset=offset; + streamfile->offset = offset; /* decide how much must be read this time */ - if (length>streamfile->buffersize) length_to_read=streamfile->buffersize; - else length_to_read=length; + if (length > streamfile->buffersize) + length_to_read = streamfile->buffersize; + else + length_to_read = length; - /* always try to fill the buffer */ + /* fill the buffer */ try { length_read = streamfile->m_file->read(streamfile->buffer,streamfile->buffersize,*streamfile->p_abort); } catch(...) { #ifdef PROFILE_STREAMFILE streamfile->error_count++; #endif - return 0; //fail miserably + return 0; /* fail miserably */ } - streamfile->validsize=length_read; + streamfile->validsize = length_read; #ifdef PROFILE_STREAMFILE streamfile->bytes_read += length_read; #endif - /* if we can't get enough to satisfy the request we give up */ + /* if we can't get enough to satisfy the request (EOF) we give up */ if (length_read < length_to_read) { memcpy(dest,streamfile->buffer,length_read); - length_read_total+=length_read; - return length_read_total; + +#if STREAMFILE_IGNORE_EOF + memset(dest+length_read,0,length-length_read); + return length_read_total + length; /* partially-read + 0-set buffer */ +#else + return length_read_total + length_read; /* partially-read buffer */ +#endif } /* use the new buffer */ memcpy(dest,streamfile->buffer,length_to_read); - length_read_total+=length_to_read; - length-=length_to_read; - dest+=length_to_read; - offset+=length_to_read; + length_read_total += length_to_read; + length -= length_to_read; + dest += length_to_read; + offset += length_to_read; } return length_read_total; @@ -109,23 +126,32 @@ static size_t read_the_rest_foo(uint8_t * dest, off_t offset, size_t length, FOO static size_t read_foo(FOO_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) { - if (!streamfile || !dest || length<=0) return 0; - - /* if entire request is within the buffer */ - if (offset >= streamfile->offset && offset+length <= streamfile->offset+streamfile->validsize) { - memcpy(dest,streamfile->buffer+(offset-streamfile->offset),length); - return length; - } + if (!streamfile || !dest || length<=0) + return 0; /* request outside file: ignore to avoid seek/read in read_the_rest_foo() */ if (offset > streamfile->filesize) { streamfile->offset = streamfile->filesize; - memset(dest, 0, length); + +#if STREAMFILE_IGNORE_EOF + memset(dest,0,length); + return length; /* 0-set buffer */ +#else + return 0; /* nothing to read */ +#endif + } + + /* just copy if entire request is within the buffer */ + if (offset >= streamfile->offset && offset + length <= streamfile->offset + streamfile->validsize) { + off_t offset_into_buffer = offset - streamfile->offset; + memcpy(dest,streamfile->buffer + offset_into_buffer,length); return length; } /* request outside buffer: new fread */ - return read_the_rest_foo(dest,offset,length,streamfile); + { + return read_the_rest_foo(dest,offset,length,streamfile); + } } STREAMFILE * open_foo_streamfile(const char * const filename, abort_callback * p_abort, t_filestats * stats) { diff --git a/src/streamfile.c b/src/streamfile.c index f1125eda..26bada22 100644 --- a/src/streamfile.c +++ b/src/streamfile.c @@ -5,15 +5,23 @@ #include "util.h" #include "vgmstream.h" + +/* On EOF reads we can return length 0, or ignore and return the requested length + 0-set the buffer. + * Some decoders don't check for EOF and may decode garbage if returned 0, as read_Nbit() funcs return -1. + * Only matters for metas that get num_samples wrong (bigger than total data). */ +#define STREAMFILE_IGNORE_EOF 0 + + +/* buffered file reader */ typedef struct { - STREAMFILE sf; - FILE * infile; + STREAMFILE sf; /* callbacks */ + FILE * infile; /* actual FILE */ char name[PATH_LIMIT]; - off_t offset; - size_t validsize; - uint8_t * buffer; - size_t buffersize; - size_t filesize; + off_t offset; /* current offset */ + size_t validsize; /* current buffer size */ + uint8_t * buffer; /* data buffer */ + size_t buffersize; /* max buffer size */ + size_t filesize; /* cached file size (max offset) */ #ifdef VGM_DEBUG_OUTPUT int error_notified; #endif @@ -28,19 +36,20 @@ static STREAMFILE * open_stdio_streamfile_buffer_by_FILE(FILE *infile,const char static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOSTREAMFILE * streamfile) { size_t length_read_total=0; - /* is the beginning at least there? */ - if (offset >= streamfile->offset && offset < streamfile->offset+streamfile->validsize) { + /* is the part of the requested length in the buffer? */ + if (offset >= streamfile->offset && offset < streamfile->offset + streamfile->validsize) { size_t length_read; - off_t offset_into_buffer = offset-streamfile->offset; - length_read = streamfile->validsize-offset_into_buffer; - memcpy(dest,streamfile->buffer+offset_into_buffer,length_read); + off_t offset_into_buffer = offset - streamfile->offset; + length_read = streamfile->validsize - offset_into_buffer; + + memcpy(dest,streamfile->buffer + offset_into_buffer,length_read); length_read_total += length_read; length -= length_read; offset += length_read; dest += length_read; } - /* TODO: What would make more sense here is to read the whole request + /* What would make more sense here is to read the whole request * at once into the dest buffer, as it must be large enough, and then * copy some part of that into our own buffer. * The destination buffer is supposed to be much smaller than the @@ -48,23 +57,29 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST * to the buffer size to avoid having to deal with things like this * which are outside of my intended use. */ - /* read as much of the beginning of the request as possible, proceed */ - while (length>0) { + /* read the rest of the requested length */ + while (length > 0) { size_t length_to_read; size_t length_read; - streamfile->validsize=0; + streamfile->validsize = 0; /* buffer is empty now */ /* request outside file: ignore to avoid seek/read */ if (offset > streamfile->filesize) { - #ifdef VGM_DEBUG_OUTPUT + streamfile->offset = streamfile->filesize; + +#ifdef VGM_DEBUG_OUTPUT if (!streamfile->error_notified) { - VGM_LOG("ERROR: reading outside filesize, at offset 0x%lx + 0x%x (buggy meta?)\n", offset, length); + VGM_LOG("ERROR: reading over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length); streamfile->error_notified = 1; } - #endif - streamfile->offset = streamfile->filesize; - memset(dest,0,length); - return length; /* return partially-read buffer and 0-set the rest */ +#endif + +#if STREAMFILE_IGNORE_EOF + memset(dest,0,length); /* dest is already shifted */ + return length_read_total + length; /* partially-read + 0-set buffer */ +#else + return length_read_total; /* partially-read buffer */ +#endif } /* position to new offset */ @@ -73,18 +88,19 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST #ifdef PROFILE_STREAMFILE streamfile->error_count++; #endif - return 0; //fail miserably + return 0; /* fail miserably (fseek shouldn't fail and reach this) */ } - - streamfile->offset=offset; + streamfile->offset = offset; /* decide how much must be read this time */ - if (length>streamfile->buffersize) length_to_read=streamfile->buffersize; - else length_to_read=length; + if (length > streamfile->buffersize) + length_to_read = streamfile->buffersize; + else + length_to_read = length; - /* always try to fill the buffer */ - length_read = fread(streamfile->buffer,1,streamfile->buffersize,streamfile->infile); - streamfile->validsize=length_read; + /* fill the buffer */ + length_read = fread(streamfile->buffer,sizeof(uint8_t),streamfile->buffersize,streamfile->infile); + streamfile->validsize = length_read; #ifdef PROFILE_STREAMFILE if (ferror(streamfile->infile)) { @@ -95,19 +111,24 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST streamfile->bytes_read += length_read; #endif - /* if we can't get enough to satisfy the request we give up */ + /* if we can't get enough to satisfy the request (EOF) we give up */ if (length_read < length_to_read) { memcpy(dest,streamfile->buffer,length_read); - length_read_total+=length_read; - return length_read_total; + +#if STREAMFILE_IGNORE_EOF + memset(dest+length_read,0,length-length_read); + return length_read_total + length; /* partially-read + 0-set buffer */ +#else + return length_read_total + length_read; /* partially-read buffer */ +#endif } /* use the new buffer */ memcpy(dest,streamfile->buffer,length_to_read); - length_read_total+=length_to_read; - length-=length_to_read; - dest+=length_to_read; - offset+=length_to_read; + length_read_total += length_to_read; + length -= length_to_read; + dest += length_to_read; + offset += length_to_read; } return length_read_total; @@ -115,25 +136,32 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST static size_t read_stdio(STDIOSTREAMFILE *streamfile,uint8_t * dest, off_t offset, size_t length) { - if (!streamfile || !dest || length<=0) return 0; - - /* if entire request is within the buffer */ - if (offset >= streamfile->offset && offset+length <= streamfile->offset+streamfile->validsize) { - memcpy(dest,streamfile->buffer+(offset-streamfile->offset),length); - return length; - } + if (!streamfile || !dest || length<=0) + return 0; /* request outside file: ignore to avoid seek/read in read_the_rest() */ if (offset > streamfile->filesize) { + streamfile->offset = streamfile->filesize; + #ifdef VGM_DEBUG_OUTPUT if (!streamfile->error_notified) { - VGM_LOG("ERROR: reading outside filesize, at offset over 0x%lx (buggy meta?)\n", offset); + VGM_LOG("ERROR: offset over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length); streamfile->error_notified = 1; } #endif - streamfile->offset = streamfile->filesize; +#if STREAMFILE_IGNORE_EOF memset(dest,0,length); + return length; /* 0-set buffer */ +#else + return 0; /* nothing to read */ +#endif + } + + /* just copy if entire request is within the buffer */ + if (offset >= streamfile->offset && offset + length <= streamfile->offset + streamfile->validsize) { + off_t offset_into_buffer = offset - streamfile->offset; + memcpy(dest,streamfile->buffer + offset_into_buffer,length); return length; } @@ -523,4 +551,3 @@ int find_chunk(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, in return 0; } - From 779bf68ab170064d9346a3e835cd32de12d8ca1a Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 29 Apr 2017 16:23:50 +0200 Subject: [PATCH 12/16] Fix some compiler errors with -Werror=format-security --- src/vgmstream.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vgmstream.c b/src/vgmstream.c index 67e3ea16..2a1feb0c 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1994,9 +1994,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data; if (vgmstream->codec_data) { if (data->codec && data->codec->long_name) { - snprintf(temp,TEMPSIZE,data->codec->long_name); + snprintf(temp,TEMPSIZE,"%s",data->codec->long_name); } else if (data->codec && data->codec->name) { - snprintf(temp,TEMPSIZE,data->codec->name); + snprintf(temp,TEMPSIZE,"%s",data->codec->name); } else { snprintf(temp,TEMPSIZE,"FFmpeg (unknown codec)"); } @@ -2010,7 +2010,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { description = get_vgmstream_coding_description(vgmstream->coding_type); if (!description) description = "CANNOT DECODE"; - strncpy(temp,description,TEMPSIZE); + snprintf(temp,TEMPSIZE,"%s",description); break; } concatn(length,desc,temp); @@ -2023,7 +2023,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { description = get_vgmstream_layout_description(vgmstream->layout_type); if (!description) description = "INCONCEIVABLE"; - strncpy(temp,description,TEMPSIZE); + snprintf(temp,TEMPSIZE,"%s",description); break; } concatn(length,desc,temp); @@ -2073,7 +2073,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { description = get_vgmstream_meta_description(vgmstream->meta_type); if (!description) description = "THEY SHOULD HAVE SENT A POET"; - strncpy(temp,description,TEMPSIZE); + snprintf(temp,TEMPSIZE,"%s",description); break; } concatn(length,desc,temp); From af2b5d4e76873430dc55d834287a695cee82b73e Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 29 Apr 2017 16:54:13 +0200 Subject: [PATCH 13/16] Fix AKB MSADPCM loop samples --- src/meta/akb.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/meta/akb.c b/src/meta/akb.c index 40c8224c..7c34461c 100644 --- a/src/meta/akb.c +++ b/src/meta/akb.c @@ -50,7 +50,7 @@ VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) { goto fail; channel_count = read_8bit(0x0d,streamFile); - loop_flag = read_32bitLE(0x18,streamFile) > 0; + loop_flag = read_32bitLE(0x18,streamFile) > 0; /* loop end */ /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); @@ -86,12 +86,17 @@ VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = read_16bitLE(extra_data_offset + 0x02,streamFile); - vgmstream->num_samples = read_32bitLE(extra_data_offset + 0x04, streamFile); /* lower than header num_samples */ + /* adjusted samples; bigger or smaller than base samples, but seems more accurate + * (base samples may have more than possible and read over file size otherwise, very strange) + * loop_end seems to exist even with loop disabled */ + vgmstream->num_samples = read_32bitLE(extra_data_offset + 0x04, streamFile); + vgmstream->loop_start_sample = read_32bitLE(extra_data_offset + 0x08, streamFile); + vgmstream->loop_end_sample = read_32bitLE(extra_data_offset + 0x0c, streamFile); break; } #ifdef VGM_USE_FFMPEG - case 0x05: { /* ogg vorbis [Final Fantasy VI, Dragon Quest II-VI] */ + case 0x05: { /* Ogg Vorbis [Final Fantasy VI, Dragon Quest II-VI] */ /* Starting from an offset in the current libvorbis code is a bit hard so just use FFmpeg. * Decoding seems to produce the same output with (inaudible) +-1 lower byte differences due to rounding. */ ffmpeg_codec_data *ffmpeg_data; @@ -173,7 +178,7 @@ VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile) { header_offset = material; channel_count = read_8bit(header_offset+0x02,streamFile); - loop_flag = read_32bitLE(header_offset+0x14,streamFile) > 0; + loop_flag = read_32bitLE(header_offset+0x14,streamFile) > 0; /* loop end */ /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); @@ -187,17 +192,23 @@ VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile) { * Actual num_samples would be loop_end_sample+1, but more testing is needed */ vgmstream->num_samples = read_32bitLE(header_offset+0x0c,streamFile); vgmstream->loop_start_sample = read_32bitLE(header_offset+0x10,streamFile); - vgmstream->loop_end_sample = read_32bitLE(header_offset+0x14,streamFile); + vgmstream->loop_end_sample = read_32bitLE(header_offset+0x14,streamFile); vgmstream->meta_type = meta_AKB; switch (codec) { - case 0x02: { /* msadpcm [The Irregular at Magic High School Lost Zero (Android)] */ + case 0x02: { /* MSAPDCM [The Irregular at Magic High School Lost Zero (Android)] */ if (encryption_flag) goto fail; - vgmstream->num_samples = read_32bitLE(extradata + 0x04, streamFile); vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = read_16bitLE(extradata + 0x02, streamFile); + + /* adjusted samples; bigger or smaller than base samples, but seems more accurate + * (base samples may have more than possible and read over file size otherwise, very strange) + * loop_end seems to exist even with loop disabled */ + vgmstream->num_samples = read_32bitLE(extradata + 0x04, streamFile); + vgmstream->loop_start_sample = read_32bitLE(extradata + 0x08, streamFile); + vgmstream->loop_end_sample = read_32bitLE(extradata + 0x0c, streamFile); break; } From cac3af887aea708eebdbc47b01c049fb898a3271 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 29 Apr 2017 20:28:14 +0200 Subject: [PATCH 14/16] Allow mono MSADPCM; validate interleave for endless loops in some codecs --- src/meta/genh.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/meta/genh.c b/src/meta/genh.c index ad6a59be..afb2e9e0 100644 --- a/src/meta/genh.c +++ b/src/meta/genh.c @@ -165,17 +165,27 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { { if (coding == coding_SDX2) { coding = coding_SDX2_int; - vgmstream->coding_type = coding_SDX2_int; } - //todo if 0 do this too (most codecs seem to enter an infinite loop otherwise) - if(vgmstream->interleave_block_size==0xffffffff) - vgmstream->layout_type=layout_none; + + if (vgmstream->interleave_block_size==0xffffffff) { + vgmstream->layout_type = layout_none; + } else { vgmstream->layout_type = layout_interleave; - if(coding==coding_DVI_IMA) - coding=coding_DVI_IMA_int; - if(coding==coding_IMA) - coding=coding_IMA_int; + if (coding == coding_DVI_IMA) + coding = coding_DVI_IMA_int; + if (coding == coding_IMA) + coding = coding_IMA_int; + } + + /* to avoid endless loops */ + if (!interleave && ( + coding == coding_PSX || + coding == coding_PSX_badflags || + coding == coding_IMA_int || + coding == coding_DVI_IMA_int || + coding == coding_SDX2_int) ) { + goto fail; } } else { vgmstream->layout_type = layout_none; @@ -191,11 +201,15 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { break; case coding_MS_IMA: + if (!interleave) goto fail; /* creates garbage */ + vgmstream->interleave_block_size = interleave; vgmstream->layout_type = layout_none; break; case coding_MSADPCM: - if (channel_count != 2) goto fail; + if (channel_count > 2) goto fail; + if (!interleave) goto fail; /* creates garbage */ + vgmstream->interleave_block_size = interleave; vgmstream->layout_type = layout_none; break; @@ -208,9 +222,11 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { break; case coding_NGC_DSP: if (dsp_interleave_type == 0) { + if (!interleave) goto fail; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = interleave; } else if (dsp_interleave_type == 1) { + if (!interleave) goto fail; vgmstream->layout_type = layout_interleave_byte; vgmstream->interleave_block_size = interleave; } else if (dsp_interleave_type == 2) { From 6cf0195d25063e8701d7868b82ba61ec3cc08f0c Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 29 Apr 2017 22:37:15 +0200 Subject: [PATCH 15/16] Move reset/seek/free code to decoders (vgmstream.c cleanup) --- src/coding/at3_decoder.c | 37 +++- src/coding/coding.h | 42 ++-- src/coding/g719_decoder.c | 34 +++- src/coding/g7221_decoder.c | 34 +++- src/coding/hca_decoder.c | 28 ++- src/coding/mp4_aac_decoder.c | 25 +++ src/coding/ogg_vorbis_decoder.c | 31 ++- src/vgmstream.c | 328 ++++++++++++-------------------- 8 files changed, 312 insertions(+), 247 deletions(-) diff --git a/src/coding/at3_decoder.c b/src/coding/at3_decoder.c index c9c538d0..a8b444ec 100644 --- a/src/coding/at3_decoder.c +++ b/src/coding/at3_decoder.c @@ -1,12 +1,10 @@ -#include "../vgmstream.h" - -#ifdef VGM_USE_MAIATRAC3PLUS -#include "maiatrac3plus.h" #include "coding.h" #include "../util.h" -void decode_at3plus(VGMSTREAM * vgmstream, - sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) { +#ifdef VGM_USE_MAIATRAC3PLUS +#include "maiatrac3plus.h" + +void decode_at3plus(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) { VGMSTREAMCHANNEL *ch = &vgmstream->ch[0]; maiatrac3plus_codec_data *data = vgmstream->codec_data; int i; @@ -37,4 +35,31 @@ void decode_at3plus(VGMSTREAM * vgmstream, } } + +void reset_at3plus(VGMSTREAM *vgmstream) { + maiatrac3plus_codec_data *data = vgmstream->codec_data; + + if (data->handle) + Atrac3plusDecoder_closeContext(data->handle); + data->handle = Atrac3plusDecoder_openContext(); + data->samples_discard = 0; +} + +void seek_at3plus(VGMSTREAM *vgmstream, int32_t num_sample) { + int blocks_to_skip = num_sample / 2048; + int samples_to_discard = num_sample % 2048; + maiatrac3plus_codec_data *data = (maiatrac3plus_codec_data *)(vgmstream->codec_data); + vgmstream->loop_ch[0].offset = + vgmstream->loop_ch[0].channel_start_offset + + vgmstream->interleave_block_size * blocks_to_skip; + data->samples_discard = samples_to_discard; +} + +void free_at3plus(maiatrac3plus_codec_data *data) { + if (data) { + if (data->handle) Atrac3plusDecoder_closeContext(data->handle); + free(data); + } +} + #endif diff --git a/src/coding/coding.h b/src/coding/coding.h index 780f2239..e6b0811d 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -77,7 +77,6 @@ void decode_maxis_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspaci /* sdx2_decoder */ void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -/* sdx2_decoder */ void decode_cbd2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); @@ -118,77 +117,88 @@ void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbu /* hca_decoder */ void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels); - +void reset_hca(VGMSTREAM *vgmstream); +void loop_hca(VGMSTREAM *vgmstream); +void free_hca(hca_codec_data * data); #ifdef VGM_USE_VORBIS /* ogg_vorbis_decoder */ void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels); +void reset_ogg_vorbis(VGMSTREAM *vgmstream); +void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample); +void free_ogg_vorbis(ogg_vorbis_codec_data *data); /* fsb_vorbis_decoder */ vorbis_codec_data * init_fsb_vorbis_codec_data(STREAMFILE *streamfile, off_t start_offset, int channels, int sample_rate, uint32_t setup_id); void decode_fsb_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels); - -void free_fsb_vorbis(vorbis_codec_data *data); void reset_fsb_vorbis(VGMSTREAM *vgmstream); void seek_fsb_vorbis(VGMSTREAM *vgmstream, int32_t num_sample); +void free_fsb_vorbis(vorbis_codec_data *data); /* wwise_vorbis_decoder */ vorbis_codec_data * init_wwise_vorbis_codec_data(STREAMFILE *streamfile, off_t start_offset, int channels, int sample_rate, int blocksize_0_exp, int blocksize_1_exp, wwise_setup_type setup_type, wwise_header_type header_type, wwise_packet_type packet_type, int big_endian); void decode_wwise_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels); - -void free_wwise_vorbis(vorbis_codec_data *data); void reset_wwise_vorbis(VGMSTREAM *vgmstream); void seek_wwise_vorbis(VGMSTREAM *vgmstream, int32_t num_sample); +void free_wwise_vorbis(vorbis_codec_data *data); /* ogl_vorbis_decoder */ vorbis_codec_data * init_ogl_vorbis_codec_data(STREAMFILE *streamFile, off_t start_offset, off_t * data_start_offset); void decode_ogl_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels); - -void free_ogl_vorbis(vorbis_codec_data *data); void reset_ogl_vorbis(VGMSTREAM *vgmstream); void seek_ogl_vorbis(VGMSTREAM *vgmstream, int32_t num_sample); +void free_ogl_vorbis(vorbis_codec_data *data); #endif -/* mpeg_decoder */ #ifdef VGM_USE_MPEG +/* mpeg_decoder */ mpeg_codec_data *init_mpeg_codec_data(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels); mpeg_codec_data *init_mpeg_codec_data_interleaved(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels, int fixed_frame_size, int fsb_padding); mpeg_codec_data *init_mpeg_codec_data_ahx(STREAMFILE *streamFile, off_t start_offset, int channel_count); void decode_mpeg(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels); void decode_fake_mpeg2_l2(VGMSTREAMCHANNEL * stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do); - -void free_mpeg(mpeg_codec_data *data); void reset_mpeg(VGMSTREAM *vgmstream); void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample); +void free_mpeg(mpeg_codec_data *data); long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data *data); void mpeg_set_error_logging(mpeg_codec_data * data, int enable); #endif -/* g7221_decoder */ #ifdef VGM_USE_G7221 +/* g7221_decoder */ void decode_g7221(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel); +void reset_g7221(VGMSTREAM *vgmstream); +void free_g7221(VGMSTREAM *vgmstream); #endif -/* g719_decoder */ #ifdef VGM_USE_G719 +/* g719_decoder */ void decode_g719(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel); +void reset_g719(VGMSTREAM *vgmstream); +void free_g719(VGMSTREAM *vgmstream); #endif -/* mp4_aac_decoder */ #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) +/* mp4_aac_decoder */ void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels); +void reset_mp4_aac(VGMSTREAM *vgmstream); +void seek_mp4_aac(VGMSTREAM *vgmstream, int32_t num_sample); +void free_mp4_aac(mp4_aac_codec_data * data); #endif -/* at3_decoder */ #ifdef VGM_USE_MAIATRAC3PLUS +/* at3_decoder */ void decode_at3plus(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel); +void reset_at3plus(VGMSTREAM *vgmstream); +void seek_at3plus(VGMSTREAM *vgmstream, int32_t num_sample); +void free_at3plus(maiatrac3plus_codec_data *data); #endif -/* ffmpeg_decoder */ #ifdef VGM_USE_FFMPEG +/* ffmpeg_decoder */ void decode_ffmpeg(VGMSTREAM *stream, sample * outbuf, int32_t samples_to_do, int channels); void reset_ffmpeg(VGMSTREAM *vgmstream); void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample); diff --git a/src/coding/g719_decoder.c b/src/coding/g719_decoder.c index 67a98aed..01238642 100644 --- a/src/coding/g719_decoder.c +++ b/src/coding/g719_decoder.c @@ -1,12 +1,10 @@ -#include "../vgmstream.h" - -#ifdef VGM_USE_G719 #include "coding.h" #include "../util.h" + +#ifdef VGM_USE_G719 #include "../stack_alloc.h" -void decode_g719(VGMSTREAM * vgmstream, - sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) { +void decode_g719(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) { VGMSTREAMCHANNEL *ch = &vgmstream->ch[channel]; g719_codec_data *data = vgmstream->codec_data; g719_codec_data *ch_data = &data[channel]; @@ -26,4 +24,30 @@ void decode_g719(VGMSTREAM * vgmstream, } } + +void reset_g719(VGMSTREAM *vgmstream) { + g719_codec_data *data = vgmstream->codec_data; + int i; + + for (i = 0; i < vgmstream->channels; i++) + { + g719_reset(data[i].handle); + } +} + +void free_g719(VGMSTREAM *vgmstream) { + g719_codec_data *data = (g719_codec_data *) vgmstream->codec_data; + + if (data) + { + int i; + + for (i = 0; i < vgmstream->channels; i++) + { + g719_free(data[i].handle); + } + free(data); + } +} + #endif diff --git a/src/coding/g7221_decoder.c b/src/coding/g7221_decoder.c index 6ca80b03..32481ea1 100644 --- a/src/coding/g7221_decoder.c +++ b/src/coding/g7221_decoder.c @@ -1,11 +1,9 @@ -#include "../vgmstream.h" - -#ifdef VGM_USE_G7221 #include "coding.h" #include "../util.h" -void decode_g7221(VGMSTREAM * vgmstream, - sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) { +#ifdef VGM_USE_G7221 + +void decode_g7221(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) { VGMSTREAMCHANNEL *ch = &vgmstream->ch[channel]; g7221_codec_data *data = vgmstream->codec_data; g7221_codec_data *ch_data = &data[channel]; @@ -24,4 +22,30 @@ void decode_g7221(VGMSTREAM * vgmstream, } } + +void reset_g7221(VGMSTREAM *vgmstream) { + g7221_codec_data *data = vgmstream->codec_data; + int i; + + for (i = 0; i < vgmstream->channels; i++) + { + g7221_reset(data[i].handle); + } +} + +void free_g7221(VGMSTREAM *vgmstream) { + g7221_codec_data *data = (g7221_codec_data *) vgmstream->codec_data; + + if (data) + { + int i; + + for (i = 0; i < vgmstream->channels; i++) + { + g7221_free(data[i].handle); + } + free(data); + } +} + #endif diff --git a/src/coding/hca_decoder.c b/src/coding/hca_decoder.c index 5e43dbc6..c8476b7f 100644 --- a/src/coding/hca_decoder.c +++ b/src/coding/hca_decoder.c @@ -1,4 +1,4 @@ -#include "../vgmstream.h" +#include "coding.h" void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) { int samples_done = 0; @@ -80,3 +80,29 @@ void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, i free( hca_data ); } + + +void reset_hca(VGMSTREAM *vgmstream) { + hca_codec_data *data = vgmstream->codec_data; + /*clHCA *hca = (clHCA *)(data + 1);*/ + data->curblock = 0; + data->sample_ptr = clHCA_samplesPerBlock; + data->samples_discard = 0; +} + +void loop_hca(VGMSTREAM *vgmstream) { + hca_codec_data *data = (hca_codec_data *)(vgmstream->codec_data); + data->curblock = data->info.loopStart; + data->sample_ptr = clHCA_samplesPerBlock; + data->samples_discard = 0; +} + +void free_hca(hca_codec_data * data) { + if (data) { + clHCA *hca = (clHCA *)(data + 1); + clHCA_done(hca); + if (data->streamfile) + close_streamfile(data->streamfile); + free(data); + } +} diff --git a/src/coding/mp4_aac_decoder.c b/src/coding/mp4_aac_decoder.c index 7b6a2589..4675b78f 100644 --- a/src/coding/mp4_aac_decoder.c +++ b/src/coding/mp4_aac_decoder.c @@ -82,4 +82,29 @@ void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_ data->sample_ptr = samples_remain; } } + + +void reset_mp4_aac(VGMSTREAM *vgmstream) { + mp4_aac_codec_data *data = vgmstream->codec_data; + data->sampleId = 0; + data->sample_ptr = data->samples_per_frame; + data->samples_discard = 0; +} + +void seek_mp4_aac(VGMSTREAM *vgmstream, int32_t num_sample) { + mp4_aac_codec_data *data = (mp4_aac_codec_data *)(vgmstream->codec_data); + data->sampleId = 0; + data->sample_ptr = data->samples_per_frame; + data->samples_discard = num_sample; +} + +void free_mp4_aac(mp4_aac_codec_data * data) { + if (data) { + if (data->h_aacdecoder) aacDecoder_Close(data->h_aacdecoder); + if (data->h_mp4file) MP4Close(data->h_mp4file, 0); + if (data->if_file.streamfile) close_streamfile(data->if_file.streamfile); + free(data); + } +} + #endif diff --git a/src/coding/ogg_vorbis_decoder.c b/src/coding/ogg_vorbis_decoder.c index c29e16f5..ceb12675 100644 --- a/src/coding/ogg_vorbis_decoder.c +++ b/src/coding/ogg_vorbis_decoder.c @@ -1,9 +1,8 @@ -#include "../vgmstream.h" +#include "coding.h" +#include "../util.h" #ifdef VGM_USE_VORBIS #include -#include "coding.h" -#include "../util.h" void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) { int samples_done = 0; @@ -21,4 +20,30 @@ void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t sa swap_samples_le(outbuf, samples_to_do*channels); } + +void reset_ogg_vorbis(VGMSTREAM *vgmstream) { + ogg_vorbis_codec_data *data = vgmstream->codec_data; + OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file); + + ov_pcm_seek(ogg_vorbis_file, 0); +} + +void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) { + ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *)(vgmstream->codec_data); + OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file); + + ov_pcm_seek_lap(ogg_vorbis_file, num_sample); +} + +void free_ogg_vorbis(ogg_vorbis_codec_data *data) { + if (!data) { + OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file); + + ov_clear(ogg_vorbis_file); + + close_streamfile(data->ov_streamfile.streamfile); + free(data); + } +} + #endif diff --git a/src/vgmstream.c b/src/vgmstream.c index 2a1feb0c..9820d2e0 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -18,8 +18,7 @@ static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFi /* - * List of functions that will recognize files. These should correspond pretty - * directly to the metadata types + * List of functions that will recognize files. */ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_adx, @@ -374,22 +373,20 @@ VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) { fcns_size = (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0])); /* try a series of formats, see which works */ - for (i=0;inum_samples <= 0) { - VGM_LOG("VGMSTREAM: wrong num_samples (ns=%i)\n", vgmstream->num_samples); + VGM_LOG("VGMSTREAM: wrong num_samples (ns=%i / 0x%08x)\n", vgmstream->num_samples, vgmstream->num_samples); close_vgmstream(vgmstream); continue; } - /* everything should have a reasonable sample rate - * (a verification of the metadata) */ + /* everything should have a reasonable sample rate (a verification of the metadata) */ if (!check_sample_rate(vgmstream->sample_rate)) { VGM_LOG("VGMSTREAM: wrong sample rate (sr=%i)\n", vgmstream->sample_rate); close_vgmstream(vgmstream); @@ -480,11 +477,7 @@ void reset_vgmstream(VGMSTREAM * vgmstream) { #ifdef VGM_USE_VORBIS if (vgmstream->coding_type==coding_ogg_vorbis) { - ogg_vorbis_codec_data *data = vgmstream->codec_data; - - OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file); - - ov_pcm_seek(ogg_vorbis_file, 0); + reset_ogg_vorbis(vgmstream); } if (vgmstream->coding_type==coding_fsb_vorbis) { @@ -499,59 +492,40 @@ void reset_vgmstream(VGMSTREAM * vgmstream) { reset_ogl_vorbis(vgmstream); } #endif + if (vgmstream->coding_type==coding_CRI_HCA) { - hca_codec_data *data = vgmstream->codec_data; - /*clHCA *hca = (clHCA *)(data + 1);*/ - data->curblock = 0; - data->sample_ptr = clHCA_samplesPerBlock; - data->samples_discard = 0; + reset_hca(vgmstream); } + #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) if (vgmstream->coding_type==coding_MP4_AAC) { - mp4_aac_codec_data *data = vgmstream->codec_data; - data->sampleId = 0; - data->sample_ptr = data->samples_per_frame; - data->samples_discard = 0; + reset_mp4_aac(vgmstream); } #endif + #ifdef VGM_USE_MPEG if (vgmstream->layout_type==layout_mpeg || vgmstream->layout_type==layout_fake_mpeg) { reset_mpeg(vgmstream); } #endif + #ifdef VGM_USE_G7221 if (vgmstream->coding_type==coding_G7221 || vgmstream->coding_type==coding_G7221C) { - g7221_codec_data *data = vgmstream->codec_data; - int i; - - for (i = 0; i < vgmstream->channels; i++) - { - g7221_reset(data[i].handle); - } + reset_g7221(vgmstream); } #endif #ifdef VGM_USE_G719 if (vgmstream->coding_type==coding_G719) { - g719_codec_data *data = vgmstream->codec_data; - int i; - - for (i = 0; i < vgmstream->channels; i++) - { - g719_reset(data[i].handle); - } + reset_g719(vgmstream); } #endif #ifdef VGM_USE_MAIATRAC3PLUS if (vgmstream->coding_type==coding_AT3plus) { - maiatrac3plus_codec_data *data = vgmstream->codec_data; - - if (data->handle) Atrac3plusDecoder_closeContext(data->handle); - data->handle = Atrac3plusDecoder_openContext(); - data->samples_discard = 0; + reset_at3plus(vgmstream); } #endif @@ -681,20 +655,13 @@ VGMSTREAM * allocate_vgmstream(int channel_count, int looped) { void close_vgmstream(VGMSTREAM * vgmstream) { int i,j; - if (!vgmstream) return; + if (!vgmstream) + return; #ifdef VGM_USE_VORBIS if (vgmstream->coding_type==coding_ogg_vorbis) { - ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *) vgmstream->codec_data; - if (vgmstream->codec_data) { - OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file); - - ov_clear(ogg_vorbis_file); - - close_streamfile(data->ov_streamfile.streamfile); - free(vgmstream->codec_data); - vgmstream->codec_data = NULL; - } + free_ogg_vorbis(vgmstream->codec_data); + vgmstream->codec_data = NULL; } if (vgmstream->coding_type==coding_fsb_vorbis) { @@ -714,43 +681,28 @@ void close_vgmstream(VGMSTREAM * vgmstream) { #endif if (vgmstream->coding_type==coding_CRI_HCA) { - hca_codec_data *data = (hca_codec_data *) vgmstream->codec_data; - if (vgmstream->codec_data) { - clHCA *hca = (clHCA *)(data + 1); - clHCA_done(hca); - if (data->streamfile) close_streamfile(data->streamfile); - free(vgmstream->codec_data); - vgmstream->codec_data = NULL; - } + free_hca(vgmstream->codec_data); + vgmstream->codec_data = NULL; } #ifdef VGM_USE_FFMPEG if (vgmstream->coding_type==coding_FFmpeg) { - ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data; - if (vgmstream->codec_data) { - free_ffmpeg(data); - vgmstream->codec_data = NULL; - } + free_ffmpeg(vgmstream->codec_data); + vgmstream->codec_data = NULL; } #endif #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) if (vgmstream->coding_type==coding_MP4_AAC) { - mp4_aac_codec_data *data = (mp4_aac_codec_data *) vgmstream->codec_data; - if (vgmstream->codec_data) { - if (data->h_aacdecoder) aacDecoder_Close(data->h_aacdecoder); - if (data->h_mp4file) MP4Close(data->h_mp4file, 0); - if (data->if_file.streamfile) close_streamfile(data->if_file.streamfile); - free(vgmstream->codec_data); - vgmstream->codec_data = NULL; - } + free_mp4_aac(vgmstream->codec_data); + vgmstream->codec_data = NULL; } #endif #ifdef VGM_USE_MPEG - if (vgmstream->layout_type==layout_fake_mpeg|| + if (vgmstream->layout_type==layout_fake_mpeg || vgmstream->layout_type==layout_mpeg) { - free_mpeg((mpeg_codec_data *)vgmstream->codec_data); + free_mpeg(vgmstream->codec_data); vgmstream->codec_data = NULL; } #endif @@ -758,52 +710,22 @@ void close_vgmstream(VGMSTREAM * vgmstream) { #ifdef VGM_USE_G7221 if (vgmstream->coding_type == coding_G7221 || vgmstream->coding_type == coding_G7221C) { - - g7221_codec_data *data = (g7221_codec_data *) vgmstream->codec_data; - - if (data) - { - int i; - - for (i = 0; i < vgmstream->channels; i++) - { - g7221_free(data[i].handle); - } - free(data); - } - + free_g7221(vgmstream); vgmstream->codec_data = NULL; } #endif #ifdef VGM_USE_G719 if (vgmstream->coding_type == coding_G719) { - g719_codec_data *data = (g719_codec_data *) vgmstream->codec_data; - - if (data) - { - int i; - - for (i = 0; i < vgmstream->channels; i++) - { - g719_free(data[i].handle); - } - free(data); - } - + free_g719(vgmstream); vgmstream->codec_data = NULL; } #endif #ifdef VGM_USE_MAIATRAC3PLUS if (vgmstream->coding_type == coding_AT3plus) { - maiatrac3plus_codec_data *data = (maiatrac3plus_codec_data *) vgmstream->codec_data; - - if (data) - { - if (data->handle) Atrac3plusDecoder_closeContext(data->handle); - free(data); - } + free_at3plus(vgmstream->codec_data); + vgmstream->codec_data = NULL; } #endif @@ -885,9 +807,7 @@ void close_vgmstream(VGMSTREAM * vgmstream) { vgmstream->coding_type == coding_NWA5 ) { nwa_codec_data *data = (nwa_codec_data *) vgmstream->codec_data; - close_nwa(data->nwa); - free(data); vgmstream->codec_data = NULL; @@ -1095,8 +1015,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_EA_ADPCM: return 14*vgmstream->channels; case coding_WS: - /* only works if output sample size is 8 bit, which is always - is for WS ADPCM */ + /* only works if output sample size is 8 bit, which always is for WS ADPCM */ return vgmstream->ws_output_size; case coding_MSADPCM: return (vgmstream->interleave_block_size-(7-1)*vgmstream->channels)*2/vgmstream->channels; @@ -1817,135 +1736,122 @@ int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMST } /* if it's a framed encoding don't do more than one frame */ - if (samples_per_frame>1 && (vgmstream->samples_into_block%samples_per_frame)+samples_to_do>samples_per_frame) samples_to_do=samples_per_frame-(vgmstream->samples_into_block%samples_per_frame); + if (samples_per_frame>1 && (vgmstream->samples_into_block%samples_per_frame)+samples_to_do>samples_per_frame) + samples_to_do = samples_per_frame - (vgmstream->samples_into_block%samples_per_frame); return samples_to_do; } /* return 1 if we just looped */ int vgmstream_do_loop(VGMSTREAM * vgmstream) { -/* if (vgmstream->loop_flag) {*/ - /* is this the loop end? */ - if (vgmstream->current_sample==vgmstream->loop_end_sample) { - /* against everything I hold sacred, preserve adpcm - * history through loop for certain types */ - if (vgmstream->meta_type == meta_DSP_STD || - vgmstream->meta_type == meta_DSP_RS03 || - vgmstream->meta_type == meta_DSP_CSTR || - vgmstream->coding_type == coding_PSX || - vgmstream->coding_type == coding_PSX_bmdx || - vgmstream->coding_type == coding_PSX_badflags) { - int i; - for (i=0;ichannels;i++) { - vgmstream->loop_ch[i].adpcm_history1_16 = vgmstream->ch[i].adpcm_history1_16; - vgmstream->loop_ch[i].adpcm_history2_16 = vgmstream->ch[i].adpcm_history2_16; - vgmstream->loop_ch[i].adpcm_history1_32 = vgmstream->ch[i].adpcm_history1_32; - vgmstream->loop_ch[i].adpcm_history2_32 = vgmstream->ch[i].adpcm_history2_32; - } - } - /* todo preserve ADPCM (ex hevag) history? */ + /*if (vgmstream->loop_flag) return 0;*/ - if (vgmstream->coding_type==coding_CRI_HCA) { - hca_codec_data *data = (hca_codec_data *)(vgmstream->codec_data); - data->curblock = data->info.loopStart; - data->sample_ptr = clHCA_samplesPerBlock; - data->samples_discard = 0; + /* is this the loop end? */ + if (vgmstream->current_sample==vgmstream->loop_end_sample) { + + /* against everything I hold sacred, preserve adpcm + * history through loop for certain types */ + if (vgmstream->meta_type == meta_DSP_STD || + vgmstream->meta_type == meta_DSP_RS03 || + vgmstream->meta_type == meta_DSP_CSTR || + vgmstream->coding_type == coding_PSX || + vgmstream->coding_type == coding_PSX_bmdx || + vgmstream->coding_type == coding_PSX_badflags) { + int i; + for (i=0;ichannels;i++) { + vgmstream->loop_ch[i].adpcm_history1_16 = vgmstream->ch[i].adpcm_history1_16; + vgmstream->loop_ch[i].adpcm_history2_16 = vgmstream->ch[i].adpcm_history2_16; + vgmstream->loop_ch[i].adpcm_history1_32 = vgmstream->ch[i].adpcm_history1_32; + vgmstream->loop_ch[i].adpcm_history2_32 = vgmstream->ch[i].adpcm_history2_32; } + } + + + /* prepare certain codecs' internal state for looping */ + + if (vgmstream->coding_type==coding_CRI_HCA) { + loop_hca(vgmstream); + } #ifdef VGM_USE_VORBIS - if (vgmstream->coding_type==coding_ogg_vorbis) { - ogg_vorbis_codec_data *data = - (ogg_vorbis_codec_data *)(vgmstream->codec_data); - OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file); - - ov_pcm_seek_lap(ogg_vorbis_file, vgmstream->loop_sample); - } + if (vgmstream->coding_type==coding_ogg_vorbis) { + seek_ogg_vorbis(vgmstream, vgmstream->loop_sample); + } - if (vgmstream->coding_type==coding_fsb_vorbis) { - seek_fsb_vorbis(vgmstream, vgmstream->loop_start_sample); - } + if (vgmstream->coding_type==coding_fsb_vorbis) { + seek_fsb_vorbis(vgmstream, vgmstream->loop_start_sample); + } - if (vgmstream->coding_type==coding_wwise_vorbis) { - seek_wwise_vorbis(vgmstream, vgmstream->loop_start_sample); - } + if (vgmstream->coding_type==coding_wwise_vorbis) { + seek_wwise_vorbis(vgmstream, vgmstream->loop_start_sample); + } - if (vgmstream->coding_type==coding_ogl_vorbis) { - seek_ogl_vorbis(vgmstream, vgmstream->loop_start_sample); - } + if (vgmstream->coding_type==coding_ogl_vorbis) { + seek_ogl_vorbis(vgmstream, vgmstream->loop_start_sample); + } #endif #ifdef VGM_USE_FFMPEG - if (vgmstream->coding_type==coding_FFmpeg) { - seek_ffmpeg(vgmstream, vgmstream->loop_start_sample); - } + if (vgmstream->coding_type==coding_FFmpeg) { + seek_ffmpeg(vgmstream, vgmstream->loop_start_sample); + } #endif #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) - if (vgmstream->coding_type==coding_MP4_AAC) { - mp4_aac_codec_data *data = (mp4_aac_codec_data *)(vgmstream->codec_data); - data->sampleId = 0; - data->sample_ptr = data->samples_per_frame; - data->samples_discard = vgmstream->loop_sample; - } + if (vgmstream->coding_type==coding_MP4_AAC) { + seek_mp4_aac(vgmstream, vgmstream->loop_sample); + } #endif #ifdef VGM_USE_MAIATRAC3PLUS - if (vgmstream->coding_type==coding_AT3plus) { - int blocks_to_skip = vgmstream->loop_sample / 2048; - int samples_to_discard = vgmstream->loop_sample % 2048; - maiatrac3plus_codec_data *data = (maiatrac3plus_codec_data *)(vgmstream->codec_data); - vgmstream->loop_ch[0].offset = - vgmstream->loop_ch[0].channel_start_offset + - vgmstream->interleave_block_size * blocks_to_skip; - data->samples_discard = samples_to_discard; - } + if (vgmstream->coding_type==coding_AT3plus) { + seek_at3plus(vgmstream, vgmstream->loop_sample); + } #endif #ifdef VGM_USE_MPEG - /* won't work for fake MPEG */ - if (vgmstream->layout_type==layout_mpeg) { - seek_mpeg(vgmstream, vgmstream->loop_sample); - } + if (vgmstream->layout_type==layout_mpeg) { + seek_mpeg(vgmstream, vgmstream->loop_sample); /* won't work for fake MPEG */ + } #endif - if (vgmstream->coding_type == coding_NWA0 || - vgmstream->coding_type == coding_NWA1 || - vgmstream->coding_type == coding_NWA2 || - vgmstream->coding_type == coding_NWA3 || - vgmstream->coding_type == coding_NWA4 || - vgmstream->coding_type == coding_NWA5) - { - nwa_codec_data *data = vgmstream->codec_data; - - seek_nwa(data->nwa, vgmstream->loop_sample); - } - - /* restore! */ - memcpy(vgmstream->ch,vgmstream->loop_ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); - vgmstream->current_sample=vgmstream->loop_sample; - vgmstream->samples_into_block=vgmstream->loop_samples_into_block; - vgmstream->current_block_size=vgmstream->loop_block_size; - vgmstream->current_block_offset=vgmstream->loop_block_offset; - vgmstream->next_block_offset=vgmstream->loop_next_block_offset; - - return 1; + if (vgmstream->coding_type == coding_NWA0 || + vgmstream->coding_type == coding_NWA1 || + vgmstream->coding_type == coding_NWA2 || + vgmstream->coding_type == coding_NWA3 || + vgmstream->coding_type == coding_NWA4 || + vgmstream->coding_type == coding_NWA5) + { + nwa_codec_data *data = vgmstream->codec_data; + seek_nwa(data->nwa, vgmstream->loop_sample); } + /* restore! */ + memcpy(vgmstream->ch,vgmstream->loop_ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); + vgmstream->current_sample = vgmstream->loop_sample; + vgmstream->samples_into_block = vgmstream->loop_samples_into_block; + vgmstream->current_block_size = vgmstream->loop_block_size; + vgmstream->current_block_offset = vgmstream->loop_block_offset; + vgmstream->next_block_offset = vgmstream->loop_next_block_offset; - /* is this the loop start? */ - if (!vgmstream->hit_loop && vgmstream->current_sample==vgmstream->loop_start_sample) { - /* save! */ - memcpy(vgmstream->loop_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); + return 1; /* looped */ + } - vgmstream->loop_sample=vgmstream->current_sample; - vgmstream->loop_samples_into_block=vgmstream->samples_into_block; - vgmstream->loop_block_size=vgmstream->current_block_size; - vgmstream->loop_block_offset=vgmstream->current_block_offset; - vgmstream->loop_next_block_offset=vgmstream->next_block_offset; - vgmstream->hit_loop=1; - } - /*}*/ - return 0; + + /* is this the loop start? */ + if (!vgmstream->hit_loop && vgmstream->current_sample==vgmstream->loop_start_sample) { + /* save! */ + memcpy(vgmstream->loop_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); + + vgmstream->loop_sample = vgmstream->current_sample; + vgmstream->loop_samples_into_block = vgmstream->samples_into_block; + vgmstream->loop_block_size = vgmstream->current_block_size; + vgmstream->loop_block_offset = vgmstream->current_block_offset; + vgmstream->loop_next_block_offset = vgmstream->next_block_offset; + vgmstream->hit_loop = 1; + } + + return 0; /* not looped */ } /* build a descriptive string */ From 0e59e6de4cf527815ca145247dc4db8d69d547b0 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 30 Apr 2017 02:09:35 +0200 Subject: [PATCH 16/16] Minor Winamp unicode preps --- winamp/in_vgmstream.c | 62 +++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/winamp/in_vgmstream.c b/winamp/in_vgmstream.c index 8d6fda52..02bc22ca 100644 --- a/winamp/in_vgmstream.c +++ b/winamp/in_vgmstream.c @@ -5,7 +5,8 @@ ** Copyright (c) 1998, Justin Frankel/Nullsoft Inc. */ -/* Winamp uses wchar_t when this is on, so extra steps are needed */ +/* Winamp uses wchar_t filenames when this is on, so extra steps are needed. + * To open unicode filenames it needs to use _wfopen, inside a WA_STREAMFILE to pass around */ //#define UNICODE_INPUT_PLUGIN @@ -45,9 +46,6 @@ In_Module input_module; /* the input module, declared at the bottom of this file */ DWORD WINAPI __stdcall decode(void *arg); -#define WINAMP_MAX_PATH 32768 /* originally 260+1 */ -char lastfn[WINAMP_MAX_PATH] = {0}; /* name of the currently playing file */ - #define DEFAULT_FADE_SECONDS "10.00" #define DEFAULT_FADE_DELAY_SECONDS "0.00" @@ -66,6 +64,8 @@ char lastfn[WINAMP_MAX_PATH] = {0}; /* name of the currently playing file */ char *priority_strings[] = {"Idle","Lowest","Below Normal","Normal","Above Normal","Highest (not recommended)","Time Critical (not recommended)"}; int priority_values[] = {THREAD_PRIORITY_IDLE,THREAD_PRIORITY_LOWEST,THREAD_PRIORITY_BELOW_NORMAL,THREAD_PRIORITY_NORMAL,THREAD_PRIORITY_ABOVE_NORMAL,THREAD_PRIORITY_HIGHEST,THREAD_PRIORITY_TIME_CRITICAL}; +#define WINAMP_MAX_PATH 32768 /* originally 260+1 */ +in_char lastfn[WINAMP_MAX_PATH] = {0}; /* name of the currently playing file */ /* Winamp Play extension list, needed to accept/play and associate extensions in Windows */ #define EXTENSION_LIST_SIZE VGM_EXTENSION_LIST_CHAR_SIZE * 6 @@ -177,6 +177,23 @@ static void build_extension_list() { } } +/* unicode utils */ +static void copy_title(in_char * dst, int dst_size, const in_char * src) { +#ifdef UNICODE_INPUT_PLUGIN + in_char *p = (in_char*)src + wcslen(src); /* find end */ + while (*p != '\\' && p >= src) /* and find last "\" */ + p--; + p++; + wcscpy(dst,p); /* copy filename only */ +#else + in_char *p = (in_char*)src + strlen(src); /* find end */ + while (*p != '\\' && p >= src) /* and find last "\" */ + p--; + p++; + strcpy(dst,p); /* copy filename only */ +#endif +} + /* ***************************************** */ /* about dialog */ @@ -254,6 +271,7 @@ int play(const in_char *fn) { /* TODO: this should either pop up an error box or close the file */ return 1; /* error */ } + /* open the stream, set up */ vgmstream = init_vgmstream(fn); /* were we able to open it? */ @@ -378,8 +396,7 @@ void setpan(int pan) { /* display information */ int infoDlg(const in_char *fn, HWND hwnd) { VGMSTREAM * infostream = NULL; - char description[1024]; - description[0]='\0'; + char description[1024] = {0}; concatn(sizeof(description),description,PLUGIN_DESCRIPTION "\n\n"); @@ -400,36 +417,35 @@ int infoDlg(const in_char *fn, HWND hwnd) { /* retrieve information on this or possibly another file */ void getfileinfo(const in_char *filename, in_char *title, int *length_in_ms) { - if (!filename || !*filename) /* currently playing file*/ + + if (!filename || !*filename) /* no filename = use currently playing file */ { - if (!vgmstream) return; - if (length_in_ms) *length_in_ms=getlength(); - if (title) - { - char *p=lastfn+strlen(lastfn); - while (*p != '\\' && p >= lastfn) p--; - strcpy((char*)title,++p); + if (!vgmstream) + return; + if (length_in_ms) + *length_in_ms = getlength(); + + if (title) { + copy_title(title,GETFILEINFO_TITLE_LENGTH, lastfn); } } else /* some other file */ { VGMSTREAM * infostream; - if (length_in_ms) - { + + if (length_in_ms) { *length_in_ms=-1000; - if ((infostream=init_vgmstream(filename))) - { + + if ((infostream=init_vgmstream(filename))) { *length_in_ms = get_vgmstream_play_samples(loop_count,fade_seconds,fade_delay_seconds,infostream)*1000LL/infostream->sample_rate; close_vgmstream(infostream); infostream=NULL; } } - if (title) - { - const char *p = filename + strlen(filename); - while (*p != '\\' && p >= filename) p--; - strcpy((char*)title,++p); + + if (title) { + copy_title(title,GETFILEINFO_TITLE_LENGTH, filename); } } }