Subversion Repositories Kolibri OS

Rev

Rev 1842 | Rev 3495 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. //
  2. //   This file is part of the AC97 mp3 player.
  3. //   (C) copyright Serge 2006-2007 infinity_sound@mail.ru
  4. //   (C) copyright Quantum 2007    ufmod@users.sf.net
  5. //
  6. //   This program is free software; you can redistribute it and/or modify
  7. //   it under the terms of the GNU General Public License as published by
  8. //   the Free Software Foundation; either version 2 of the License, or
  9. //   (at your option) any later version.
  10. //
  11. //   This program is distributed in the hope that it will be useful,
  12. //   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. //   GNU General Public License for more details.
  15.  
  16. #include "../kolibri.h"
  17. #include "string.h"
  18. #include "ac97wav.h"
  19. #include "../mpg/mpg123.h"
  20. #include "../sound.h"
  21. #include "../ufmod-codec.h"                   /* uFMOD integration */
  22. void exit();                                  /* uFMOD integration */
  23.  
  24. #define DOCKABLE_WINDOW
  25. #define MP3_ERROR_OUT_OF_BUFFER  5
  26. int m_last_error;
  27.  
  28. void _stdcall thread_proc(void *param);
  29. int _stdcall create_thread(void *proc, void *param, int stack_size);
  30.  
  31. #ifdef DOCKABLE_WINDOW
  32. void GetThreadInfo (char *info, int slot); //Asper+
  33. #endif
  34.  
  35. void touch(char *buf, int size);
  36. int mp3FindSync(byte* buf, int size, int* sync);
  37. int stream_read_raw(struct reader *rd,unsigned char *buf, int size);
  38.  
  39. int __cdecl _stricmp (const char * dst, const char * src);
  40. char *__cdecl strrchr (const char * string,int ch);
  41. int _strncmp(char *src, char *dst, DWORD n); //Asper+
  42. int _strncpy (char *dst, char *src, int n); //Asper+
  43. void uint2str(unsigned int value, char *string); //Asper+
  44.  
  45. struct reader rd;
  46. struct frame fr;
  47.  
  48. DWORD hDrv;
  49. DWORD hSound;
  50. SNDBUF hBuff;
  51.  
  52. CTRL_INFO info;
  53.  
  54. FILEINFO   fileinfo;
  55. const char filename[256];
  56. const char *fileext;
  57. char full_filename[4096];
  58.  
  59. int m_vol;
  60. int l_vol=-700;     //-7db
  61. int r_vol=-700;
  62. int pan =0;
  63.  
  64. DWORD status;
  65. DWORD first_sync;
  66. DWORD PLStatus=0; //Asper+
  67.  
  68. #ifdef DOCKABLE_WINDOW
  69. byte thread_info[1024]; //Asper+
  70. #endif
  71.  
  72. int tid, pl_tid;
  73. const DWORD main_wh=92, pl_ww=300, pl_wh=382; //Asper+
  74. DWORD pl_wx=100, pl_wy=101+92;  //Asper+
  75. //DWORD main_wc=0x404040, main_bc=0x808080;  //Asper+ ac97snd Classic style
  76. //DWORD main_wc=0x002040, main_bc=0x008080, main_ic=0x002040, selected_ic=0x1010F0;  //Asper+
  77. DWORD main_wc=0x101030, main_bc=0x008080, main_ic=0x000000, selected_ic=0x1010F0;  //Asper+
  78.  
  79. unsigned char *testbuff;
  80. unsigned char *outbuf;
  81. unsigned char *inpbuf;
  82. unsigned char *outPtr;
  83.  
  84. int inpsize;
  85. int outsize;
  86. int outremain;
  87. int totalout;
  88. int done;
  89.  
  90. char header[] = "AC97 MP3 player";
  91. char header_PL[] = "PLAYLIST";
  92. char buttons_xm[]  = " Play    Stop                    Vol-    Vol+"; /* uFMOD integration */
  93. char buttons_wav[] = " Play    Stop     <<      >>     Vol-    Vol+"; /* uFMOD integration */
  94. char button_PL[] = "PL"; //Asper+
  95. char *buttons_text = buttons_wav;                                     /* uFMOD integration */
  96.  
  97. void play_xm();                                                       /* uFMOD integration */
  98. void (*snd_play)();
  99.  
  100.  
  101. //Asper_____________________Play List code start_____________________________
  102. #define PLI_BUTTON_HEIGHT    13
  103. #define PL_MAX_SHOWN_ITEMS   (pl_wh-PLI_BUTTON_HEIGHT-40)/PLI_BUTTON_HEIGHT
  104. #define MAX_TEXT_WIDTH       46
  105.  
  106. int currSelected, currActive, currFirstShowed;
  107. unsigned char *pl_buff;
  108. char pl_path[4096];
  109. int pl_items_number;
  110.  
  111. int ShowPLContent(char *filebuffer);
  112. int GetFileNameFromPL(const char *fbuff, int index, char *name);
  113. void Win2Dos (char *st, int len);
  114.  
  115. void HidePLWindow()
  116. {
  117.    BeginDraw();
  118.    ResizeReplaceWindow(pl_wx,pl_wy,0,0);
  119.    EndDraw();
  120. }
  121.  
  122. void ShowPLWindow()
  123. {
  124.    unsigned int i;
  125.  
  126.    BeginDraw();
  127.    DrawWindow(pl_wx,pl_wy,pl_ww,pl_wh,main_ic,4,0,0,0);
  128.  
  129.    for (i=0; i<PL_MAX_SHOWN_ITEMS; i++)
  130.            make_button(7,24+i*(PLI_BUTTON_HEIGHT+1),285,PLI_BUTTON_HEIGHT, (0x10+i)|BT_NORMAL|BT_NOFRAME, main_ic);
  131.  
  132.    write_text(8,8,FONT0, header_PL, sizeof(header_PL)-1);
  133.    ShowPLContent(pl_buff);
  134.    EndDraw();
  135. }
  136.  
  137. int LoadTrack(int i)
  138. {
  139.         if (GetFileNameFromPL(pl_buff, i, filename))
  140.         {
  141.                 strcpy (full_filename, pl_path);
  142.                 strcat (full_filename, filename);
  143.                 return 1;
  144.         }
  145.         return 0;
  146. }
  147.  
  148. void _stdcall pl_thread_proc(void *param)
  149. {  int evnt;
  150.    int key, button;
  151.    DWORD tmp_x, tmp_y, i; //Asper+
  152.    char ipc_buff[16]="";
  153.  
  154.    set_event_mask(0x47); //Asper + IPC event
  155.    ipc_init(ipc_buff, 16);
  156.    
  157.   _asm
  158.   {
  159.     mov eax, 66
  160.     mov ebx, 1
  161.     mov ecx, 1
  162.     int 0x40
  163.   };
  164.    
  165.   ShowPLWindow();
  166.  
  167.   while(1)
  168.   {
  169.         if (PLStatus&0xF0)
  170.     {
  171.                 switch(PLStatus)
  172.                 {
  173.                         case 0x11:
  174.                                 HidePLWindow();
  175.                         break;
  176.                         case 0x12:
  177.                                 ResizeReplaceWindow(pl_wx,pl_wy,pl_ww,pl_wh);                  
  178.                         break;
  179.                 }
  180.                 PLStatus&=0x0F;
  181.         }
  182.         switch (status)
  183.         {
  184.                 case ST_TRACK:
  185.                         break;
  186.                 case ST_EXIT:
  187.                         PLStatus=0x00;
  188.                         exit();
  189.         }
  190.  
  191. #ifdef DOCKABLE_WINDOW
  192.         tmp_x = (DWORD)thread_info[35]*0x100+(DWORD)thread_info[34];
  193.         tmp_y = (DWORD)thread_info[38]+main_wh+1;
  194.         if (pl_wx!= tmp_x || pl_wy!=tmp_y)
  195.         {
  196.                 pl_wx=tmp_x;
  197.                 pl_wy=tmp_y;
  198.                 ResizeReplaceWindow(pl_wx,pl_wy,-1,-1);
  199.         }
  200. #endif
  201.  
  202.     evnt = wait_for_event(20);
  203.  
  204.     switch(evnt)
  205.     {
  206.       case EV_REDRAW:
  207.                           ShowPLWindow();
  208.         break;
  209.  
  210.       case EV_KEY:
  211.         if(!get_key(&key))
  212.         {
  213.        
  214.           switch(key)
  215.           {  case 0xE0:
  216.              case 0xE1:
  217.                break;
  218.              default:
  219.                switch (key)
  220.                {
  221.                  case 0x01:  //Esc
  222.                                          PLStatus=0x00;
  223.                                          exit();
  224.                                          break;
  225.  
  226.                                  case 0x1C:  //Enter                  
  227.                                          currActive=currFirstShowed+currSelected-1;
  228.                                          status = ST_TRACK;
  229.                                          break;
  230.                  case 0x47:  //Home
  231.                                          if(l_vol < 0)
  232.                                          { l_vol+=100;
  233.                                            r_vol+=100;  
  234.                                            SetVolume(hBuff,l_vol,r_vol);
  235.                                          };
  236.                                    break;
  237.                  case 0x48:  //Up
  238.                                          if (currSelected==0)
  239.                                          {
  240.                                                  if (currFirstShowed>0)
  241.                                                          currFirstShowed--;
  242.                                                  ShowPLContent(pl_buff);
  243.                                                  break;
  244.                                          }
  245.                                          currSelected--;
  246.                                          ShowPLContent(pl_buff);
  247.                                          break;
  248.                  case 0x50:  //Down
  249.                                          if (currSelected+currFirstShowed > pl_items_number-2) break;
  250.                                          if (currSelected==PL_MAX_SHOWN_ITEMS-1)
  251.                                          {
  252.                                                  //if (currFirstShowed<pl_items_number)
  253.                                                          currFirstShowed++;
  254.                                                  ShowPLContent(pl_buff);
  255.                                                  break;
  256.                                          }
  257.                                          //if (currSelected<PL_MAX_SHOWN_ITEMS)
  258.                                          currSelected++;
  259.                                          ShowPLContent(pl_buff);
  260.                                          break;
  261.                  case 0x4F:  //End                
  262.                                          if(l_vol > -10000)
  263.                                          { l_vol-=100;
  264.                                            r_vol-=100;  
  265.                                            SetVolume(hBuff,l_vol,r_vol);
  266.                                          };
  267.                                          break;
  268.                  case 0x53:
  269.                                          if(pan > -10000)
  270.                                          { pan -=100;
  271.                                            SetPan(hBuff,pan);
  272.                                          };
  273.                                          break;  
  274.                  case 0x51:
  275.                                          if(pan < 10000)
  276.                                          { pan +=100;
  277.                                            SetPan(hBuff,pan);
  278.                                          };
  279.                                          break;  
  280.                            }
  281.                   };    
  282.                 };  
  283.                 break;
  284.  
  285.       case EV_BUTTON:
  286.                   button=get_button_id();
  287.                   if (button==1)
  288.                   {
  289.                           PLStatus=0x00;
  290.                           exit();
  291.                   }
  292.                   for (i=0;i<PL_MAX_SHOWN_ITEMS;i++)
  293.                   {
  294.                           if (button==0x10+i)
  295.                           {
  296.                                   currActive=currFirstShowed+i-1;
  297.                                   status = ST_TRACK;
  298.                                   break;
  299.                           }
  300.                   }
  301.                   break;
  302.           case EV_IPC:
  303.                   *ipc_buff='\0';
  304.                   ShowPLContent(pl_buff);
  305.                   break;
  306.  
  307.         }
  308.   }
  309. }
  310.  
  311. void Win2Dos (char *st, int len)
  312. {
  313.         int i;
  314.         unsigned char ch;
  315.  
  316.         for (i=0; i<len; i++)
  317.         {
  318.                 ch = st[i];
  319.                 if (ch>=192)
  320.                 {
  321.                         if (ch>=240) ch-=16;
  322.                         else ch-=64;
  323.                 }
  324.                 else
  325.                 {
  326.                         if (ch==168) ch = 240;
  327.                         if (ch==184) ch = 241;
  328.                         if (ch==185) ch = 252;
  329.                         if ((ch==147) || (ch==148) || (ch==171) || (ch==187)) ch = 34;
  330.                         if ((ch==150) || (ch==151)) ch = 45;
  331.                 }
  332.                 st[i]=ch;
  333.         }
  334. }
  335.  
  336. int GetFileNameFromPL(const char *plbuff, int index, char *name)
  337. {
  338.         int count=0,i=0,j=0;
  339.         char ch;
  340.  
  341.         do{            
  342.                 ch=plbuff[i];
  343.                 if (ch!='#' && i && plbuff[i-1]=='\n')
  344.                         count++;
  345.                 if (count-1==index)
  346.                 {
  347.                         if (j>MAX_TEXT_WIDTH || ch=='\n')
  348.                         {
  349.                                 name[j-1]='\0';
  350.                                 break;
  351.                         }
  352.                         if (ch=='\\') ch='/';
  353.                         name[j++]=ch;
  354.                 }
  355.                 else if (count-1>index) break;
  356.                 i++;
  357.         }while (ch);
  358.         if (!ch) return 0;
  359.         return j;
  360. }
  361.  
  362. int CountFileNamesInPL(const char *plbuff)
  363. {
  364.         int count=0,i=0;
  365.         char ch;
  366.  
  367.         do{            
  368.                 ch=plbuff[i];
  369.                 if (ch!='#' && i && plbuff[i-1]=='\n')
  370.                         count++;
  371.                 i++;
  372.         }while (ch);
  373.         if (count) count--;
  374.         return count;
  375. }
  376.  
  377. int ShowPLContent(char *filebuffer)
  378. {
  379.         char st[MAX_TEXT_WIDTH+10]="", tmp[MAX_TEXT_WIDTH+1]="";
  380.         unsigned int len=8,i;
  381.         DWORD text_color;
  382.  
  383.         draw_bar(7,24,285,PLI_BUTTON_HEIGHT*(PL_MAX_SHOWN_ITEMS+2), main_ic);
  384.         draw_bar(7,24+currSelected*(PLI_BUTTON_HEIGHT+1),285,PLI_BUTTON_HEIGHT, selected_ic);
  385.         for (i=0; i<PL_MAX_SHOWN_ITEMS; i++)
  386.         {
  387.                 text_color = (currFirstShowed+i==currActive?0xFFFFFF|FONT0:0x00FF20|FONT0);
  388.                 if (!GetFileNameFromPL(filebuffer, i+currFirstShowed, tmp)) break;
  389.                 uint2str(currFirstShowed+i+1, st);
  390.                 strcat(st, ". ");
  391.                 strcat(st, tmp);
  392.                 len = strlen(st);
  393.                 if (len > MAX_TEXT_WIDTH)
  394.                         len = MAX_TEXT_WIDTH;
  395.                 write_text(11,i*(PLI_BUTTON_HEIGHT+1)+27,text_color, st, len);
  396.         }
  397.         return 1;
  398. }
  399. //Asper_____________________Play List code end_____________________________
  400.  
  401. void update_dinamic_content() //Asper +
  402. {
  403.         int len;                                                          /* uFMOD integration */
  404.         draw_bar(7,41,286,11,main_wc);
  405.        
  406.         draw_bar(7,55,286,11,main_wc);
  407.         len = strlen(filename);                                                /* uFMOD integration */
  408.         if(len > 47) len = 47;                                              /* uFMOD integration */
  409.         write_text(11,57,0x00FF20|FONT0, filename, len);                        /* uFMOD integration */
  410. }
  411.  
  412. void draw_window()
  413. {
  414.    BeginDraw();
  415.  
  416.    DrawWindow(100,100,299,main_wh,main_wc,4,0,0,0); //Asper+  
  417.  
  418.    make_button(7,24,45,13, 0x10|BT_NORMAL,main_bc);
  419.    make_button(56,24,45,13, 0x11|BT_NORMAL,main_bc);
  420.    make_button(104,24,45,13, 0x12|BT_NORMAL,main_bc);
  421.    make_button(152,24,45,13, 0x13|BT_NORMAL,main_bc);
  422.    make_button(200,24,45,13, 0x14|BT_NORMAL,main_bc);
  423.    make_button(248,24,45,13, 0x15|BT_NORMAL,main_bc);
  424.  
  425.    make_button(268,70,25,13, 0x16|BT_NORMAL,main_bc); //Asper+ PL button
  426.  
  427.    make_button(7,41,286,11, 0x30|BT_HIDE|BT_NOFRAME,main_wc);
  428.  
  429.    update_dinamic_content();
  430.    write_text(8,8,FONT0, header, sizeof(header)-1);                     /* uFMOD integration */
  431.    write_text(12,28,main_wc|FONT0,buttons_text,sizeof(buttons_wav)-1); /* uFMOD integration */
  432.    write_text(11,27,0xA0FFA0|FONT0,buttons_text,sizeof(buttons_wav)-1); /* uFMOD integration */
  433.  
  434.    write_text(276,74,main_wc|FONT0,button_PL,sizeof(button_PL)-1); //Asper+ PL button text
  435.    write_text(275,73,0xA0FFA0|FONT0,button_PL,sizeof(button_PL)-1); //Asper+
  436.    EndDraw();
  437. };
  438.  
  439. void draw_progress_bar()
  440. {  DWORD x;
  441.    x = (DWORD)(287.0f * (float)(rd.filepos-rd.strremain)/(float)fileinfo.size); /* uFMOD integration */
  442.    if(x==0) return;
  443.    draw_bar(7,41,x,11,0xA0A0A0);
  444.    draw_bar(x+7,41,287-x,11,main_wc);
  445. };
  446.  
  447. void debug_out_str(const char* str)
  448. {
  449.   while (*str != 0)
  450.   {
  451.     debug_out(*str);
  452.     str++;
  453.   }
  454. }
  455.  
  456. int LoadPL(char *fname)
  457. {
  458.         DWORD fmt;
  459.         DWORD r_bytes;
  460.         int retval;
  461.         int i;
  462. //              char st[100]="";
  463.  
  464.         char *pch;
  465.  
  466.         r_bytes=0;
  467.         pch=strrchr(fname, '/');
  468.         if (pch)
  469.                 i=pch-fname+1;
  470.         else
  471.                 i=strlen(fname);
  472.  
  473.         _strncpy (pl_path, fname, i);
  474.         pl_path[i]='\0';
  475.  
  476.         if (!pl_buff)
  477.                 pl_buff = UserAlloc(0x40000);
  478.         retval=read_file (fname,pl_buff,0,0x40000,&r_bytes);
  479.  
  480.         if ( retval && (r_bytes==0))
  481.                 return 0;
  482.  
  483.         Win2Dos(pl_buff, r_bytes);
  484.         pl_items_number=CountFileNamesInPL(pl_buff);
  485. /*
  486.         debug_out_str("\n\rPlay List files number = ");
  487.         itoa(pl_items_number, st, 10);
  488.         debug_out_str(st);
  489. */
  490.         fmt = test_m3u(pl_buff);
  491.  
  492.         if(!fmt)
  493.         {
  494.                 debug_out_str("\n\rInvalid M3U file");
  495.                 return 0;
  496.         }
  497.         debug_out_str("\n\rValid M3U file");
  498.         currSelected=currFirstShowed=0;
  499.         currActive=-1;
  500.         return 1;
  501. }
  502.  
  503. int LoadFile(char *fname)
  504. {
  505.    DWORD fmt;
  506.    DWORD r_bytes;
  507.    int retval;
  508.    int err;
  509.    unsigned char *ttl, *cur;               /* uFMOD integration */
  510.  
  511.    debug_out_str("\n\rPlay file ");
  512.    debug_out_str(fname);
  513.    debug_out_str("\n\r");
  514.  
  515.    if(get_fileinfo(fname, &fileinfo)==FILE_NOT_FOUND)
  516.    {  debug_out_str("\n\rfile not found\n\r");
  517.       return 0;
  518.    }
  519.  
  520.    r_bytes=0;
  521.    strcpy(filename, strrchr(fname,'/')+1);
  522.    if( !(fileext = strrchr(filename,'.')))
  523.            return 0;
  524.  
  525.    if(!_stricmp(fileext,".m3u"))
  526.    {
  527.            LoadPL(fname);
  528.            status=ST_TRACK;
  529.            return 1;
  530.    }
  531.  
  532.    if (!testbuff)
  533.            testbuff = UserAlloc(4096);
  534.  
  535.    retval=read_file (fname,testbuff,0,2048,&r_bytes);
  536.    if ( retval && (r_bytes==0))
  537.            return 0;
  538.  
  539.    if (!inpbuf)
  540.    {
  541.            inpbuf = UserAlloc(0x10000);
  542.            touch(inpbuf, 0x10000);
  543.    }
  544.    create_reader(&rd, inpbuf, 0x10000);
  545.    init_reader(&rd,fname);
  546.  
  547.    if(!_stricmp(fileext,".mp3"))
  548.    {   
  549.                         fmt = test_mp3(testbuff);              
  550.                         if(!fmt)
  551.                         {
  552.                           debug_out_str("\n\rInvalid MP3 file");
  553.                           return 0;                    
  554.                         };
  555.                         snd_play = &play_mp3;
  556.                         outremain = 0x40000;
  557.                         if (!outbuf)
  558.                         {
  559.                                 outbuf = UserAlloc(outremain);
  560.                                 touch(outbuf, outremain);
  561.                         }
  562.                         make_decode_tables(32767);
  563.                         init_layer2();
  564.                         init_layer3(32);
  565.                         fr.single = -1;
  566.                         goto play;
  567.    };
  568.      
  569.    if(!_stricmp(fileext,".xm"))
  570.    {
  571.            if(uFMOD_LoadSong(fname))
  572.            {      
  573.               buttons_text = buttons_xm;               /* uFMOD integration */
  574.               fmt = PCM_2_16_48;                       /* uFMOD integration */
  575.               snd_play = &play_xm;                     /* uFMOD integration */
  576.               ttl = uFMOD_GetTitle();                  /* uFMOD integration */
  577.               cur = ttl;                               /* uFMOD integration */
  578.               err = 0;                                 /* uFMOD integration */
  579.               while(*cur && *cur++ != ' ') err++;      /* uFMOD integration */
  580.               if(err){                                 /* uFMOD integration */
  581.                       cur = fname;                             /* uFMOD integration */
  582.                              while(*cur) cur++;                       /* uFMOD integration */
  583.                              *cur++ = ' ';                            /* uFMOD integration */
  584.                              *cur++ = '|';                            /* uFMOD integration */
  585.                              *cur++ = ' ';                            /* uFMOD integration */
  586.                              while(*ttl) *cur++ = *ttl++;             /* uFMOD integration */
  587.                     }
  588.                     goto play;
  589.                  }  
  590.                  debug_out_str("\n\rInvalid XM file");
  591.      return 0;
  592.          };
  593.          
  594.          if(!_stricmp(fileext, ".wav"))
  595.          {
  596.        fmt = test_wav((WAVEHEADER*)testbuff);
  597.            if(fmt)
  598.                  {                                  
  599.                    snd_play = &play_wave;            
  600.                    set_reader(&rd, 44);              
  601.                    outbuf = UserAlloc(32*1024);      
  602.                    touch(outbuf, 32768);
  603.                    goto play;
  604.                  }
  605.      debug_out_str("\n\rInvalid WAV file");
  606.      return 0;
  607.          };    
  608.  
  609.    debug_out_str("\n\rUnsupported file");
  610.    return 0;
  611.  
  612. play:
  613.  
  614.    status = ST_PLAY;
  615.    SetFormat(hBuff, fmt);
  616.    SetVolume(hBuff,l_vol,r_vol);
  617.    GetVolume(hBuff,&l_vol,&r_vol);
  618.  
  619.    return 1;
  620. }
  621.  
  622. int main(int argc, char *argv[])
  623. {
  624.    int err, ver;
  625.    int i;
  626.    char ipc_msg[2]="\0\0";
  627.    
  628.    strcpy (full_filename, argv[1]);
  629.    pl_items_number=0;
  630.    
  631.    InitHeap(1024*1024);
  632.    
  633.    if(err = InitSound(&ver))
  634.    {  
  635.      debug_out_str("Sound service not installed\n\r");
  636.      return 0;
  637.    }
  638.    
  639.    if( (SOUND_VERSION>(ver&0xFFFF)) ||
  640.        (SOUND_VERSION<(ver >> 16)))
  641.    {  
  642.      debug_out_str("Sound service version mismatch\n\r");
  643.      return 0;
  644.    }
  645.  
  646.    if (err = CreateBuffer(PCM_2_16_48, 0, &hBuff))
  647.    {
  648.      debug_out_str("create buffer return error\n\r");
  649.      return 0;
  650.    }
  651.  
  652.    if (!LoadFile(full_filename))
  653.            return 0;
  654.    tid=create_thread(thread_proc, 0, 4096);
  655.    
  656.    while(1)
  657.    {  delay(10);
  658.       switch(status)
  659.       {  case ST_TRACK:
  660.                         StopBuffer(hBuff);
  661.                         if (LoadTrack(++currActive))
  662.                         {
  663.                                 if (LoadFile(full_filename))
  664.                                         status = ST_PLAY;
  665.                         }
  666.                         else status = ST_STOP;
  667.  
  668.                         //Update ac97snd and PL windows
  669.                         i=currActive-currFirstShowed;
  670.                         if (i>PL_MAX_SHOWN_ITEMS-1)
  671.                                 currFirstShowed = currActive - PL_MAX_SHOWN_ITEMS/2;
  672.                         ipc_send_msg(tid, ipc_msg);
  673.                         ipc_send_msg(pl_tid, ipc_msg);
  674.                         continue;
  675.          
  676.           case ST_PLAY:
  677.                   snd_play();
  678.                   continue;
  679.  
  680.           case ST_STOP:
  681.                   StopBuffer(hBuff);
  682.                   status = ST_DONE;
  683.                   continue;
  684.  
  685.           case ST_EXIT:
  686.                   uFMOD_StopSong();          /* uFMOD integration */
  687.                   StopBuffer(hBuff);
  688.                   DestroyBuffer(hBuff);
  689.                   return 0;
  690.           };
  691.    };
  692.    return 0;
  693. };
  694.  
  695. void touch(char *buf, int size)
  696. { int i;
  697.    char a;
  698.     for ( i = 0;i < size; i+=4096)     //alloc all pages
  699.       a = buf[i];
  700. };
  701.  
  702. DWORD test_m3u(char *buf) //Asper+
  703. {
  704.         char  *sign="#EXTM3U";
  705.         return _strncmp(buf, sign, 7);
  706. }
  707.  
  708. DWORD test_mp3(char *buf)
  709. {  unsigned long hdr;
  710.     WAVEHEADER whdr;
  711.      
  712.     while (1)
  713.     {  if(rd.filepos > 102400)
  714.           return 0;
  715.         if(!rd.head_read(&rd,&hdr))
  716.                         return 0;
  717.         if(!decode_header(&fr,hdr))
  718.         {
  719.          if((hdr & 0xffffff00) == 0x49443300)
  720.               {
  721.                     int id3length = 0;
  722.                     id3length = parse_new_id3(&rd, hdr);
  723.                     continue;
  724.               };
  725.           rd.strpos-=3;
  726.           rd.stream-=3;
  727.           rd.strremain+=3;
  728.           continue;
  729.         };
  730.         break;
  731.     };
  732.          
  733.     first_sync = rd.filepos-rd.strremain-4;
  734.          
  735.     whdr.riff_id = 0x46464952;
  736.     whdr.riff_format = 0x45564157;
  737.     whdr.wFormatTag = 0x01;
  738.     whdr.nSamplesPerSec = freqs[fr.sampling_frequency];
  739.     whdr.nChannels = 2;
  740.     whdr.wBitsPerSample = 16;
  741.    
  742.     return test_wav(&whdr);
  743. };
  744.  
  745.  
  746. void play_mp3()
  747. {  char *outPtr;
  748.     int totalout;
  749.     int outcount;
  750.  
  751.  //   memset(&fr,0,sizeof(fr));
  752.     fr.down_sample_sblimit = 32;
  753.     fr.single = -1;
  754.     reset_mpg();
  755.  
  756.     outPtr = outbuf;
  757.     totalout=0;
  758.     done = 0;
  759.     outremain=0x40000;
  760.  
  761.     memset(outbuf,0,0x40000);
  762.     set_reader(&rd, 0);    //;first_sync);
  763.  
  764.     while(1)
  765.     { if(status!=ST_PLAY)
  766.              break;
  767.  
  768.      for(;;)
  769.      {   outcount = 0;                          
  770.           if( !read_frame(&rd, &fr))
  771.           {  done = 1;
  772.               break;
  773.           };
  774.           fr.do_layer(&fr, outPtr,&outcount);
  775.           outPtr+= outcount;
  776.           totalout+=outcount;
  777.           outremain-=outcount;
  778.           if(outremain < outcount*2)
  779.             break;  
  780.     };
  781.  
  782.     if(done)
  783.     { if(totalout < 4096)
  784.       {  memset(outPtr,0,4096-totalout);
  785.                 totalout = 4096;
  786.       };
  787.     }
  788.     else
  789.       if(totalout < 8192)
  790.         continue;
  791.  
  792.     outPtr = outbuf;      
  793.     while (totalout >= 4096)
  794.     {
  795.    
  796.       WaveOut(hBuff,outPtr,4096);
  797.       if(status!=ST_PLAY)
  798.       { if ((status != ST_EXIT) && (status != ST_STOP))
  799.          status = ST_TRACK;
  800.         return;
  801.       };
  802.       totalout-=4096;
  803.       outPtr+=4096;
  804.       outremain+=4096;
  805.     };
  806.     if(done)
  807.       break;
  808.      
  809.     memmove(outbuf,outPtr, totalout);
  810.     outPtr = outbuf+totalout;
  811.    }
  812.  
  813.     if ((status != ST_EXIT) && (status != ST_STOP))
  814.       status =  ST_TRACK;
  815. };
  816.  
  817. void play_wave()
  818. {  int count;
  819.  
  820.    set_reader(&rd,44);
  821.    while(1)
  822.    {
  823.       if(status!=ST_PLAY)
  824.         break;
  825.  
  826.       if( count=stream_read_raw(&rd,outbuf,32768))
  827.       {
  828.         WaveOut(hBuff,outbuf,count);
  829.         continue;
  830.       }
  831.       done = 1;
  832.       break;
  833.    };
  834.  
  835.    if ((status != ST_EXIT) && (status != ST_STOP))
  836.      status =  ST_TRACK;
  837. };
  838.  
  839. void play_xm(){                             /* uFMOD integration */
  840.         while(status == ST_PLAY){                 /* uFMOD integration */
  841.                 uFMOD_WaveOut(hBuff);                   /* uFMOD integration */
  842.                 delay(8);                               /* uFMOD integration */
  843.         }                                         /* uFMOD integration */
  844.         if ((status != ST_EXIT) && (status != ST_STOP)) status = ST_TRACK;   /* uFMOD integration */
  845. }                                           /* uFMOD integration */
  846.  
  847. void snd_stop()
  848. {
  849.   StopBuffer(hBuff);
  850. };
  851.  
  852. void _stdcall thread_proc(void *param)
  853. {  int evnt;
  854.    int pos;
  855.    int key;
  856.    DWORD offset;
  857.    char ipc_buff[16];
  858.  
  859.    set_event_mask(0x47); //Asper + IPC event
  860.    ipc_init(ipc_buff, 16);
  861.  
  862.   _asm
  863.   {
  864.     mov eax, 66
  865.     mov ebx, 1
  866.     mov ecx, 1
  867.     int 0x40
  868.   };
  869.    
  870.   draw_window();
  871.  
  872.   while(1)
  873.   {
  874.          if(status==ST_PLAY)
  875.      {  draw_progress_bar();
  876.         evnt = wait_for_event(80);             
  877.      }
  878.      else
  879.                  evnt = wait_for_event_infinite();
  880.  
  881. #ifdef DOCKABLE_WINDOW
  882.      GetThreadInfo(thread_info, -1);
  883. #endif
  884.  
  885.     switch(evnt)
  886.     {
  887.       case EV_REDRAW:
  888.                   draw_window();
  889.                   break;
  890.  
  891.       case EV_KEY:
  892.         if(!get_key(&key))
  893.         {
  894.        
  895.           switch(key)
  896.           {  case 0xE0:
  897.              case 0xE1:
  898.                break;
  899.              default:
  900.                switch (key)
  901.                {
  902.                  case 0x01:  //Esc
  903.                    status = ST_EXIT;
  904.                    exit();
  905.                    break;
  906.                
  907.                  case 0x47:  //Home
  908.                    if(l_vol < 0)
  909.                    { l_vol+=100;
  910.                      r_vol+=100;  
  911.                      SetVolume(hBuff,l_vol,r_vol);
  912.                    };
  913.                    break;
  914.                  case 0x4F:  //End                
  915.                    if(l_vol > -10000)
  916.                    { l_vol-=100;
  917.                      r_vol-=100;  
  918.                      SetVolume(hBuff,l_vol,r_vol);
  919.                    };
  920.                    break;
  921.                  case 0x53:
  922.                    if(pan > -10000)
  923.                    { pan -=100;
  924.                      SetPan(hBuff,pan);
  925.                    };
  926.                    break;  
  927.                  case 0x51:
  928.                    if(pan < 10000)
  929.                    { pan +=100;
  930.                      SetPan(hBuff,pan);
  931.                    };
  932.                    break;  
  933.                }
  934.           };    
  935.         };  
  936.         break;
  937.  
  938.       case EV_BUTTON:
  939.         switch(get_button_id())
  940.         {  case 1:
  941.              status = ST_EXIT;
  942.              exit();
  943.              break;
  944.              
  945.            case 0x10:
  946.              status = ST_PLAY;
  947.              continue;
  948.  
  949.            case 0x11:
  950.              status = ST_STOP;
  951.              break;
  952.            case 0x12:
  953.                            currActive-=2;
  954.                            status = ST_TRACK;
  955.                            break;
  956.            case 0x13:
  957.                            status = ST_TRACK;
  958.                            break;
  959.            case 0x14:
  960.             if(l_vol > -10000)
  961.             {
  962.               l_vol-=100;
  963.               r_vol-=100;  
  964.               SetVolume(hBuff,l_vol,r_vol);
  965.             };
  966.             break;
  967.  
  968.            case 0x15:
  969.             if(l_vol < 0)
  970.             { l_vol+=100;
  971.               r_vol+=100;  
  972.               SetVolume(hBuff,l_vol,r_vol);
  973.             };
  974.             break;
  975.  
  976.            case 0x16: //Asper+ PL button action
  977.                            switch (PLStatus)
  978.                            {    case 0x00: //PL not started.
  979.                                                 pl_tid=create_thread(pl_thread_proc, 0, 4096);              
  980.                                                 PLStatus=0x12;
  981.                                     break;
  982.                                         case 0x01: //PL started, but hidden.
  983.                                                 PLStatus=0x12;
  984.                                     break;
  985.                                         case 0x02: //PL started and showed.
  986.                                                 PLStatus=0x11;
  987.                                         break;
  988.                            }
  989.             break;
  990.  
  991.            case 0x30:
  992.             if(status==ST_DONE)
  993.               break;
  994.             pos = (GetMousePos(REL_WINDOW)>>16)-7;
  995.             offset = ((fileinfo.size-44)/286*pos+44)&0xFFFFFFFC;
  996.             set_reader(&rd, offset);
  997.             draw_progress_bar();
  998.             break;
  999.         };
  1000.                 break;
  1001.  
  1002.           case EV_IPC:
  1003.                   *ipc_buff='\0';
  1004.                   update_dinamic_content();
  1005.                   break;
  1006.  
  1007.     };
  1008.   };
  1009. };
  1010.  
  1011. void delay (int val)
  1012. {
  1013.   _asm
  1014.  {    
  1015.       mov   eax,5
  1016.       mov   ebx, [val]
  1017.       int   0x40
  1018.   };  
  1019. }
  1020.  
  1021. int wait_for_event(int time)
  1022. { int retval;
  1023.   _asm
  1024.  {  
  1025.      mov  eax,23
  1026.      mov  ebx,[time]
  1027.      int  0x40
  1028.      mov [retval], eax
  1029.  };
  1030.  return retval;
  1031. };
  1032.  
  1033. int wait_for_event_infinite()
  1034. { int retval;
  1035.   _asm
  1036.   {  
  1037.       mov  eax,10
  1038.       int  0x40
  1039.       mov [retval], eax
  1040.   };
  1041.   return retval;
  1042. };
  1043.  
  1044. void BeginDraw()
  1045. {_asm
  1046.  {  
  1047.     mov   eax,12
  1048.     mov   ebx, 1
  1049.     int   0x40
  1050.   };  
  1051. };
  1052.  
  1053. void EndDraw()
  1054. { _asm
  1055.  {  
  1056.     mov   eax,12
  1057.     mov   ebx, 2
  1058.     int   0x40
  1059.   };  
  1060. };
  1061.  
  1062. //Asper+_______start KolibriOS sys functions___________________
  1063. void ResizeReplaceWindow (DWORD x, DWORD y, DWORD w, DWORD h) //Asper+
  1064. {
  1065.   _asm
  1066.  {    
  1067.       mov   eax, 67
  1068.       mov   ebx, [x]
  1069.       mov   ecx, [y]
  1070.       mov   edx, [w]
  1071.       mov   esi, [h]
  1072.       int   0x40
  1073.   };  
  1074. }
  1075.  
  1076. #ifdef DOCKABLE_WINDOW
  1077. void GetThreadInfo (char *info, int slot) //Asper+
  1078. {
  1079.         _asm
  1080.         {    
  1081.                 mov   eax, 9
  1082.                 mov   ebx, [info]
  1083.                 mov   ecx, [slot]
  1084.                 int   0x40
  1085.         }  
  1086. }
  1087. #endif
  1088.  
  1089. void set_event_mask(int mask)
  1090. {
  1091.         _asm
  1092.         {  
  1093.                 mov  eax, 40
  1094.                 mov  ebx, [mask]
  1095.                 int  0x40    
  1096.         }
  1097. }
  1098.  
  1099. void ipc_init(char *buf, int bufsize)
  1100. {
  1101.         _asm
  1102.         {  
  1103.                 mov  eax, 60
  1104.                 mov  ebx, 1
  1105.                 mov  ecx, [buf]
  1106.                 mov  edx, [bufsize]
  1107.                 int  0x40    
  1108.         }
  1109. }
  1110.  
  1111. int ipc_send_msg(int PID, char *msg)
  1112. {
  1113.         int len = strlen(msg);
  1114.         int retval;
  1115.         _asm
  1116.         {  
  1117.                 mov  eax, 60
  1118.                 mov  ebx, 2
  1119.                 mov  ecx, [PID]
  1120.                 mov  edx, [msg]
  1121.                 mov  esi, [len]
  1122.                 int  0x40    
  1123.                 mov [retval], eax
  1124.         }
  1125. }
  1126. //Asper+_______end KolibriOS sys functions___________________
  1127.  
  1128. //Asper+_______start strings routines___________________
  1129. int _strncmp(char *src, char *dst, DWORD n)
  1130. {
  1131.         _asm{
  1132.                 mov             esi, src
  1133.                 mov             edi, dst
  1134.                 mov             ecx, n
  1135.         }
  1136.  l1:
  1137.         _asm{
  1138.                 cmpsb
  1139.                 jne     err
  1140.                 loop    l1     
  1141.         }
  1142.         return 1;
  1143.  err:
  1144.         return 0;
  1145. }
  1146.  
  1147. int _strncpy (char *dst, char *src, int n)
  1148. {
  1149.         int  i;
  1150.         for (i=0; i<n; i++)
  1151.         {
  1152.                 dst[i]=src[i];
  1153.                 if (src[i]=='\0') break;
  1154.         }
  1155.         return 0;
  1156. }
  1157.  
  1158. void uint2str(unsigned int value, char *string)
  1159. {
  1160.   char tmp[33];
  1161.   int i, j;
  1162.   unsigned v;
  1163.  
  1164.   v = (unsigned)value;
  1165.   j = 0;
  1166.   do{
  1167.     i = v % 10;
  1168.     v = v / 10;
  1169.     if (i < 10)
  1170.       tmp[j] = i+'0';
  1171.     else
  1172.       tmp[j] = i + 'a' - 10;
  1173.         j++;
  1174.   }while (v);
  1175.  
  1176.   for (i=0; i<j; i++)
  1177.     string[i] = tmp[j-i-1];
  1178.   string[i] = '\0';
  1179. }
  1180.  
  1181. //Asper+_______end strings routines___________________
  1182.  
  1183.  
  1184. ///*********
  1185. void *__cdecl memmove ( void * dst, const void * src, unsigned int count)  /* uFMOD integration */
  1186. { void *ret;
  1187.   ret = dst;
  1188.  
  1189.   if (dst <= src || (char *)dst >= ((char *)src + count))
  1190.   {
  1191.       while (count--)
  1192.       { *(char *)dst = *(char *)src;
  1193.           dst = (char *)dst + 1;
  1194.           src = (char *)src + 1;
  1195.       }
  1196.    }
  1197.    else
  1198.     {
  1199.         dst = (char *)dst + count - 1;
  1200.         src = (char *)src + count - 1;
  1201.          while (count--)
  1202.           {  *(char *)dst = *(char *)src;
  1203.               dst = (char *)dst - 1;
  1204.               src = (char *)src - 1;
  1205.           }
  1206.     }
  1207.     return ret;
  1208. };
  1209. //**********/
  1210.  
  1211. void * __cdecl mem_cpy(void * dst,const void * src,size_t count)
  1212. {    void * ret = dst;
  1213.       while (count--)
  1214.       {  *(char *)dst = *(char *)src;
  1215.           dst = (char *)dst + 1;
  1216.           src = (char *)src + 1;
  1217.       };
  1218.       return(ret);
  1219. }
  1220.  
  1221. char * __cdecl strrchr (const char * string,int ch)
  1222. {
  1223.         char *start = (char *)string;
  1224.  
  1225.         while (*string++)                       /* find end of string */
  1226.                 ;
  1227.                                                 /* search towards front */
  1228.         while (--string != start && *string != (char)ch)
  1229.                 ;
  1230.  
  1231.         if (*string == (char)ch)                /* char found ? */
  1232.                 return( (char *)string );
  1233.  
  1234.         return(NULL);
  1235. }
  1236.  
  1237. int __cdecl _stricmp (const char * dst, const char * src)
  1238. {
  1239.     int f, l;
  1240.  
  1241.     do
  1242.     {
  1243.         if ( ((f = (unsigned char)(*(dst++))) >= 'A') && (f <= 'Z') )
  1244.             f -= 'A' - 'a';
  1245.         if ( ((l = (unsigned char)(*(src++))) >= 'A') && (l <= 'Z') )
  1246.             l -= 'A' - 'a';
  1247.     }
  1248.     while ( f && (f == l) );
  1249.  
  1250.     return(f - l);
  1251. }
  1252.  
  1253.  
  1254.