in_flac.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:10k
源码类别:

Windows CE

开发平台:

C/C++

  1. /* in_flac - Winamp2 FLAC input plugin
  2.  * Copyright (C) 2000,2001,2002,2003,2004,2005  Josh Coalson
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  */
  18. #include <windows.h>
  19. #include <stdio.h>
  20. #include "winamp2/in2.h"
  21. #include "config.h"
  22. #include "infobox.h"
  23. #include "tagz.h"
  24. #define PLUGIN_VERSION          "1.1.2"
  25. static In_Module mod_;                      /* the input module (declared near the bottom of this file) */
  26. static char lastfn_[MAX_PATH];              /* currently playing file (used for getting info on the current file) */
  27. flac_config_t flac_cfg;
  28. static file_info_struct file_info_;
  29. static int paused;
  30. static FLAC__FileDecoder *decoder_;
  31. static char sample_buffer_[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8) * 2];
  32. /* (24/8) for max bytes per sample, and 2 for DSPs */
  33. static HANDLE thread_handle = NULL;         /* the handle to the decode thread */
  34. static DWORD WINAPI DecodeThread(void *b);  /* the decode thread procedure */
  35. /*
  36.  *  init/quit
  37.  */
  38. static void init()
  39. {
  40. decoder_ = FLAC__file_decoder_new();
  41. strcpy(lastfn_, "");
  42. InitConfig();
  43. ReadConfig();
  44. InitInfobox();
  45. }
  46. static void quit()
  47. {
  48. WriteConfig();
  49. DeinitInfobox();
  50. FLAC_plugin__decoder_delete(decoder_);
  51. decoder_ = 0;
  52. }
  53. /*
  54.  *  open/close
  55.  */
  56. static int isourfile(char *fn) { return 0; }
  57. static int play(char *fn)
  58. {
  59. LONGLONG filesize;
  60. DWORD thread_id;
  61. int   maxlatency;
  62. /* checks */
  63. if (decoder_ == 0) return 1;
  64. if (!(filesize = FileSize(fn))) return -1;
  65. /* init decoder */
  66. if (!FLAC_plugin__decoder_init(decoder_, fn, filesize, &file_info_, &flac_cfg.output))
  67. return 1;
  68. strcpy(lastfn_, fn);
  69. /* open output */
  70. maxlatency = mod_.outMod->Open(file_info_.sample_rate, file_info_.channels, file_info_.output_bits_per_sample, -1, -1);
  71. if (maxlatency < 0)
  72. {
  73. FLAC_plugin__decoder_finish(decoder_);
  74. return 1;
  75. }
  76. /* set defaults */
  77. mod_.outMod->SetVolume(-666);
  78. mod_.outMod->SetPan(0);
  79. /* initialize vis stuff */
  80. mod_.SAVSAInit(maxlatency, file_info_.sample_rate);
  81. mod_.VSASetInfo(file_info_.sample_rate, file_info_.channels);
  82. /* set info */
  83. mod_.SetInfo(file_info_.average_bps, file_info_.sample_rate/1000, file_info_.channels, 1);
  84. /* start playing thread */
  85. paused = 0;
  86. thread_handle = CreateThread(NULL, 0, DecodeThread, NULL, 0, &thread_id);
  87. if (!thread_handle) return 1;
  88. return 0;
  89. }
  90. static void stop()
  91. {
  92. if (thread_handle)
  93. {
  94. file_info_.is_playing = false;
  95. if (WaitForSingleObject(thread_handle, 2000) == WAIT_TIMEOUT)
  96. {
  97. FLAC_plugin__show_error("Error while stopping decoding thread.");
  98. TerminateThread(thread_handle, 0);
  99. }
  100. CloseHandle(thread_handle);
  101. thread_handle = NULL;
  102. }
  103. FLAC_plugin__decoder_finish(decoder_);
  104. mod_.outMod->Close();
  105. mod_.SAVSADeInit();
  106. }
  107. /*
  108.  *  play control
  109.  */
  110. static void pause()
  111. {
  112. paused = 1;
  113. mod_.outMod->Pause(1);
  114. }
  115. static void unpause()
  116. {
  117. paused = 0;
  118. mod_.outMod->Pause(0);
  119. }
  120. static int ispaused()
  121. {
  122. return paused;
  123. }
  124. static int getlength()
  125. {
  126. return file_info_.length_in_msec;
  127. }
  128. static int getoutputtime()
  129. {
  130. return mod_.outMod->GetOutputTime();
  131. }
  132. static void setoutputtime(int time_in_ms)
  133. {
  134. file_info_.seek_to = time_in_ms;
  135. }
  136. static void setvolume(int volume)
  137. {
  138. mod_.outMod->SetVolume(volume);
  139. }
  140. static void setpan(int pan)
  141. {
  142. mod_.outMod->SetPan(pan);
  143. }
  144. static void eq_set(int on, char data[10], int preamp) {}
  145. /*
  146.  *  playing loop
  147.  */
  148. static void do_vis(char *data, int nch, int resolution, int position, unsigned samples)
  149. {
  150. static char vis_buffer[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
  151. char *ptr;
  152. int size, count;
  153. /*
  154.  * Winamp visuals may have problems accepting sample sizes larger than
  155.  * 16 bits, so we reduce the sample size here if necessary.
  156.  */
  157. switch(resolution) {
  158. case 32:
  159. case 24:
  160. size  = resolution / 8;
  161. count = samples * nch;
  162. data += size - 1;
  163. ptr = vis_buffer;
  164. while(count--) {
  165. *ptr++ = data[0] ^ 0x80;
  166. data += size;
  167. }
  168. data = vis_buffer;
  169. resolution = 8;
  170. /* fall through */
  171. case 16:
  172. case 8:
  173. mod_.SAAddPCMData(data, nch, resolution, position);
  174. mod_.VSAAddPCMData(data, nch, resolution, position);
  175. }
  176. }
  177. static DWORD WINAPI DecodeThread(void *unused)
  178. {
  179. const unsigned channels = file_info_.channels;
  180. const unsigned bits_per_sample = file_info_.bits_per_sample;
  181. const unsigned target_bps = file_info_.output_bits_per_sample;
  182. const unsigned sample_rate = file_info_.sample_rate;
  183. const unsigned fact = channels * (target_bps/8);
  184. while (file_info_.is_playing)
  185. {
  186. /* seek needed */
  187. if (file_info_.seek_to != -1)
  188. {
  189. const int pos = FLAC_plugin__seek(decoder_, &file_info_);
  190. if (pos != -1) mod_.outMod->Flush(pos);
  191. }
  192. /* stream ended */
  193. else if (file_info_.eof)
  194. {
  195. if (!mod_.outMod->IsPlaying())
  196. {
  197. PostMessage(mod_.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
  198. return 0;
  199. }
  200. Sleep(10);
  201. }
  202. /* decode */
  203. else
  204. {
  205. /* decode samples */
  206. int bytes = FLAC_plugin__decode(decoder_, &file_info_, sample_buffer_);
  207. const int n = bytes / fact;
  208. /* visualization */
  209. do_vis(sample_buffer_, channels, target_bps, mod_.outMod->GetWrittenTime(), n);
  210. /* dsp */
  211. if (mod_.dsp_isactive())
  212. bytes = mod_.dsp_dosamples((short*)sample_buffer_, n, target_bps, channels, sample_rate) * fact;
  213. /* output */
  214. while (mod_.outMod->CanWrite()<bytes && file_info_.is_playing && file_info_.seek_to==-1)
  215. Sleep(20);
  216. if (file_info_.is_playing && file_info_.seek_to==-1)
  217. mod_.outMod->Write(sample_buffer_, bytes);
  218. /* show bitrate */
  219. if (flac_cfg.display.show_bps)
  220. {
  221. const int rate = FLAC_plugin__get_rate(mod_.outMod->GetWrittenTime(), mod_.outMod->GetOutputTime(), &file_info_);
  222. if (rate) mod_.SetInfo(rate/1000, file_info_.sample_rate/1000, file_info_.channels, 1);
  223. }
  224. }
  225. }
  226. return 0;
  227. }
  228. /*
  229.  *  title formatting
  230.  */
  231. static T_CHAR *get_tag(const T_CHAR *tag, void *param)
  232. {
  233. FLAC__StreamMetadata *tags = (FLAC__StreamMetadata*)param;
  234. char *tagname, *p;
  235. T_CHAR *val;
  236. if (!tag)
  237. return 0;
  238. /* Vorbis comment names must be ASCII, so convert 'tag' first */
  239. tagname = malloc(wcslen(tag)+1);
  240. for(p=tagname;*tag;) {
  241. if(*tag > 0x7d) {
  242. free(tagname);
  243. return 0;
  244. }
  245. else
  246. *p++ = (char)(*tag++);
  247. }
  248. *p++ = '';
  249. /* now get it */
  250. val = FLAC_plugin__tags_get_tag_ucs2(tags, tagname);
  251. free(tagname);
  252. /* some "user friendly cheavats" */
  253. if (!val)
  254. {
  255. if (!wcsicmp(tag, L"ARTIST"))
  256. {
  257. val = FLAC_plugin__tags_get_tag_ucs2(tags, "PERFORMER");
  258. if (!val) val = FLAC_plugin__tags_get_tag_ucs2(tags, "COMPOSER");
  259. }
  260. else if (!wcsicmp(tag, L"YEAR") || !wcsicmp(tag, L"DATE"))
  261. {
  262. val = FLAC_plugin__tags_get_tag_ucs2(tags, "YEAR_RECORDED");
  263. if (!val) val = FLAC_plugin__tags_get_tag_ucs2(tags, "YEAR_PERFORMED");
  264. }
  265. }
  266. return val;
  267. }
  268. static void free_tag(T_CHAR *tag, void *param)
  269. {
  270. (void)param;
  271. free(tag);
  272. }
  273. static void format_title(const char *filename, WCHAR *title, unsigned max_size)
  274. {
  275. FLAC__StreamMetadata *tags;
  276. ReadTags(filename, &tags, /*forDisplay=*/true);
  277. tagz_format(flac_cfg.title.tag_format_w, get_tag, free_tag, tags, title, max_size);
  278. FLAC_plugin__tags_destroy(&tags);
  279. }
  280. static void getfileinfo(char *filename, char *title, int *length_in_msec)
  281. {
  282. FLAC__StreamMetadata streaminfo;
  283. if (!filename || !*filename)
  284. {
  285. filename = lastfn_;
  286. if (length_in_msec)
  287. {
  288. *length_in_msec = (int)file_info_.length_in_msec;
  289. length_in_msec  = 0;    /* force skip in following code */
  290. }
  291. }
  292. if (!FLAC__metadata_get_streaminfo(filename, &streaminfo))
  293. {
  294. if (length_in_msec)
  295. *length_in_msec = -1;
  296. return;
  297. }
  298. if (title)
  299. {
  300. static WCHAR buffer[400];
  301. format_title(filename, buffer, 400);
  302. WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, buffer, -1, title, 400, NULL, NULL);
  303. }
  304. if (length_in_msec)
  305. /* with VC++ you have to spoon feed it the casting from uint64->int64->double */
  306. *length_in_msec = (int)((double)(FLAC__int64)streaminfo.data.stream_info.total_samples / (double)streaminfo.data.stream_info.sample_rate * 1000.0 + 0.5);
  307. }
  308. /*
  309.  *  interface
  310.  */
  311. void FLAC_plugin__show_error(const char *message,...)
  312. {
  313. char foo[512];
  314. va_list args;
  315. va_start(args, message);
  316. vsprintf(foo, message, args);
  317. va_end(args);
  318. MessageBox(mod_.hMainWindow, foo, "FLAC Plug-in Error", MB_ICONSTOP);
  319. }
  320. static void about(HWND hwndParent)
  321. {
  322. MessageBox(hwndParent, "Winamp2 FLAC Plugin v"PLUGIN_VERSION"nby Josh Coalson and X-Fixernnuses libFLAC "VERSION"nSee http://flac.sourceforge.net/n", "About FLAC Plugin", MB_ICONINFORMATION);
  323. }
  324. static void config(HWND hwndParent)
  325. {
  326. if (DoConfig(mod_.hDllInstance, hwndParent))
  327. WriteConfig();
  328. }
  329. static int infobox(char *fn, HWND hwnd)
  330. {
  331. DoInfoBox(mod_.hDllInstance, hwnd, fn);
  332. return 0;
  333. }
  334. /*
  335.  *  exported stuff
  336.  */
  337. static In_Module mod_ =
  338. {
  339. IN_VER,
  340. "FLAC Decoder v" PLUGIN_VERSION,
  341. 0,                                    /* hMainWindow */
  342. 0,                                    /* hDllInstance */
  343. "FLACFLAC Audio File (*.FLAC)",
  344. 1,                                    /* is_seekable */
  345. 1,                                    /* uses output */
  346. config,
  347. about,
  348. init,
  349. quit,
  350. getfileinfo,
  351. infobox,
  352. isourfile,
  353. play,
  354. pause,
  355. unpause,
  356. ispaused,
  357. stop,
  358. getlength,
  359. getoutputtime,
  360. setoutputtime,
  361. setvolume,
  362. setpan,
  363. 0,0,0,0,0,0,0,0,0,                    /* vis stuff */
  364. 0,0,                                  /* dsp */
  365. eq_set,
  366. NULL,                                 /* setinfo */
  367. 0                                     /* out_mod */
  368. };
  369. __declspec(dllexport) In_Module *winampGetInModule2()
  370. {
  371. return &mod_;
  372. }
  373. BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
  374. {
  375. return TRUE;
  376. }