main.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. #define STRICT
  2. #include <windows.h>
  3. #include <windowsx.h>
  4. #include <commctrl.h>
  5. #include <shlobj.h>
  6. #include <mmreg.h>
  7. #include <msacm.h>
  8. #include "out_disk.h"
  9. #include "../winamp/wa_ipc.h"
  10. #include <shlwapi.h>
  11. #include <strsafe.h>
  12. // wasabi based services for localisation support
  13. api_service *WASABI_API_SVC = 0;
  14. api_language *WASABI_API_LNG = 0;
  15. HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
  16. class CriticalSection : public CRITICAL_SECTION
  17. {
  18. public:
  19. inline void Enter() {EnterCriticalSection(this);}
  20. inline void Leave() {LeaveCriticalSection(this);}
  21. CriticalSection() {InitializeCriticalSection(this);}
  22. ~CriticalSection() {DeleteCriticalSection(this);}
  23. //BOOL TryEnter() {return TryEnterCriticalSection(this);}
  24. };
  25. class __T_SYNC
  26. {
  27. private:
  28. CriticalSection *p;
  29. public:
  30. inline __T_SYNC(CriticalSection& s) {p=&s;p->Enter();}
  31. inline void Leave() {if (p) p->Leave();}
  32. inline void Enter() {if (p) p->Enter();}
  33. inline void Abort() {p=0;}
  34. inline ~__T_SYNC() {Leave();}
  35. };
  36. static CriticalSection g_sync;
  37. #define SYNCFUNC __T_SYNC __sync(g_sync);
  38. #define tabsize(X) (sizeof(X)/sizeof(*X))
  39. enum
  40. {
  41. MODE_AUTO=0,
  42. MODE_WAV=1,
  43. MODE_RAW=2
  44. };
  45. int mode_names_idx[] = {IDS_AUTO_RECOMMENDED,IDS_FORCE_WAV_FILE,IDS_FORCE_RAW_DATA};
  46. static const wchar_t* format_names[]={L"%title%",L"%filename%",L"%title%_%extension%",L"%filename%_%extension%"};
  47. static wchar_t szDescription[256];
  48. int index_name_idx[] = {IDS_DISABLED,IDS_1_DIGIT,IDS_2_DIGITS,IDS_3_DIGITS,IDS_4_DIGITS};
  49. #define rev32(X) ((((DWORD)(X)&0xFF)<<24)|(((DWORD)(X)&0xFF00)<<8)|(((DWORD)(X)&0xFF0000)>>8)|(((DWORD)(X)&0xFF000000)>>24))
  50. static char cfg_output_dir[MAX_PATH]="c:\\";
  51. static char cfg_singlefile_output[MAX_PATH]="c:\\output.wav";
  52. static bool cfg_singlefile_enabled = 0;
  53. static bool cfg_convert_enabled=0;
  54. static bool cfg_thread_override = 0;
  55. static bool cfg_output_source_dir = 0;
  56. static int cfg_output_mode=0;
  57. static bool cfg_show_saveas=0;
  58. static int cfg_format_mode=0;
  59. static int cfg_format_index=2;
  60. static bool use_convert;
  61. static bool GetCheck(HWND wnd,int id) {return !!SendDlgItemMessage(wnd,id,BM_GETCHECK,0,0);}
  62. static void SetCheck(HWND wnd,int id,bool b) {SendDlgItemMessage(wnd,id,BM_SETCHECK,b ? BST_CHECKED : BST_UNCHECKED,0);}
  63. void SetPathChoiceButtonText(HWND hwndDlg, char* path, UINT id)
  64. {
  65. HWND control = GetDlgItem(hwndDlg, id);
  66. HDC hdc = GetDC(control);
  67. RECT r = {0};
  68. char temp[MAX_PATH] = {0};
  69. lstrcpynA(temp, path, MAX_PATH);
  70. SelectObject(hdc, (HFONT)SendMessage(control, WM_GETFONT, 0, 0));
  71. GetClientRect(control, &r);
  72. r.left += 5;
  73. r.right -= 5;
  74. DrawTextA(hdc, temp, -1, &r, DT_PATH_ELLIPSIS|DT_WORD_ELLIPSIS|DT_MODIFYSTRING);
  75. SetWindowTextA(control, temp);
  76. ReleaseDC(control, hdc);
  77. }
  78. BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam)
  79. {
  80. char cl[32] = {0};
  81. GetClassNameA(hwnd, cl, ARRAYSIZE(cl));
  82. if (!lstrcmpiA(cl, WC_TREEVIEW))
  83. {
  84. PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd));
  85. return FALSE;
  86. }
  87. return TRUE;
  88. }
  89. static int _stdcall browzaproc(HWND hwnd, UINT msg, LPARAM lp, LPARAM dat)
  90. {
  91. if (msg == BFFM_INITIALIZED)
  92. {
  93. SendMessage(hwnd, BFFM_SETSELECTION, 1, dat);
  94. // this is not nice but it fixes the selection not working correctly on all OSes
  95. EnumChildWindows(hwnd, browseEnumProc, 0);
  96. }
  97. return 0;
  98. }
  99. char g_tmp[MAX_PATH] = {0}, g_tmp_sf[MAX_PATH] = {0};
  100. static void d_browza(HWND wnd,HWND bt,wchar_t* tx)
  101. {
  102. IMalloc* pMalloc=0;
  103. SHGetMalloc(&pMalloc);
  104. if (!pMalloc) return;
  105. BROWSEINFOW bi=
  106. {
  107. wnd,
  108. 0,
  109. 0,
  110. tx,
  111. BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE,
  112. browzaproc,
  113. #ifdef WIN64
  114. (long long)g_tmp,
  115. #else
  116. (long)g_tmp,
  117. #endif
  118. 0
  119. };
  120. LPITEMIDLIST li=SHBrowseForFolderW(&bi);
  121. if (li)
  122. {
  123. SHGetPathFromIDListA(li,g_tmp);
  124. SetPathChoiceButtonText(wnd, g_tmp, IDC_OUTPUT_DIRECTORY);
  125. pMalloc->Free(li);
  126. }
  127. pMalloc->Release();
  128. }
  129. static WAVEFORMATEX singlefile_wfx,singlefile_wfx_temp;
  130. #define WFSIZ 0x800
  131. typedef struct
  132. {
  133. WAVEFORMATEX wfx;
  134. BYTE crap[WFSIZ];
  135. } EXT_WFX;
  136. EXT_WFX convert_wfx,convert_wfx_temp;
  137. static const WAVEFORMATEX wfx_default =
  138. {
  139. WAVE_FORMAT_PCM,
  140. 2,
  141. 44100,
  142. 44100*4,
  143. 4,
  144. 16,
  145. 0
  146. };
  147. void _inline ACM_gettext1(char* tx, int txCch)
  148. {
  149. ACMFORMATDETAILS afd;
  150. ZeroMemory(&afd, sizeof(afd));
  151. afd.cbStruct = sizeof(afd);
  152. afd.dwFormatTag = WAVE_FORMAT_PCM;
  153. afd.pwfx = &singlefile_wfx_temp;
  154. afd.cbwfx = sizeof(singlefile_wfx_temp);
  155. if (!acmFormatDetails(0, &afd, ACM_FORMATDETAILSF_FORMAT))
  156. {
  157. lstrcpyn(tx, afd.szFormat, txCch);
  158. }
  159. }
  160. void _inline ACM_gettext(char* tx)
  161. {
  162. ACMFORMATTAGDETAILS aftd;
  163. ZeroMemory(&aftd,sizeof(aftd));
  164. aftd.cbStruct=sizeof(aftd);
  165. aftd.dwFormatTag=convert_wfx_temp.wfx.wFormatTag;
  166. if (!acmFormatTagDetails(0,&aftd,ACM_FORMATTAGDETAILSF_FORMATTAG))
  167. {
  168. char* p=aftd.szFormatTag;
  169. while(p && *p) *(tx++)=*(p++);
  170. *(tx++)=13;
  171. *(tx++)=10;
  172. }
  173. ACMFORMATDETAILS afd;
  174. ZeroMemory(&afd,sizeof(afd));
  175. afd.cbStruct=sizeof(afd);
  176. afd.dwFormatTag=convert_wfx_temp.wfx.wFormatTag;
  177. afd.pwfx=&convert_wfx_temp.wfx;
  178. afd.cbwfx=sizeof(convert_wfx_temp);
  179. if (!acmFormatDetails(0,&afd,ACM_FORMATDETAILSF_FORMAT))
  180. {
  181. char* p=afd.szFormat;
  182. while(p && *p) *(tx++)=*(p++);
  183. }
  184. *tx=0;
  185. }
  186. void ACM_choose(HWND w,bool pcm)
  187. {
  188. ACMFORMATCHOOSE afc;
  189. memset(&afc,0,sizeof(afc));
  190. afc.cbStruct=sizeof(afc);
  191. afc.fdwStyle=ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT;
  192. if (pcm)
  193. {
  194. singlefile_wfx_temp.wFormatTag=WAVE_FORMAT_PCM;
  195. afc.pwfxEnum=&singlefile_wfx_temp;
  196. afc.fdwEnum=ACM_FORMATENUMF_WFORMATTAG;
  197. afc.pwfx = &singlefile_wfx_temp;
  198. afc.cbwfx = sizeof(singlefile_wfx_temp);
  199. }
  200. else
  201. {
  202. afc.pwfx = &convert_wfx_temp.wfx;
  203. afc.cbwfx = sizeof(convert_wfx_temp);
  204. }
  205. afc.hwndOwner=w;
  206. if (!acmFormatChoose(&afc))
  207. {
  208. if (pcm)
  209. {
  210. SetDlgItemText(w,IDC_SINGLEFILE_FORMAT_BUTTON,afc.szFormat);
  211. }
  212. else
  213. {
  214. char tmp[512] = {0};
  215. StringCchPrintf(tmp, 512, "%s\x0d\x0a%s",afc.szFormatTag,afc.szFormat);
  216. SetDlgItemText(w,IDC_CONVERT_BUTTON,tmp);
  217. }
  218. }
  219. }
  220. void _inline do_acm_text(HWND wnd)
  221. {
  222. char tmp[256] = {0};
  223. ACM_gettext(tmp);
  224. SetDlgItemText(wnd,IDC_CONVERT_BUTTON,tmp);
  225. }
  226. void _inline do_acm_text1(HWND wnd)
  227. {
  228. char tmp[256] = {0};
  229. ACM_gettext1(tmp, 256);
  230. SetDlgItemText(wnd,IDC_SINGLEFILE_FORMAT_BUTTON,tmp);
  231. }
  232. void wav1_set(HWND w,bool b)
  233. {
  234. static struct
  235. {
  236. WORD id;
  237. bool t;
  238. } wav1_w_c[]=
  239. {
  240. {IDC_OUTPUT_STATIC,1},
  241. {IDC_OUTPUT_DIRECTORY_STATIC,1},
  242. {IDC_OUTPUT_DIRECTORY,1},
  243. {IDC_OUTPUT_SRCDIR,1},
  244. {IDC_FILENAME_SAVEAS,1},
  245. {IDC_FILENAME_INDEX_STATIC,1},
  246. {IDC_FILENAME_INDEX,1},
  247. {IDC_OUTMODE_STATIC,1},
  248. {IDC_OUTMODE,1},
  249. {IDC_CONVERT_STATIC,1},
  250. {IDC_CONVERT_CHECK,1},
  251. {IDC_CONVERT_BUTTON,1},
  252. {IDC_CONVERT_NOTE,1},
  253. {IDC_FILENAME_FORMAT,1},
  254. {IDC_FILENAME_FORMAT_STATIC,1},
  255. {IDC_SINGLEFILE_FILE_STATIC,0},
  256. {IDC_SINGLEFILE_FILE_BUTTON,0},
  257. {IDC_SINGLEFILE_FORMAT_STATIC,0},
  258. {IDC_SINGLEFILE_FORMAT_BUTTON,0},
  259. };
  260. UINT n;
  261. for(n=0;n<tabsize(wav1_w_c);n++)
  262. {
  263. EnableWindow(GetDlgItem(w,wav1_w_c[n].id),wav1_w_c[n].t^b);
  264. }
  265. }
  266. BOOL CALLBACK DlgProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
  267. {
  268. switch(msg)
  269. {
  270. case WM_INITDIALOG:
  271. {
  272. wchar_t title[128] = {0}, temp[128] = {0};
  273. StringCchPrintfW(title,128,WASABI_API_LNGSTRINGW(IDS_SETTINGS_TITLE),WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_DISK_WRITER_OLD, temp, 128));
  274. SetWindowTextW(wnd,title);
  275. SetDlgItemText(wnd,IDC_OUTPUT_DIRECTORY,cfg_output_dir);
  276. SetPathChoiceButtonText(wnd,cfg_output_dir,IDC_OUTPUT_DIRECTORY);
  277. lstrcpyn(g_tmp,cfg_output_dir,MAX_PATH);
  278. SetCheck(wnd,IDC_CONVERT,cfg_convert_enabled);
  279. memcpy(&convert_wfx_temp,&convert_wfx,sizeof(convert_wfx));
  280. memcpy(&singlefile_wfx_temp,&singlefile_wfx,sizeof(WAVEFORMATEX));
  281. SetCheck(wnd,IDC_SINGLEFILE_CHECK,cfg_singlefile_enabled);
  282. SetCheck(wnd,IDC_THREAD_HACK,cfg_thread_override);
  283. SetPathChoiceButtonText(wnd,cfg_singlefile_output,IDC_SINGLEFILE_FILE_BUTTON);
  284. lstrcpyn(g_tmp_sf,cfg_singlefile_output,MAX_PATH);
  285. do_acm_text(wnd);
  286. do_acm_text1(wnd);
  287. {
  288. HWND w=GetDlgItem(wnd,IDC_MODE);
  289. int n;
  290. for(n=0;n<tabsize(mode_names_idx);n++)
  291. SendMessageW(w,CB_ADDSTRING,0,
  292. #ifdef WIN64
  293. (long long)WASABI_API_LNGSTRINGW(mode_names_idx[n])
  294. #else
  295. (long)WASABI_API_LNGSTRINGW(mode_names_idx[n])
  296. #endif
  297. );
  298. SendMessage(w,CB_SETCURSEL,cfg_output_mode,0);
  299. w=GetDlgItem(wnd,IDC_FILENAME_FORMAT);
  300. for(n=0;n<tabsize(format_names);n++)
  301. SendMessageW(w,CB_ADDSTRING,0,
  302. #ifdef WIN64
  303. (long long)format_names[n]
  304. #else
  305. (long)format_names[n]
  306. #endif
  307. );
  308. SendMessage(w,CB_SETCURSEL,cfg_format_mode,0);
  309. w=GetDlgItem(wnd,IDC_FILENAME_INDEX);
  310. for(n=0;n<tabsize(index_name_idx);n++)
  311. SendMessageW(w,CB_ADDSTRING,0,
  312. #ifdef WIN64
  313. (long long)WASABI_API_LNGSTRINGW(index_name_idx[n])
  314. #else
  315. (long)WASABI_API_LNGSTRINGW(index_name_idx[n])
  316. #endif
  317. );
  318. SendMessage(w,CB_SETCURSEL,cfg_format_index,0);
  319. }
  320. wav1_set(wnd,cfg_singlefile_enabled);
  321. SetCheck(wnd,IDC_OUTPUT_SRCDIR,cfg_output_source_dir);
  322. SetCheck(wnd,IDC_FILENAME_SAVEAS,cfg_show_saveas);
  323. return 1;
  324. }
  325. case WM_COMMAND:
  326. if (wp==IDC_CONVERT_BUTTON)
  327. {
  328. ACM_choose(wnd,0);
  329. }
  330. else if (wp==IDC_OUTPUT_DIRECTORY)
  331. {
  332. d_browza(wnd,(HWND)lp,WASABI_API_LNGSTRINGW(IDS_SELECT_OUTPUT_DIRECTORY));
  333. }
  334. else if (wp==IDCANCEL) EndDialog(wnd,0);
  335. else if (wp==IDOK)
  336. {
  337. cfg_convert_enabled=GetCheck(wnd,IDC_CONVERT);
  338. lstrcpyn(cfg_output_dir,g_tmp,MAX_PATH);
  339. memcpy(&convert_wfx,&convert_wfx_temp,sizeof(convert_wfx));
  340. memcpy(&singlefile_wfx,&singlefile_wfx_temp,sizeof(WAVEFORMATEX));
  341. cfg_singlefile_enabled=GetCheck(wnd,IDC_SINGLEFILE_CHECK);
  342. cfg_thread_override=GetCheck(wnd,IDC_THREAD_HACK);
  343. cfg_output_mode=(int)SendDlgItemMessage(wnd,IDC_MODE,CB_GETCURSEL,0,0);
  344. lstrcpyn(cfg_singlefile_output,g_tmp_sf,MAX_PATH);
  345. cfg_output_source_dir=GetCheck(wnd,IDC_OUTPUT_SRCDIR);
  346. cfg_show_saveas=GetCheck(wnd,IDC_FILENAME_SAVEAS);
  347. cfg_format_mode=(int)SendDlgItemMessage(wnd,IDC_FILENAME_FORMAT,CB_GETCURSEL,0,0);
  348. cfg_format_index=(int)SendDlgItemMessage(wnd,IDC_FILENAME_INDEX,CB_GETCURSEL,0,0);
  349. EndDialog(wnd,0);
  350. }
  351. else if (wp==IDC_SINGLEFILE_FILE_BUTTON)
  352. {
  353. char tmp[MAX_PATH] = {0}, filter[64] = {0};
  354. StringCchPrintf(filter,64, WASABI_API_LNGSTRING(IDS_X_FILES_DOT_X),"WAV",".wav");
  355. char * ptr=filter;
  356. while(ptr && *ptr)
  357. {
  358. if (*ptr=='|') *ptr=0;
  359. ptr++;
  360. }
  361. GetDlgItemText(wnd,IDC_SINGLEFILE_FILE_BUTTON,tmp,MAX_PATH);
  362. lstrcpyn(tmp,g_tmp_sf,MAX_PATH);
  363. OPENFILENAME ofn = {0};
  364. ofn.lStructSize=sizeof(ofn);
  365. ofn.hwndOwner=wnd;
  366. ofn.lpstrFilter=filter;
  367. ofn.lpstrFile=tmp;
  368. ofn.nMaxFile=MAX_PATH;
  369. ofn.Flags=OFN_HIDEREADONLY|OFN_PATHMUSTEXIST;
  370. ofn.lpstrDefExt="wav";
  371. if (GetSaveFileName(&ofn))
  372. {
  373. SetPathChoiceButtonText(wnd,tmp,IDC_SINGLEFILE_FILE_BUTTON);
  374. lstrcpyn(g_tmp_sf, tmp, MAX_PATH);
  375. }
  376. }
  377. else if (wp==IDC_SINGLEFILE_FORMAT_BUTTON) ACM_choose(wnd,1);
  378. else if (wp==IDC_SINGLEFILE_CHECK) wav1_set(wnd,GetCheck(wnd,IDC_SINGLEFILE_CHECK));
  379. break;
  380. }
  381. return 0;
  382. }
  383. void Config(HWND hWnd)
  384. {
  385. WASABI_API_DIALOGBOXW(IDD_DIALOG1,hWnd,DlgProc);
  386. }
  387. static int nsam;
  388. static int g_freq,g_nch,g_bps;
  389. static int paused;
  390. const static char badchars[]={'.','\\','/',':','*','?','\"','<','>','|'};
  391. char* GetDefaultSaveToFolder(char* path_to_store)
  392. {
  393. if(FAILED(SHGetFolderPathA(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, path_to_store)))
  394. {
  395. if(FAILED(SHGetFolderPathA(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path_to_store)))
  396. {
  397. lstrcpynA(path_to_store, "C:\\", MAX_PATH);
  398. }
  399. }
  400. return path_to_store;
  401. }
  402. static void GetName(char* out, int outCch, const char* format_ext)
  403. {
  404. int index = (int)SendMessage(mod.hMainWindow,WM_USER,0,IPC_GETLISTPOS);
  405. if (cfg_output_source_dir)
  406. {
  407. const char * dir=(const char *)SendMessage(mod.hMainWindow,WM_USER,index,211);
  408. const char * last=strrchr(dir,'\\');
  409. while(dir<=last) {*(out++)=*(dir++);}
  410. }
  411. else
  412. {
  413. char * dir=cfg_output_dir;
  414. if (!*dir)
  415. {
  416. char tmp[MAX_PATH] = {0};
  417. dir=GetDefaultSaveToFolder(tmp);
  418. }
  419. while(dir && *dir) {*(out++)=*(dir++);}
  420. if (out[-1]!='\\') *(out++)='\\';
  421. }
  422. char * badchar_test = out;
  423. if (cfg_format_index>0)
  424. {
  425. char temp[16] = {0};
  426. StringCchPrintf(temp, 16, "%09u_",index+1);
  427. lstrcpyn(out, temp+9-cfg_format_index, outCch);
  428. out+=cfg_format_index+1;
  429. }
  430. if (cfg_format_mode&1)//filename
  431. {
  432. const char * source_full = (const char*)SendMessage(mod.hMainWindow,WM_USER,index,211);
  433. const char * source = strrchr(source_full,'\\');
  434. if (!source) source = source_full;
  435. else source++;
  436. const char * dot = strrchr(source,'.');
  437. if (dot) while(source<dot) *(out++)=*(source++);
  438. else while(source && *source) *(out++)=*(source++);
  439. }
  440. else //title
  441. {
  442. const char * source = (const char*)SendMessage(mod.hMainWindow,WM_USER,index,212);
  443. if (!source) source = "(unknown title)";
  444. while(source && *source) *(out++)=*(source++);
  445. }
  446. if (cfg_format_mode&2)
  447. {//add extension
  448. const char * extension = strrchr((const char*)SendMessage(mod.hMainWindow,WM_USER,index,211),'.');
  449. while(extension && *extension) *(out++)=*(extension++);
  450. }
  451. while(badchar_test<out)
  452. {
  453. BYTE c = *badchar_test;
  454. int n;
  455. for(n=0;n<tabsize(badchars);n++)
  456. {
  457. if (c==badchars[n]) {*badchar_test='_';break;}
  458. }
  459. badchar_test++;
  460. }
  461. while(format_ext && *format_ext) *(out++)=*(format_ext++);
  462. *out=0;
  463. }
  464. static HANDLE hOut=INVALID_HANDLE_VALUE;
  465. static HACMSTREAM hStream;
  466. static DWORD fact_ofs,data_ofs;
  467. static bool riff;
  468. static DWORD FileTell(HANDLE hFile) {return SetFilePointer(hFile,0,0,FILE_CURRENT);}
  469. static void FileAlign(HANDLE hFile) {if (FileTell(hFile)&1) SetFilePointer(hFile,1,0,FILE_CURRENT);}
  470. #define BUFSIZE 0x20000
  471. static BYTE *acm_outbuf;
  472. static UINT acm_outbufsize;
  473. static BYTE *acm_buf;
  474. static BYTE *acm_buf1;
  475. static UINT inbuf,inbuf1;
  476. static ACMSTREAMHEADER ahd,ahd1;
  477. static bool active;
  478. static void file_err(char* f, wchar_t* t)
  479. {
  480. wchar_t tmp[512+128] = {0};
  481. StringCchPrintfW(tmp, 512+128, L"%s: \"%hs\"", t, f);
  482. MessageBoxW(mod.hMainWindow, tmp, szDescription, MB_ICONERROR);
  483. }
  484. void acm_close();
  485. static int pos_delta;
  486. int Open(int sr,int nch,int bps,int xx,int xxx)
  487. {
  488. // if someone didn't call Close(), close the file for them
  489. if (hOut!=INVALID_HANDLE_VALUE)
  490. {
  491. CloseHandle(hOut);
  492. hOut=INVALID_HANDLE_VALUE;
  493. }
  494. int failFlags = 0;
  495. SYNCFUNC;
  496. char fn[512] = {0};
  497. use_convert=cfg_convert_enabled;
  498. DWORD bw = 0, t = 0;
  499. WAVEFORMATEX wfx=
  500. {
  501. WAVE_FORMAT_PCM,
  502. (WORD)nch,
  503. (DWORD)sr,
  504. (DWORD)(sr*nch*(bps>>3)),
  505. (WORD)(nch*(bps>>3)),
  506. (WORD)bps,
  507. 0
  508. };
  509. bool append=0;
  510. WAVEFORMATEX *pDst=&convert_wfx.wfx;
  511. if (!cfg_convert_enabled) pDst=&wfx;
  512. if (cfg_singlefile_enabled)
  513. {
  514. pDst=&singlefile_wfx;
  515. use_convert=1;
  516. lstrcpyn(fn, cfg_singlefile_output,512);
  517. riff=1;
  518. }
  519. else
  520. {
  521. const char* ext=".wav";
  522. riff=1;
  523. if (cfg_output_mode==MODE_RAW)
  524. {
  525. riff=0;
  526. ext=".raw";
  527. }
  528. else if (cfg_output_mode==MODE_AUTO)
  529. {
  530. if (pDst->wFormatTag==WAVE_FORMAT_MPEGLAYER3)
  531. {
  532. riff=0;
  533. ext=".mp3";
  534. }
  535. }
  536. GetName(fn, 512, ext);
  537. if (cfg_show_saveas)
  538. {
  539. char filter[64] = {0}, title[128] = {0}, title2[128] = {0};
  540. StringCchPrintf(filter,64, WASABI_API_LNGSTRING(IDS_X_FILES_DOT_X),ext,ext);
  541. char * ptr=filter;
  542. while(ptr && *ptr)
  543. {
  544. if (*ptr=='|') *ptr=0;
  545. ptr++;
  546. }
  547. OPENFILENAME ofn= {0};
  548. ofn.lStructSize=sizeof(ofn);
  549. ofn.hwndOwner=mod.hMainWindow;
  550. ofn.lpstrFilter = filter;
  551. ofn.lpstrFile = fn;
  552. StringCchPrintf(title,128,WASABI_API_LNGSTRING(IDS_CHOOSE_FILE_NAME),
  553. WASABI_API_LNGSTRING_BUF(IDS_NULLSOFT_DISK_WRITER,title2,128));
  554. ofn.lpstrTitle = title;
  555. ofn.nMaxFile = tabsize(fn);
  556. ofn.Flags = OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT;
  557. ofn.lpstrDefExt = ext;
  558. if (!GetOpenFileName(&ofn)) return -1;
  559. }
  560. }
  561. if (memcmp(&wfx,pDst,sizeof(wfx))==0) use_convert=0;
  562. nsam=0;
  563. g_freq=sr;
  564. g_nch=nch;
  565. g_bps=bps;
  566. paused=0;
  567. SetLastError(0);
  568. hOut=CreateFile(fn,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,0);
  569. if (hOut==INVALID_HANDLE_VALUE)
  570. {
  571. DWORD e=GetLastError();
  572. if (e==ERROR_ALREADY_EXISTS || e==0x50)
  573. {
  574. if (cfg_singlefile_enabled)
  575. {
  576. append=1;
  577. goto _ap;
  578. }
  579. wchar_t tmp[512+128] = {0};
  580. StringCchPrintfW(tmp, 512+128, WASABI_API_LNGSTRINGW(IDS_FILE_ALREADY_EXISTS_OVERWRITE),fn);
  581. if (MessageBoxW(mod.hMainWindow,tmp,szDescription,MB_ICONQUESTION|MB_OKCANCEL)==IDOK)
  582. {
  583. hOut=CreateFile(fn,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0);
  584. }
  585. else return -1;
  586. }
  587. if (hOut==INVALID_HANDLE_VALUE)
  588. {
  589. file_err(fn, WASABI_API_LNGSTRINGW(IDS_CANNOT_CREATE_OUTPUT_FILE));
  590. return -1;
  591. }
  592. }
  593. _ap:
  594. fact_ofs=data_ofs=0;
  595. if (append)
  596. {
  597. hOut=CreateFile(fn,GENERIC_WRITE|GENERIC_READ,0,0,OPEN_EXISTING,0,0);
  598. if (hOut==INVALID_HANDLE_VALUE)
  599. {
  600. file_err(fn, WASABI_API_LNGSTRINGW(IDS_CANNOT_OPEN_FILE));
  601. return -1;
  602. }
  603. {
  604. DWORD br=0;
  605. DWORD rf=0,wfs=0;
  606. ReadFile(hOut,&rf,4,&br,0);
  607. if (rf!='FFIR') goto ap_f;
  608. SetFilePointer(hOut,4,0,FILE_CURRENT);
  609. br=0; ReadFile(hOut,&rf,4,&br,0);
  610. if (rf!='EVAW') goto ap_f;
  611. br=0; ReadFile(hOut,&rf,4,&br,0);
  612. if (rf!=' tmf') goto ap_f;
  613. static WAVEFORMATEX ap_wfx;
  614. br=0; ReadFile(hOut,&wfs,4,&br,0);
  615. if (wfs<sizeof(ap_wfx)-2 || wfs>sizeof(ap_wfx)) goto ap_f;
  616. br=0; ReadFile(hOut,&ap_wfx,wfs,&br,0);
  617. if (ap_wfx.wFormatTag!=WAVE_FORMAT_PCM) goto ap_f;
  618. br=0; ReadFile(hOut,&rf,4,&br,0);
  619. pDst=&ap_wfx;
  620. if (rf!='atad') goto ap_f;
  621. data_ofs=8+4+8+wfs+4;
  622. DWORD data_size=0;
  623. br=0; ReadFile(hOut,&data_size,4,&br,0);
  624. SetFilePointer(hOut,data_size,0,FILE_CURRENT);
  625. SetEndOfFile(hOut);
  626. use_convert = !!memcmp(&wfx,&ap_wfx,sizeof(wfx));
  627. }
  628. goto ap_ok;
  629. ap_f:
  630. file_err(fn, WASABI_API_LNGSTRINGW(IDS_NOT_A_PCM_WAV_FILE));
  631. if (hOut && hOut!=INVALID_HANDLE_VALUE) {CloseHandle(hOut);hOut=INVALID_HANDLE_VALUE;}
  632. return -1;
  633. ap_ok:;
  634. }
  635. if (riff && !append)
  636. {
  637. t=rev32('RIFF');
  638. bw = 0; WriteFile(hOut,&t,4,&bw,0);
  639. SetFilePointer(hOut,4,0,FILE_CURRENT);
  640. t=rev32('WAVE');
  641. bw = 0; WriteFile(hOut,&t,4,&bw,0);
  642. t=rev32('fmt ');
  643. bw = 0; WriteFile(hOut,&t,4,&bw,0);
  644. }
  645. if (use_convert)
  646. {
  647. #ifdef SSRC
  648. if (pDst->wFormatTag==WAVE_FORMAT_PCM)
  649. {
  650. if ((wfx.nChannels!=1 && wfx.nChannels!=2) || (pDst->nChannels!=1 && pDst->nChannels!=2)) goto fail;
  651. res = SSRC_create(wfx.nSamplesPerSec,pDst->nSamplesPerSec,wfx.wBitsPerSample,pDst->wBitsPerSample,wfx.nChannels,2,1,0,0,wfx.nChannels!=pDst->nChannels);
  652. acm_outbuf=0;
  653. acm_outbufsize=0;
  654. }
  655. else
  656. #endif
  657. {
  658. MMRESULT rs=acmStreamOpen(&hStream,0,&wfx,pDst,0,0,0,ACM_STREAMOPENF_NONREALTIME);
  659. if (rs)
  660. {
  661. WAVEFORMATEX wfx1;
  662. ZeroMemory(&wfx1,sizeof(wfx1));
  663. wfx1.wFormatTag=WAVE_FORMAT_PCM;
  664. if (acmFormatSuggest(0,pDst,&wfx1,sizeof(WAVEFORMATEX),ACM_FORMATSUGGESTF_WFORMATTAG)) goto fail;
  665. if (acmStreamOpen(&hStream,0,&wfx1,pDst,0,0,0,ACM_STREAMOPENF_NONREALTIME)) goto fail;
  666. if ((wfx.nChannels!=1 && wfx.nChannels!=2) || (wfx1.nChannels!=1 && wfx1.nChannels!=2)) goto fail;
  667. #ifdef SSRC
  668. res = SSRC_create(wfx.nSamplesPerSec,wfx1.nSamplesPerSec,wfx.wBitsPerSample,wfx1.wBitsPerSample,wfx.nChannels,2,1,0,0,wfx.nChannels!=wfx1.nChannels);
  669. //TODO fix different channel setups
  670. #endif
  671. acm_buf1=(BYTE*)malloc(BUFSIZE);
  672. if (!acm_buf1
  673. #ifdef SSRC
  674. || !res
  675. #endif
  676. )
  677. goto fail;
  678. }
  679. acm_buf=(BYTE*)malloc(BUFSIZE);
  680. acm_outbuf=(BYTE*)malloc(BUFSIZE);
  681. if (!acm_buf || !acm_outbuf) goto fail;
  682. ZeroMemory(&ahd,sizeof(ahd));
  683. ahd.cbStruct=sizeof(ahd);
  684. ahd.pbSrc=acm_buf;
  685. ahd.cbSrcLength=BUFSIZE;
  686. ahd.pbDst=acm_outbuf;
  687. ahd.cbDstLength=BUFSIZE;
  688. if (acmStreamPrepareHeader(hStream,&ahd,0)) goto fail;
  689. }
  690. if (riff && !append)
  691. {
  692. if (pDst->wFormatTag==WAVE_FORMAT_PCM) t=0x10;
  693. else t=sizeof(WAVEFORMATEX)+pDst->cbSize;
  694. bw = 0; WriteFile(hOut,&t,4,&bw,0);
  695. bw = 0; WriteFile(hOut,pDst,t,&bw,0);
  696. FileAlign(hOut);
  697. if (pDst->wFormatTag!=WAVE_FORMAT_PCM)
  698. {
  699. t=rev32('fact');
  700. bw = 0; WriteFile(hOut,&t,4,&bw,0);
  701. t=4;
  702. bw = 0; WriteFile(hOut,&t,4,&bw,0);
  703. fact_ofs=FileTell(hOut);
  704. SetFilePointer(hOut,4,0,FILE_CURRENT);
  705. }
  706. t=rev32('data');
  707. bw = 0; WriteFile(hOut,&t,4,&bw,0);
  708. data_ofs=FileTell(hOut);
  709. SetFilePointer(hOut,4,0,FILE_CURRENT);
  710. }
  711. }
  712. else if (riff && !append)
  713. {
  714. t=0x10;
  715. //t=sizeof(WAVEFORMATEX)+pDst->cbSize;
  716. bw = 0; WriteFile(hOut,&t,4,&bw,0);
  717. bw = 0; WriteFile(hOut,&wfx,t,&bw,0);
  718. t=rev32('data');
  719. bw = 0; WriteFile(hOut,&t,4,&bw,0);
  720. data_ofs=FileTell(hOut);
  721. SetFilePointer(hOut,4,0,FILE_CURRENT);
  722. }
  723. inbuf1=inbuf=0;
  724. active=1;
  725. pos_delta=0;
  726. return 0;
  727. fail:
  728. if (hOut && hOut!=INVALID_HANDLE_VALUE)
  729. {
  730. CloseHandle(hOut);
  731. hOut=INVALID_HANDLE_VALUE;
  732. DeleteFile(fn);
  733. }
  734. hOut=0;
  735. acm_close();
  736. MessageBoxW(mod.hMainWindow,WASABI_API_LNGSTRINGW(IDS_ERROR_INITIALIZING_OUTPUT),
  737. szDescription,MB_ICONERROR);
  738. return -1;
  739. }
  740. void acm_close()
  741. {
  742. #ifdef SSRC
  743. if (res)
  744. {
  745. if (acm_buf1)
  746. {
  747. free(acm_buf1);
  748. acm_buf1=0;
  749. }
  750. delete res;
  751. res=0;
  752. }
  753. #endif
  754. if (hStream)
  755. {
  756. if (ahd.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) acmStreamUnprepareHeader(hStream,&ahd,0);
  757. ZeroMemory(&ahd,sizeof(ahd));
  758. acmStreamClose(hStream,0);
  759. hStream=0;
  760. if (acm_buf)
  761. {
  762. free(acm_buf);
  763. acm_buf=0;
  764. }
  765. if (acm_outbuf)
  766. {
  767. free(acm_outbuf);
  768. acm_outbuf=0;
  769. }
  770. }
  771. }
  772. void do_cvt(BYTE* data,UINT size);
  773. void Close()
  774. {
  775. SYNCFUNC;
  776. active=0;
  777. if (use_convert)
  778. {
  779. do_cvt(0,0);
  780. acm_close();
  781. }
  782. if (hOut!=INVALID_HANDLE_VALUE)
  783. {
  784. if (riff)
  785. {
  786. FileAlign(hOut);
  787. DWORD t,bw = 0;
  788. SetFilePointer(hOut,4,0,FILE_BEGIN);
  789. t=GetFileSize(hOut,0)-8;
  790. WriteFile(hOut,&t,4,&bw,0);
  791. if (data_ofs)
  792. {
  793. DWORD data_size=GetFileSize(hOut,0)-(data_ofs+4);
  794. SetFilePointer(hOut,data_ofs,0,FILE_BEGIN);
  795. bw = 0; WriteFile(hOut,&data_size,4,&bw,0);
  796. }
  797. if (fact_ofs)
  798. {
  799. SetFilePointer(hOut,fact_ofs,0,FILE_BEGIN);
  800. t=nsam;
  801. bw = 0; WriteFile(hOut,&t,4,&bw,0);
  802. }
  803. }
  804. CloseHandle(hOut);
  805. hOut=INVALID_HANDLE_VALUE;
  806. }
  807. }
  808. void do_cvt(BYTE* data,UINT size)
  809. {
  810. #ifdef SSRC
  811. if (res && !hStream)
  812. {
  813. if (!data || !size) res->Finish();
  814. else res->Write(data,size);
  815. UINT out_size;
  816. void *out = res->GetBuffer(&out_size);
  817. DWORD bw = 0;
  818. WriteFile(hOut,out,out_size,&bw,0);
  819. res->Read(out_size);
  820. }
  821. else
  822. #endif
  823. {
  824. DWORD flags=0;
  825. if (nsam==0) flags|=ACM_STREAMCONVERTF_START;
  826. if (data) flags|=ACM_STREAMCONVERTF_BLOCKALIGN;
  827. #ifdef SSRC
  828. if (res)
  829. {
  830. if (inbuf1+size>BUFSIZE) return;
  831. if (data)
  832. {
  833. memcpy(acm_buf1+inbuf1,data,size);
  834. inbuf1+=size;
  835. }
  836. res->Write(acm_buf1,inbuf1);
  837. memcpy(acm_buf1,acm_buf1+inbuf1,inbuf1);
  838. inbuf1=0;
  839. if (!data || !size) res->Finish();
  840. data = (BYTE*)res->GetBuffer(&size);
  841. if (inbuf+size>BUFSIZE) return;
  842. memcpy(acm_buf+inbuf,data,size);
  843. inbuf+=size;
  844. res->Read(size);
  845. }
  846. else
  847. #endif
  848. if (data)
  849. {
  850. if (inbuf+size>BUFSIZE) return;
  851. memcpy(acm_buf+inbuf,data,size);
  852. inbuf+=size;
  853. }
  854. ahd.cbSrcLength=inbuf;
  855. acmStreamConvert(hStream,&ahd,flags);
  856. inbuf-=ahd.cbSrcLengthUsed;
  857. memmove(acm_buf,acm_buf+ahd.cbSrcLengthUsed,inbuf);//memmove
  858. DWORD bw = 0;
  859. WriteFile(hOut,acm_outbuf,ahd.cbDstLengthUsed,&bw,0);
  860. }
  861. }
  862. int Write(char *data, int len)
  863. {
  864. SYNCFUNC;
  865. if (!active) return 0;
  866. if (cfg_thread_override) SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL);
  867. else Sleep(0);
  868. len-=len%((g_bps>>3)*g_nch);
  869. nsam+=len/((g_bps>>3)*g_nch);
  870. if (use_convert)
  871. {
  872. do_cvt((BYTE*)data,len);
  873. }
  874. else
  875. {
  876. DWORD bw = 0;
  877. WriteFile(hOut,data,len,&bw,0);
  878. }
  879. return 0;
  880. }
  881. int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
  882. {
  883. MSGBOXPARAMSW msgbx = {sizeof(MSGBOXPARAMSW),0};
  884. msgbx.lpszText = message;
  885. msgbx.lpszCaption = title;
  886. msgbx.lpszIcon = MAKEINTRESOURCEW(102);
  887. msgbx.hInstance = GetModuleHandle(0);
  888. msgbx.dwStyle = MB_USERICON;
  889. msgbx.hwndOwner = parent;
  890. return MessageBoxIndirectW(&msgbx);
  891. }
  892. void About(HWND hwndParent)
  893. {
  894. wchar_t message[1024] = {0}, text[1024] = {0};
  895. WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_DISK_WRITER_OLD,text,1024);
  896. StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT),
  897. szDescription, __DATE__);
  898. DoAboutMessageBox(hwndParent,text,message);
  899. }
  900. static bool _cfg_store;
  901. static const char *inifile;
  902. #define CFG_NAME "out_disk"//fixme
  903. static void wppi(char* nam,UINT val)
  904. {
  905. char t[16] = {0};
  906. StringCchPrintf(t,16, "%u",val);
  907. WritePrivateProfileString(CFG_NAME,nam,t,inifile);
  908. }
  909. #define WritePrivateProfileInt(A,B,C,D) wppi(B,C)
  910. static int _do_int(int x,char* nam)
  911. {
  912. if (_cfg_store)
  913. {
  914. WritePrivateProfileInt(CFG_NAME,nam,x,inifile);
  915. return x;
  916. }
  917. else
  918. {
  919. return GetPrivateProfileInt(CFG_NAME,nam,x,inifile);
  920. }
  921. }
  922. #define do_int(x) x=_do_int(x,#x)
  923. #define do_bool(x) x=!!_do_int(x,#x)
  924. static void _do_string(char* x,char* nam)
  925. {
  926. if (_cfg_store)
  927. {
  928. WritePrivateProfileString(CFG_NAME,nam,x,inifile);
  929. }
  930. else
  931. {
  932. GetPrivateProfileString(CFG_NAME,nam,x,x,MAX_PATH,inifile);
  933. }
  934. }
  935. #define do_string(x) _do_string(x,#x)
  936. void do_cfg()
  937. {
  938. if (!_cfg_store)
  939. {
  940. GetDefaultSaveToFolder(cfg_output_dir);
  941. PathCombine(cfg_singlefile_output, cfg_output_dir, "output.wav");
  942. }
  943. do_string(cfg_output_dir);
  944. do_string(cfg_singlefile_output);
  945. do_bool(cfg_singlefile_enabled);
  946. do_bool(cfg_convert_enabled);
  947. do_bool(cfg_thread_override);
  948. do_int(cfg_output_mode);
  949. do_bool(cfg_output_source_dir);
  950. do_bool(cfg_show_saveas);
  951. do_int(cfg_format_mode);
  952. do_int(cfg_format_index);
  953. if (_cfg_store)
  954. {
  955. UINT _s=sizeof(WAVEFORMATEX)+convert_wfx.wfx.cbSize;
  956. WritePrivateProfileInt(CFG_NAME,"cfg_wfx_s",_s,inifile);
  957. WritePrivateProfileStruct(CFG_NAME,"cfg_wfx",&convert_wfx,_s,inifile);
  958. WritePrivateProfileStruct(CFG_NAME,"cfg_wfx1",&singlefile_wfx,sizeof(singlefile_wfx),inifile);
  959. }
  960. else
  961. {
  962. UINT _s=GetPrivateProfileInt(CFG_NAME,"cfg_wfx_s",0,inifile);
  963. if (_s && _s<=sizeof(convert_wfx))
  964. {
  965. GetPrivateProfileStruct(CFG_NAME,"cfg_wfx",&convert_wfx,_s,inifile);
  966. }
  967. GetPrivateProfileStruct(CFG_NAME,"cfg_wfx1",&singlefile_wfx,sizeof(singlefile_wfx),inifile);
  968. }
  969. }
  970. void Init()
  971. {
  972. SYNCFUNC;
  973. if (!mod.hMainWindow)
  974. return;
  975. inifile = (const char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE);
  976. singlefile_wfx = wfx_default;
  977. convert_wfx.wfx = wfx_default;
  978. memset(convert_wfx.crap, 0, sizeof(convert_wfx.crap));
  979. // loader so that we can get the localisation service api for use
  980. WASABI_API_SVC = (api_service*)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
  981. if (WASABI_API_SVC == (api_service*)1) WASABI_API_SVC = NULL;
  982. waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(languageApiGUID);
  983. if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
  984. // need to have this initialised before we try to do anything with localisation features
  985. WASABI_API_START_LANG(mod.hDllInstance,OutDiskLangGUID);
  986. StringCchPrintfW(szDescription, 256, WASABI_API_LNGSTRINGW(IDS_NULLSOFT_DISK_WRITER), PLUGIN_VERSION);
  987. mod.description = (char*)szDescription;
  988. _cfg_store=0;
  989. do_cfg();
  990. }
  991. void Quit()
  992. {
  993. SYNCFUNC;
  994. if (active) Close();
  995. _cfg_store=1;
  996. do_cfg();
  997. }
  998. int CanWrite()
  999. {
  1000. return paused ? 0 : 666666666;
  1001. }
  1002. int IsPlaying()
  1003. {
  1004. return 0;
  1005. }
  1006. int Pause(int p)
  1007. {
  1008. int _p=paused;
  1009. paused=p;
  1010. return _p;
  1011. }
  1012. void SetVolume(int volume)
  1013. {
  1014. }
  1015. void SetPan(int pan)
  1016. {
  1017. }
  1018. void Flush(int t)
  1019. {
  1020. nsam=0;
  1021. pos_delta=t;
  1022. }
  1023. int GetOutputTime()
  1024. {
  1025. return pos_delta+MulDiv(nsam,1000,g_freq);
  1026. }
  1027. Out_Module mod=
  1028. {
  1029. OUT_VER_U,
  1030. 0,
  1031. 426119909,
  1032. 0,
  1033. 0,
  1034. Config,
  1035. About,
  1036. Init,
  1037. Quit,
  1038. Open,
  1039. Close,
  1040. Write,
  1041. CanWrite,
  1042. IsPlaying,
  1043. Pause,
  1044. SetVolume,
  1045. SetVolume,
  1046. Flush,
  1047. GetOutputTime,
  1048. GetOutputTime
  1049. };
  1050. extern "C"
  1051. {
  1052. __declspec( dllexport ) Out_Module * winampGetOutModule()
  1053. {
  1054. return &mod;
  1055. }
  1056. }
  1057. BOOL APIENTRY DllMain(HANDLE hMod,DWORD r,void*)
  1058. {
  1059. if (r==DLL_PROCESS_ATTACH)
  1060. {
  1061. DisableThreadLibraryCalls((HMODULE)hMod);
  1062. }
  1063. return TRUE;
  1064. }