Subversion Repositories Kolibri OS

Rev

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