OSDN Git Service

Import UnkoTim220
[timidity41/timidity41.git] / kbtim / kbtim_kpi.cpp
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif /* HAVE_CONFIG_H */
4 #include <windows.h>
5 #include <stdio.h>
6 #include "kmp_pi.h"
7 #include "kbtim_common.h"
8 #include "kbstr.h"
9 #include "common.h"
10
11 #ifdef _MSC_VER
12 #define HAVE_SNPRINTF
13 #define snprintf _snprintf
14 #endif
15
16 #ifndef _DEBUG
17 //#pragma comment(linker, "/opt:nowin98")  
18 //#pragma comment(linker, "/nodefaultlib") 
19 //#pragma comment(linker, "/entry:\"DllMain\"")
20 #endif
21
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
26
27 static void __fastcall kbReplaceFileName(char *szDest, const char *cszReplace)
28 {
29     char *p = szDest;
30     char *lastPathDelimiter = szDest;
31     while(*p){
32         if(IsDBCSLeadByte((BYTE)*p)){
33             p += 2;
34             continue;
35         }
36         else if(*p == '\\'){
37             lastPathDelimiter = p+1;
38         }
39         p++;
40     }
41     strcpy(lastPathDelimiter, cszReplace);
42 }
43 BOOL APIENTRY DllMain(HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
44 {
45     switch (ul_reason_for_call){
46         case DLL_PROCESS_ATTACH:{
47             g_hDll1 = (HINSTANCE)hModule;
48             DisableThreadLibraryCalls((HMODULE)hModule);
49             kbStr_Initialize();
50             break;
51         }
52         case DLL_PROCESS_DETACH:{
53             break;
54         }
55     }
56     return TRUE;
57 }
58
59 static void WINAPI kmp_Init(void)
60 {
61     if(g_pModule){
62         if(g_pModule->Init){
63             g_pModule->Init();
64         }
65     }        
66 }
67 static void WINAPI kmp_Deinit(void)
68 {
69     if(g_pModule){
70         if(g_pModule->Deinit){
71             g_pModule->Deinit();
72         }
73         g_pModule = NULL;
74     }
75     if(g_hDll2){
76         FreeLibrary(g_hDll2);
77         g_hDll2 = NULL;
78     }
79 }
80
81 KMPMODULE* WINAPI kmp_GetTestModule(void)
82 {
83     static KMPMODULE Module;
84     static KMPMODULE *pModule = NULL;
85     if(!pModule){
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);
93         if(!hDll){
94             return NULL;
95         }
96         pfnTimGetModule kbtim_GetModule = (pfnTimGetModule)GetProcAddress(hDll, "kbtim_GetModule");
97         if(!kbtim_GetModule){
98             FreeLibrary(hDll);
99             return NULL;
100         }
101         pModule = kbtim_GetModule(g_hDll1, KBTIM_GETMODULE_VERSION);
102         if(!pModule){
103             FreeLibrary(hDll);
104         }else{
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
110                 g_pModule = pModule;
111             }
112             pModule = &Module;
113             g_hDll2 = hDll;
114         }
115     }
116     return pModule;
117 }
118
119 DWORD WINAPI kmp_Config(HWND hWnd, DWORD dwVersion, DWORD dwReserved)
120 {
121     if(dwVersion == 0){
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"
127         //*.kpi
128         GetModuleFileName(g_hDll1, szDll1, sizeof(szDll1));
129         //kbtimsetup.exe
130         kbExtractFilePath(szKbTimSetupExe, szDll1, sizeof(szKbTimSetupExe));
131 #ifdef _WIN64
132         kbStrLCat(szKbTimSetupExe, "kbtimsetup_x64.exe", sizeof(szKbTimSetupExe));
133 #else
134         kbStrLCat(szKbTimSetupExe, "kbtimsetup.exe", sizeof(szKbTimSetupExe));
135 #endif
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);
142     }
143     return 0;
144 }
145
146
147
148
149
150 /*
151 Winamp TiMidity++ input plug-in
152
153
154 based
155 Example Winamp .RAW input plug-in
156 */
157
158 #include "../Winamp/in2.h"
159
160
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.
163 // /*
164 BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
165 {
166         return TRUE;
167 }
168 // */
169
170 // post this to the main window at end of file (after playback as stopped)
171 #define WM_WA_MPEG_EOF WM_USER+2
172
173 // def configuration.
174 #define NCH 2
175 #define SAMPLERATE 44100
176 #define BPS 16
177
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
189
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;
195 int play_load = 0;
196 int kpi_wrapper = 0; // 0:in_tim 1: in_kpi
197
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];
207
208 static SOUNDINFO InfoKPI =
209 {       // init param
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
218 };
219
220 // module definition.
221 void config(HWND hwndParent);
222 void about(HWND hwndParent);
223 void init(void);
224 void quit(void);
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);
229 void pause(void);
230 void unpause(void);
231 int ispaused(void);
232 void stop(void);
233 int getlength(void);
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);
239
240 In_Module mod = 
241 {
242         IN_VER, // defined in IN2.H
243         "Timidity++ MIDI Plugin"
244         // winamp runs on both alpha systems and x86 ones. :)
245 #ifdef __alpha
246         " (AXP)"
247 #else
248         " (x86)"
249 #endif
250         ,
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.
262         ,
263         1,      // is_seekable
264         1,      // uses output plug-in system
265         config,
266         about,
267         init,
268         quit,
269         getfileinfo,
270         infoDlg,
271         isourfile,
272         play,
273         pause,
274         unpause,
275         ispaused,
276         stop,   
277         getlength,
278         getoutputtime,
279         setoutputtime,
280         setvolume,
281         setpan,
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
284         eq_set,
285         NULL,           // setinfo call filled in by winamp
286         0 // out_mod filled in by winamp
287
288 };
289
290 static void create_sample_buffer(void)
291 {
292         // sample buffer. twice as // big as the blocksize
293         // max = MAX_RENDER_SAMPLES * 2ch * 32bit/byte * twice;
294         if(!sample_buffer)
295                 sample_buffer = (char *)malloc(MAX_RENDER_SAMPLES * 2 * (32 / 8) * 2);
296 }
297
298 static void free_sample_buffer(void)
299 {
300         if(sample_buffer)
301                 free(sample_buffer);
302 }
303
304 static void get_playmode(void)
305 {
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;
309
310         InfoKPI.dwSamplesPerSec = GetPrivateProfileInt("TIMIDITY", "output_rate", 0, szIni1);
311     GetPrivateProfileString("TIMIDITY", "opt_playmode", "", opt_playmode, size, szIni1);
312     opt_playmode[size - 1] = 0;         
313         arg = opt_playmode;
314         while (*(++arg))
315                 switch (*arg) {
316                 case 'S':       /* stereo */
317                         InfoKPI.dwChannels = 2;
318                         break;
319                 case 'M':
320                         InfoKPI.dwChannels = 1;
321                         break;
322                 //case 'D':     /* D for float 64-bit */
323                 //      InfoKPI.dwBitsPerSample = -64;
324                 //      break;
325                 //case '6':     /* 6 for 64-bit */
326                 //      InfoKPI.dwBitsPerSample = 64;
327                 //      break;
328                 //case 'f':     /* f for float 32-bit */
329                 //      InfoKPI.dwBitsPerSample = -32;
330                 //      break;
331                 case '3':       /* 3 for 32-bit */
332                         InfoKPI.dwBitsPerSample = 32;
333                         break;
334                 case '2':       /* 2 for 24-bit */
335                         InfoKPI.dwBitsPerSample = 24;
336                         break;
337                 case '1':       /* 1 for 16-bit */
338                         InfoKPI.dwBitsPerSample = 16;
339                         break;
340                 case '8':
341                         InfoKPI.dwBitsPerSample = 8;
342                         break;
343                 default:
344                         break;
345                 }
346         InfoKPI.dwUnitRender = RENDER_SAMPLES * InfoKPI.dwChannels * InfoKPI.dwBitsPerSample / 8;
347 }
348
349 static void load_wrapper_config(void)
350 {
351         int i;
352         int end = 0;
353     static KMPMODULE Module;
354     static KMPMODULE *pModule = NULL;
355         
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;
362                 get_playmode(); 
363                 kbExtractFilePath(szDll2, szDll1, sizeof(szDll1));
364                 kbStrLCat(szDll2, "kbtim.dll", sizeof(szDll2));
365                 hDll = LoadLibrary(szDll2);
366                 if(!hDll){
367                         return;
368                 }
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){
372                         FreeLibrary(hDll);
373                         return;
374                 }
375                 pModule = kbtim_GetModule(g_hDll1, KBTIM_GETMODULE_VERSION);
376                 if(!pModule){
377                         FreeLibrary(hDll);
378                         return;
379                 }               
380                 memcpy(&Module, pModule, sizeof(KMPMODULE));
381                 if(pModule->dwReentrant != 0xFFFFFFFF) //kbtim.dll \82ª\96¢\8eg\97p
382                         g_pModule = pModule;
383                 pModule = &Module;
384                 g_hDll2 = hDll;    
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
401                 }
402                 // load kpi
403                 hKpi = LoadLibrary(szDll2);
404                 if(!hKpi){
405                         return;
406                 }
407                 pfnGetKMPModule GetModule = (pfnGetKMPModule)GetProcAddress(hKpi, SZ_KMP_GETMODULE);
408                 if(!GetModule){
409                         FreeLibrary(hKpi);
410                         return;
411                 }
412                 pModule = GetModule();
413                 if(!pModule){
414                         FreeLibrary(hKpi);
415                         return;
416                 }               
417                 memcpy(&Module, pModule, sizeof(KMPMODULE));            
418             if(pModule->dwReentrant != 0xFFFFFFFF)
419                         g_pModule = pModule;
420                 pModule = &Module;
421                 g_hDll2 = hKpi;         
422                 // Description
423                 kbStrLCat(szDll2Dsc, g_pModule->pszDescription, EXT_INFO_MAX);
424 #ifdef __alpha
425                 kbStrLCat(szDll2Dsc, " (AXP)", EXT_INFO_MAX);
426 #else // windows
427 #ifdef _WIN64
428                 kbStrLCat(szDll2Dsc, " (x64)", EXT_INFO_MAX);
429 #else
430                 kbStrLCat(szDll2Dsc, " (x86)", EXT_INFO_MAX);
431 #endif
432 #endif
433                 mod.description = szDll2Dsc;
434                 // Extension Info
435                 for(i = 0; i < 16; i++){
436                         int tmp1, tmp2;
437                         char szext[EXT_INFO_MAX], szinf[EXT_INFO_MAX];
438                         char *str = (char *)g_pModule->ppszSupportExts[i];
439
440                         if(str == NULL)
441                                 break;
442                         memset(szext, 0, sizeof(szext));
443                         memset(szinf, 0, sizeof(szinf));
444                         tmp1 = kbStrLen(str);
445                         --tmp1; 
446                         if(tmp1 <= 0)
447                                 break;
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);
452                         if(tmp1 && tmp2){
453                                 memcpy(szDll2Ext + end, szext, tmp1);
454                                 end += tmp1;
455                                 szDll2Ext[end] = '\0';
456                                 end++;
457                                 memcpy(szDll2Ext + end, szinf, tmp2);
458                                 end += tmp2;
459                                 szDll2Ext[end] = '\0';
460                                 end++;
461                         }       
462                 }
463                 mod.FileExtensions = szDll2Ext; 
464         }
465 }
466
467 typedef DWORD (WINAPI *kmp_Config_gui)(HWND hWnd, DWORD dwVersion, DWORD dwReserved);
468
469 void config(HWND hwndParent)
470 {
471 //      MessageBox(hwndParent, "No configuration.", "Configuration",MB_OK);
472         if(!kpi_wrapper){
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"
476                 //*.kpi
477                 GetModuleFileName(g_hDll1, szDll1, sizeof(szDll1));
478                 //kbtimsetup.exe
479                 kbExtractFilePath(szKbTimSetupExe, szDll1, sizeof(szKbTimSetupExe));
480 #ifdef _WIN64
481                 kbStrLCat(szKbTimSetupExe, "kbtimsetup_x64.exe", sizeof(szKbTimSetupExe));
482 #else
483                 kbStrLCat(szKbTimSetupExe, "kbtimsetup.exe", sizeof(szKbTimSetupExe));
484 #endif
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); 
491         }else{
492                 ((kmp_Config_gui)GetProcAddress(g_hDll2, "kmp_Config"))(hwndParent, 0, 0);
493         }
494     return;
495 }
496
497 void about(HWND hwndParent)
498 {
499         if(!kpi_wrapper)
500                 MessageBox(hwndParent,"Timidity++ MIDI Plugin", "About Plugin",MB_OK);
501         else
502                 MessageBox(hwndParent,"KbMedia Player Plugin wrapper", "About Plugin",MB_OK);
503 }
504
505 void init(void) { 
506         create_sample_buffer();
507         if(g_pModule){
508         if(g_pModule->Init)
509             g_pModule->Init();
510     }
511 }
512
513 void quit(void) { 
514     if(g_pModule){
515         if(g_pModule->Deinit){
516             g_pModule->Deinit();
517         }
518         g_pModule = NULL;
519     }
520     if(g_hDll2){
521         FreeLibrary(g_hDll2);
522         g_hDll2 = NULL;
523     }
524         free_sample_buffer();
525 }
526
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
530         return 0; 
531
532
533 // called when winamp wants to play a file
534 int play(const char *fn) 
535 {       
536         int maxlatency;
537         DWORD thread_id;
538         int tmp_byte = InfoKPI.dwUnitRender;
539         
540         paused=0;
541         decode_pos_ms=0;
542         seek_needed=-1;         
543         first_render_play = 0;
544         first_render_byte = 0;
545         memset(sample_buffer, 0, sizeof(sample_buffer));
546         
547     if(g_pModule){
548         if(g_pModule->Open){
549             hkmp = g_pModule->Open(fn, &InfoKPI);
550         }
551     }
552         if(!hkmp)
553                 return 1;
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;
557         }
558
559         // -1 and -1 are to specify buffer and prebuffer lengths.
560         // -1 means to use the default, which all input plug-ins should
561         // really do.
562         maxlatency = mod.outMod->Open(InfoKPI.dwSamplesPerSec, InfoKPI.dwChannels, InfoKPI.dwBitsPerSample, -1, -1); 
563
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
566         // system.
567         if (maxlatency < 0) // error opening device
568                 return 1;
569
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);
574
575         // initialize visualization stuff
576         mod.SAVSAInit(maxlatency, InfoKPI.dwSamplesPerSec);
577         mod.VSASetInfo(InfoKPI.dwSamplesPerSec, InfoKPI.dwChannels);
578
579         // set the output plug-ins default volume.
580         // volume is 0-255, -666 is a token for
581         // current volume.
582         mod.outMod->SetVolume(-666);             
583         
584         // for aimp3 timeout
585         if(play_load){
586                 if(g_pModule){
587                         if(g_pModule->Render)                           
588                                 first_render_byte = g_pModule->Render(hkmp, (BYTE*)sample_buffer, InfoKPI.dwUnitRender); // retrieve samples                    
589                 }
590         }else{
591                 first_render_play = 1;
592         }
593
594         // launch decode thread
595         killDecodeThread=0;
596         thread_handle = (HANDLE)CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) DecodeThread,NULL,0,&thread_id);
597
598         return 0; 
599 }
600
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; }
605
606
607 // stop playing.
608 void stop() { 
609         if (thread_handle != INVALID_HANDLE_VALUE)
610         {
611                 killDecodeThread=1;
612                 if (WaitForSingleObject(thread_handle,10000) == WAIT_TIMEOUT)
613                 {
614                         MessageBox(mod.hMainWindow,"error asking thread to die!\n",
615                                 "error killing decode thread",0);
616                         TerminateThread(thread_handle,0);
617                 }
618                 CloseHandle(thread_handle);
619                 thread_handle = INVALID_HANDLE_VALUE;
620         }
621         // close output system
622         mod.outMod->Close();
623         // deinitialize visualization
624         mod.SAVSADeInit();      
625
626     if(g_pModule){
627         if(g_pModule->Close){
628             g_pModule->Close(hkmp);
629         }
630     } 
631 }
632
633 // returns length of playing track
634 int getlength() {
635         return InfoKPI.dwLength; 
636 }
637
638
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
642 // that wrong.
643 int getoutputtime() { 
644         return decode_pos_ms + (mod.outMod->GetOutputTime() - mod.outMod->GetWrittenTime()); 
645 }
646
647
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; 
654 }
655
656
657 // standard volume/pan functions
658 void setvolume(int volume) { }
659 void setpan(int pan) { }
660
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)
664 {
665         // CHANGEME! Write your own info dialog code here
666         return 0;
667 }
668
669
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.
677
678 static void get_filename(const char *filename, char *title)
679 {
680         char *p=lastfn+strlen(filename);
681         while (*p != '\\' && p >= filename) p--;
682         strcpy(title,++p);
683 }
684
685 #define BIN_SIZE (0xC0)
686
687 static void get_title(const char *filename, char *title)
688 {
689         FILE *file = NULL;
690         char bin[BIN_SIZE];
691         int i = 0, j = 0, flg = 0;
692
693         file = fopen(filename, "rb");   
694         if(file){
695                 while (!feof(file)) {
696                         if(i >= BIN_SIZE)
697                                 break;
698                         bin[i] = fgetc(file);
699                         i++;
700                 }
701                 fclose(file);
702         }
703         if(i < BIN_SIZE)
704                 flg = 1; // no title
705         else if(memcmp(bin, "melo", 4) == 0) // mfi
706                 flg = 1; // no title
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){
710                                 title[j] = '\0';
711                                 break;
712                         }else if(bin[i] == (char)0x20 && bin[i + 1] == (char)0x20 && bin[i + 2] == (char)0x20){ // space*3
713                                 title[j] = '\0';
714                                 break;
715                         }
716                         title[j++] = bin[i];
717                 }
718                 title[j] = '\0';
719         }else if(strncmp(bin, "RIFF", 4) == 0 || strncmp(bin, "MThd", 4) == 0){ // rmf or smf
720                 int stp = 0;
721                 i = 0;
722                 while (i <= BIN_SIZE - 4) {
723                         if(memcmp(bin + i, "MTrk", 4) == 0){
724                                 stp = 1;
725                                 break;
726                         }
727                         i++;
728                 }
729                 if(stp){
730                         stp = 0;
731                         while (i <= BIN_SIZE - 4) {
732                                 if(bin[i] == (char)0x00 && bin[i + 1] == (char)0xFF && bin[i + 2] == (char)0x03){
733                                         stp = 1;
734                                         break;
735                                 }
736                                 i++;
737                         }
738                         if(stp){
739                                 i += 4; // skip 00FFxxxx                
740                                 for(; i < BIN_SIZE; i++){
741                                         if(bin[i] == (char)0x00 || bin[i + 1] == (char)0xFF){
742                                                 title[j] = '\0';
743                                                 break;
744                                         }
745                                         title[j++] = bin[i];
746                                 }
747                         }else
748                                 flg = 1; // no title
749                 }else
750                         flg = 1; // no title
751         }else // if(memcmp(bin, "melo", 4) == 0) // mfi
752                 flg = 1; // no title 
753         if(flg)
754                 get_filename(filename, title); // get non path portion of filename
755 }
756
757 #if defined(_MSC_VER)
758 #ifndef strncasecmp
759 #define strncasecmp(a,b,c)      _strnicmp((a),(b),(c))
760 #endif
761 #else
762 #undef strncasecmp
763 #endif
764
765 static void get_title_filename(const char *filename, char *title)
766 {
767         const char *ext;
768         
769         if(filename[0] == 0)
770                 return;
771         if(!kpi_wrapper){ // only midi ext
772                 get_title(filename, title); // title or get non path portion of filename        
773                 return;
774         }
775         ext = kbExtractFileExt(filename);
776 #ifdef strncasecmp
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
785 #else
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
802 #endif
803                 get_title(filename, title); // title or get non path portion of filename        
804         else
805                 get_filename(filename, title); // get non path portion of filename
806 }
807
808 void getfileinfo(const char *filename, char *title, int *length_in_ms)
809 {
810         if (!filename || !*filename)  // currently playing file
811         {
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
814
815         }
816         else // some other file
817         {
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       
820         }
821 }
822
823 void eq_set(int on, char data[10], int preamp) 
824
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. 
830 }
831
832 DWORD WINAPI DecodeThread(LPVOID b)
833 {
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;
836
837         while (!killDecodeThread) 
838         {
839                 if (seek_needed != -1) // seek is needed.
840                 {
841                         int offs;
842                         decode_pos_ms = seek_needed;
843                         seek_needed=-1;
844                         done=0;
845                         mod.outMod->Flush(decode_pos_ms); // flush output device and set // output position to the seek position                        
846                         if(g_pModule){
847                                 if(g_pModule->SetPosition){
848                                         g_pModule->SetPosition(hkmp, decode_pos_ms);
849                                 }
850                         } 
851                 }
852                 if (done) // done was set to TRUE during decoding, signaling eof
853                 {
854                         mod.outMod->CanWrite();         // some output drivers need CanWrite // to be called on a regular basis.
855                         if (!mod.outMod->IsPlaying()) 
856                         {
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
860                         }
861                         Sleep(10);              // give a little CPU time back to the system.
862                 }
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).
868                 {       
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
871                         
872                         if(!first_render_play){ // first render play()
873                                 first_render_play = 1;
874                                 l = first_render_byte;
875                         }else if(g_pModule){
876                                 if(g_pModule->Render)
877                                         l = g_pModule->Render(hkmp, (BYTE*)sample_buffer, render_byte); // retrieve samples
878                         } 
879                         if (!l)                 // no samples means we're at eof
880                         {
881                                 done=1;          
882                         }
883                         else    // we got samples!
884                         {
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);
897                         }
898                 }
899                 else Sleep(20); 
900                 // if we can't write data, wait a little bit. Otherwise, continue 
901                 // through the loop writing more data (without sleeping)
902         }
903         return 0;
904 }
905
906
907
908 // exported symbol. Returns output module.
909
910 __declspec( dllexport ) In_Module * winampGetInModule2()
911 {
912         load_wrapper_config();
913         return &mod;
914 }