main.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. //#define PLUGIN_NAME "Nullsoft MPEG Audio Decoder"
  2. #include "main.h"
  3. #include <time.h>
  4. #include "DecodeThread.h"
  5. #include "api__in_mp3.h"
  6. #include "../Winamp/wa_ipc.h"
  7. #include "../nu/ServiceBuilder.h"
  8. #include "config.h"
  9. #include "AlbumArt.h"
  10. #include "MetadataFactory.h"
  11. #include "../nu/Singleton.h"
  12. #include "RawMediaReader.h"
  13. char lastfn_status[256] = {0};
  14. int lastfn_status_err = 0;
  15. CRITICAL_SECTION g_lfnscs;
  16. CRITICAL_SECTION streamInfoLock;
  17. int lastfn_data_ready;
  18. int config_fastvis=0;
  19. unsigned char config_miscopts=0;
  20. unsigned char allow_sctitles=1;
  21. unsigned char sctitle_format=1;
  22. unsigned char config_eqmode=4,config_http_proxynonport80=1;
  23. unsigned int winampVersion=0x00005010; // default version # to use if winamp version is 5.1 or less (and therefore doesn't have a valid HWND during Init)
  24. char config_http_save_dir[MAX_PATH] = "C:\\";
  25. int config_http_buffersize=64, config_http_prebuffer=40, config_http_prebuffer_underrun=10;
  26. unsigned char config_downmix=0, config_downsample=0, allow_scartwork=1;
  27. int config_max_bufsize_k=128;
  28. int config_gapless=1;
  29. char INI_FILE[MAX_PATH] = {0};
  30. wchar_t lastfn[8192] = {0}; // currently playing file (used for getting info on the current file)
  31. // Used for correcting DSP plug-in pitch changes
  32. int paused = 0; // are we paused?
  33. int m_is_stream = 0;
  34. bool m_is_stream_seekable = true;
  35. volatile int killDecodeThread=0; // the kill switch for the decode thread
  36. HANDLE thread_handle=INVALID_HANDLE_VALUE; // the handle to the decode thread
  37. DWORD WINAPI DecodeThread(LPVOID b); // the decode thread procedure
  38. extern char *getfileextensions();
  39. #include "api/service/waservicefactory.h"
  40. #include "FactoryHelper.h"
  41. // wasabi based services for localisation support
  42. HINSTANCE WASABI_API_LNG_HINST = 0;
  43. HINSTANCE WASABI_API_ORIG_HINST = 0;
  44. api_language *WASABI_API_LNG = 0;
  45. api_application *WASABI_API_APP = 0;
  46. api_config *AGAVE_API_CONFIG = 0;
  47. api_memmgr *WASABI_API_MEMMGR = 0;
  48. AlbumArtFactory albumArtFactory;
  49. MetadataFactory metadataFactory;
  50. static RawMediaReaderService raw_media_reader_service;
  51. static SingletonServiceFactory<svc_raw_media_reader, RawMediaReaderService> raw_factory;
  52. int init()
  53. {
  54. if (!IsWindow(mod.hMainWindow))
  55. return IN_INIT_FAILURE;
  56. winampVersion = (unsigned int)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETVERSION);
  57. mod.service->service_register(&metadataFactory);
  58. mod.service->service_register(&albumArtFactory);
  59. raw_factory.Register(mod.service, &raw_media_reader_service);
  60. ServiceBuild(AGAVE_API_CONFIG, AgaveConfigGUID);
  61. ServiceBuild(WASABI_API_LNG, languageApiGUID);
  62. ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
  63. ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
  64. // need to have this initialised before we try to do anything with localisation features
  65. WASABI_API_START_LANG(mod.hDllInstance,InMp3LangGUID);
  66. static wchar_t szDescription[256];
  67. swprintf(szDescription, 256, WASABI_API_LNGSTRINGW(IDS_NULLSOFT_MPEG_AUDIO_DECODER), PLUGIN_VERSION);
  68. mod.description = (char*)szDescription;
  69. InitializeCriticalSection(&g_lfnscs);
  70. InitializeCriticalSection(&streamInfoLock);
  71. mod.UsesOutputPlug|=2;
  72. config_read();
  73. mod.FileExtensions=getfileextensions();
  74. return IN_INIT_SUCCESS;
  75. }
  76. void quit()
  77. {
  78. DeleteCriticalSection(&g_lfnscs);
  79. DeleteCriticalSection(&streamInfoLock);
  80. ServiceRelease(mod.service, AGAVE_API_CONFIG, AgaveConfigGUID);
  81. ServiceRelease(mod.service, WASABI_API_APP, applicationApiServiceGuid);
  82. ServiceRelease(mod.service, WASABI_API_MEMMGR, memMgrApiServiceGuid);
  83. mod.service->service_deregister(&albumArtFactory);
  84. raw_factory.Deregister(mod.service);
  85. }
  86. int g_eq_ok;
  87. int isourfile(const wchar_t *fn)
  88. {
  89. if (!_wcsnicmp(fn,L"uvox://",7)) return 1;
  90. if (!_wcsnicmp(fn,L"icy://",6)) return 1;
  91. if (!_wcsnicmp(fn,L"sc://",5)) return 1;
  92. if (!_wcsnicmp(fn,L"shoutcast://",12)) return 1;
  93. return 0;
  94. }
  95. int m_force_seek=-1;
  96. // called when winamp wants to play a file
  97. int play(const in_char *fn)
  98. {
  99. DWORD thread_id;
  100. lastfn_status_err=0;
  101. paused=0;
  102. g_length=-1000;
  103. decode_pos_ms=0;
  104. seek_needed=m_force_seek;
  105. m_force_seek=-1;
  106. m_is_stream = 0;
  107. m_is_stream_seekable = false;
  108. killDecodeThread=0;
  109. g_sndopened=0;
  110. lastfn_data_ready=0;
  111. lastfn_status[0]=0;
  112. g_bufferstat=0;
  113. g_closeaudio=0;
  114. lstrcpynW(lastfn,fn, 8192);
  115. mod.is_seekable = 0;
  116. mod.SetInfo(0,0,0,0);
  117. g_ds=config_downsample;
  118. g_eq_ok=1;
  119. // launch decode thread
  120. thread_handle = (HANDLE)CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) DecodeThread,NULL,0,&thread_id);
  121. SetThreadPriority(thread_handle, (int)AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
  122. return 0;
  123. }
  124. // standard pause implementation
  125. void pause()
  126. {
  127. paused=1;
  128. if (g_sndopened)
  129. mod.outMod->Pause(1);
  130. }
  131. void unpause()
  132. {
  133. paused=0;
  134. if (g_sndopened)
  135. mod.outMod->Pause(0);
  136. }
  137. int ispaused()
  138. {
  139. return paused;
  140. }
  141. // stop playing.
  142. void stop()
  143. {
  144. killDecodeThread=1;
  145. WaitForSingleObject(thread_handle,INFINITE);
  146. CloseHandle(thread_handle);
  147. g_eq_ok=0;
  148. thread_handle = INVALID_HANDLE_VALUE;
  149. g_length=-1000;
  150. lastfn[0]=0;
  151. if (g_closeaudio)
  152. {
  153. g_closeaudio=0;
  154. mod.outMod->Close();
  155. mod.SAVSADeInit();
  156. }
  157. g_sndopened=0;
  158. m_force_seek=-1;
  159. }
  160. // returns length of playing track
  161. int getlength()
  162. {
  163. return g_length;
  164. }
  165. // returns current output position, in ms.
  166. // you could just use return mod.outMod->GetOutputTime(),
  167. // but the dsp plug-ins that do tempo changing tend to make
  168. // that wrong.
  169. int getoutputtime()
  170. {
  171. if (g_bufferstat)
  172. return g_bufferstat;
  173. if (!lastfn_data_ready||!g_sndopened)
  174. return 0;
  175. if (seek_needed!=-1)
  176. return seek_needed;
  177. return decode_pos_ms +
  178. (mod.outMod->GetOutputTime()-mod.outMod->GetWrittenTime());
  179. }
  180. // called when the user releases the seek scroll bar.
  181. // usually we use it to set seek_needed to the seek
  182. // point (seek_needed is -1 when no seek is needed)
  183. // and the decode thread checks seek_needed.
  184. void setoutputtime(int time_in_ms)
  185. {
  186. if (m_is_stream == 0 || (m_is_stream !=0 && m_is_stream_seekable))
  187. {
  188. seek_needed=time_in_ms;
  189. m_force_seek=-1;
  190. }
  191. }
  192. // standard volume/pan functions
  193. void setvolume(int volume)
  194. {
  195. mod.outMod->SetVolume(volume);
  196. }
  197. void setpan(int pan)
  198. {
  199. mod.outMod->SetPan(pan);
  200. }
  201. // this is an odd function. it is used to get the title and/or
  202. // length of a track.
  203. // if filename is either NULL or of length 0, it means you should
  204. // return the info of lastfn. Otherwise, return the information
  205. // for the file in filename.
  206. // if title is NULL, no title is copied into it.
  207. // if length_in_ms is NULL, no length is copied into it.
  208. static int memcmpv(char *d, char v, int l)
  209. {
  210. while (l--)
  211. if (*d++ != v) return 1;
  212. return 0;
  213. }
  214. void eq_set(int on, char data[10], int preamp)
  215. {
  216. int x;
  217. eq_preamp = preamp;
  218. eq_enabled = on;
  219. for (x = 0; x < 10; x ++)
  220. eq_tab[x] = data[x];
  221. // if eq zeroed out, dont use eq
  222. if (eq_enabled && preamp==31 && !memcmpv(data,31,10))
  223. eq_enabled=0;
  224. }
  225. // render 576 samples into buf.
  226. // this function is only used by DecodeThread.
  227. // note that if you adjust the size of sample_buffer, for say, 1024
  228. // sample blocks, it will still work, but some of the visualization
  229. // might not look as good as it could. Stick with 576 sample blocks
  230. // if you can, and have an additional auxiliary (overflow) buffer if
  231. // necessary..
  232. // module definition.
  233. extern In_Module mod =
  234. {
  235. IN_VER_RET, // defined in IN2.H
  236. "nullsoft(in_mp3.dll)",
  237. 0, // hMainWindow (filled in by winamp)
  238. 0, // hDllInstance (filled in by winamp)
  239. 0,
  240. // this is a double-null limited list. "EXT\0Description\0EXT\0Description\0" etc.
  241. 0, // is_seekable
  242. 1, // uses output plug-in system
  243. config,
  244. about,
  245. init,
  246. quit,
  247. getfileinfo,
  248. id3Dlg,
  249. isourfile,
  250. play,
  251. pause,
  252. unpause,
  253. ispaused,
  254. stop,
  255. getlength,
  256. getoutputtime,
  257. setoutputtime,
  258. setvolume,
  259. setpan,
  260. 0,0,0,0,0,0,0,0,0, // visualization calls filled in by winamp
  261. 0,0, // dsp calls filled in by winamp
  262. eq_set,
  263. NULL, // setinfo call filled in by winamp
  264. 0, // out_mod filled in by winamp
  265. };
  266. // exported symbol. Returns output module.
  267. extern "C"
  268. {
  269. __declspec(dllexport) In_Module * winampGetInModule2()
  270. {
  271. return &mod;
  272. }
  273. }