1203 lines
27 KiB
C++
1203 lines
27 KiB
C++
#define STRICT
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <commctrl.h>
|
|
#include <shlobj.h>
|
|
#include <mmreg.h>
|
|
#include <msacm.h>
|
|
#include "out_disk.h"
|
|
#include "../winamp/wa_ipc.h"
|
|
#include <shlwapi.h>
|
|
#include <strsafe.h>
|
|
|
|
// wasabi based services for localisation support
|
|
api_service *WASABI_API_SVC = 0;
|
|
api_language *WASABI_API_LNG = 0;
|
|
HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
|
|
|
|
class CriticalSection : public CRITICAL_SECTION
|
|
{
|
|
public:
|
|
inline void Enter() {EnterCriticalSection(this);}
|
|
inline void Leave() {LeaveCriticalSection(this);}
|
|
CriticalSection() {InitializeCriticalSection(this);}
|
|
~CriticalSection() {DeleteCriticalSection(this);}
|
|
//BOOL TryEnter() {return TryEnterCriticalSection(this);}
|
|
};
|
|
|
|
class __T_SYNC
|
|
{
|
|
private:
|
|
CriticalSection *p;
|
|
public:
|
|
inline __T_SYNC(CriticalSection& s) {p=&s;p->Enter();}
|
|
inline void Leave() {if (p) p->Leave();}
|
|
inline void Enter() {if (p) p->Enter();}
|
|
inline void Abort() {p=0;}
|
|
inline ~__T_SYNC() {Leave();}
|
|
};
|
|
|
|
static CriticalSection g_sync;
|
|
|
|
#define SYNCFUNC __T_SYNC __sync(g_sync);
|
|
|
|
#define tabsize(X) (sizeof(X)/sizeof(*X))
|
|
|
|
enum
|
|
{
|
|
MODE_AUTO=0,
|
|
MODE_WAV=1,
|
|
MODE_RAW=2
|
|
};
|
|
|
|
int mode_names_idx[] = {IDS_AUTO_RECOMMENDED,IDS_FORCE_WAV_FILE,IDS_FORCE_RAW_DATA};
|
|
static const wchar_t* format_names[]={L"%title%",L"%filename%",L"%title%_%extension%",L"%filename%_%extension%"};
|
|
static wchar_t szDescription[256];
|
|
int index_name_idx[] = {IDS_DISABLED,IDS_1_DIGIT,IDS_2_DIGITS,IDS_3_DIGITS,IDS_4_DIGITS};
|
|
|
|
#define rev32(X) ((((DWORD)(X)&0xFF)<<24)|(((DWORD)(X)&0xFF00)<<8)|(((DWORD)(X)&0xFF0000)>>8)|(((DWORD)(X)&0xFF000000)>>24))
|
|
|
|
static char cfg_output_dir[MAX_PATH]="c:\\";
|
|
static char cfg_singlefile_output[MAX_PATH]="c:\\output.wav";
|
|
static bool cfg_singlefile_enabled = 0;
|
|
static bool cfg_convert_enabled=0;
|
|
static bool cfg_thread_override = 0;
|
|
static bool cfg_output_source_dir = 0;
|
|
static int cfg_output_mode=0;
|
|
static bool cfg_show_saveas=0;
|
|
static int cfg_format_mode=0;
|
|
static int cfg_format_index=2;
|
|
|
|
static bool use_convert;
|
|
|
|
|
|
static bool GetCheck(HWND wnd,int id) {return !!SendDlgItemMessage(wnd,id,BM_GETCHECK,0,0);}
|
|
|
|
static void SetCheck(HWND wnd,int id,bool b) {SendDlgItemMessage(wnd,id,BM_SETCHECK,b ? BST_CHECKED : BST_UNCHECKED,0);}
|
|
|
|
void SetPathChoiceButtonText(HWND hwndDlg, char* path, UINT id)
|
|
{
|
|
HWND control = GetDlgItem(hwndDlg, id);
|
|
HDC hdc = GetDC(control);
|
|
RECT r = {0};
|
|
char temp[MAX_PATH] = {0};
|
|
|
|
lstrcpynA(temp, path, MAX_PATH);
|
|
SelectObject(hdc, (HFONT)SendMessage(control, WM_GETFONT, 0, 0));
|
|
GetClientRect(control, &r);
|
|
r.left += 5;
|
|
r.right -= 5;
|
|
DrawTextA(hdc, temp, -1, &r, DT_PATH_ELLIPSIS|DT_WORD_ELLIPSIS|DT_MODIFYSTRING);
|
|
SetWindowTextA(control, temp);
|
|
ReleaseDC(control, hdc);
|
|
}
|
|
|
|
BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam)
|
|
{
|
|
char cl[32] = {0};
|
|
GetClassNameA(hwnd, cl, ARRAYSIZE(cl));
|
|
if (!lstrcmpiA(cl, WC_TREEVIEW))
|
|
{
|
|
PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int _stdcall browzaproc(HWND hwnd, UINT msg, LPARAM lp, LPARAM dat)
|
|
{
|
|
if (msg == BFFM_INITIALIZED)
|
|
{
|
|
SendMessage(hwnd, BFFM_SETSELECTION, 1, dat);
|
|
|
|
// this is not nice but it fixes the selection not working correctly on all OSes
|
|
EnumChildWindows(hwnd, browseEnumProc, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char g_tmp[MAX_PATH] = {0}, g_tmp_sf[MAX_PATH] = {0};
|
|
static void d_browza(HWND wnd,HWND bt,wchar_t* tx)
|
|
{
|
|
IMalloc* pMalloc=0;
|
|
SHGetMalloc(&pMalloc);
|
|
if (!pMalloc) return;
|
|
|
|
BROWSEINFOW bi=
|
|
{
|
|
wnd,
|
|
0,
|
|
0,
|
|
tx,
|
|
BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE,
|
|
browzaproc,
|
|
#ifdef WIN64
|
|
(long long)g_tmp,
|
|
#else
|
|
(long)g_tmp,
|
|
#endif
|
|
0
|
|
};
|
|
LPITEMIDLIST li=SHBrowseForFolderW(&bi);
|
|
if (li)
|
|
{
|
|
SHGetPathFromIDListA(li,g_tmp);
|
|
SetPathChoiceButtonText(wnd, g_tmp, IDC_OUTPUT_DIRECTORY);
|
|
pMalloc->Free(li);
|
|
}
|
|
pMalloc->Release();
|
|
}
|
|
|
|
static WAVEFORMATEX singlefile_wfx,singlefile_wfx_temp;
|
|
|
|
#define WFSIZ 0x800
|
|
typedef struct
|
|
{
|
|
WAVEFORMATEX wfx;
|
|
BYTE crap[WFSIZ];
|
|
} EXT_WFX;
|
|
|
|
EXT_WFX convert_wfx,convert_wfx_temp;
|
|
static const WAVEFORMATEX wfx_default =
|
|
{
|
|
WAVE_FORMAT_PCM,
|
|
2,
|
|
44100,
|
|
44100*4,
|
|
4,
|
|
16,
|
|
0
|
|
};
|
|
|
|
void _inline ACM_gettext1(char* tx, int txCch)
|
|
{
|
|
ACMFORMATDETAILS afd;
|
|
ZeroMemory(&afd, sizeof(afd));
|
|
afd.cbStruct = sizeof(afd);
|
|
afd.dwFormatTag = WAVE_FORMAT_PCM;
|
|
afd.pwfx = &singlefile_wfx_temp;
|
|
afd.cbwfx = sizeof(singlefile_wfx_temp);
|
|
if (!acmFormatDetails(0, &afd, ACM_FORMATDETAILSF_FORMAT))
|
|
{
|
|
lstrcpyn(tx, afd.szFormat, txCch);
|
|
}
|
|
}
|
|
|
|
void _inline ACM_gettext(char* tx)
|
|
{
|
|
ACMFORMATTAGDETAILS aftd;
|
|
ZeroMemory(&aftd,sizeof(aftd));
|
|
aftd.cbStruct=sizeof(aftd);
|
|
aftd.dwFormatTag=convert_wfx_temp.wfx.wFormatTag;
|
|
if (!acmFormatTagDetails(0,&aftd,ACM_FORMATTAGDETAILSF_FORMATTAG))
|
|
{
|
|
char* p=aftd.szFormatTag;
|
|
while(p && *p) *(tx++)=*(p++);
|
|
*(tx++)=13;
|
|
*(tx++)=10;
|
|
}
|
|
ACMFORMATDETAILS afd;
|
|
ZeroMemory(&afd,sizeof(afd));
|
|
afd.cbStruct=sizeof(afd);
|
|
afd.dwFormatTag=convert_wfx_temp.wfx.wFormatTag;
|
|
afd.pwfx=&convert_wfx_temp.wfx;
|
|
afd.cbwfx=sizeof(convert_wfx_temp);
|
|
if (!acmFormatDetails(0,&afd,ACM_FORMATDETAILSF_FORMAT))
|
|
{
|
|
char* p=afd.szFormat;
|
|
while(p && *p) *(tx++)=*(p++);
|
|
}
|
|
*tx=0;
|
|
}
|
|
|
|
void ACM_choose(HWND w,bool pcm)
|
|
{
|
|
ACMFORMATCHOOSE afc;
|
|
memset(&afc,0,sizeof(afc));
|
|
afc.cbStruct=sizeof(afc);
|
|
afc.fdwStyle=ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT;
|
|
if (pcm)
|
|
{
|
|
singlefile_wfx_temp.wFormatTag=WAVE_FORMAT_PCM;
|
|
afc.pwfxEnum=&singlefile_wfx_temp;
|
|
afc.fdwEnum=ACM_FORMATENUMF_WFORMATTAG;
|
|
afc.pwfx = &singlefile_wfx_temp;
|
|
afc.cbwfx = sizeof(singlefile_wfx_temp);
|
|
}
|
|
else
|
|
{
|
|
afc.pwfx = &convert_wfx_temp.wfx;
|
|
afc.cbwfx = sizeof(convert_wfx_temp);
|
|
}
|
|
|
|
afc.hwndOwner=w;
|
|
|
|
if (!acmFormatChoose(&afc))
|
|
{
|
|
if (pcm)
|
|
{
|
|
SetDlgItemText(w,IDC_SINGLEFILE_FORMAT_BUTTON,afc.szFormat);
|
|
}
|
|
else
|
|
{
|
|
char tmp[512] = {0};
|
|
StringCchPrintf(tmp, 512, "%s\x0d\x0a%s",afc.szFormatTag,afc.szFormat);
|
|
SetDlgItemText(w,IDC_CONVERT_BUTTON,tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void _inline do_acm_text(HWND wnd)
|
|
{
|
|
char tmp[256] = {0};
|
|
ACM_gettext(tmp);
|
|
SetDlgItemText(wnd,IDC_CONVERT_BUTTON,tmp);
|
|
}
|
|
|
|
void _inline do_acm_text1(HWND wnd)
|
|
{
|
|
char tmp[256] = {0};
|
|
ACM_gettext1(tmp, 256);
|
|
SetDlgItemText(wnd,IDC_SINGLEFILE_FORMAT_BUTTON,tmp);
|
|
}
|
|
|
|
void wav1_set(HWND w,bool b)
|
|
{
|
|
static struct
|
|
{
|
|
WORD id;
|
|
bool t;
|
|
} wav1_w_c[]=
|
|
{
|
|
{IDC_OUTPUT_STATIC,1},
|
|
{IDC_OUTPUT_DIRECTORY_STATIC,1},
|
|
{IDC_OUTPUT_DIRECTORY,1},
|
|
{IDC_OUTPUT_SRCDIR,1},
|
|
{IDC_FILENAME_SAVEAS,1},
|
|
{IDC_FILENAME_INDEX_STATIC,1},
|
|
{IDC_FILENAME_INDEX,1},
|
|
{IDC_OUTMODE_STATIC,1},
|
|
{IDC_OUTMODE,1},
|
|
{IDC_CONVERT_STATIC,1},
|
|
{IDC_CONVERT_CHECK,1},
|
|
{IDC_CONVERT_BUTTON,1},
|
|
{IDC_CONVERT_NOTE,1},
|
|
{IDC_FILENAME_FORMAT,1},
|
|
{IDC_FILENAME_FORMAT_STATIC,1},
|
|
{IDC_SINGLEFILE_FILE_STATIC,0},
|
|
{IDC_SINGLEFILE_FILE_BUTTON,0},
|
|
{IDC_SINGLEFILE_FORMAT_STATIC,0},
|
|
{IDC_SINGLEFILE_FORMAT_BUTTON,0},
|
|
};
|
|
|
|
UINT n;
|
|
for(n=0;n<tabsize(wav1_w_c);n++)
|
|
{
|
|
EnableWindow(GetDlgItem(w,wav1_w_c[n].id),wav1_w_c[n].t^b);
|
|
}
|
|
}
|
|
|
|
BOOL CALLBACK DlgProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
|
|
{
|
|
switch(msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
wchar_t title[128] = {0}, temp[128] = {0};
|
|
StringCchPrintfW(title,128,WASABI_API_LNGSTRINGW(IDS_SETTINGS_TITLE),WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_DISK_WRITER_OLD, temp, 128));
|
|
SetWindowTextW(wnd,title);
|
|
SetDlgItemText(wnd,IDC_OUTPUT_DIRECTORY,cfg_output_dir);
|
|
SetPathChoiceButtonText(wnd,cfg_output_dir,IDC_OUTPUT_DIRECTORY);
|
|
lstrcpyn(g_tmp,cfg_output_dir,MAX_PATH);
|
|
SetCheck(wnd,IDC_CONVERT,cfg_convert_enabled);
|
|
memcpy(&convert_wfx_temp,&convert_wfx,sizeof(convert_wfx));
|
|
memcpy(&singlefile_wfx_temp,&singlefile_wfx,sizeof(WAVEFORMATEX));
|
|
SetCheck(wnd,IDC_SINGLEFILE_CHECK,cfg_singlefile_enabled);
|
|
SetCheck(wnd,IDC_THREAD_HACK,cfg_thread_override);
|
|
SetPathChoiceButtonText(wnd,cfg_singlefile_output,IDC_SINGLEFILE_FILE_BUTTON);
|
|
lstrcpyn(g_tmp_sf,cfg_singlefile_output,MAX_PATH);
|
|
do_acm_text(wnd);
|
|
do_acm_text1(wnd);
|
|
|
|
{
|
|
HWND w=GetDlgItem(wnd,IDC_MODE);
|
|
int n;
|
|
for(n=0;n<tabsize(mode_names_idx);n++)
|
|
SendMessageW(w,CB_ADDSTRING,0,
|
|
#ifdef WIN64
|
|
(long long)WASABI_API_LNGSTRINGW(mode_names_idx[n])
|
|
#else
|
|
(long)WASABI_API_LNGSTRINGW(mode_names_idx[n])
|
|
#endif
|
|
);
|
|
SendMessage(w,CB_SETCURSEL,cfg_output_mode,0);
|
|
|
|
w=GetDlgItem(wnd,IDC_FILENAME_FORMAT);
|
|
for(n=0;n<tabsize(format_names);n++)
|
|
SendMessageW(w,CB_ADDSTRING,0,
|
|
#ifdef WIN64
|
|
(long long)format_names[n]
|
|
#else
|
|
(long)format_names[n]
|
|
#endif
|
|
);
|
|
SendMessage(w,CB_SETCURSEL,cfg_format_mode,0);
|
|
|
|
w=GetDlgItem(wnd,IDC_FILENAME_INDEX);
|
|
for(n=0;n<tabsize(index_name_idx);n++)
|
|
SendMessageW(w,CB_ADDSTRING,0,
|
|
#ifdef WIN64
|
|
(long long)WASABI_API_LNGSTRINGW(index_name_idx[n])
|
|
#else
|
|
(long)WASABI_API_LNGSTRINGW(index_name_idx[n])
|
|
#endif
|
|
);
|
|
SendMessage(w,CB_SETCURSEL,cfg_format_index,0);
|
|
}
|
|
|
|
wav1_set(wnd,cfg_singlefile_enabled);
|
|
|
|
SetCheck(wnd,IDC_OUTPUT_SRCDIR,cfg_output_source_dir);
|
|
SetCheck(wnd,IDC_FILENAME_SAVEAS,cfg_show_saveas);
|
|
|
|
return 1;
|
|
}
|
|
case WM_COMMAND:
|
|
if (wp==IDC_CONVERT_BUTTON)
|
|
{
|
|
ACM_choose(wnd,0);
|
|
}
|
|
else if (wp==IDC_OUTPUT_DIRECTORY)
|
|
{
|
|
d_browza(wnd,(HWND)lp,WASABI_API_LNGSTRINGW(IDS_SELECT_OUTPUT_DIRECTORY));
|
|
}
|
|
else if (wp==IDCANCEL) EndDialog(wnd,0);
|
|
else if (wp==IDOK)
|
|
{
|
|
cfg_convert_enabled=GetCheck(wnd,IDC_CONVERT);
|
|
lstrcpyn(cfg_output_dir,g_tmp,MAX_PATH);
|
|
memcpy(&convert_wfx,&convert_wfx_temp,sizeof(convert_wfx));
|
|
memcpy(&singlefile_wfx,&singlefile_wfx_temp,sizeof(WAVEFORMATEX));
|
|
cfg_singlefile_enabled=GetCheck(wnd,IDC_SINGLEFILE_CHECK);
|
|
cfg_thread_override=GetCheck(wnd,IDC_THREAD_HACK);
|
|
cfg_output_mode=(int)SendDlgItemMessage(wnd,IDC_MODE,CB_GETCURSEL,0,0);
|
|
lstrcpyn(cfg_singlefile_output,g_tmp_sf,MAX_PATH);
|
|
cfg_output_source_dir=GetCheck(wnd,IDC_OUTPUT_SRCDIR);
|
|
cfg_show_saveas=GetCheck(wnd,IDC_FILENAME_SAVEAS);
|
|
|
|
cfg_format_mode=(int)SendDlgItemMessage(wnd,IDC_FILENAME_FORMAT,CB_GETCURSEL,0,0);
|
|
cfg_format_index=(int)SendDlgItemMessage(wnd,IDC_FILENAME_INDEX,CB_GETCURSEL,0,0);
|
|
|
|
EndDialog(wnd,0);
|
|
}
|
|
else if (wp==IDC_SINGLEFILE_FILE_BUTTON)
|
|
{
|
|
char tmp[MAX_PATH] = {0}, filter[64] = {0};
|
|
|
|
StringCchPrintf(filter,64, WASABI_API_LNGSTRING(IDS_X_FILES_DOT_X),"WAV",".wav");
|
|
char * ptr=filter;
|
|
while(ptr && *ptr)
|
|
{
|
|
if (*ptr=='|') *ptr=0;
|
|
ptr++;
|
|
}
|
|
|
|
GetDlgItemText(wnd,IDC_SINGLEFILE_FILE_BUTTON,tmp,MAX_PATH);
|
|
lstrcpyn(tmp,g_tmp_sf,MAX_PATH);
|
|
OPENFILENAME ofn = {0};
|
|
ofn.lStructSize=sizeof(ofn);
|
|
ofn.hwndOwner=wnd;
|
|
ofn.lpstrFilter=filter;
|
|
ofn.lpstrFile=tmp;
|
|
ofn.nMaxFile=MAX_PATH;
|
|
ofn.Flags=OFN_HIDEREADONLY|OFN_PATHMUSTEXIST;
|
|
ofn.lpstrDefExt="wav";
|
|
if (GetSaveFileName(&ofn))
|
|
{
|
|
SetPathChoiceButtonText(wnd,tmp,IDC_SINGLEFILE_FILE_BUTTON);
|
|
lstrcpyn(g_tmp_sf, tmp, MAX_PATH);
|
|
}
|
|
}
|
|
else if (wp==IDC_SINGLEFILE_FORMAT_BUTTON) ACM_choose(wnd,1);
|
|
else if (wp==IDC_SINGLEFILE_CHECK) wav1_set(wnd,GetCheck(wnd,IDC_SINGLEFILE_CHECK));
|
|
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void Config(HWND hWnd)
|
|
{
|
|
WASABI_API_DIALOGBOXW(IDD_DIALOG1,hWnd,DlgProc);
|
|
}
|
|
|
|
static int nsam;
|
|
static int g_freq,g_nch,g_bps;
|
|
static int paused;
|
|
|
|
const static char badchars[]={'.','\\','/',':','*','?','\"','<','>','|'};
|
|
|
|
char* GetDefaultSaveToFolder(char* path_to_store)
|
|
{
|
|
if(FAILED(SHGetFolderPathA(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, path_to_store)))
|
|
{
|
|
if(FAILED(SHGetFolderPathA(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path_to_store)))
|
|
{
|
|
lstrcpynA(path_to_store, "C:\\", MAX_PATH);
|
|
}
|
|
}
|
|
return path_to_store;
|
|
}
|
|
|
|
static void GetName(char* out, int outCch, const char* format_ext)
|
|
{
|
|
int index = (int)SendMessage(mod.hMainWindow,WM_USER,0,IPC_GETLISTPOS);
|
|
|
|
if (cfg_output_source_dir)
|
|
{
|
|
const char * dir=(const char *)SendMessage(mod.hMainWindow,WM_USER,index,211);
|
|
const char * last=strrchr(dir,'\\');
|
|
while(dir<=last) {*(out++)=*(dir++);}
|
|
}
|
|
else
|
|
{
|
|
char * dir=cfg_output_dir;
|
|
if (!*dir)
|
|
{
|
|
char tmp[MAX_PATH] = {0};
|
|
dir=GetDefaultSaveToFolder(tmp);
|
|
}
|
|
while(dir && *dir) {*(out++)=*(dir++);}
|
|
if (out[-1]!='\\') *(out++)='\\';
|
|
}
|
|
|
|
char * badchar_test = out;
|
|
|
|
if (cfg_format_index>0)
|
|
{
|
|
char temp[16] = {0};
|
|
StringCchPrintf(temp, 16, "%09u_",index+1);
|
|
lstrcpyn(out, temp+9-cfg_format_index, outCch);
|
|
out+=cfg_format_index+1;
|
|
}
|
|
|
|
if (cfg_format_mode&1)//filename
|
|
{
|
|
const char * source_full = (const char*)SendMessage(mod.hMainWindow,WM_USER,index,211);
|
|
const char * source = strrchr(source_full,'\\');
|
|
if (!source) source = source_full;
|
|
else source++;
|
|
|
|
const char * dot = strrchr(source,'.');
|
|
if (dot) while(source<dot) *(out++)=*(source++);
|
|
else while(source && *source) *(out++)=*(source++);
|
|
}
|
|
else //title
|
|
{
|
|
const char * source = (const char*)SendMessage(mod.hMainWindow,WM_USER,index,212);
|
|
if (!source) source = "(unknown title)";
|
|
while(source && *source) *(out++)=*(source++);
|
|
}
|
|
|
|
if (cfg_format_mode&2)
|
|
{//add extension
|
|
const char * extension = strrchr((const char*)SendMessage(mod.hMainWindow,WM_USER,index,211),'.');
|
|
while(extension && *extension) *(out++)=*(extension++);
|
|
}
|
|
|
|
|
|
while(badchar_test<out)
|
|
{
|
|
BYTE c = *badchar_test;
|
|
int n;
|
|
for(n=0;n<tabsize(badchars);n++)
|
|
{
|
|
if (c==badchars[n]) {*badchar_test='_';break;}
|
|
}
|
|
|
|
badchar_test++;
|
|
}
|
|
|
|
while(format_ext && *format_ext) *(out++)=*(format_ext++);
|
|
*out=0;
|
|
}
|
|
|
|
static HANDLE hOut=INVALID_HANDLE_VALUE;
|
|
|
|
static HACMSTREAM hStream;
|
|
|
|
static DWORD fact_ofs,data_ofs;
|
|
static bool riff;
|
|
|
|
static DWORD FileTell(HANDLE hFile) {return SetFilePointer(hFile,0,0,FILE_CURRENT);}
|
|
static void FileAlign(HANDLE hFile) {if (FileTell(hFile)&1) SetFilePointer(hFile,1,0,FILE_CURRENT);}
|
|
|
|
#define BUFSIZE 0x20000
|
|
|
|
static BYTE *acm_outbuf;
|
|
static UINT acm_outbufsize;
|
|
static BYTE *acm_buf;
|
|
static BYTE *acm_buf1;
|
|
static UINT inbuf,inbuf1;
|
|
|
|
static ACMSTREAMHEADER ahd,ahd1;
|
|
static bool active;
|
|
|
|
static void file_err(char* f, wchar_t* t)
|
|
{
|
|
wchar_t tmp[512+128] = {0};
|
|
StringCchPrintfW(tmp, 512+128, L"%s: \"%hs\"", t, f);
|
|
MessageBoxW(mod.hMainWindow, tmp, szDescription, MB_ICONERROR);
|
|
}
|
|
|
|
void acm_close();
|
|
|
|
static int pos_delta;
|
|
|
|
int Open(int sr,int nch,int bps,int xx,int xxx)
|
|
{
|
|
// if someone didn't call Close(), close the file for them
|
|
if (hOut!=INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hOut);
|
|
hOut=INVALID_HANDLE_VALUE;
|
|
}
|
|
int failFlags = 0;
|
|
SYNCFUNC;
|
|
char fn[512] = {0};
|
|
use_convert=cfg_convert_enabled;
|
|
DWORD bw = 0, t = 0;
|
|
WAVEFORMATEX wfx=
|
|
{
|
|
WAVE_FORMAT_PCM,
|
|
(WORD)nch,
|
|
(DWORD)sr,
|
|
(DWORD)(sr*nch*(bps>>3)),
|
|
(WORD)(nch*(bps>>3)),
|
|
(WORD)bps,
|
|
0
|
|
};
|
|
bool append=0;
|
|
|
|
WAVEFORMATEX *pDst=&convert_wfx.wfx;
|
|
if (!cfg_convert_enabled) pDst=&wfx;
|
|
if (cfg_singlefile_enabled)
|
|
{
|
|
pDst=&singlefile_wfx;
|
|
use_convert=1;
|
|
lstrcpyn(fn, cfg_singlefile_output,512);
|
|
riff=1;
|
|
}
|
|
else
|
|
{
|
|
const char* ext=".wav";
|
|
riff=1;
|
|
if (cfg_output_mode==MODE_RAW)
|
|
{
|
|
riff=0;
|
|
ext=".raw";
|
|
}
|
|
else if (cfg_output_mode==MODE_AUTO)
|
|
{
|
|
if (pDst->wFormatTag==WAVE_FORMAT_MPEGLAYER3)
|
|
{
|
|
riff=0;
|
|
ext=".mp3";
|
|
}
|
|
}
|
|
GetName(fn, 512, ext);
|
|
if (cfg_show_saveas)
|
|
{
|
|
char filter[64] = {0}, title[128] = {0}, title2[128] = {0};
|
|
StringCchPrintf(filter,64, WASABI_API_LNGSTRING(IDS_X_FILES_DOT_X),ext,ext);
|
|
char * ptr=filter;
|
|
while(ptr && *ptr)
|
|
{
|
|
if (*ptr=='|') *ptr=0;
|
|
ptr++;
|
|
}
|
|
|
|
OPENFILENAME ofn= {0};
|
|
ofn.lStructSize=sizeof(ofn);
|
|
ofn.hwndOwner=mod.hMainWindow;
|
|
ofn.lpstrFilter = filter;
|
|
ofn.lpstrFile = fn;
|
|
StringCchPrintf(title,128,WASABI_API_LNGSTRING(IDS_CHOOSE_FILE_NAME),
|
|
WASABI_API_LNGSTRING_BUF(IDS_NULLSOFT_DISK_WRITER,title2,128));
|
|
ofn.lpstrTitle = title;
|
|
ofn.nMaxFile = tabsize(fn);
|
|
ofn.Flags = OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT;
|
|
ofn.lpstrDefExt = ext;
|
|
if (!GetOpenFileName(&ofn)) return -1;
|
|
}
|
|
}
|
|
|
|
if (memcmp(&wfx,pDst,sizeof(wfx))==0) use_convert=0;
|
|
|
|
nsam=0;
|
|
g_freq=sr;
|
|
g_nch=nch;
|
|
g_bps=bps;
|
|
paused=0;
|
|
|
|
SetLastError(0);
|
|
hOut=CreateFile(fn,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,0);
|
|
|
|
if (hOut==INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD e=GetLastError();
|
|
|
|
if (e==ERROR_ALREADY_EXISTS || e==0x50)
|
|
{
|
|
if (cfg_singlefile_enabled)
|
|
{
|
|
append=1;
|
|
goto _ap;
|
|
}
|
|
wchar_t tmp[512+128] = {0};
|
|
StringCchPrintfW(tmp, 512+128, WASABI_API_LNGSTRINGW(IDS_FILE_ALREADY_EXISTS_OVERWRITE),fn);
|
|
if (MessageBoxW(mod.hMainWindow,tmp,szDescription,MB_ICONQUESTION|MB_OKCANCEL)==IDOK)
|
|
{
|
|
hOut=CreateFile(fn,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0);
|
|
}
|
|
else return -1;
|
|
}
|
|
if (hOut==INVALID_HANDLE_VALUE)
|
|
{
|
|
file_err(fn, WASABI_API_LNGSTRINGW(IDS_CANNOT_CREATE_OUTPUT_FILE));
|
|
return -1;
|
|
}
|
|
}
|
|
_ap:
|
|
fact_ofs=data_ofs=0;
|
|
if (append)
|
|
{
|
|
|
|
hOut=CreateFile(fn,GENERIC_WRITE|GENERIC_READ,0,0,OPEN_EXISTING,0,0);
|
|
if (hOut==INVALID_HANDLE_VALUE)
|
|
{
|
|
file_err(fn, WASABI_API_LNGSTRINGW(IDS_CANNOT_OPEN_FILE));
|
|
return -1;
|
|
}
|
|
{
|
|
DWORD br=0;
|
|
DWORD rf=0,wfs=0;
|
|
ReadFile(hOut,&rf,4,&br,0);
|
|
if (rf!='FFIR') goto ap_f;
|
|
SetFilePointer(hOut,4,0,FILE_CURRENT);
|
|
br=0; ReadFile(hOut,&rf,4,&br,0);
|
|
if (rf!='EVAW') goto ap_f;
|
|
br=0; ReadFile(hOut,&rf,4,&br,0);
|
|
if (rf!=' tmf') goto ap_f;
|
|
static WAVEFORMATEX ap_wfx;
|
|
br=0; ReadFile(hOut,&wfs,4,&br,0);
|
|
if (wfs<sizeof(ap_wfx)-2 || wfs>sizeof(ap_wfx)) goto ap_f;
|
|
br=0; ReadFile(hOut,&ap_wfx,wfs,&br,0);
|
|
if (ap_wfx.wFormatTag!=WAVE_FORMAT_PCM) goto ap_f;
|
|
br=0; ReadFile(hOut,&rf,4,&br,0);
|
|
pDst=&ap_wfx;
|
|
if (rf!='atad') goto ap_f;
|
|
data_ofs=8+4+8+wfs+4;
|
|
DWORD data_size=0;
|
|
br=0; ReadFile(hOut,&data_size,4,&br,0);
|
|
SetFilePointer(hOut,data_size,0,FILE_CURRENT);
|
|
SetEndOfFile(hOut);
|
|
use_convert = !!memcmp(&wfx,&ap_wfx,sizeof(wfx));
|
|
}
|
|
goto ap_ok;
|
|
ap_f:
|
|
file_err(fn, WASABI_API_LNGSTRINGW(IDS_NOT_A_PCM_WAV_FILE));
|
|
if (hOut && hOut!=INVALID_HANDLE_VALUE) {CloseHandle(hOut);hOut=INVALID_HANDLE_VALUE;}
|
|
return -1;
|
|
ap_ok:;
|
|
}
|
|
|
|
if (riff && !append)
|
|
{
|
|
t=rev32('RIFF');
|
|
bw = 0; WriteFile(hOut,&t,4,&bw,0);
|
|
SetFilePointer(hOut,4,0,FILE_CURRENT);
|
|
t=rev32('WAVE');
|
|
bw = 0; WriteFile(hOut,&t,4,&bw,0);
|
|
t=rev32('fmt ');
|
|
bw = 0; WriteFile(hOut,&t,4,&bw,0);
|
|
}
|
|
|
|
if (use_convert)
|
|
{
|
|
#ifdef SSRC
|
|
if (pDst->wFormatTag==WAVE_FORMAT_PCM)
|
|
{
|
|
if ((wfx.nChannels!=1 && wfx.nChannels!=2) || (pDst->nChannels!=1 && pDst->nChannels!=2)) goto fail;
|
|
|
|
res = SSRC_create(wfx.nSamplesPerSec,pDst->nSamplesPerSec,wfx.wBitsPerSample,pDst->wBitsPerSample,wfx.nChannels,2,1,0,0,wfx.nChannels!=pDst->nChannels);
|
|
|
|
acm_outbuf=0;
|
|
acm_outbufsize=0;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
MMRESULT rs=acmStreamOpen(&hStream,0,&wfx,pDst,0,0,0,ACM_STREAMOPENF_NONREALTIME);
|
|
if (rs)
|
|
{
|
|
WAVEFORMATEX wfx1;
|
|
ZeroMemory(&wfx1,sizeof(wfx1));
|
|
wfx1.wFormatTag=WAVE_FORMAT_PCM;
|
|
if (acmFormatSuggest(0,pDst,&wfx1,sizeof(WAVEFORMATEX),ACM_FORMATSUGGESTF_WFORMATTAG)) goto fail;
|
|
if (acmStreamOpen(&hStream,0,&wfx1,pDst,0,0,0,ACM_STREAMOPENF_NONREALTIME)) goto fail;
|
|
|
|
if ((wfx.nChannels!=1 && wfx.nChannels!=2) || (wfx1.nChannels!=1 && wfx1.nChannels!=2)) goto fail;
|
|
#ifdef SSRC
|
|
res = SSRC_create(wfx.nSamplesPerSec,wfx1.nSamplesPerSec,wfx.wBitsPerSample,wfx1.wBitsPerSample,wfx.nChannels,2,1,0,0,wfx.nChannels!=wfx1.nChannels);
|
|
//TODO fix different channel setups
|
|
#endif
|
|
acm_buf1=(BYTE*)malloc(BUFSIZE);
|
|
|
|
if (!acm_buf1
|
|
#ifdef SSRC
|
|
|| !res
|
|
#endif
|
|
)
|
|
goto fail;
|
|
}
|
|
acm_buf=(BYTE*)malloc(BUFSIZE);
|
|
acm_outbuf=(BYTE*)malloc(BUFSIZE);
|
|
if (!acm_buf || !acm_outbuf) goto fail;
|
|
ZeroMemory(&ahd,sizeof(ahd));
|
|
ahd.cbStruct=sizeof(ahd);
|
|
ahd.pbSrc=acm_buf;
|
|
ahd.cbSrcLength=BUFSIZE;
|
|
ahd.pbDst=acm_outbuf;
|
|
ahd.cbDstLength=BUFSIZE;
|
|
if (acmStreamPrepareHeader(hStream,&ahd,0)) goto fail;
|
|
}
|
|
|
|
if (riff && !append)
|
|
{
|
|
if (pDst->wFormatTag==WAVE_FORMAT_PCM) t=0x10;
|
|
else t=sizeof(WAVEFORMATEX)+pDst->cbSize;
|
|
bw = 0; WriteFile(hOut,&t,4,&bw,0);
|
|
bw = 0; WriteFile(hOut,pDst,t,&bw,0);
|
|
FileAlign(hOut);
|
|
|
|
if (pDst->wFormatTag!=WAVE_FORMAT_PCM)
|
|
{
|
|
t=rev32('fact');
|
|
bw = 0; WriteFile(hOut,&t,4,&bw,0);
|
|
t=4;
|
|
bw = 0; WriteFile(hOut,&t,4,&bw,0);
|
|
fact_ofs=FileTell(hOut);
|
|
SetFilePointer(hOut,4,0,FILE_CURRENT);
|
|
}
|
|
|
|
t=rev32('data');
|
|
bw = 0; WriteFile(hOut,&t,4,&bw,0);
|
|
data_ofs=FileTell(hOut);
|
|
SetFilePointer(hOut,4,0,FILE_CURRENT);
|
|
}
|
|
}
|
|
else if (riff && !append)
|
|
{
|
|
t=0x10;
|
|
//t=sizeof(WAVEFORMATEX)+pDst->cbSize;
|
|
bw = 0; WriteFile(hOut,&t,4,&bw,0);
|
|
bw = 0; WriteFile(hOut,&wfx,t,&bw,0);
|
|
t=rev32('data');
|
|
bw = 0; WriteFile(hOut,&t,4,&bw,0);
|
|
data_ofs=FileTell(hOut);
|
|
SetFilePointer(hOut,4,0,FILE_CURRENT);
|
|
}
|
|
inbuf1=inbuf=0;
|
|
|
|
active=1;
|
|
|
|
pos_delta=0;
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
if (hOut && hOut!=INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hOut);
|
|
hOut=INVALID_HANDLE_VALUE;
|
|
DeleteFile(fn);
|
|
}
|
|
hOut=0;
|
|
acm_close();
|
|
MessageBoxW(mod.hMainWindow,WASABI_API_LNGSTRINGW(IDS_ERROR_INITIALIZING_OUTPUT),
|
|
szDescription,MB_ICONERROR);
|
|
return -1;
|
|
}
|
|
|
|
void acm_close()
|
|
{
|
|
#ifdef SSRC
|
|
if (res)
|
|
{
|
|
if (acm_buf1)
|
|
{
|
|
free(acm_buf1);
|
|
acm_buf1=0;
|
|
}
|
|
delete res;
|
|
res=0;
|
|
}
|
|
#endif
|
|
if (hStream)
|
|
{
|
|
if (ahd.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) acmStreamUnprepareHeader(hStream,&ahd,0);
|
|
ZeroMemory(&ahd,sizeof(ahd));
|
|
acmStreamClose(hStream,0);
|
|
hStream=0;
|
|
if (acm_buf)
|
|
{
|
|
free(acm_buf);
|
|
acm_buf=0;
|
|
}
|
|
if (acm_outbuf)
|
|
{
|
|
free(acm_outbuf);
|
|
acm_outbuf=0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void do_cvt(BYTE* data,UINT size);
|
|
|
|
void Close()
|
|
{
|
|
SYNCFUNC;
|
|
active=0;
|
|
if (use_convert)
|
|
{
|
|
do_cvt(0,0);
|
|
acm_close();
|
|
}
|
|
if (hOut!=INVALID_HANDLE_VALUE)
|
|
{
|
|
if (riff)
|
|
{
|
|
FileAlign(hOut);
|
|
|
|
DWORD t,bw = 0;
|
|
SetFilePointer(hOut,4,0,FILE_BEGIN);
|
|
t=GetFileSize(hOut,0)-8;
|
|
WriteFile(hOut,&t,4,&bw,0);
|
|
if (data_ofs)
|
|
{
|
|
DWORD data_size=GetFileSize(hOut,0)-(data_ofs+4);
|
|
SetFilePointer(hOut,data_ofs,0,FILE_BEGIN);
|
|
bw = 0; WriteFile(hOut,&data_size,4,&bw,0);
|
|
}
|
|
if (fact_ofs)
|
|
{
|
|
SetFilePointer(hOut,fact_ofs,0,FILE_BEGIN);
|
|
t=nsam;
|
|
bw = 0; WriteFile(hOut,&t,4,&bw,0);
|
|
}
|
|
}
|
|
CloseHandle(hOut);
|
|
hOut=INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
void do_cvt(BYTE* data,UINT size)
|
|
{
|
|
#ifdef SSRC
|
|
if (res && !hStream)
|
|
{
|
|
if (!data || !size) res->Finish();
|
|
else res->Write(data,size);
|
|
|
|
UINT out_size;
|
|
void *out = res->GetBuffer(&out_size);
|
|
DWORD bw = 0;
|
|
WriteFile(hOut,out,out_size,&bw,0);
|
|
res->Read(out_size);
|
|
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
DWORD flags=0;
|
|
if (nsam==0) flags|=ACM_STREAMCONVERTF_START;
|
|
if (data) flags|=ACM_STREAMCONVERTF_BLOCKALIGN;
|
|
#ifdef SSRC
|
|
if (res)
|
|
{
|
|
if (inbuf1+size>BUFSIZE) return;
|
|
if (data)
|
|
{
|
|
memcpy(acm_buf1+inbuf1,data,size);
|
|
inbuf1+=size;
|
|
}
|
|
res->Write(acm_buf1,inbuf1);
|
|
memcpy(acm_buf1,acm_buf1+inbuf1,inbuf1);
|
|
inbuf1=0;
|
|
if (!data || !size) res->Finish();
|
|
data = (BYTE*)res->GetBuffer(&size);
|
|
if (inbuf+size>BUFSIZE) return;
|
|
memcpy(acm_buf+inbuf,data,size);
|
|
inbuf+=size;
|
|
res->Read(size);
|
|
}
|
|
else
|
|
#endif
|
|
if (data)
|
|
{
|
|
if (inbuf+size>BUFSIZE) return;
|
|
memcpy(acm_buf+inbuf,data,size);
|
|
inbuf+=size;
|
|
}
|
|
|
|
ahd.cbSrcLength=inbuf;
|
|
acmStreamConvert(hStream,&ahd,flags);
|
|
inbuf-=ahd.cbSrcLengthUsed;
|
|
memmove(acm_buf,acm_buf+ahd.cbSrcLengthUsed,inbuf);//memmove
|
|
DWORD bw = 0;
|
|
WriteFile(hOut,acm_outbuf,ahd.cbDstLengthUsed,&bw,0);
|
|
}
|
|
}
|
|
|
|
int Write(char *data, int len)
|
|
{
|
|
SYNCFUNC;
|
|
if (!active) return 0;
|
|
if (cfg_thread_override) SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL);
|
|
else Sleep(0);
|
|
|
|
len-=len%((g_bps>>3)*g_nch);
|
|
|
|
nsam+=len/((g_bps>>3)*g_nch);
|
|
|
|
if (use_convert)
|
|
{
|
|
do_cvt((BYTE*)data,len);
|
|
}
|
|
else
|
|
{
|
|
DWORD bw = 0;
|
|
WriteFile(hOut,data,len,&bw,0);
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
|
|
{
|
|
MSGBOXPARAMSW msgbx = {sizeof(MSGBOXPARAMSW),0};
|
|
msgbx.lpszText = message;
|
|
msgbx.lpszCaption = title;
|
|
msgbx.lpszIcon = MAKEINTRESOURCEW(102);
|
|
msgbx.hInstance = GetModuleHandle(0);
|
|
msgbx.dwStyle = MB_USERICON;
|
|
msgbx.hwndOwner = parent;
|
|
return MessageBoxIndirectW(&msgbx);
|
|
}
|
|
|
|
void About(HWND hwndParent)
|
|
{
|
|
wchar_t message[1024] = {0}, text[1024] = {0};
|
|
WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_DISK_WRITER_OLD,text,1024);
|
|
StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT),
|
|
szDescription, __DATE__);
|
|
DoAboutMessageBox(hwndParent,text,message);
|
|
}
|
|
|
|
static bool _cfg_store;
|
|
static const char *inifile;
|
|
|
|
#define CFG_NAME "out_disk"//fixme
|
|
|
|
static void wppi(char* nam,UINT val)
|
|
{
|
|
char t[16] = {0};
|
|
StringCchPrintf(t,16, "%u",val);
|
|
WritePrivateProfileString(CFG_NAME,nam,t,inifile);
|
|
}
|
|
|
|
#define WritePrivateProfileInt(A,B,C,D) wppi(B,C)
|
|
|
|
static int _do_int(int x,char* nam)
|
|
{
|
|
if (_cfg_store)
|
|
{
|
|
WritePrivateProfileInt(CFG_NAME,nam,x,inifile);
|
|
return x;
|
|
}
|
|
else
|
|
{
|
|
return GetPrivateProfileInt(CFG_NAME,nam,x,inifile);
|
|
}
|
|
}
|
|
|
|
#define do_int(x) x=_do_int(x,#x)
|
|
#define do_bool(x) x=!!_do_int(x,#x)
|
|
|
|
static void _do_string(char* x,char* nam)
|
|
{
|
|
if (_cfg_store)
|
|
{
|
|
WritePrivateProfileString(CFG_NAME,nam,x,inifile);
|
|
}
|
|
else
|
|
{
|
|
GetPrivateProfileString(CFG_NAME,nam,x,x,MAX_PATH,inifile);
|
|
}
|
|
}
|
|
|
|
#define do_string(x) _do_string(x,#x)
|
|
|
|
void do_cfg()
|
|
{
|
|
if (!_cfg_store)
|
|
{
|
|
GetDefaultSaveToFolder(cfg_output_dir);
|
|
PathCombine(cfg_singlefile_output, cfg_output_dir, "output.wav");
|
|
}
|
|
|
|
do_string(cfg_output_dir);
|
|
do_string(cfg_singlefile_output);
|
|
do_bool(cfg_singlefile_enabled);
|
|
do_bool(cfg_convert_enabled);
|
|
do_bool(cfg_thread_override);
|
|
do_int(cfg_output_mode);
|
|
do_bool(cfg_output_source_dir);
|
|
do_bool(cfg_show_saveas);
|
|
do_int(cfg_format_mode);
|
|
do_int(cfg_format_index);
|
|
|
|
|
|
if (_cfg_store)
|
|
{
|
|
UINT _s=sizeof(WAVEFORMATEX)+convert_wfx.wfx.cbSize;
|
|
WritePrivateProfileInt(CFG_NAME,"cfg_wfx_s",_s,inifile);
|
|
WritePrivateProfileStruct(CFG_NAME,"cfg_wfx",&convert_wfx,_s,inifile);
|
|
WritePrivateProfileStruct(CFG_NAME,"cfg_wfx1",&singlefile_wfx,sizeof(singlefile_wfx),inifile);
|
|
}
|
|
else
|
|
{
|
|
UINT _s=GetPrivateProfileInt(CFG_NAME,"cfg_wfx_s",0,inifile);
|
|
if (_s && _s<=sizeof(convert_wfx))
|
|
{
|
|
GetPrivateProfileStruct(CFG_NAME,"cfg_wfx",&convert_wfx,_s,inifile);
|
|
}
|
|
GetPrivateProfileStruct(CFG_NAME,"cfg_wfx1",&singlefile_wfx,sizeof(singlefile_wfx),inifile);
|
|
}
|
|
}
|
|
|
|
void Init()
|
|
{
|
|
SYNCFUNC;
|
|
if (!mod.hMainWindow)
|
|
return;
|
|
inifile = (const char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE);
|
|
singlefile_wfx = wfx_default;
|
|
convert_wfx.wfx = wfx_default;
|
|
memset(convert_wfx.crap, 0, sizeof(convert_wfx.crap));
|
|
|
|
// loader so that we can get the localisation service api for use
|
|
WASABI_API_SVC = (api_service*)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
|
|
if (WASABI_API_SVC == (api_service*)1) WASABI_API_SVC = NULL;
|
|
|
|
waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(languageApiGUID);
|
|
if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
|
|
|
|
// need to have this initialised before we try to do anything with localisation features
|
|
WASABI_API_START_LANG(mod.hDllInstance,OutDiskLangGUID);
|
|
|
|
StringCchPrintfW(szDescription, 256, WASABI_API_LNGSTRINGW(IDS_NULLSOFT_DISK_WRITER), PLUGIN_VERSION);
|
|
mod.description = (char*)szDescription;
|
|
|
|
_cfg_store=0;
|
|
do_cfg();
|
|
}
|
|
|
|
void Quit()
|
|
{
|
|
SYNCFUNC;
|
|
if (active) Close();
|
|
|
|
_cfg_store=1;
|
|
do_cfg();
|
|
}
|
|
|
|
int CanWrite()
|
|
{
|
|
return paused ? 0 : 666666666;
|
|
}
|
|
|
|
int IsPlaying()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int Pause(int p)
|
|
{
|
|
int _p=paused;
|
|
paused=p;
|
|
return _p;
|
|
}
|
|
|
|
void SetVolume(int volume)
|
|
{
|
|
}
|
|
|
|
void SetPan(int pan)
|
|
{
|
|
}
|
|
|
|
void Flush(int t)
|
|
{
|
|
nsam=0;
|
|
pos_delta=t;
|
|
}
|
|
|
|
int GetOutputTime()
|
|
{
|
|
return pos_delta+MulDiv(nsam,1000,g_freq);
|
|
}
|
|
|
|
Out_Module mod=
|
|
{
|
|
OUT_VER_U,
|
|
0,
|
|
426119909,
|
|
0,
|
|
0,
|
|
Config,
|
|
About,
|
|
Init,
|
|
Quit,
|
|
Open,
|
|
Close,
|
|
Write,
|
|
CanWrite,
|
|
IsPlaying,
|
|
Pause,
|
|
SetVolume,
|
|
SetVolume,
|
|
Flush,
|
|
GetOutputTime,
|
|
GetOutputTime
|
|
};
|
|
|
|
extern "C"
|
|
{
|
|
__declspec( dllexport ) Out_Module * winampGetOutModule()
|
|
{
|
|
return &mod;
|
|
}
|
|
}
|
|
|
|
BOOL APIENTRY DllMain(HANDLE hMod,DWORD r,void*)
|
|
{
|
|
if (r==DLL_PROCESS_ATTACH)
|
|
{
|
|
DisableThreadLibraryCalls((HMODULE)hMod);
|
|
}
|
|
return TRUE;
|
|
} |