3 #endif /* HAVE_CONFIG_H */
7 #include "kbtim_common.h"
13 #define snprintf _snprintf
17 //#pragma comment(linker, "/opt:nowin98")
18 //#pragma comment(linker, "/nodefaultlib")
19 //#pragma comment(linker, "/entry:\"DllMain\"")
22 typedef KMPMODULE* (WINAPI *pfnTimGetModule)(HINSTANCE hInstance, DWORD dwVersion);
23 static HINSTANCE g_hDll1; //kbtim.kpi
\82Ì
\83C
\83\93\83X
\83^
\83\93\83X
\83n
\83\93\83h
\83\8b
24 static HINSTANCE g_hDll2; //kbtim.dll
\82Ì
\83C
\83\93\83X
\83^
\83\93\83X
\83n
\83\93\83h
\83\8b
25 static KMPMODULE *g_pModule;//kbtim.dll
\82ª
\95Ô
\82µ
\82½ KMPMODULE
27 static void __fastcall kbReplaceFileName(char *szDest, const char *cszReplace)
30 char *lastPathDelimiter = szDest;
32 if(IsDBCSLeadByte((BYTE)*p)){
37 lastPathDelimiter = p+1;
41 strcpy(lastPathDelimiter, cszReplace);
43 BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
45 switch (ul_reason_for_call){
46 case DLL_PROCESS_ATTACH:{
47 g_hDll1 = (HINSTANCE)hModule;
48 DisableThreadLibraryCalls((HMODULE)hModule);
52 case DLL_PROCESS_DETACH:{
59 static void WINAPI kmp_Init(void)
67 static void WINAPI kmp_Deinit(void)
70 if(g_pModule->Deinit){
81 KMPMODULE* WINAPI kmp_GetTestModule(void)
83 static KMPMODULE Module;
84 static KMPMODULE *pModule = NULL;
86 //kbtim_GetModule
\82Í 1
\89ñ
\82µ
\82©
\8cÄ
\82ñ
\82Å
\82Í
\82¢
\82¯
\82È
\82¢
87 char szDll1[FILEPATH_MAX];
88 char szDll2[FILEPATH_MAX];
89 GetModuleFileName(g_hDll1, szDll1, sizeof(szDll1));
90 kbExtractFilePath(szDll2, szDll1, sizeof(szDll2));
91 kbStrLCat(szDll2, "kbtim.dll", sizeof(szDll2));
92 HINSTANCE hDll = LoadLibrary(szDll2);
96 pfnTimGetModule kbtim_GetModule = (pfnTimGetModule)GetProcAddress(hDll, "kbtim_GetModule");
101 pModule = kbtim_GetModule(g_hDll1, KBTIM_GETMODULE_VERSION);
105 memcpy(&Module, pModule, sizeof(KMPMODULE));
106 Module.Init = kmp_Init;
107 Module.Deinit = kmp_Deinit;
108 if(pModule->dwReentrant != 0xFFFFFFFF){
109 //kbtim.dll
\82ª
\96¢
\8eg
\97p
119 DWORD WINAPI kmp_Config(HWND hWnd, DWORD dwVersion, DWORD dwReserved)
122 //
\83v
\83\89\83O
\83C
\83\93\82Æ
\93¯
\82¶
\83t
\83H
\83\8b\83_
\82É
\82 \82é kbtimsetup.exe
\82ð
\8bN
\93®
\82·
\82é
123 //
\83R
\83}
\83\93\83h
\83\89\83C
\83\93\83p
\83\89\83\81\81[
\83^
\82Æ
\82µ
\82Ä
\81A
\8e©
\95ª
\8e©
\90g(kbtim(_xxx).kpi)
\82Ì
\83t
\83\8b\83p
\83X
\82ð
\93n
\82·
124 char szDll1[FILEPATH_MAX]; //X:\...\kbtim(_xxx).kpi
125 char szKbTimSetupExe[FILEPATH_MAX]; //X:\...\kbtimsetup.exe
126 char szKbTimSetupParam[FILEPATH_MAX];//"X:\...\kbtim(_xxx).kpi"
128 GetModuleFileName(g_hDll1, szDll1, sizeof(szDll1));
130 kbExtractFilePath(szKbTimSetupExe, szDll1, sizeof(szKbTimSetupExe));
132 kbStrLCat(szKbTimSetupExe, "kbtimsetup_x64.exe", sizeof(szKbTimSetupExe));
134 kbStrLCat(szKbTimSetupExe, "kbtimsetup.exe", sizeof(szKbTimSetupExe));
136 //
\83R
\83}
\83\93\83h
\83\89\83C
\83\93\83p
\83\89\83\81\81[
\83^(""
\82Å
\8a\87\82é)
137 szKbTimSetupParam[0] = '"';
138 szKbTimSetupParam[1] = 0;
139 kbStrLCat(szKbTimSetupParam, szDll1, sizeof(szKbTimSetupParam));
140 kbStrLCat(szKbTimSetupParam, "\"", sizeof(szKbTimSetupParam));
141 ShellExecute(NULL, "open", szKbTimSetupExe, szKbTimSetupParam, NULL, SW_SHOWNORMAL);
151 Winamp TiMidity++ input plug-in
155 Example Winamp .RAW input plug-in
158 #include "../Winamp/in2.h"
161 // avoid CRT. Evil. Big. Bloated. Only uncomment this code if you are using
162 // 'ignore default libraries' in VC++. Keeps DLL size way down.
164 BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
170 // post this to the main window at end of file (after playback as stopped)
171 #define WM_WA_MPEG_EOF WM_USER+2
173 // def configuration.
175 #define SAMPLERATE 44100
178 char lastfn[MAX_PATH]; // currently playing file (used for getting info on the current file)
179 int file_length; // file length, in bytes
180 int decode_pos_ms; // current decoding position, in milliseconds.
181 // Used for correcting DSP plug-in pitch changes
182 int paused; // are we paused?
183 volatile int seek_needed; // if != -1, it is the point that the decode
184 // thread should seek to, in ms.
185 HANDLE input_file=INVALID_HANDLE_VALUE; // input file handle
186 volatile int killDecodeThread=0; // the kill switch for the decode thread
187 HANDLE thread_handle=INVALID_HANDLE_VALUE; // the handle to the decode thread
188 DWORD WINAPI DecodeThread(LPVOID b); // the decode thread procedure
190 #define RENDER_SAMPLES 576 // winamp plugin default
191 #define MAX_RENDER_SAMPLES 4096
192 static char *sample_buffer = NULL; // sample buffer. twice as // big as the blocksize
193 int first_render_play;
194 int first_render_byte;
196 int kpi_wrapper = 0; // 0:in_tim 1: in_kpi
198 typedef KMPMODULE* (WINAPI *pfnTimGetModule)(HINSTANCE hInstance, DWORD dwVersion);
199 static HKMP hkmp = NULL;
200 static char szDll1[FILEPATH_MAX];
201 static char szDll2[FILEPATH_MAX];
202 static char szIni1[FILEPATH_MAX];
203 static char szDll2File[FILEPATH_MAX];
204 #define EXT_INFO_MAX 32000
205 static char szDll2Ext[EXT_INFO_MAX];
206 static char szDll2Dsc[EXT_INFO_MAX];
208 static SOUNDINFO InfoKPI =
210 SAMPLERATE, // DWORD dwSamplesPerSec
\83T
\83\93\83v
\83\8a\83\93\83O
\8eü
\94g
\90\94(44100, 22050
\82È
\82Ç)
211 NCH, // DWORD dwChannels
\83`
\83\83\83\93\83l
\83\8b\90\94( mono = 1, stereo = 2)
212 BPS, // DWORD dwBitsPerSample
\97Ê
\8eq
\89»
\83r
\83b
\83g
\90\94( 8 or 16)
213 0xFFFFFFFF, // DWORD dwLength
\8bÈ
\82Ì
\92·
\82³
\81iSPC
\82Ì
\82æ
\82¤
\82É
\8cv
\8eZ
\95s
\89Â
\94\
\82È
\8fê
\8d\87\82Í 0xFFFFFFFF
\81j
214 1, // DWORD dwSeekable
\83V
\81[
\83N
\82ð
\83T
\83|
\81[
\83g
\82µ
\82Ä
\82¢
\82é
\8fê
\8d\87\82Í 1
\81A
\82µ
\82È
\82¢
\8fê
\8d\87\82Í 0
215 0, // DWORD dwUnitRender Render
\8aÖ
\90\94\82Ì
\91æ
\82R
\88ø
\90\94\82Í
\82±
\82Ì
\92l
\82Ì
\94{
\90\94\82ª
\93n
\82³
\82ê
\82é
\81i
\82Ç
\82ñ
\82È
\92l
\82Å
\82à
\97Ç
\82¢
\8fê
\8d\87\82Í 0
\81j
216 0, // DWORD dwReserved1
\8fí
\82É 0
217 0, // DWORD dwReserved2
\8fí
\82É 0
220 // module definition.
221 void config(HWND hwndParent);
222 void about(HWND hwndParent);
225 void getfileinfo(const char *filename, char *title, int *length_in_ms);
226 int infoDlg(const char *fn, HWND hwnd);
227 int isourfile(const char *fn);
228 int play(const char *fn);
234 int getoutputtime(void);
235 void setoutputtime(int time_in_ms);
236 void setvolume(int volume);
237 void setpan(int pan);
238 void eq_set(int on, char data[10], int preamp);
242 IN_VER, // defined in IN2.H
243 "Timidity++ MIDI Plugin"
244 // winamp runs on both alpha systems and x86 ones. :)
251 0, // hMainWindow (filled in by winamp)
252 0, // hDllInstance (filled in by winamp)
253 "MID\0SMF File (*.MID)\0"
254 "MIDI\0SMF File (*.MID)\0"
255 "SMF\0SMF File (*.SMF)\0"
256 "RMI\0RMID File (*.RMI)\0"
257 "RCP\0RCP File (*.RCP)\0"
258 "R36\0RCP File (*.R36)\0"
259 "G18\0RCP File (*.G18)\0"
260 "G36\0RCP File (*.G36)\0"
261 // this is a double-null limited list. "EXT\0Description\0EXT\0Description\0" etc.
264 1, // uses output plug-in system
282 0,0,0,0,0,0,0,0,0, // visualization calls filled in by winamp
283 0,0, // dsp calls filled in by winamp
285 NULL, // setinfo call filled in by winamp
286 0 // out_mod filled in by winamp
290 static void create_sample_buffer(void)
292 // sample buffer. twice as // big as the blocksize
293 // max = MAX_RENDER_SAMPLES * 2ch * 32bit/byte * twice;
295 sample_buffer = (char *)malloc(MAX_RENDER_SAMPLES * 2 * (32 / 8) * 2);
298 static void free_sample_buffer(void)
304 static void get_playmode(void)
306 // kbtim
\82Æ
\88á
\82¢
\83T
\83\93\83v
\83\8b\83\8c\81[
\83g
\93\99\82Íini
\82Å
\90Ý
\92è
\82·
\82é
307 char opt_playmode[16], *arg;
308 int size = sizeof(opt_playmode) - 1;
310 InfoKPI.dwSamplesPerSec = GetPrivateProfileInt("TIMIDITY", "output_rate", 0, szIni1);
311 GetPrivateProfileString("TIMIDITY", "opt_playmode", "", opt_playmode, size, szIni1);
312 opt_playmode[size - 1] = 0;
316 case 'S': /* stereo */
317 InfoKPI.dwChannels = 2;
320 InfoKPI.dwChannels = 1;
322 //case 'D': /* D for float 64-bit */
323 // InfoKPI.dwBitsPerSample = -64;
325 //case '6': /* 6 for 64-bit */
326 // InfoKPI.dwBitsPerSample = 64;
328 //case 'f': /* f for float 32-bit */
329 // InfoKPI.dwBitsPerSample = -32;
331 case '3': /* 3 for 32-bit */
332 InfoKPI.dwBitsPerSample = 32;
334 case '2': /* 2 for 24-bit */
335 InfoKPI.dwBitsPerSample = 24;
337 case '1': /* 1 for 16-bit */
338 InfoKPI.dwBitsPerSample = 16;
341 InfoKPI.dwBitsPerSample = 8;
346 InfoKPI.dwUnitRender = RENDER_SAMPLES * InfoKPI.dwChannels * InfoKPI.dwBitsPerSample / 8;
349 static void load_wrapper_config(void)
353 static KMPMODULE Module;
354 static KMPMODULE *pModule = NULL;
356 GetModuleFileName(g_hDll1, szDll1, sizeof(szDll1));
357 kbExtractReplacedFileExt(szIni1, szDll1, ".ini");// ini
\8eæ
\93¾
\83v
\83\89\83O
\83C
\83\93\82Æ
\83t
\83@
\83C
\83\8b\96¼
\82ª
\93¯
\82¶
\82Å
\8ag
\92£
\8eq
\82ª INI
358 kpi_wrapper = GetPrivateProfileInt("wrapper", "kpi_wrapper", 0, szIni1);
359 play_load = GetPrivateProfileInt("wrapper", "play_load", 0, szIni1);
360 if(!kpi_wrapper){ // in_kbtim
361 HINSTANCE hDll = NULL;
363 kbExtractFilePath(szDll2, szDll1, sizeof(szDll1));
364 kbStrLCat(szDll2, "kbtim.dll", sizeof(szDll2));
365 hDll = LoadLibrary(szDll2);
369 //kbtim_GetModule
\82Í 1
\89ñ
\82µ
\82©
\8cÄ
\82ñ
\82Å
\82Í
\82¢
\82¯
\82È
\82¢
370 pfnTimGetModule kbtim_GetModule = (pfnTimGetModule)GetProcAddress(hDll, "kbtim_GetModule");
371 if(!kbtim_GetModule){
375 pModule = kbtim_GetModule(g_hDll1, KBTIM_GETMODULE_VERSION);
380 memcpy(&Module, pModule, sizeof(KMPMODULE));
381 if(pModule->dwReentrant != 0xFFFFFFFF) //kbtim.dll
\82ª
\96¢
\8eg
\97p
385 }else{ // in_kpi_wrapper
386 // kbtim
\82Æ
\88á
\82¢
\83T
\83\93\83v
\83\8b\83\8c\81[
\83g
\93\99\82Íini
\82Å
\90Ý
\92è
\82·
\82é
387 HINSTANCE hKpi = NULL;
388 InfoKPI.dwSamplesPerSec = GetPrivateProfileInt("wrapper", "output_rate", 0, szIni1);
389 InfoKPI.dwBitsPerSample = GetPrivateProfileInt("wrapper", "output_bit", 0, szIni1);
390 InfoKPI.dwChannels = GetPrivateProfileInt("wrapper", "output_channel", 0, szIni1);
391 InfoKPI.dwUnitRender = RENDER_SAMPLES * InfoKPI.dwChannels * InfoKPI.dwBitsPerSample / 8;
392 GetPrivateProfileString("wrapper", "file", "", szDll2File, sizeof(szDll2File), szIni1); // kpi
\83t
\83@
\83C
\83\8b\96¼
\8eæ
\93¾
393 if(kbStrLen(szDll2File)){ // kpi
\8eæ
\93¾
\83t
\83@
\83C
\83\8b\96¼
\8ew
\92è
394 kbExtractFilePath(szDll2, szDll1, sizeof(szDll2));
395 kbStrLCat(szDll2, szDll2File, sizeof(szDll2));
396 }else{// kpi
\8eæ
\93¾
\83v
\83\89\83O
\83C
\83\93\83t
\83@
\83C
\83\8b\96¼
\82©
\82ç"in_"
\8dí
\8f\9c \8ag
\92£
\8eq
\82ª KPI
397 const char *file = kbExtractFileName(szDll1) + 3; // delete "in_"
398 kbExtractFilePath(szDll2File, szDll1, sizeof(szDll2));
399 kbStrLCat(szDll2File, file, sizeof(szDll2));
400 kbExtractReplacedFileExt(szDll2, szDll2File, ".kpi");//
\8ag
\92£
\8eq
\82ª KPI
403 hKpi = LoadLibrary(szDll2);
407 pfnGetKMPModule GetModule = (pfnGetKMPModule)GetProcAddress(hKpi, SZ_KMP_GETMODULE);
412 pModule = GetModule();
417 memcpy(&Module, pModule, sizeof(KMPMODULE));
418 if(pModule->dwReentrant != 0xFFFFFFFF)
423 kbStrLCat(szDll2Dsc, g_pModule->pszDescription, EXT_INFO_MAX);
425 kbStrLCat(szDll2Dsc, " (AXP)", EXT_INFO_MAX);
428 kbStrLCat(szDll2Dsc, " (x64)", EXT_INFO_MAX);
430 kbStrLCat(szDll2Dsc, " (x86)", EXT_INFO_MAX);
433 mod.description = szDll2Dsc;
435 for(i = 0; i < 16; i++){
437 char szext[EXT_INFO_MAX], szinf[EXT_INFO_MAX];
438 char *str = (char *)g_pModule->ppszSupportExts[i];
442 memset(szext, 0, sizeof(szext));
443 memset(szinf, 0, sizeof(szinf));
444 tmp1 = kbStrLen(str);
448 memcpy(szext, (char *)str + 1, tmp1); // delete piriod
449 snprintf(szinf, sizeof(szinf), "%s file (*.%s)", szext, szext);
450 tmp1 = kbStrLen(szext);
451 tmp2 = kbStrLen(szinf);
453 memcpy(szDll2Ext + end, szext, tmp1);
455 szDll2Ext[end] = '\0';
457 memcpy(szDll2Ext + end, szinf, tmp2);
459 szDll2Ext[end] = '\0';
463 mod.FileExtensions = szDll2Ext;
467 typedef DWORD (WINAPI *kmp_Config_gui)(HWND hWnd, DWORD dwVersion, DWORD dwReserved);
469 void config(HWND hwndParent)
471 // MessageBox(hwndParent, "No configuration.", "Configuration",MB_OK);
473 char szDll1[FILEPATH_MAX]; //X:\...\kbtim(_xxx).kpi
474 char szKbTimSetupExe[FILEPATH_MAX]; //X:\...\kbtimsetup.exe
475 char szKbTimSetupParam[FILEPATH_MAX];//"X:\...\kbtim(_xxx).kpi"
477 GetModuleFileName(g_hDll1, szDll1, sizeof(szDll1));
479 kbExtractFilePath(szKbTimSetupExe, szDll1, sizeof(szKbTimSetupExe));
481 kbStrLCat(szKbTimSetupExe, "kbtimsetup_x64.exe", sizeof(szKbTimSetupExe));
483 kbStrLCat(szKbTimSetupExe, "kbtimsetup.exe", sizeof(szKbTimSetupExe));
485 //
\83R
\83}
\83\93\83h
\83\89\83C
\83\93\83p
\83\89\83\81\81[
\83^(""
\82Å
\8a\87\82é)
486 szKbTimSetupParam[0] = '"';
487 szKbTimSetupParam[1] = 0;
488 kbStrLCat(szKbTimSetupParam, szDll1, sizeof(szKbTimSetupParam));
489 kbStrLCat(szKbTimSetupParam, "\"", sizeof(szKbTimSetupParam));
490 ShellExecute(NULL, "open", szKbTimSetupExe, szKbTimSetupParam, NULL, SW_SHOWNORMAL);
492 ((kmp_Config_gui)GetProcAddress(g_hDll2, "kmp_Config"))(hwndParent, 0, 0);
497 void about(HWND hwndParent)
500 MessageBox(hwndParent,"Timidity++ MIDI Plugin", "About Plugin",MB_OK);
502 MessageBox(hwndParent,"KbMedia Player Plugin wrapper", "About Plugin",MB_OK);
506 create_sample_buffer();
515 if(g_pModule->Deinit){
521 FreeLibrary(g_hDll2);
524 free_sample_buffer();
527 int isourfile(const char *fn) {
528 // used for detecting URL streams.. unused here.
529 // return !strncmp(fn,"http://",7); to detect HTTP streams, etc
533 // called when winamp wants to play a file
534 int play(const char *fn)
538 int tmp_byte = InfoKPI.dwUnitRender;
543 first_render_play = 0;
544 first_render_byte = 0;
545 memset(sample_buffer, 0, sizeof(sample_buffer));
549 hkmp = g_pModule->Open(fn, &InfoKPI);
554 if(InfoKPI.dwUnitRender <= 0){ //
\82È
\82º
\82©0
\82É
\82³
\82ê
\82é
\8fê
\8d\87
555 InfoKPI.dwUnitRender = tmp_byte;
556 // InfoKPI.dwUnitRender = RENDER_SAMPLES;
559 // -1 and -1 are to specify buffer and prebuffer lengths.
560 // -1 means to use the default, which all input plug-ins should
562 maxlatency = mod.outMod->Open(InfoKPI.dwSamplesPerSec, InfoKPI.dwChannels, InfoKPI.dwBitsPerSample, -1, -1);
564 // maxlatency is the maxium latency between a outMod->Write() call and
565 // when you hear those samples. In ms. Used primarily by the visualization
567 if (maxlatency < 0) // error opening device
570 // dividing by 1000 for the first parameter of setinfo makes it
571 // display 'H'... for hundred.. i.e. 14H Kbps.
572 mod.SetInfo((InfoKPI.dwSamplesPerSec * InfoKPI.dwBitsPerSample * InfoKPI.dwChannels) / 1000,
573 InfoKPI.dwSamplesPerSec / 1000, InfoKPI.dwChannels >= 2 ? 1 : 0, 1);
575 // initialize visualization stuff
576 mod.SAVSAInit(maxlatency, InfoKPI.dwSamplesPerSec);
577 mod.VSASetInfo(InfoKPI.dwSamplesPerSec, InfoKPI.dwChannels);
579 // set the output plug-ins default volume.
580 // volume is 0-255, -666 is a token for
582 mod.outMod->SetVolume(-666);
587 if(g_pModule->Render)
588 first_render_byte = g_pModule->Render(hkmp, (BYTE*)sample_buffer, InfoKPI.dwUnitRender); // retrieve samples
591 first_render_play = 1;
594 // launch decode thread
596 thread_handle = (HANDLE)CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) DecodeThread,NULL,0,&thread_id);
601 // standard pause implementation
602 void pause() { paused=1; mod.outMod->Pause(1); }
603 void unpause() { paused=0; mod.outMod->Pause(0); }
604 int ispaused() { return paused; }
609 if (thread_handle != INVALID_HANDLE_VALUE)
612 if (WaitForSingleObject(thread_handle,10000) == WAIT_TIMEOUT)
614 MessageBox(mod.hMainWindow,"error asking thread to die!\n",
615 "error killing decode thread",0);
616 TerminateThread(thread_handle,0);
618 CloseHandle(thread_handle);
619 thread_handle = INVALID_HANDLE_VALUE;
621 // close output system
623 // deinitialize visualization
627 if(g_pModule->Close){
628 g_pModule->Close(hkmp);
633 // returns length of playing track
635 return InfoKPI.dwLength;
639 // returns current output position, in ms.
640 // you could just use return mod.outMod->GetOutputTime(),
641 // but the dsp plug-ins that do tempo changing tend to make
643 int getoutputtime() {
644 return decode_pos_ms + (mod.outMod->GetOutputTime() - mod.outMod->GetWrittenTime());
648 // called when the user releases the seek scroll bar.
649 // usually we use it to set seek_needed to the seek
650 // point (seek_needed is -1 when no seek is needed)
651 // and the decode thread checks seek_needed.
652 void setoutputtime(int time_in_ms) {
653 seek_needed = time_in_ms;
657 // standard volume/pan functions
658 void setvolume(int volume) { }
659 void setpan(int pan) { }
661 // this gets called when the use hits Alt+3 to get the file info.
662 // if you need more info, ask me :)
663 int infoDlg(const char *fn, HWND hwnd)
665 // CHANGEME! Write your own info dialog code here
670 // this is an odd function. it is used to get the title and/or
671 // length of a track.
672 // if filename is either NULL or of length 0, it means you should
673 // return the info of lastfn. Otherwise, return the information
674 // for the file in filename.
675 // if title is NULL, no title is copied into it.
676 // if length_in_ms is NULL, no length is copied into it.
678 static void get_filename(const char *filename, char *title)
680 char *p=lastfn+strlen(filename);
681 while (*p != '\\' && p >= filename) p--;
685 #define BIN_SIZE (0xC0)
687 static void get_title(const char *filename, char *title)
691 int i = 0, j = 0, flg = 0;
693 file = fopen(filename, "rb");
695 while (!feof(file)) {
698 bin[i] = fgetc(file);
705 else if(memcmp(bin, "melo", 4) == 0) // mfi
707 else if(memcmp(bin, "RCM-", 4) == 0 || memcmp(bin, "COME", 4) == 0){ // rcp
708 for(i = 0x20; i < BIN_SIZE; i++){
709 if(bin[i] == (char)0x00){
712 }else if(bin[i] == (char)0x20 && bin[i + 1] == (char)0x20 && bin[i + 2] == (char)0x20){ // space*3
719 }else if(strncmp(bin, "RIFF", 4) == 0 || strncmp(bin, "MThd", 4) == 0){ // rmf or smf
722 while (i <= BIN_SIZE - 4) {
723 if(memcmp(bin + i, "MTrk", 4) == 0){
731 while (i <= BIN_SIZE - 4) {
732 if(bin[i] == (char)0x00 && bin[i + 1] == (char)0xFF && bin[i + 2] == (char)0x03){
739 i += 4; // skip 00FFxxxx
740 for(; i < BIN_SIZE; i++){
741 if(bin[i] == (char)0x00 || bin[i + 1] == (char)0xFF){
751 }else // if(memcmp(bin, "melo", 4) == 0) // mfi
754 get_filename(filename, title); // get non path portion of filename
757 #if defined(_MSC_VER)
759 #define strncasecmp(a,b,c) _strnicmp((a),(b),(c))
765 static void get_title_filename(const char *filename, char *title)
771 if(!kpi_wrapper){ // only midi ext
772 get_title(filename, title); // title or get non path portion of filename
775 ext = kbExtractFileExt(filename);
777 if(strncasecmp(ext, ".MID", 4) == 0
778 || strncasecmp(ext, ".MIDI", 5) == 0
779 || strncasecmp(ext, ".SMF", 4) == 0
780 || strncasecmp(ext, ".RMI", 4) == 0
781 || strncasecmp(ext, ".RCP", 4) == 0
782 || strncasecmp(ext, ".R36", 4) == 0
783 || strncasecmp(ext, ".G18", 4) == 0
784 || strncasecmp(ext, ".G36", 4) == 0) // search midi ext
786 if(strncmp(ext, ".mid", 4) == 0
787 || strncmp(ext, ".MID", 4) == 0
788 || strncmp(ext, ".midi", 5) == 0
789 || strncmp(ext, ".MIDI", 5) == 0
790 || strncmp(ext, ".smf", 4) == 0
791 || strncmp(ext, ".SMF", 4) == 0
792 || strncmp(ext, ".rmi", 4) == 0
793 || strncmp(ext, ".RMI", 4) == 0
794 || strncmp(ext, ".rcp", 4) == 0
795 || strncmp(ext, ".RCP", 4) == 0
796 || strncmp(ext, ".r36", 4) == 0
797 || strncmp(ext, ".R36", 4) == 0
798 || strncmp(ext, ".g18", 4) == 0
799 || strncmp(ext, ".G18", 4) == 0
800 || strncmp(ext, ".g36", 4) == 0
801 || strncmp(ext, ".G36", 4) == 0) // search midi ext
803 get_title(filename, title); // title or get non path portion of filename
805 get_filename(filename, title); // get non path portion of filename
808 void getfileinfo(const char *filename, char *title, int *length_in_ms)
810 if (!filename || !*filename) // currently playing file
812 if (length_in_ms) *length_in_ms = -1000; // the default is unknown file length (-1000).
813 if (title) get_title_filename(lastfn, title); // title or get non-path portion.of filename
816 else // some other file
818 if (length_in_ms) *length_in_ms = -1000; // the default is unknown file length (-1000).
819 if (title) get_title_filename(filename, title); // title or get non path portion of filename
823 void eq_set(int on, char data[10], int preamp)
825 // most plug-ins can't even do an EQ anyhow.. I'm working on writing
826 // a generic PCM EQ, but it looks like it'll be a little too CPU
827 // consuming to be useful :)
828 // if you _CAN_ do EQ with your format, each data byte is 0-63 (+20db <-> -20db)
829 // and preamp is the same.
832 DWORD WINAPI DecodeThread(LPVOID b)
834 int done=0; // set to TRUE if decoding has finished
835 int byte = InfoKPI.dwBitsPerSample / 8, ch_byte = InfoKPI.dwChannels * byte, render_byte = InfoKPI.dwUnitRender;//RENDER_SAMPLES * ch_byte;
837 while (!killDecodeThread)
839 if (seek_needed != -1) // seek is needed.
842 decode_pos_ms = seek_needed;
845 mod.outMod->Flush(decode_pos_ms); // flush output device and set // output position to the seek position
847 if(g_pModule->SetPosition){
848 g_pModule->SetPosition(hkmp, decode_pos_ms);
852 if (done) // done was set to TRUE during decoding, signaling eof
854 mod.outMod->CanWrite(); // some output drivers need CanWrite // to be called on a regular basis.
855 if (!mod.outMod->IsPlaying())
857 // we're done playing, so tell Winamp and quit the thread.
858 PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);
859 return 0; // quit thread
861 Sleep(10); // give a little CPU time back to the system.
863 else if (mod.outMod->CanWrite() >= (render_byte * (mod.dsp_isactive() ? 2 : 1)))
864 // CanWrite() returns the number of bytes you can write, so we check that
865 // to the block size. the reason we multiply the block size by two if
866 // mod.dsp_isactive() is that DSP plug-ins can change it by up to a
867 // factor of two (for tempo adjustment).
869 int l = render_byte; // block length in bytes
870 static char sample_buffer[RENDER_SAMPLES * 2 * (32 / 8) * 2]; // sample buffer. twice as // big as the blocksize
872 if(!first_render_play){ // first render play()
873 first_render_play = 1;
874 l = first_render_byte;
876 if(g_pModule->Render)
877 l = g_pModule->Render(hkmp, (BYTE*)sample_buffer, render_byte); // retrieve samples
879 if (!l) // no samples means we're at eof
883 else // we got samples!
885 int samples = l / ch_byte;
886 // give the samples to the vis subsystems
887 mod.SAAddPCMData((char *)sample_buffer, InfoKPI.dwChannels, InfoKPI.dwBitsPerSample, decode_pos_ms);
888 mod.VSAAddPCMData((char *)sample_buffer, InfoKPI.dwChannels, InfoKPI.dwBitsPerSample, decode_pos_ms);
889 // adjust decode position variable
890 decode_pos_ms += (samples * 1000) / InfoKPI.dwSamplesPerSec;
891 // if we have a DSP plug-in, then call it on our samples
892 if (mod.dsp_isactive())
893 l = mod.dsp_dosamples((short *)sample_buffer, samples, InfoKPI.dwBitsPerSample, InfoKPI.dwChannels, InfoKPI.dwSamplesPerSec)
894 * ch_byte; // dsp_dosamples
895 // write the pcm data to the output system
896 mod.outMod->Write(sample_buffer, l);
900 // if we can't write data, wait a little bit. Otherwise, continue
901 // through the loop writing more data (without sleeping)
908 // exported symbol. Returns output module.
910 __declspec( dllexport ) In_Module * winampGetInModule2()
912 load_wrapper_config();