Subversion Repositories Kolibri OS

Rev

Rev 577 | 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
  4. //   email: infinity_sound@mail.ru
  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.  
  22. typedef struct
  23. {
  24.   int sender;
  25.   int size;
  26.   int code;
  27.   char data[1];
  28. } IPC;
  29.  
  30. int ipc_client = 0;
  31.  
  32. #define MP3_ERROR_OUT_OF_BUFFER  5
  33. int m_last_error;
  34.  
  35. void _stdcall thread_proc(void *param);
  36. void _stdcall create_thread(void *proc, void *param, int stack_size);
  37. void _stdcall init_ipc(void);
  38. void _stdcall send_ipc(int dst, DWORD code);
  39. IPC * _stdcall recieve_ipc(void);
  40.  
  41. void touch(char *buf, int size);
  42. int mp3FindSync(byte* buf, int size, int* sync);
  43. int stream_read_raw(struct reader *rd,unsigned char *buf, int size);
  44.  
  45. char *fname;
  46.  
  47. struct reader rd;
  48. struct frame fr;
  49.  
  50. void draw_window();
  51. void draw_progress_bar();
  52. void do_ipc();
  53. void exit();
  54.  
  55.  
  56. DWORD hDrv;
  57. DWORD hSound;
  58. SNDBUF hBuff;
  59. volatile int snd_init=0;
  60.  
  61. CTRL_INFO info;
  62.  
  63. FILEINFO   fileinfo;
  64.  
  65. int m_vol;
  66. int l_vol=-700;     //-7db
  67. int r_vol=-700;
  68. int pan =0;
  69.  
  70. DWORD status;
  71. DWORD offset;
  72. DWORD first_sync;
  73.  
  74. unsigned char *testbuff;
  75. unsigned char *outbuf;
  76. unsigned char *inpbuf;
  77. unsigned char *outPtr;
  78.  
  79. int inpsize;
  80. int outsize;
  81. int outremain;
  82. int totalout;
  83. int done;
  84. char path[1024];
  85. char header[] = "AC97 MP3 player";
  86. char buttons_text[]=" Play    Stop     <<      >>     Vol-    Vol+";
  87.  
  88. void (*snd_play)();
  89.  
  90.  
  91. int main(int argc, char *argv[])      //int argc, char *argv[])
  92. {
  93.    int err;
  94.    int ver;
  95.    int evnt;
  96.    int key;
  97.    int pos;
  98.    int msg;
  99.    int cnt;
  100.    IPC *incom;
  101.    
  102.    _asm
  103.    {
  104.      mov eax, 40
  105.      mov ebx, 0x47  ;recieve ipc
  106.      int 0x40
  107.      mov eax, 66
  108.      mov ebx, 1
  109.      mov ecx, 1
  110.      int 0x40
  111.    };
  112.    init_ipc();
  113.    InitHeap(0);
  114.    
  115.    if(err = InitSound(&ver))
  116.    { debug_out_str("Sound service not installed\n\r");
  117.      return 0;
  118.    }
  119.    
  120.    if( (SOUND_VERSION>(ver&0xFFFF)) ||
  121.        (SOUND_VERSION<(ver >> 16)))
  122.    { debug_out_str("Sound service version mismatch\n\r");
  123.      return 0;
  124.    }
  125.  
  126.    make_decode_tables(32767);
  127.    init_layer2();
  128.    init_layer3(32);
  129.    fr.single = -1;
  130.  
  131.    outremain = 0x40000 ;
  132.    if( !(outbuf=UserAlloc(outremain)))
  133.      return 0;
  134.      
  135.    touch(outbuf, outremain);
  136.    
  137.    if ( !(testbuff=UserAlloc(4096)))
  138.      return 0;
  139.      
  140.    if (! (inpbuf=UserAlloc(0x10000)))
  141.      return 0;
  142.    
  143.    touch(inpbuf, 0x10000);
  144.    create_reader(&rd, inpbuf, 0x10000);
  145.  
  146.    fname = argv[1];
  147.    
  148.    if(get_fileinfo(fname, &fileinfo)==FILE_NOT_FOUND)
  149.    {
  150.      _asm
  151.      {
  152.        mov eax, 23
  153.        mov ebx, 100
  154.        int 0x40
  155.        mov [msg], eax
  156.      }
  157.      if (msg != 7)
  158.      {
  159.        debug_out_str("\n\rfile not found\n\r");
  160.        return 0;
  161.      };
  162.      incom = recieve_ipc();
  163.      if(incom->code != 'CNCT')
  164.      {
  165.        debug_out_str("\n\rinvalid ipc code\n\r");
  166.        status = ST_EXIT;
  167.        return 0;
  168.      };
  169.      ipc_client = incom->sender;
  170.      send_ipc(ipc_client,'CNCT');
  171.    };
  172.    
  173.    
  174.    snd_init=0;
  175.    create_thread(thread_proc, 0, 4096);
  176.    
  177.    for(snd_init=0,cnt=100; (snd_init==0)&&(cnt!=0); cnt--)
  178.      delay(10);
  179.      
  180.    if (!snd_init)
  181.      return 0;
  182.      
  183.    draw_window();
  184.  
  185.    while(1)
  186.   {  if(status==ST_PLAY)
  187.      {  draw_progress_bar();
  188.         evnt = wait_for_event(80);
  189.      }
  190.      else
  191.         evnt = wait_for_event_infinite();
  192.  
  193.     switch(evnt)
  194.     {
  195.       case EV_REDRAW:
  196.         draw_window();
  197.         break;
  198.  
  199.       case EV_KEY:
  200.         if(!get_key(&key))
  201.         {
  202.        
  203.           switch(key)
  204.           {  case 0xE0:
  205.              case 0xE1:
  206.                break;
  207.              default:
  208.                switch (key)
  209.                {
  210.                  case 0x01:  //Esc
  211.                    status = ST_EXIT;
  212.                    exit();
  213.                    break;
  214.                
  215.                  case 0x47:  //Home
  216.                    if(l_vol < 0)
  217.                    { l_vol+=100;
  218.                      r_vol+=100;  
  219.                      SetVolume(hBuff,l_vol,r_vol);
  220.                    };
  221.                    break;
  222.                  case 0x4F:  //End                
  223.                    if(l_vol > -10000)
  224.                    { l_vol-=100;
  225.                      r_vol-=100;  
  226.                      SetVolume(hBuff,l_vol,r_vol);
  227.                    };
  228.                    break;
  229.                  case 0x53:
  230.                    if(pan > -10000)
  231.                    { pan -=100;
  232.                      SetPan(hBuff,pan);
  233.                    };
  234.                    break;  
  235.                  case 0x51:
  236.                    if(pan < 10000)
  237.                    { pan +=100;
  238.                      SetPan(hBuff,pan);
  239.                    };
  240.                    break;  
  241.                }
  242.           };    
  243.         };  
  244.         break;
  245.  
  246.       case EV_BUTTON:
  247.         switch(get_button_id())
  248.         {  case 1:
  249.              status = ST_EXIT;
  250.              exit();
  251.              break;
  252.              
  253.            case 0x10:
  254.              status = ST_PLAY;
  255.              continue;
  256.  
  257.            case 0x11:
  258.              status = ST_STOP;
  259.              break;
  260. //           case 0x12:
  261. //           case 0x13:
  262.            case 0x14:
  263.             if(l_vol > -10000)
  264.             {
  265.               l_vol-=100;
  266.               r_vol-=100;  
  267.               SetVolume(hBuff,l_vol,r_vol);
  268.             };
  269.             break;
  270.  
  271.            case 0x15:
  272.             if(l_vol < 0)
  273.             { l_vol+=100;
  274.               r_vol+=100;  
  275.               SetVolume(hBuff,l_vol,r_vol);
  276.             };
  277.             break;
  278.  
  279.            case 0x30:
  280.             if(status==ST_DONE)
  281.               break;
  282.             pos = (GetMousePos(REL_WINDOW)>>16)-7;
  283.             offset = ((fileinfo.size-44)/286*pos+44)&0xFFFFFFFC;
  284.             set_reader(&rd, offset);
  285.             draw_progress_bar();
  286.             break;
  287.         };
  288.         break;
  289.       case EV_IPC:
  290.         do_ipc();
  291.         break;
  292.     };
  293.   };
  294.  
  295.  
  296.  
  297.    
  298.    return 0;
  299. };
  300.  
  301.  
  302. void draw_window()
  303. {
  304.    BeginDraw();
  305.  
  306.    DrawWindow(100,100,299,72,0x404040,3,0,0,0);
  307.  
  308.    make_button(7,24,45,13, 0x10|BT_NORMAL,0x808080);
  309.    make_button(56,24,45,13, 0x11|BT_NORMAL,0x808080);
  310.    make_button(104,24,45,13, 0x12|BT_NORMAL,0x808080);
  311.    make_button(152,24,45,13, 0x13|BT_NORMAL,0x808080);
  312.    make_button(200,24,45,13, 0x14|BT_NORMAL,0x808080);
  313.    make_button(248,24,45,13, 0x15|BT_NORMAL,0x808080);
  314.  
  315.    make_button(7,41,286,11, 0x30|BT_HIDE|BT_NOFRAME,0x404040);
  316.    draw_bar(7,41,286,11,0x404040);
  317.  
  318.    draw_bar(7,55,286,11,0x404040);
  319.    write_text(12,58,0x004000|FONT0, fname, strlen(fname));
  320.    write_text(11,57,0x00FF20|FONT0, fname, strlen(fname));
  321.  
  322.    write_text(8,8,0xFFFFFF|FONT0, header, strlen(header));
  323.    write_text(12,28,0x404040|FONT0,buttons_text,strlen(buttons_text));
  324.    write_text(11,27,0xA0FFA0|FONT0,buttons_text,strlen(buttons_text));
  325.  
  326.    EndDraw();
  327. };
  328.  
  329. void draw_progress_bar()
  330. {  DWORD x;
  331.    x = 287.0f * (float)(rd.filepos-rd.strremain)/(float)fileinfo.size;
  332.    if(x==0) return;
  333.    draw_bar(7,41,x,11,0xA0A0A0);
  334.    draw_bar(x+7,41,287-x,11,0x404040);
  335. };
  336.  
  337. void debug_out_str(char* str)
  338. {
  339.   while (*str != 0)
  340.   {
  341.     debug_out(*str);
  342.     str++;
  343.   }
  344. }
  345.  
  346.  
  347. void touch(char *buf, int size)
  348. { int i;
  349.    char a;
  350.     for ( i = 0;i < size; i+=4096)
  351.       a = buf[i];
  352. };
  353.  
  354. DWORD test_mp3(char *buf)
  355. {  unsigned long hdr;
  356.     WAVEHEADER whdr;
  357.      
  358.     while (1)
  359.     {  if(rd.filepos > 102400)
  360.           return 0;
  361.         if(!rd.head_read(&rd,&hdr))
  362.            return 0;
  363.         if(!decode_header(&fr,hdr))
  364.         {  
  365.            if((hdr & 0xffffff00) == 0x49443300)
  366.                {
  367.                      int id3length = 0;
  368.                      id3length = parse_new_id3(&rd, hdr);
  369.                      continue;
  370.                };
  371.        
  372.            rd.strpos-=3;
  373.            rd.stream-=3;
  374.            rd.strremain+=3;
  375.            continue;
  376.         };
  377.         break;
  378.     };
  379.          
  380.     first_sync = rd.filepos-rd.strremain-4;
  381.          
  382.     whdr.riff_id = 0x46464952;
  383.     whdr.riff_format = 0x45564157;
  384.     whdr.wFormatTag = 0x01;
  385.     whdr.nSamplesPerSec = freqs[fr.sampling_frequency];
  386.     whdr.nChannels = 2; //mpginfo.channels;
  387.     whdr.wBitsPerSample = 16;
  388.    
  389.     return test_wav(&whdr);
  390. };
  391.  
  392.  
  393. void play_mp3()
  394. {  char *outPtr;
  395.     int totalout;
  396.     int outcount;
  397.  
  398.     fr.down_sample_sblimit = 32;
  399.     fr.single = -1;
  400.     reset_mpg();
  401.  
  402.     outPtr = outbuf;
  403.     totalout=0;
  404.     done = 0;
  405.     outremain=0x40000;
  406.  
  407.     memset(outbuf,0,0x40000);
  408.     set_reader(&rd, 0);    //;first_sync);
  409.  
  410.     while(1)
  411.     { if(status!=ST_PLAY)
  412.              break;
  413.  
  414.       for(;;)
  415.       {   outcount = 0;                          
  416.           if( !read_frame(&rd, &fr))
  417.           {  done = 1;
  418.               break;
  419.           };
  420.           fr.do_layer(&fr, outPtr,&outcount);
  421.           outPtr+= outcount;
  422.           totalout+=outcount;
  423.           outremain-=outcount;
  424.           if(outremain < outcount*2)
  425.             break;  
  426.       };
  427.  
  428.       if(done)
  429.       { if(totalout < 4096)
  430.         {  memset(outPtr,0,4096-totalout);
  431.            totalout = 4096;
  432.         };
  433.       }
  434.       else if(totalout < 8192) continue;
  435.      
  436.       outPtr = outbuf;      
  437.       while (totalout >= 4096)
  438.       {
  439.         WaveOut(hBuff,outPtr,4096);
  440.         if(status!=ST_PLAY)
  441.         { StopBuffer(hBuff);
  442.           return;
  443.         };
  444.         totalout-=4096;
  445.         outPtr+=4096;
  446.         outremain+=4096;
  447.       };
  448.      
  449.       if(done)
  450.       { status = ST_STOP;
  451.        
  452.         if( ipc_client)
  453.           send_ipc(ipc_client,'DONE');
  454.         return;
  455.       }  
  456.       memmove(outbuf,outPtr, totalout);
  457.       outPtr = outbuf+totalout;
  458.     };
  459. };
  460.  
  461.  
  462. int play_track(char *path)
  463. {
  464.    DWORD fmt;
  465.    DWORD r_bytes;
  466.    int retval;
  467.    int err;
  468. //   int err;
  469.  
  470.    retval = ST_DONE;
  471.    
  472.    get_fileinfo(path, &fileinfo);
  473.    offset = 0;
  474.    err=read_file (path,testbuff,0,2048,&r_bytes);
  475.    if (err)
  476.      return ST_DONE;
  477.  
  478.    init_reader(&rd,path);
  479.  
  480.    fmt = test_wav((WAVEHEADER*)testbuff);
  481.    if (fmt != 0)
  482.    {
  483.      snd_play = &play_wave;
  484.      set_reader(&rd, 44);
  485.      retval = ST_PLAY;
  486.    }  
  487.    else
  488.    { fmt = test_mp3(testbuff);
  489.      if(fmt ==0)
  490.        return ST_DONE;
  491.        
  492.      snd_play = &play_mp3;
  493.      outremain = 0x40000;
  494.      retval = ST_PLAY;
  495.    };
  496.      
  497.    SetFormat(hBuff, fmt);
  498.    return retval;
  499. };
  500.  
  501.  
  502. void play_wave()
  503. {  int retval;
  504.  
  505.    set_reader(&rd,44);
  506.    retval = 0;
  507.    while(1)
  508.    {
  509.       if(status!=ST_PLAY)
  510.         break;
  511.  
  512.       if( !stream_read_raw(&rd,outbuf,32768))
  513.       {  done = 1;
  514.           break;
  515.       };
  516.       WaveOut(hBuff,outbuf,32768);
  517.    };
  518.  
  519.    if(status != ST_EXIT)
  520.     status =  ST_STOP;
  521. };
  522.  
  523. void snd_stop()
  524. {
  525.   StopBuffer(hBuff);
  526. };
  527.  
  528. void do_ipc()
  529. {
  530.   IPC *incom;
  531.   incom = recieve_ipc();
  532.   switch(incom->code)
  533.   {
  534.     case 'PLAY':
  535.       fname = incom->data;  
  536.       status = ST_TRACK;
  537.       return;
  538.      
  539.     case 'STOP':
  540.       status = ST_STOP;
  541.       return;
  542.        
  543.     case 'EXIT':
  544.       status = ST_EXIT;
  545.       exit();
  546.   };
  547. };
  548.  
  549. void _stdcall thread_proc(void *param)
  550. {
  551.    int err;
  552.  
  553.    if (err = CreateBuffer(PCM_ALL|PCM_OUT,0, &hBuff))
  554.    {
  555.      debug_out_str("create buffer return error\n\r");
  556.      exit();
  557.    };
  558.    
  559.    SetVolume(hBuff,l_vol,r_vol);
  560.    GetVolume(hBuff,&l_vol,&r_vol);
  561. //   debug_out_hex(l_vol);
  562. //   debug_out_str("\n\r");
  563. //   debug_out_hex(r_vol);
  564. //   debug_out_str("\n\r");
  565.  
  566.    if(fname[0] !='/0')
  567.      status = play_track(fname);  
  568.  
  569.    debug_out_str("\n\rPlay file ");
  570.    debug_out_str(fname);
  571.    debug_out_str("\n\r");
  572.    
  573.    snd_init = 1;
  574.    
  575.    while(1)
  576.    {  delay(10);
  577.       switch(status)
  578.       {  
  579.          case ST_TRACK:
  580.            strcpy(path, fname);
  581.            status = play_track(fname);  
  582.            if( ipc_client & (status == ST_DONE))
  583.            { send_ipc(ipc_client,'DONE');
  584.              continue;
  585.            };
  586.      
  587.          case ST_PLAY:
  588.            snd_play();
  589.            continue;
  590.  
  591.          case ST_STOP:
  592.            StopBuffer(hBuff);
  593.            status = ST_DONE;
  594.            continue;
  595.  
  596.          case ST_EXIT:
  597.            StopBuffer(hBuff);
  598.            DestroyBuffer(hBuff);
  599.            if (ipc_client)
  600.              send_ipc(ipc_client,'EXIT');
  601.            return;
  602.       };
  603.    };
  604.  
  605.    
  606. };
  607.  
  608. void delay (int val)
  609. {
  610.   _asm
  611.   {   mov   eax,5
  612.       mov   ebx, [val]
  613.       int   0x40
  614.   };  
  615. }
  616.  
  617. int wait_for_event(int time)
  618. { int retval;
  619.   _asm
  620.  {  mov  eax,23
  621.      mov  ebx,[time]
  622.      int  0x40
  623.      mov [retval], eax
  624.  };
  625.  return retval;
  626. };
  627.  
  628. int wait_for_event_infinite()
  629. { int retval;
  630.   _asm
  631.   {  mov  eax,10
  632.       int  0x40
  633.       mov [retval], eax
  634.   };
  635.   return retval;
  636. };
  637.  
  638. void BeginDraw()
  639. {_asm
  640.  { mov   eax,12
  641.     mov   ebx, 1
  642.     int   0x40
  643.   };  
  644. };
  645.  
  646. void EndDraw()
  647. { _asm
  648.  { mov   eax,12
  649.     mov   ebx, 2
  650.     int   0x40
  651.   };  
  652. };
  653.  
  654. ///*********
  655. void *memmove ( void * dst, void * src, int count)
  656. { void *ret;
  657.   ret = dst;
  658.  
  659.   if (dst <= src || (char *)dst >= ((char *)src + count))
  660.   {
  661.       while (count--)
  662.       { *(char *)dst = *(char *)src;
  663.           dst = (char *)dst + 1;
  664.           src = (char *)src + 1;
  665.       }
  666.    }
  667.    else
  668.     {
  669.         dst = (char *)dst + count - 1;
  670.         src = (char *)src + count - 1;
  671.          while (count--)
  672.           {  *(char *)dst = *(char *)src;
  673.               dst = (char *)dst - 1;
  674.               src = (char *)src - 1;
  675.           }
  676.     }
  677.     return ret;
  678. };
  679. //**********/
  680.  
  681. void * __cdecl mem_cpy(void * dst,const void * src,size_t count)
  682. {    void * ret = dst;
  683.       while (count--)
  684.       {  *(char *)dst = *(char *)src;
  685.           dst = (char *)dst + 1;
  686.           src = (char *)src + 1;
  687.       };
  688.       return(ret);
  689. }
  690.  
  691. //   debug_out_str(formats[fmt]);
  692. //   debug_out_str("\x0D\x0A\x00");
  693.  
  694. //   debug_out_str("pci cmd: ");
  695. //   debug_out_hex(info.pci_cmd);
  696. //   debug_out_str("\x0D\x0A\x00");
  697.  
  698. //   debug_out_str("irq line: ");
  699. //   debug_out_hex(info.irq);
  700. //   debug_out_str("\x0D\x0A\x00");
  701.  
  702. //   debug_out_str("global control: ");
  703. //   debug_out_hex(info.glob_cntrl);
  704. //   debug_out_str("\x0D\x0A\x00");
  705.  
  706. //   debug_out_str("global status:  ");
  707. //   debug_out_hex(info.glob_sta);
  708. //   debug_out_str("\x0D\x0A\x00");
  709.  
  710.  
  711.   // call _print_volume
  712.  
  713. //   debug_out_hex(whdr.nChannels);
  714. //   debug_out_str("\x0D\x0A\x00");
  715. //   debug_out_hex(whdr.nSamplesPerSec);
  716. //   debug_out_str("\x0D\x0A\x00");
  717.  
  718. //   debug_out_hex(fmt);
  719. //   debug_out_str("\x0D\x0A\x00");
  720.  
  721.  
  722.  
  723.