in_openmpt.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. /*
  2. * in_openmpt.cpp
  3. * --------------
  4. * Purpose: libopenmpt winamp input plugin implementation
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #ifndef NO_WINAMP
  10. #if defined(_MFC_VER) || 1
  11. #ifndef _CRT_SECURE_NO_WARNINGS
  12. #define _CRT_SECURE_NO_WARNINGS
  13. #endif
  14. #if !defined(WINVER) && !defined(_WIN32_WINDOWS)
  15. #ifndef _WIN32_WINNT
  16. #define _WIN32_WINNT 0x0501 // _WIN32_WINNT_WINXP
  17. #endif
  18. #endif
  19. #if !defined(MPT_BUILD_RETRO)
  20. #if defined(_MSC_VER)
  21. #define MPT_WITH_MFC
  22. #endif
  23. #else
  24. #if defined(_WIN32_WINNT)
  25. #if (_WIN32_WINNT >= 0x0501)
  26. #if defined(_MSC_VER)
  27. #define MPT_WITH_MFC
  28. #endif
  29. #endif
  30. #endif
  31. #endif
  32. #if defined(MPT_WITH_MFC)
  33. #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // Avoid binary bloat from linking unused MFC controls
  34. #endif // MPT_WITH_MFC
  35. #ifndef NOMINMAX
  36. #define NOMINMAX
  37. #endif
  38. #if defined(MPT_WITH_MFC)
  39. #include <afxwin.h>
  40. #include <afxcmn.h>
  41. #endif // MPT_WITH_MFC
  42. #include <windows.h>
  43. #endif // _MFC_VER
  44. #ifdef LIBOPENMPT_BUILD_DLL
  45. #undef LIBOPENMPT_BUILD_DLL
  46. #endif
  47. #ifdef _MSC_VER
  48. #ifndef _CRT_SECURE_NO_WARNINGS
  49. #define _CRT_SECURE_NO_WARNINGS
  50. #endif
  51. #ifndef _SCL_SECURE_NO_WARNINGS
  52. #define _SCL_SECURE_NO_WARNINGS
  53. #endif
  54. #endif // _MSC_VER
  55. #include "libopenmpt.hpp"
  56. #include "libopenmpt_plugin_settings.hpp"
  57. #include "libopenmpt_plugin_gui.hpp"
  58. #include "svn_version.h"
  59. #if defined(OPENMPT_VERSION_REVISION)
  60. static const char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_VERSION_REVISION);
  61. #else
  62. static const char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING;
  63. #endif
  64. #ifndef NOMINMAX
  65. #define NOMINMAX
  66. #endif
  67. #include <windows.h>
  68. #ifdef UNICODE
  69. #define UNICODE_INPUT_PLUGIN
  70. #endif
  71. #ifndef _MSC_VER
  72. #define _MSC_VER 1300
  73. #endif
  74. #include "winamp/Winamp/IN2.H"
  75. #include "winamp/Winamp/wa_ipc.h"
  76. #include <algorithm>
  77. #include <fstream>
  78. #include <iostream>
  79. #include <iterator>
  80. #include <sstream>
  81. #include <cstring>
  82. #include <tchar.h>
  83. #define BPS 16
  84. #define WINAMP_DSP_HEADROOM_FACTOR 2
  85. #define WINAMP_BUFFER_SIZE_FRAMES 576
  86. #define WM_OPENMPT_SEEK (WM_USER+3)
  87. #define SHORT_TITLE "in_openmpt"
  88. static void apply_options();
  89. static std::string StringEncode( const std::wstring &src, UINT codepage )
  90. {
  91. int required_size = WideCharToMultiByte( codepage, 0, src.c_str(), -1, NULL, 0, NULL, NULL );
  92. if(required_size <= 0)
  93. {
  94. return std::string();
  95. }
  96. std::vector<CHAR> encoded_string( required_size );
  97. WideCharToMultiByte( codepage, 0, src.c_str(), -1, &encoded_string[0], encoded_string.size(), NULL, NULL );
  98. return &encoded_string[0];
  99. }
  100. static std::wstring StringDecode( const std::string & src, UINT codepage )
  101. {
  102. int required_size = MultiByteToWideChar( codepage, 0, src.c_str(), -1, NULL, 0 );
  103. if(required_size <= 0)
  104. {
  105. return std::wstring();
  106. }
  107. std::vector<WCHAR> decoded_string( required_size );
  108. MultiByteToWideChar( codepage, 0, src.c_str(), -1, &decoded_string[0], decoded_string.size() );
  109. return &decoded_string[0];
  110. }
  111. #if defined(UNICODE)
  112. static std::wstring StringToWINAPI( const std::wstring & src )
  113. {
  114. return src;
  115. }
  116. #else
  117. static std::string StringToWINAPI( const std::wstring & src )
  118. {
  119. return StringEncode( src, CP_ACP );
  120. }
  121. #endif
  122. template <typename Tstring, typename Tstring2, typename Tstring3>
  123. static inline Tstring StringReplace( Tstring str, const Tstring2 & oldStr_, const Tstring3 & newStr_ ) {
  124. std::size_t pos = 0;
  125. const Tstring oldStr = oldStr_;
  126. const Tstring newStr = newStr_;
  127. while ( ( pos = str.find( oldStr, pos ) ) != Tstring::npos ) {
  128. str.replace( pos, oldStr.length(), newStr );
  129. pos += newStr.length();
  130. }
  131. return str;
  132. }
  133. struct self_winamp_t {
  134. std::vector<char> filetypes_string;
  135. libopenmpt::plugin::settings settings;
  136. int samplerate;
  137. int channels;
  138. std::basic_string<TCHAR> cached_filename;
  139. std::basic_string<TCHAR> cached_title;
  140. int cached_length;
  141. std::basic_string<TCHAR> cached_infotext;
  142. std::int64_t decode_position_frames;
  143. openmpt::module * mod;
  144. HANDLE PlayThread;
  145. DWORD PlayThreadID;
  146. bool paused;
  147. std::vector<std::int16_t> buffer;
  148. std::vector<std::int16_t> interleaved_buffer;
  149. self_winamp_t() : settings(TEXT(SHORT_TITLE), true) {
  150. filetypes_string.clear();
  151. settings.changed = apply_options;
  152. settings.load();
  153. std::vector<std::string> extensions = openmpt::get_supported_extensions();
  154. for ( std::vector<std::string>::iterator ext = extensions.begin(); ext != extensions.end(); ++ext ) {
  155. std::copy( (*ext).begin(), (*ext).end(), std::back_inserter( filetypes_string ) );
  156. filetypes_string.push_back('\0');
  157. std::copy( SHORT_TITLE, SHORT_TITLE + std::strlen(SHORT_TITLE), std::back_inserter( filetypes_string ) );
  158. filetypes_string.push_back('\0');
  159. }
  160. filetypes_string.push_back('\0');
  161. samplerate = settings.samplerate;
  162. channels = settings.channels;
  163. cached_filename = std::basic_string<TCHAR>();
  164. cached_title = std::basic_string<TCHAR>();
  165. cached_length = 0;
  166. cached_infotext = std::basic_string<TCHAR>();
  167. decode_position_frames = 0;
  168. mod = 0;
  169. PlayThread = 0;
  170. PlayThreadID = 0;
  171. paused = false;
  172. buffer.resize( WINAMP_BUFFER_SIZE_FRAMES * channels );
  173. interleaved_buffer.resize( WINAMP_BUFFER_SIZE_FRAMES * channels * WINAMP_DSP_HEADROOM_FACTOR );
  174. }
  175. ~self_winamp_t() {
  176. return;
  177. }
  178. };
  179. static self_winamp_t * self = 0;
  180. static void apply_options() {
  181. if ( self->mod ) {
  182. self->mod->set_repeat_count( self->settings.repeatcount );
  183. self->mod->set_render_param( openmpt::module::RENDER_MASTERGAIN_MILLIBEL, self->settings.mastergain_millibel );
  184. self->mod->set_render_param( openmpt::module::RENDER_STEREOSEPARATION_PERCENT, self->settings.stereoseparation );
  185. self->mod->set_render_param( openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH, self->settings.interpolationfilterlength );
  186. self->mod->set_render_param( openmpt::module::RENDER_VOLUMERAMPING_STRENGTH, self->settings.ramping );
  187. self->mod->ctl_set_boolean( "render.resampler.emulate_amiga", self->settings.use_amiga_resampler ? true : false );
  188. switch ( self->settings.amiga_filter_type ) {
  189. case 0:
  190. self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "auto" );
  191. break;
  192. case 1:
  193. self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "unfiltered" );
  194. break;
  195. case 0xA500:
  196. self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a500" );
  197. break;
  198. case 0xA1200:
  199. self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a1200" );
  200. break;
  201. }
  202. }
  203. self->settings.save();
  204. }
  205. extern In_Module inmod;
  206. static DWORD WINAPI DecodeThread( LPVOID );
  207. static std::basic_string<TCHAR> generate_infotext( const std::basic_string<TCHAR> & filename, const openmpt::module & mod ) {
  208. std::basic_ostringstream<TCHAR> str;
  209. str << TEXT("filename: ") << filename << std::endl;
  210. str << TEXT("duration: ") << mod.get_duration_seconds() << TEXT("seconds") << std::endl;
  211. std::vector<std::string> metadatakeys = mod.get_metadata_keys();
  212. for ( std::vector<std::string>::iterator key = metadatakeys.begin(); key != metadatakeys.end(); ++key ) {
  213. if ( *key == "message_raw" ) {
  214. continue;
  215. }
  216. str << StringToWINAPI( StringDecode( *key, CP_UTF8 ) ) << TEXT(": ") << StringToWINAPI( StringDecode( mod.get_metadata(*key), CP_UTF8 ) ) << std::endl;
  217. }
  218. return str.str();
  219. }
  220. static void config( HWND hwndParent ) {
  221. #if 1
  222. libopenmpt::plugin::gui_edit_settings( &self->settings, hwndParent, TEXT(SHORT_TITLE) );
  223. #else
  224. static_cast<void>(hwndParent);
  225. #endif
  226. apply_options();
  227. }
  228. static void about( HWND hwndParent ) {
  229. std::ostringstream about;
  230. about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl;
  231. about << " Copyright (c) 2013-2022 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl;
  232. about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl;
  233. about << std::endl;
  234. about << openmpt::string::get( "contact" ) << std::endl;
  235. about << std::endl;
  236. about << "Show full credits?" << std::endl;
  237. if ( MessageBox( hwndParent, StringToWINAPI( StringDecode( about.str(), CP_UTF8 ) ).c_str(), TEXT(SHORT_TITLE), MB_ICONINFORMATION | MB_YESNOCANCEL | MB_DEFBUTTON1 ) != IDYES ) {
  238. return;
  239. }
  240. std::ostringstream credits;
  241. credits << openmpt::string::get( "credits" );
  242. #if 1
  243. libopenmpt::plugin::gui_show_file_info( hwndParent, TEXT(SHORT_TITLE), StringToWINAPI( StringReplace( StringDecode( credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ) );
  244. #else
  245. MessageBox( hwndParent, StringToWINAPI( StringReplace(StringDecode(credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ).c_str(), TEXT(SHORT_TITLE), MB_OK );
  246. #endif
  247. }
  248. static void init() {
  249. if ( !self ) {
  250. self = new self_winamp_t();
  251. inmod.FileExtensions = &(self->filetypes_string[0]);
  252. }
  253. }
  254. static void quit() {
  255. if ( self ) {
  256. inmod.FileExtensions = NULL;
  257. delete self;
  258. self = 0;
  259. }
  260. }
  261. static int isourfile( const in_char * /* fn */ ) {
  262. return 0;
  263. }
  264. static int play( const in_char * fn ) {
  265. if ( !fn ) {
  266. return -1;
  267. }
  268. try {
  269. std::ifstream s( fn, std::ios::binary );
  270. std::map< std::string, std::string > ctls;
  271. ctls["seek.sync_samples"] = "1";
  272. self->mod = new openmpt::module( s, std::clog, ctls );
  273. self->cached_filename = fn;
  274. self->cached_title = StringToWINAPI( StringDecode( self->mod->get_metadata( "title" ), CP_UTF8 ) );
  275. self->cached_length = static_cast<int>( self->mod->get_duration_seconds() * 1000.0 );
  276. self->cached_infotext = generate_infotext( self->cached_filename, *self->mod );
  277. apply_options();
  278. self->samplerate = self->settings.samplerate;
  279. self->channels = self->settings.channels;
  280. int maxlatency = inmod.outMod->Open( self->samplerate, self->channels, BPS, -1, -1 );
  281. std::ostringstream str;
  282. str << maxlatency;
  283. inmod.SetInfo( self->mod->get_num_channels(), self->samplerate/1000, self->channels, 1 );
  284. inmod.SAVSAInit( maxlatency, self->samplerate );
  285. inmod.VSASetInfo( self->channels, self->samplerate );
  286. inmod.outMod->SetVolume( -666 );
  287. inmod.outMod->SetPan( 0 );
  288. self->paused = false;
  289. self->decode_position_frames = 0;
  290. self->PlayThread = CreateThread( NULL, 0, DecodeThread, NULL, 0, &self->PlayThreadID );
  291. return 0;
  292. } catch ( ... ) {
  293. if ( self->mod ) {
  294. delete self->mod;
  295. self->mod = 0;
  296. }
  297. return -1;
  298. }
  299. }
  300. static void pause() {
  301. self->paused = true;
  302. inmod.outMod->Pause( 1 );
  303. }
  304. static void unpause() {
  305. self->paused = false;
  306. inmod.outMod->Pause( 0 );
  307. }
  308. static int ispaused() {
  309. return self->paused ? 1 : 0;
  310. }
  311. static void stop() {
  312. PostThreadMessage( self->PlayThreadID, WM_QUIT, 0, 0 );
  313. WaitForSingleObject( self->PlayThread, INFINITE );
  314. CloseHandle( self->PlayThread );
  315. self->PlayThread = 0;
  316. self->PlayThreadID = 0;
  317. delete self->mod;
  318. self->mod = 0;
  319. inmod.outMod->Close();
  320. inmod.SAVSADeInit();
  321. }
  322. static int getlength() {
  323. return self->cached_length;
  324. }
  325. static int getoutputtime() {
  326. //return (int)( self->decode_position_frames * 1000 / self->mod->get_render_param( openmpt::module::RENDER_SAMPLERATE_HZ ) /* + ( inmod.outMod->GetOutputTime() - inmod.outMod->GetWrittenTime() ) */ );
  327. return inmod.outMod->GetOutputTime();
  328. }
  329. static void setoutputtime( int time_in_ms ) {
  330. PostThreadMessage( self->PlayThreadID, WM_OPENMPT_SEEK, 0, time_in_ms );
  331. }
  332. static void setvolume( int volume ) {
  333. inmod.outMod->SetVolume( volume );
  334. }
  335. static void setpan( int pan ) {
  336. inmod.outMod->SetPan( pan );
  337. }
  338. static int infobox( const in_char * fn, HWND hWndParent ) {
  339. if ( fn && fn[0] != '\0' && self->cached_filename != std::basic_string<TCHAR>(fn) ) {
  340. try {
  341. std::ifstream s( fn, std::ios::binary );
  342. openmpt::module mod( s );
  343. #if 1
  344. libopenmpt::plugin::gui_show_file_info( hWndParent, TEXT(SHORT_TITLE), StringReplace( generate_infotext( fn, mod ), TEXT("\n"), TEXT("\r\n") ) );
  345. #else
  346. MessageBox( hWndParent, StringReplace( generate_infotext( fn, mod ), TEXT("\n"), TEXT("\r\n") ).c_str(), TEXT(SHORT_TITLE), MB_OK );
  347. #endif
  348. } catch ( ... ) {
  349. }
  350. } else {
  351. #if 1
  352. libopenmpt::plugin::gui_show_file_info( hWndParent, TEXT(SHORT_TITLE), StringReplace( self->cached_infotext, TEXT("\n"), TEXT("\r\n") ) );
  353. #else
  354. MessageBox( hWndParent, StringReplace( self->cached_infotext, TEXT("\n"), TEXT("\r\n") ).c_str(), TEXT(SHORT_TITLE), MB_OK );
  355. #endif
  356. }
  357. return INFOBOX_UNCHANGED;
  358. }
  359. static void getfileinfo( const in_char * filename, in_char * title, int * length_in_ms ) {
  360. if ( !filename || *filename == '\0' ) {
  361. if ( length_in_ms ) {
  362. *length_in_ms = self->cached_length;
  363. }
  364. if ( title ) {
  365. std::basic_string<TCHAR> truncated_title = self->cached_title;
  366. if ( truncated_title.length() >= GETFILEINFO_TITLE_LENGTH ) {
  367. truncated_title.resize( GETFILEINFO_TITLE_LENGTH - 1 );
  368. }
  369. _tcscpy( title, truncated_title.c_str() );
  370. }
  371. } else {
  372. try {
  373. std::ifstream s( filename, std::ios::binary );
  374. openmpt::module mod( s );
  375. if ( length_in_ms ) {
  376. *length_in_ms = static_cast<int>( mod.get_duration_seconds() * 1000.0 );
  377. }
  378. if ( title ) {
  379. std::basic_string<TCHAR> truncated_title = StringToWINAPI( StringDecode( mod.get_metadata("title"), CP_UTF8 ) );
  380. if ( truncated_title.length() >= GETFILEINFO_TITLE_LENGTH ) {
  381. truncated_title.resize( GETFILEINFO_TITLE_LENGTH - 1 );
  382. }
  383. _tcscpy( title, truncated_title.c_str() );
  384. }
  385. } catch ( ... ) {
  386. }
  387. }
  388. }
  389. static void eq_set( int /* on */ , char /* data */ [10], int /* preamp */ ) {
  390. return;
  391. }
  392. static DWORD WINAPI DecodeThread( LPVOID ) {
  393. MSG msg;
  394. PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE );
  395. bool eof = false;
  396. while ( true ) {
  397. bool quit = false;
  398. while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
  399. if ( msg.message == WM_QUIT ) {
  400. quit = true;
  401. } else if ( msg.message == WM_OPENMPT_SEEK ) {
  402. double pos_seconds = self->mod->set_position_seconds( msg.lParam * 0.001 );
  403. self->decode_position_frames = (std::int64_t)( pos_seconds * (double)self->samplerate);
  404. eof = false;
  405. inmod.outMod->Flush( (int)( pos_seconds * 1000.0 ) );
  406. }
  407. }
  408. if ( quit ) {
  409. break;
  410. }
  411. if ( eof ) {
  412. inmod.outMod->CanWrite(); // update output plugin state
  413. if ( !inmod.outMod->IsPlaying() ) {
  414. PostMessage( inmod.hMainWindow, WM_WA_MPEG_EOF, 0, 0 );
  415. return 0;
  416. }
  417. Sleep( 10 );
  418. } else {
  419. bool dsp_active = inmod.dsp_isactive() ? true : false;
  420. if ( inmod.outMod->CanWrite() >= (int)( WINAMP_BUFFER_SIZE_FRAMES * self->channels * sizeof( signed short ) ) * ( dsp_active ? WINAMP_DSP_HEADROOM_FACTOR : 1 ) ) {
  421. int frames = 0;
  422. switch ( self->channels ) {
  423. case 1:
  424. frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES );
  425. for ( int frame = 0; frame < frames; frame++ ) {
  426. self->interleaved_buffer[frame*1+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame];
  427. }
  428. break;
  429. case 2:
  430. frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+1*WINAMP_BUFFER_SIZE_FRAMES );
  431. for ( int frame = 0; frame < frames; frame++ ) {
  432. self->interleaved_buffer[frame*2+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame];
  433. self->interleaved_buffer[frame*2+1] = self->buffer[1*WINAMP_BUFFER_SIZE_FRAMES+frame];
  434. }
  435. break;
  436. case 4:
  437. frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+1*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+2*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+3*WINAMP_BUFFER_SIZE_FRAMES );
  438. for ( int frame = 0; frame < frames; frame++ ) {
  439. self->interleaved_buffer[frame*4+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame];
  440. self->interleaved_buffer[frame*4+1] = self->buffer[1*WINAMP_BUFFER_SIZE_FRAMES+frame];
  441. self->interleaved_buffer[frame*4+2] = self->buffer[2*WINAMP_BUFFER_SIZE_FRAMES+frame];
  442. self->interleaved_buffer[frame*4+3] = self->buffer[3*WINAMP_BUFFER_SIZE_FRAMES+frame];
  443. }
  444. break;
  445. }
  446. if ( frames == 0 ) {
  447. eof = true;
  448. } else {
  449. self->decode_position_frames += frames;
  450. std::int64_t decode_pos_ms = (self->decode_position_frames * 1000 / self->samplerate );
  451. inmod.SAAddPCMData( &( self->interleaved_buffer[0] ), self->channels, BPS, (int)decode_pos_ms );
  452. inmod.VSAAddPCMData( &( self->interleaved_buffer[0] ), self->channels, BPS, (int)decode_pos_ms );
  453. if ( dsp_active ) {
  454. frames = inmod.dsp_dosamples( &( self->interleaved_buffer[0] ), frames, BPS, self->channels, self->samplerate );
  455. }
  456. int bytes = frames * self->channels * sizeof( signed short );
  457. inmod.outMod->Write( (char*)&( self->interleaved_buffer[0] ), bytes );
  458. }
  459. } else {
  460. Sleep( 10 );
  461. }
  462. }
  463. }
  464. return 0;
  465. }
  466. #if defined(__GNUC__)
  467. extern In_Module inmod;
  468. #endif
  469. In_Module inmod = {
  470. IN_VER,
  471. const_cast< char * >( in_openmpt_string ), // SHORT_TITLE,
  472. 0, // hMainWindow
  473. 0, // hDllInstance
  474. NULL, // filled later in Init() "mptm\0ModPlug Tracker Module (*.mptm)\0",
  475. 1, // is_seekable
  476. 1, // uses output
  477. config,
  478. about,
  479. init,
  480. quit,
  481. getfileinfo,
  482. infobox,
  483. isourfile,
  484. play,
  485. pause,
  486. unpause,
  487. ispaused,
  488. stop,
  489. getlength,
  490. getoutputtime,
  491. setoutputtime,
  492. setvolume,
  493. setpan,
  494. 0,0,0,0,0,0,0,0,0, // vis
  495. 0,0, // dsp
  496. eq_set,
  497. NULL, // setinfo
  498. 0 // out_mod
  499. };
  500. extern "C" __declspec(dllexport) In_Module * winampGetInModule2();
  501. extern "C" __declspec(dllexport) In_Module * winampGetInModule2() {
  502. return &inmod;
  503. }
  504. #if defined(MPT_WITH_MFC)
  505. #ifdef _MFC_VER
  506. namespace libopenmpt {
  507. namespace plugin {
  508. void DllMainAttach() {
  509. // nothing
  510. }
  511. void DllMainDetach() {
  512. // nothing
  513. }
  514. } // namespace plugin
  515. } // namespace libopenmpt
  516. #else
  517. // nothing
  518. #endif
  519. #endif // MPT_WITH_MFC
  520. #endif // NO_WINAMP