home *** CD-ROM | disk | FTP | other *** search
/ Sound Fx / Sound Fx.iso / Software / UNZIPED / MPW181-5 / _SETUP.1 / mp2win.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-19  |  38.6 KB  |  1,571 lines

  1. /* mp2win.cpp
  2.  
  3.     Interface for maplay written by Jeff Tsay. E-mail address:
  4.     ctsay@pasteur.eecs.berkeley.edu. Basic sound file player with
  5.     file open, command line capability, pause, stop, and MPEG
  6.     properties. Also added play list and seeking functionality. Uses
  7.     threads, so will NOT work on Win32s!
  8.  
  9.    Adapted from the Sounder sample application distributed on the
  10.     Borland C++ CD */
  11.  
  12. /* Version 1.80 :
  13.  
  14.     Changes since last version:
  15.  
  16.    Seeking calls functions within the args class instead of directly reading
  17.    or writing variables internal to the class.
  18.  
  19.    Tried to signal the thread procedures to terminate themselves so that
  20.    memory will not be lost. However, this does not always work, so after
  21.    a waiting period TerminateThread is called.
  22.  
  23.    Eliminated passing the crc to maplay, instead a dummy crc is used to read
  24.    the header.
  25.  
  26.    Increased the maximum size of the playlist to 512 entries.
  27.  
  28.    Last edit : 02/01/97 */
  29.  
  30. /*    Version 1.81:
  31.  
  32.     MIDI and WAV files with filenames that contain spaces can now be loaded
  33.     and played. This was due to a suggestion by Alexander Grigoriev. */
  34.  
  35. #define STRICT
  36. #include <windows.h>
  37. #include <commctrl.h>
  38. #include <commdlg.h>
  39.  
  40. #include "crc.h"
  41. #include "ibitstr.h"
  42. #include "header.h"
  43. #include "mp2win.h"
  44. #include "args.h"
  45. #include "str_lib.h"
  46. #include <fstream.h>
  47.  
  48. #define _export
  49. #define GET_WM_COMMAND_ID(wp, lp)    LOWORD(wp)
  50. #define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp)
  51. #define GET_WM_COMMAND_CMD(wp, lp)     HIWORD(wp)
  52.  
  53. #define LIST_SIZE 512
  54.  
  55. // Argument containers
  56. MPEG_Args _maplay_args;
  57. MPEG_Args *maplay_args = &_maplay_args;
  58. MCI_Args  _mci_args;
  59. MCI_Args  *mci_args    = &_mci_args;
  60. Args* args;
  61.  
  62. // Thread functions
  63. DWORD maplay(MPEG_Args *);
  64. DWORD mciplay(MCI_Args *);
  65.  
  66. // data initialized by first instance
  67.  
  68. char szAppName[20];
  69.  
  70. // Data that can be referenced throughout the
  71. // program but not passed to other instances
  72.  
  73. char szName[MAX_PATH];           // Name of sound file
  74. char FileTitle[MAX_PATH];
  75. char TitleText[64];
  76. char command[384];         // MCI command string
  77. char scratch[1024];
  78. char Buffer[1024];           // MCI response string
  79. LPSTR PlayList[LIST_SIZE];
  80.  
  81. OPENFILENAME ofnTemp;
  82. LPSTR szFilter = "All Readable Files\0*.mp*;*.snd;*.wav;*.mid;*.txt;*.lst\0\
  83. MPEG Audio Files (*.mp*)\0*.mp*\0DALET Sound Files (*.snd)\0*.snd\0PCM Wave \
  84. Files (*.wav)\0*.wav\0MIDI Files (*.mid)\0*.mid\0Playlists (*.txt, *.lst)\0\
  85. *.txt;*.lst\0\All Files (*.*)\0*.*\0";
  86.  
  87. // Playlist position and size
  88. int32 Cur_Index = 0;
  89. int32 Max_Index = 0;
  90.  
  91. int32 scroll_range = 0;
  92. // int predecode=0;        // not implemented yet
  93.  
  94. // State variables
  95. BOOL ListMode  = FALSE;
  96. BOOL MPEG      = FALSE;
  97. BOOL CDMode    = FALSE;
  98. BOOL Repeat    = FALSE;
  99. BOOL CMDLINE   = FALSE;
  100. BOOL paused    = FALSE;
  101. BOOL can_play  = FALSE;
  102. BOOL can_pause = FALSE;
  103. BOOL can_stop  = FALSE;
  104. BOOL playing   = FALSE;
  105. BOOL scrolling = FALSE;
  106. enum e_channels mode = both;
  107.  
  108. // Dummy CRC pointer
  109. Crc16 *crc;
  110.  
  111. // WaveOut handle and its address
  112. HWAVEOUT hwo;
  113. HWAVEOUT *phwo = &hwo;
  114.  
  115. // Threads
  116. HANDLE MPEG_Thread = NULL;
  117. HANDLE MCI_Thread  = NULL;
  118. DWORD dwThreadId;
  119.  
  120. HINSTANCE hInst;      // hInstance of application
  121. HWND      hWnd;       // hWnd of main window
  122.  
  123. // Buttons
  124. HWND openbut, playbut, pausebut, stopbut, aboutbut;
  125. HWND rewbut, ffbut, prevbut, nextbut;
  126.  
  127. // Track bar
  128. int32 line_size;
  129. HWND tracker;
  130.  
  131. // Status bar
  132. int32 panes[4]= {68, 213, 273, -1};
  133. char playlist_filename[MAX_PATH];
  134. HWND status_bar;
  135.  
  136. // Menu
  137. HMENU mainmenu;
  138.  
  139. HDC hdc;
  140. DRAWITEMSTRUCT *dis;
  141.  
  142. // Function prototypes
  143.  
  144. int32 PASCAL WinMain(HINSTANCE,HINSTANCE,LPSTR,int32);
  145. void         InitSound(HINSTANCE,HINSTANCE,LPSTR,int32);
  146. void         InitSoundFirst(HINSTANCE);
  147. void         InitSoundEvery(HINSTANCE,int32);
  148.  
  149. // Helper procedures
  150. BOOL AppFileOpen();
  151. BOOL file_load();
  152. void clear_sound();
  153. void ok_play();
  154. void no_play();
  155. void no_stop();
  156. BOOL reinit_MPEG();
  157. BOOL reinit_MCI();
  158. BOOL WaveP(LPSTR);
  159. BOOL CDAP(LPSTR);
  160. BOOL ListP(LPSTR);
  161. LPSTR Proper_Filename(LPSTR s);
  162. void CDTrack_Number(LPSTR s);
  163. void DisplayName(LPSTR);
  164. BOOL MPEG_play();
  165. BOOL MCI_play();
  166. BOOL Get_File_List(LPSTR);
  167. BOOL File_Init();
  168. void Next_Song();
  169. void Init_List();
  170. void no_list();
  171. char *time_string(int32 ms, char *dest);
  172. void update_timewin(int32 num);
  173.  
  174. // Menu procedures
  175. void file_open();
  176. void audio_play();
  177. void audio_pause();
  178. void audio_stop();
  179. void audio_properties();
  180. void gotop_List(int32 n);
  181. void about();
  182. void leave();
  183.  
  184. // Procedure for options dialog box
  185. void leave_options(HWND hDlg, BOOL save);
  186.  
  187. LRESULT APIENTRY SounderWndProc(HWND,UINT,WPARAM,LPARAM);
  188. BOOL WINAPI Options(HWND hDlg, UINT message, WPARAM wParam,
  189.                                         LPARAM lParam);
  190.  
  191. int32 APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  192.                                LPSTR lpszCmdLine, int32 cmdShow)
  193. {
  194.      MSG   msg;
  195.  
  196.      // Go init this application.
  197.      InitSound(hInstance, hPrevInstance,
  198.                   lpszCmdLine, cmdShow);
  199.  
  200.      if (lstrlen(lpszCmdLine)>1) {
  201.  
  202.          CMDLINE=TRUE;
  203.  
  204.          if (ListP(lpszCmdLine)) {
  205.  
  206.              SendMessage(hWnd, WM_CMDLINEFILE, 2, (LPARAM) lpszCmdLine);
  207.  
  208.          } else {
  209.  
  210.              if (WaveP(lpszCmdLine))
  211.                  SendMessage(hWnd, WM_CMDLINEFILE, 0, (LPARAM) lpszCmdLine);
  212.              else
  213.                  SendMessage(hWnd, WM_CMDLINEFILE, 1, (LPARAM) lpszCmdLine);
  214.  
  215.         }
  216.      }
  217.  
  218.      // Get and dispatch messages for this applicaton.
  219.      while (GetMessage(&msg, NULL, 0, 0))
  220.      {
  221.           TranslateMessage(&msg);
  222.           DispatchMessage(&msg);
  223.      }
  224.      return(msg.wParam);
  225. }
  226.  
  227. #pragma argsused
  228. void InitSound(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  229.                     LPSTR lpszCmdLine, int32 cmdShow)
  230. {
  231.      InitSoundFirst(hInstance);
  232.      InitSoundEvery(hInstance, cmdShow);  // initialization for all instances
  233. }
  234.  
  235. void InitSoundFirst(HINSTANCE hInstance)
  236.  
  237. {
  238.      WNDCLASS wcSoundClass;
  239.  
  240.      // Get string from resource with application name.
  241.      LoadString(hInstance, IDS_NAME, (LPSTR) szAppName, 20);
  242.  
  243.      // Define the window class for this application.
  244.      wcSoundClass.lpszClassName = szAppName;
  245.      wcSoundClass.hInstance     = hInstance;
  246.      wcSoundClass.lpfnWndProc   = SounderWndProc;
  247.      wcSoundClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  248.      wcSoundClass.hIcon         = LoadIcon(hInstance,
  249.                                                         MAKEINTRESOURCE(ICON_MP));
  250.      wcSoundClass.lpszMenuName  = MAKEINTRESOURCE(MENU_1);
  251.      wcSoundClass.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH);
  252.      wcSoundClass.style         = CS_HREDRAW | CS_VREDRAW;
  253.      wcSoundClass.cbClsExtra    = 0;
  254.      wcSoundClass.cbWndExtra    = 0;
  255.  
  256.      // Register the class
  257.      RegisterClass(&wcSoundClass);
  258. }
  259.  
  260. void InitSoundEvery(HINSTANCE hInstance, int32 cmdShow)
  261. {
  262.      int32 i;
  263.      for(i=0; i<LIST_SIZE; i++)
  264.         PlayList[i]=NULL;
  265.      Cur_Index=0;
  266.      Max_Index=0;
  267.  
  268.      hInst = hInstance;       // save for use by window procs
  269.  
  270.      InitCommonControls();
  271.  
  272.      // Create applications main window.
  273.      hWnd =     CreateWindowEx(
  274.                       WS_EX_ACCEPTFILES | WS_EX_CONTROLPARENT,
  275.                         szAppName,         // window class name
  276.                         szAppName,         // window title
  277.                         WS_OVERLAPPED | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU,
  278.                                      // type of window
  279.                         100,               // x  window location
  280.                         100,               // y
  281.                         310,               // cx and size
  282.                         145,               // cy
  283.                         NULL,              // no parent for this window
  284.                         NULL,              // use the main menu
  285.                         hInstance,         // who created this window
  286.                         NULL);             // no parms to pass on
  287.  
  288.  
  289.      // Update display of main window.
  290.      mainmenu=GetMenu(hWnd);
  291.  
  292.      ShowWindow(hWnd, cmdShow);
  293.      UpdateWindow(hWnd);
  294.  
  295.      ofnTemp.lStructSize       = sizeof(OPENFILENAME);
  296.     ofnTemp.hwndOwner         = hWnd;
  297.     ofnTemp.hInstance         = 0;
  298.     ofnTemp.lpstrFilter       = (LPSTR)szFilter;
  299.     ofnTemp.lpstrCustomFilter = NULL;
  300.     ofnTemp.nMaxCustFilter    = 0;
  301.     ofnTemp.nFilterIndex      = 1;
  302.     ofnTemp.lpstrFile         = (LPSTR)szName;
  303.     ofnTemp.nMaxFile          = sizeof(szName);
  304.     ofnTemp.lpstrFileTitle    = FileTitle;
  305.     ofnTemp.nMaxFileTitle     = sizeof(FileTitle);
  306.     ofnTemp.lpstrInitialDir   = NULL;
  307.     ofnTemp.lpstrTitle        = "Open Sound File";
  308.     ofnTemp.Flags             = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST |
  309.                                            OFN_HIDEREADONLY  | OFN_EXPLORER;
  310.     ofnTemp.nFileOffset       = 0;
  311.     ofnTemp.nFileExtension    = 0;
  312.     ofnTemp.lpstrDefExt       = "MP*";
  313.     ofnTemp.lCustData         = 0;
  314.     ofnTemp.lpfnHook          = NULL;
  315.     ofnTemp.lpTemplateName    = NULL;
  316. }
  317.  
  318. BOOL AppFileOpen()
  319. {
  320.   DWORD Errval;
  321.  
  322.   if (!GetOpenFileName((LPOPENFILENAME) &ofnTemp))
  323.   {
  324.      Errval = CommDlgExtendedError();
  325.      if (Errval != 0) // 0 value means user selected Cancel
  326.         MessageBox(hWnd, "Could not open file.", "Warning", MB_OK | MB_ICONSTOP);
  327.  
  328.      return(FALSE);
  329.   }
  330.  
  331.   return(TRUE);
  332. }
  333.  
  334. char *time_string(int32 ms, char *dest)
  335. {
  336.     int32 i, j, nmlength;
  337.     int32 seconds, minutes;
  338.     char second_str[4];
  339.     char minute_str[4];
  340.  
  341.     minutes = ms / 60000;
  342.     seconds = ms / 1000 - minutes * 60;
  343.  
  344.     my_itoa(minutes, minute_str, 10);
  345.     my_itoa(seconds, second_str, 10);
  346.  
  347.     nmlength = 3 - lstrlen(minute_str);
  348.  
  349.     for (i=0; i < nmlength ; i++)
  350.         dest[i] = '0';
  351.  
  352.     for (i = nmlength, j=0; i<3; i++, j++)
  353.         dest[i] = minute_str[j];
  354.  
  355.     dest[3] = ':';
  356.  
  357.     nmlength = 6 - lstrlen(second_str);
  358.  
  359.     for (i=4; i < nmlength ; i++)
  360.         dest[i] = '0';
  361.  
  362.     for (i=nmlength, j=0; i<6; i++, j++)
  363.         dest[i] = second_str[j];
  364.  
  365.     dest[6]='\0';
  366.  
  367.     return (dest);
  368. }
  369.  
  370. void clear_sound()
  371. {
  372.     scrolling = FALSE;
  373.  
  374.     if (MPEG) {
  375.  
  376.        if (MPEG_Thread) {
  377.  
  378.          SetThreadPriority(MPEG_Thread, THREAD_PRIORITY_HIGHEST);
  379.  
  380.             if (paused) {
  381.  
  382.                 paused      = FALSE;
  383.             waveOutReset(*phwo);
  384.                waveOutRestart(*phwo);
  385.                 ResumeThread(MPEG_Thread);
  386.              }
  387.  
  388.             WaitForSingleObject(maplay_args->mutex, INFINITE);
  389.  
  390.          if (!maplay_args->done) {
  391.                 maplay_args->stop = TRUE;
  392.  
  393.                 ReleaseMutex(maplay_args->mutex);
  394.  
  395.              if (WaitForSingleObject(MPEG_Thread, 5000) == WAIT_TIMEOUT) {
  396.                  TerminateThread(MPEG_Thread, 0);
  397.                       waveOutReset(*phwo);
  398.                     waveOutClose(*phwo);
  399.             }
  400.           } else {
  401.                 ReleaseMutex(maplay_args->mutex);
  402.          }
  403.  
  404.          CloseHandle(MPEG_Thread);
  405.       }
  406.  
  407.         MPEG_Thread = NULL; // ensures next call to clear_sound() will not
  408.                                // attempt to kill thread
  409.  
  410.         delete maplay_args->stream;
  411.         maplay_args->stream = NULL;
  412.  
  413.         delete maplay_args->MPEGheader;
  414.       maplay_args->MPEGheader = NULL;
  415.  
  416.       CloseHandle(maplay_args->mutex);
  417.  
  418.     } else {
  419.  
  420.        if (MCI_Thread) {
  421.  
  422.           WaitForSingleObject(mci_args->mutex, INFINITE);
  423.  
  424.             mci_args->stop = TRUE;
  425.          ReleaseMutex(mci_args->mutex);
  426.  
  427.           if(WaitForSingleObject(MCI_Thread, 5000) == WAIT_TIMEOUT)
  428.                 TerminateThread(MCI_Thread, 0);
  429.  
  430.          CloseHandle(MCI_Thread);
  431.       }
  432.  
  433.         MCI_Thread = NULL; // ensures next call to clear_sound() will not
  434.                          // attempt to kill thread
  435.  
  436.         mciSendString((LPSTR)"stop sounder",  NULL, 0, NULL);
  437.         mciSendString((LPSTR)"close sounder", NULL, 0, NULL);
  438.     }
  439.  
  440.     SendMessage(status_bar, SB_SETTEXT, 0, (LPARAM) "Stopped");
  441.     SendMessage(status_bar, SB_SETTEXT, 2, (LPARAM) "000:00");
  442.  
  443.     return;
  444. }
  445.  
  446. void ok_play()
  447. {
  448.     can_play  = TRUE;
  449.     can_pause = FALSE;
  450.     playing   = FALSE;
  451.     EnableMenuItem(mainmenu,CM_AUDIOPLAY, MF_ENABLED);
  452.     EnableWindow(playbut, TRUE);
  453.     EnableMenuItem(mainmenu,CM_AUDIOPAUSE, MF_GRAYED);
  454.     EnableWindow(pausebut, FALSE);
  455.     return;
  456. }
  457.  
  458. void no_play()
  459. {
  460.     can_play=FALSE;
  461.     can_pause=TRUE;
  462.     can_stop=TRUE;
  463.     playing=TRUE;
  464.     EnableMenuItem(mainmenu,CM_AUDIOPLAY, MF_GRAYED);
  465.     EnableWindow(playbut, FALSE);
  466.     EnableMenuItem(mainmenu,CM_AUDIOPAUSE, MF_ENABLED);
  467.     EnableWindow(pausebut, TRUE);
  468.     EnableMenuItem(mainmenu,CM_AUDIOSTOP, MF_ENABLED);
  469.     EnableWindow(stopbut, TRUE);
  470.     return;
  471. }
  472.  
  473. void no_stop()
  474. {
  475.     can_stop = FALSE;
  476.     EnableMenuItem(mainmenu,CM_AUDIOSTOP, MF_GRAYED);
  477.     EnableWindow(stopbut, FALSE);
  478.     return;
  479. }
  480.  
  481. BOOL reinit_MPEG()
  482. {
  483.     MPEG = TRUE;
  484.     args = maplay_args;
  485.  
  486.     args->hWnd  = hWnd;
  487.     args->mutex = CreateMutex(NULL, FALSE, "m");
  488.    args->stop  = FALSE;
  489.    args->done  = FALSE;
  490.  
  491.     args->position_change  = FALSE;
  492.    args->desired_position = 0;
  493.  
  494.     maplay_args->stream      = new Ibitstream(szName);
  495.     maplay_args->MPEGheader  = new Header;
  496.     maplay_args->phwo        = phwo;
  497.     maplay_args->which_c     = mode;
  498.    maplay_args->stdout_mode = FALSE;
  499.    maplay_args->use_own_scalefactor = FALSE;
  500.  
  501.     if (!maplay_args->MPEGheader->read_header(maplay_args->stream, &crc)){
  502.         MessageBox(hWnd, "No header found!",
  503.         "File format error", MB_OK | MB_ICONSTOP);
  504.         return(FALSE);
  505.     }
  506.  
  507.     scroll_range = maplay_args->MPEGheader->min_number_of_frames(maplay_args->stream);
  508.     line_size = scroll_range >> 3;
  509.  
  510.     SendMessage(tracker, TBM_SETRANGEMIN, FALSE, 0);
  511.     SendMessage(tracker, TBM_SETRANGEMAX, FALSE, scroll_range);
  512.     SendMessage(tracker, TBM_SETPOS, TRUE, 0);
  513.     SendMessage(tracker, TBM_SETTICFREQ, scroll_range>>4, 1);
  514.     SendMessage(tracker, TBM_SETLINESIZE, 0, line_size);
  515.  
  516.     EnableMenuItem(mainmenu,CM_AUDIOPROPERTIES, MF_ENABLED);
  517.     EnableMenuItem(mainmenu,CM_OPTIONS, MF_ENABLED);
  518.     EnableWindow(tracker, TRUE);
  519.  
  520.     return(TRUE);
  521. }
  522.  
  523. BOOL reinit_MCI()
  524. {
  525.     MPEG   = FALSE;
  526.    CDMode = CDAP(szName);
  527.  
  528.     EnableMenuItem(mainmenu,CM_AUDIOPROPERTIES, MF_GRAYED);
  529.     EnableMenuItem(mainmenu,CM_OPTIONS, MF_GRAYED);
  530.  
  531.     lstrcpy(command, "open \"");
  532.     lstrcat(command, CDMode ? "cdaudio" : szName);
  533.     lstrcat(command, "\" alias sounder wait");
  534.     mciSendString ((LPSTR)command, Buffer, 1024, NULL);
  535.     mciSendString("set sounder time format ms wait", Buffer, 1024, NULL);
  536.     mciSendString("status sounder length wait", Buffer, 1024, NULL);
  537.  
  538.     scroll_range      = my_atoi(Buffer);
  539.     line_size         = scroll_range >> 3;
  540.  
  541.     args              = mci_args;
  542.  
  543.      args->hWnd  = hWnd;
  544.    args->mutex = CreateMutex(NULL, FALSE, "m");
  545.    args->stop  = FALSE;
  546.    args->done  = FALSE;
  547.  
  548.     args->position_change = FALSE;
  549.     args->desired_position = 0;
  550.  
  551.     mci_args->playing = FALSE;
  552.  
  553.     SendMessage(tracker, TBM_SETRANGEMIN, FALSE, 0);
  554.     SendMessage(tracker, TBM_SETRANGEMAX, FALSE, scroll_range);
  555.     SendMessage(tracker, TBM_SETPOS, TRUE, 0);
  556.     SendMessage(tracker, TBM_SETTICFREQ, scroll_range >> 4, 1);
  557.     SendMessage(tracker, TBM_SETLINESIZE, 0, line_size);
  558.     EnableWindow(tracker, TRUE);
  559.  
  560.     return (TRUE);
  561. }
  562.  
  563.  
  564. BOOL WaveP(LPSTR t)
  565. // Check if the file is a format the Windows multimedia system supports.
  566. {
  567.     return ((lstrcmp(t + lstrlen(t)-3, "WAV") == 0) ||
  568.               (lstrcmp(t + lstrlen(t)-3, "wav") == 0) ||
  569.               (lstrcmp(t + lstrlen(t)-3, "MID") == 0) ||
  570.               (lstrcmp(t + lstrlen(t)-3, "mid") == 0) ||
  571.               (lstrcmp(t + lstrlen(t)-3, "CDA") == 0) ||
  572.               (lstrcmp(t + lstrlen(t)-3, "cda") == 0));
  573. }
  574.  
  575. BOOL CDAP(LPSTR t)
  576. {
  577.     return ((lstrcmp(t + lstrlen(t)-3, "CDA") == 0) ||
  578.               (lstrcmp(t + lstrlen(t)-3, "cda") == 0));
  579. }
  580.  
  581. BOOL ListP(LPSTR t)
  582. {
  583.     return ((lstrcmp(t + lstrlen(t)-3, "TXT") == 0) ||
  584.               (lstrcmp(t + lstrlen(t)-3, "txt") == 0) ||
  585.            (lstrcmp(t + lstrlen(t)-3, "LST") == 0) ||
  586.            (lstrcmp(t + lstrlen(t)-3, "lst") == 0)) ;
  587. }
  588.  
  589.  
  590. LPSTR Proper_Filename(LPSTR s)
  591. {
  592.     int32 length = lstrlen(s);
  593.  
  594.     for(int32 i=length; i>=0; --i)
  595.         if (s[i]=='\\')
  596.             return (s+i+1);
  597.     return(s);
  598. }
  599.  
  600. void CDTrack_Number(LPSTR s, LPSTR dest)
  601. {
  602.     int32 length = lstrlen(s);
  603.    int32 chars_to_copy = 1;
  604.    int32 i = length - 5;
  605.  
  606.    while ((s[i]!='k') && (i>=0)) {
  607.        chars_to_copy++;
  608.       i--;
  609.    }
  610.  
  611.    do {
  612.        i++;
  613.       chars_to_copy--;
  614.    } while (s[i]=='0');
  615.  
  616.    lstrcpyn(s, dest, chars_to_copy);
  617.    return;
  618. }
  619.  
  620. void DisplayName(LPSTR name)
  621. {
  622.  
  623.     LoadString(hInst, IDS_NAME, (LPSTR) TitleText, 64);
  624.     lstrcat(TitleText, " - [");
  625.     if (name)
  626.         lstrcat(TitleText, Proper_Filename(name));
  627.     else
  628.         lstrcat(TitleText, FileTitle);
  629.  
  630.     lstrcat(TitleText, "]");
  631.     SetWindowText(hWnd, (LPCTSTR) TitleText);
  632.     return;
  633. }
  634.  
  635. BOOL MPEG_play()
  636. // Assumes stream, MPEGheader are already initialized
  637. {
  638.     BOOL t;
  639.     MPEG_Thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) maplay,
  640.                                         maplay_args, 0, &dwThreadId);
  641.     t = SetThreadPriority(MPEG_Thread, THREAD_PRIORITY_ABOVE_NORMAL);
  642.     return(t);
  643. }
  644.  
  645. BOOL MCI_play()
  646. {
  647.     mci_args->playing = TRUE;
  648.  
  649.    if (CDMode) {
  650.        mciSendString("set cdaudio time format tmsf", NULL, 0, NULL);
  651.         mciSendString("play cdaudio from 2 to 3 notify", Buffer, 0, hWnd);
  652.  
  653.     } else {
  654.        mciSendString ((LPSTR)"play sounder notify", Buffer, 1024, hWnd);
  655.    }
  656.  
  657.     MCI_Thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) mciplay,
  658.                                       mci_args, 0, &dwThreadId);
  659.     return(TRUE);
  660. }
  661.  
  662. BOOL Get_File_List(LPSTR listname)
  663. {
  664.     ifstream f((const char *) listname);
  665.     Cur_Index = 0;
  666.     Max_Index = 0;
  667.  
  668.     while(!(f.bad() || f.eof() || f.fail() || Max_Index>=LIST_SIZE)) {
  669.         PlayList[Max_Index] = new char[MAX_PATH];
  670.         f.getline(PlayList[Max_Index], MAX_PATH, '\n');
  671.         if ((lstrlen(PlayList[Max_Index]) > 1) &&
  672.              (GetFileAttributes(PlayList[Max_Index]) != 0xFFFFFFFF)) {
  673.             Max_Index++;
  674.       }  else {
  675.          delete [] PlayList[Max_Index];
  676.          PlayList[Max_Index] = NULL;
  677.       }
  678.     }
  679.  
  680.     f.close();
  681.  
  682.    if (Max_Index > 0) {
  683.         lstrcpy(playlist_filename, "Track 1: ");
  684.         lstrcat(playlist_filename, Proper_Filename(PlayList[0]));
  685.         SendMessage(status_bar,SB_SETTEXT, 1, (LPARAM) playlist_filename);
  686.         return(TRUE);
  687.    } else {
  688.         lstrcpy(scratch, "Unable to open the playlist \"");
  689.       lstrcat(scratch, listname);
  690.       lstrcat(scratch, "\"");
  691.        MessageBox(hWnd, scratch, "Error opening playlist", MB_OK |
  692.                  MB_ICONEXCLAMATION);
  693.        return(FALSE);
  694.    }
  695. }
  696.  
  697. BOOL File_Init()
  698. {
  699.     return (WaveP(szName) ? reinit_MCI() : reinit_MPEG());
  700. }
  701.  
  702. void Next_Song()
  703. {
  704.     if (++Cur_Index < Max_Index) {
  705.         lstrcpy(szName, PlayList[Cur_Index]);
  706.         if (File_Init()) {
  707.             ok_play();
  708.             no_stop();
  709.             lstrcpy(playlist_filename, "Track ");
  710.             lstrcat(playlist_filename, my_itoa(Cur_Index + 1, scratch, 10));
  711.             lstrcat(playlist_filename, ": ");
  712.             lstrcat(playlist_filename, Proper_Filename(szName));
  713.             SendMessage(status_bar,SB_SETTEXT, 1,(LPARAM) playlist_filename);
  714.             audio_play();
  715.         }
  716.  
  717.     } else {
  718.         if (CMDLINE)
  719.             leave();
  720.  
  721.         lstrcpy(playlist_filename, "Track 1: ");
  722.         lstrcat(playlist_filename, Proper_Filename(PlayList[0]));
  723.         SendMessage(status_bar,SB_SETTEXT, 1,(LPARAM) playlist_filename);
  724.         SendMessage(status_bar,SB_SETTEXT, 0,(LPARAM) "Ready");
  725.  
  726.         Cur_Index = 0;
  727.         lstrcpy(szName, PlayList[0]);
  728.         if (File_Init()) {
  729.             ok_play();
  730.             no_stop();
  731.             if (Repeat)
  732.                 audio_play();
  733.         }
  734.     }
  735.     return;
  736. }
  737.  
  738. void Init_List()
  739. {
  740.     ListMode = TRUE;
  741.     EnableMenuItem(mainmenu,CM_LISTPREV, MF_ENABLED);
  742.     EnableWindow(prevbut, TRUE);
  743.     EnableMenuItem(mainmenu,CM_LISTREPEAT, MF_ENABLED);
  744.     EnableMenuItem(mainmenu,CM_LISTNEXT, MF_ENABLED);
  745.     EnableWindow(nextbut, TRUE);
  746.     return;
  747. }
  748.  
  749. void gotop_List(int32 n)
  750. {
  751.     CMDLINE = FALSE;
  752.     clear_sound();
  753.  
  754.     Cur_Index += n;
  755.     if (Cur_Index >= Max_Index)
  756.         Cur_Index -= Max_Index;
  757.     else if (Cur_Index <= -1)
  758.         Cur_Index += Max_Index;
  759.  
  760.     Next_Song();
  761.     return;
  762. }
  763.  
  764. void no_list()
  765. {
  766.     int32 i;
  767.  
  768.     ListMode = FALSE;
  769.     EnableMenuItem(mainmenu,CM_LISTPREV, MF_GRAYED);
  770.     EnableWindow(prevbut, FALSE);
  771.     EnableMenuItem(mainmenu,CM_LISTREPEAT, MF_GRAYED);
  772.     EnableMenuItem(mainmenu,CM_LISTNEXT, MF_GRAYED);
  773.     EnableWindow(nextbut, FALSE);
  774.  
  775.     SendMessage(status_bar,SB_SETTEXT, 1, NULL);
  776.  
  777.     for(i=0; i<Max_Index; i++) {
  778.         delete [] PlayList[i];
  779.         PlayList[i] = NULL;
  780.     }
  781.  
  782.     Cur_Index = 0;
  783.     Max_Index = 0;
  784.  
  785.     return;
  786. }
  787.  
  788. void update_timewin(int32 num)
  789. {
  790.     if (MPEG)
  791.         SendMessage(status_bar, SB_SETTEXT, 2,
  792.                        (LPARAM) time_string(
  793.                    (int32) (num * maplay_args->MPEGheader->ms_per_frame()),
  794.                     scratch));
  795.     else
  796.         SendMessage(status_bar, SB_SETTEXT, 2,
  797.                        (LPARAM) time_string(num, scratch));
  798.  
  799.     return;
  800. }
  801.  
  802. BOOL file_load()
  803. {
  804.     clear_sound();
  805.  
  806.    no_list();
  807.     if (ListP(szName)) {
  808.        if  (Get_File_List(szName)) {
  809.          DisplayName(Proper_Filename(szName));
  810.             Init_List();
  811.             lstrcpy(szName, PlayList[0]);
  812.       } else {
  813.            return(FALSE);
  814.       }
  815.  
  816.          if (!File_Init())
  817.             return(FALSE);
  818.  
  819.    } else {
  820.  
  821.          if (!File_Init())
  822.             return(FALSE);
  823.  
  824.       DisplayName(Proper_Filename(szName));
  825.  
  826.    }
  827.  
  828.     ok_play();
  829.     no_stop();
  830.  
  831.     EnableMenuItem(mainmenu,CM_AUDIOREPEAT, MF_ENABLED);
  832.     EnableWindow(rewbut, TRUE);
  833.     EnableMenuItem(mainmenu, CM_AUDIOREWIND, MF_ENABLED);
  834.     EnableWindow(ffbut, TRUE);
  835.     EnableMenuItem(mainmenu, CM_AUDIOFAST_FORWARD, MF_ENABLED);
  836.  
  837.     SendMessage(status_bar, SB_SETTEXT, 0, (LPARAM) "Ready");
  838.     SendMessage(status_bar, SB_SETTEXT, 2, (LPARAM) "000:00");
  839.  
  840.    return(TRUE);
  841. }
  842.  
  843.  
  844. void file_open()
  845. {
  846.     CMDLINE = FALSE;
  847.  
  848. //   clear_sound();
  849.  
  850.     if (AppFileOpen())
  851.       file_load();
  852.  
  853.     return;
  854. }
  855.  
  856. void leave()
  857. {
  858.     clear_sound();
  859.    no_list();
  860.     DestroyWindow(hWnd);
  861.  
  862.     return;
  863. }
  864.  
  865. void audio_play()
  866. {
  867.     if (can_play) {
  868.         no_play();
  869.  
  870.         if (MPEG) {
  871.             if (paused && MPEG_Thread) {
  872.                 paused = FALSE;
  873.                 waveOutRestart(*phwo);
  874.                 ResumeThread(MPEG_Thread);
  875.             } else {
  876.                 MPEG_play();
  877.          }
  878.         } else {
  879.             MCI_play();
  880.         }
  881.         SendMessage(status_bar,SB_SETTEXT, 0,(LPARAM) "Playing...");
  882.     }
  883.     return;
  884. }
  885.  
  886. void audio_pause()
  887. {
  888.     if (can_pause) {
  889.  
  890.       can_pause = FALSE;
  891.         paused    = TRUE;
  892.         CMDLINE   = FALSE;
  893.  
  894.         if (MPEG) {
  895.             SuspendThread(MPEG_Thread);
  896.             waveOutPause(*phwo);
  897.         } else {
  898.             mci_args->playing = FALSE;
  899.             mciSendString ((LPSTR)"pause sounder", NULL, 0, NULL);
  900.         }
  901.         ok_play();
  902.         SendMessage(status_bar, SB_SETTEXT, 0,(LPARAM) "Paused");
  903.         return;
  904.    }
  905. }
  906.  
  907. void audio_stop()
  908. {
  909.     if (can_stop) {
  910.  
  911.         clear_sound();
  912.  
  913.       can_stop = FALSE;
  914.        CMDLINE  = FALSE;
  915.       paused   = FALSE;
  916.       playing  = FALSE;
  917.  
  918.         File_Init();
  919.         ok_play();
  920.         no_stop();
  921.    }
  922.  
  923.     return;
  924. }
  925.  
  926. void audio_properties()
  927. {
  928.      char MPEGinfo[1024];
  929.  
  930.      lstrcpy(MPEGinfo, "Layer :  ");
  931.      lstrcat(MPEGinfo, maplay_args->MPEGheader->layer_string());
  932.      lstrcat(MPEGinfo, "Checksums? : ");
  933.      lstrcat(MPEGinfo, maplay_args->MPEGheader->checksums() ?
  934.                              "Yes" : "No");
  935.      lstrcat(MPEGinfo, "\nMode : ");
  936.      lstrcat(MPEGinfo, maplay_args->MPEGheader->mode_string());
  937.      lstrcat(MPEGinfo, "Original?        : ");
  938.      lstrcat(MPEGinfo, maplay_args->MPEGheader->original() ?
  939.                              "Yes" : "No");
  940.      lstrcat(MPEGinfo, "\nSample Frequency : ");
  941.      lstrcat(MPEGinfo, maplay_args->MPEGheader->sample_frequency_string ());
  942.      lstrcat(MPEGinfo, "Copyright?     : ");
  943.      lstrcat(MPEGinfo, maplay_args->MPEGheader->copyright() ?
  944.                              "Yes" : "No");
  945.      lstrcat(MPEGinfo, "\nBitrate: ");
  946.      lstrcat(MPEGinfo, maplay_args->MPEGheader->bitrate_string());
  947.  
  948.      lstrcat(MPEGinfo, "\n\nFrames  :  ");
  949.      lstrcat(MPEGinfo, my_itoa(scroll_range, scratch, 10));
  950.      lstrcat(MPEGinfo, "\nFile Size : ");
  951.      lstrcat(MPEGinfo, my_itoa(maplay_args->stream->file_size() >> 10,
  952.                              scratch, 10));
  953.      lstrcat(MPEGinfo, " KB");
  954.  
  955.      MessageBox(hWnd, MPEGinfo, "MPEG Properties", MB_OK | MB_ICONINFORMATION);
  956.      return;
  957. }
  958.  
  959. void about()
  960. {
  961.     MessageBox(hWnd,
  962. "maplay 1.2+ for Win32 version 1.81 (04/19/97) - Pentium build.\n\n\
  963. A Full Quality MPEG-1 Audio (Layers I, II, & III) \
  964. Decoder for Windows 95 and NT.\n\
  965. Copyright ⌐ 1996, 1997 Jeff Tsay (ctsay@pasteur.eecs.berkeley.edu)\n\n\
  966. Based on maplay 1.2, Copyright ⌐ 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)\n\n\
  967. Layer III code adapted from the ISO MPEG Audio Subgroup Software Simulation \
  968. Group.\n\n\
  969. You may find information and the latest version at:\n\
  970. http://www-inst.eecs.berkeley.edu/~ctsay/mp2win32.html\n\n\
  971. Compiled with Borland C++ 5.01 courtesy of Borland International.\n\n\
  972. This program is free software. See the GNU General Public License in the file\n\
  973. COPYING for more details.",
  974. "About maplay 1.2+ for Win32", MB_OK);
  975.     return;
  976. }
  977.  
  978. #pragma argsused
  979. LRESULT APIENTRY SounderWndProc(HWND hWnd, UINT message,
  980.                                           WPARAM wParam, LPARAM lParam)
  981. {
  982.      BOOL disabled, selected;
  983.      int32 new_pos;
  984.  
  985.      switch (message)
  986.      {
  987.           case WM_CREATE:
  988.           openbut= CreateWindow ("BUTTON", NULL,
  989.                       WS_CHILD| WS_VISIBLE | WS_TABSTOP |
  990.                       BS_OWNERDRAW | BS_PUSHBUTTON,
  991.                       5, 5, 24, 24,
  992.                       hWnd, (HMENU)CM_FILEOPEN, hInst, NULL);
  993.  
  994.           playbut= CreateWindow ("BUTTON", NULL,
  995.                       WS_CHILD | WS_VISIBLE | WS_DISABLED |
  996.                       WS_TABSTOP | BS_OWNERDRAW | BS_PUSHBUTTON,
  997.                       45, 5, 24, 24,
  998.                       hWnd, (HMENU)CM_AUDIOPLAY, hInst,
  999.                       NULL);
  1000.  
  1001.           pausebut= CreateWindow ("BUTTON", NULL,
  1002.                         WS_CHILD| WS_VISIBLE| WS_DISABLED |
  1003.                         WS_TABSTOP | BS_OWNERDRAW | BS_PUSHBUTTON,
  1004.                         69, 5, 24, 24,
  1005.                         hWnd, (HMENU)CM_AUDIOPAUSE, hInst, NULL);
  1006.  
  1007.           stopbut= CreateWindow ("BUTTON", NULL,
  1008.                       WS_CHILD| WS_VISIBLE | WS_DISABLED |
  1009.                       WS_TABSTOP | BS_OWNERDRAW | BS_PUSHBUTTON,
  1010.                         93, 5, 24, 24,
  1011.                       hWnd, (HMENU)CM_AUDIOSTOP, hInst, NULL);
  1012.  
  1013.           rewbut=  CreateWindow ("BUTTON", NULL,
  1014.                       WS_CHILD| WS_VISIBLE | WS_DISABLED |
  1015.                       WS_TABSTOP | BS_PUSHBUTTON | BS_OWNERDRAW,
  1016.                       157, 5, 24, 24,
  1017.                       hWnd, (HMENU)CM_AUDIOREWIND, hInst, NULL);
  1018.  
  1019.              ffbut= CreateWindow ("BUTTON", NULL,
  1020.                       WS_CHILD| WS_VISIBLE | WS_DISABLED |
  1021.                       WS_TABSTOP | BS_PUSHBUTTON | BS_OWNERDRAW,
  1022.                       181, 5, 24, 24,
  1023.                       hWnd, (HMENU)CM_AUDIOFAST_FORWARD, hInst, NULL);
  1024.  
  1025.           prevbut= CreateWindow ("BUTTON", NULL,
  1026.                       WS_CHILD| WS_VISIBLE | WS_DISABLED |
  1027.                       WS_TABSTOP | BS_PUSHBUTTON | BS_OWNERDRAW,
  1028.                       133, 5, 24, 24,
  1029.                       hWnd, (HMENU)CM_LISTPREV, hInst, NULL);
  1030.  
  1031.           nextbut= CreateWindow ("BUTTON", NULL,
  1032.                       WS_CHILD| WS_VISIBLE | WS_DISABLED |
  1033.                       WS_TABSTOP | BS_PUSHBUTTON | BS_OWNERDRAW,
  1034.                       205, 5, 24, 24,
  1035.                       hWnd, (HMENU)CM_LISTNEXT, hInst, NULL);
  1036.  
  1037.          aboutbut= CreateWindow ("BUTTON", NULL,
  1038.                       WS_CHILD| WS_VISIBLE | WS_TABSTOP |
  1039.                       BS_PUSHBUTTON | BS_OWNERDRAW,
  1040.                       245, 5, 24, 24,
  1041.                       hWnd, (HMENU)CM_HELPABOUT, hInst, NULL);
  1042.  
  1043.           tracker= CreateWindow(TRACKBAR_CLASS, NULL,
  1044.                       WS_CHILD | WS_VISIBLE | WS_TABSTOP |
  1045.                       WS_DISABLED | TBS_AUTOTICKS,
  1046.                       5, 34, 263, 30, hWnd, (HMENU) 8, hInst,  NULL);
  1047.  
  1048.       status_bar= CreateStatusWindow(WS_CHILD | WS_VISIBLE | SBT_NOBORDERS,
  1049.                       "No file", hWnd, 0);
  1050.  
  1051.           SendMessage(status_bar, SB_SETPARTS, 4, (LPARAM) panes);
  1052.           return(DefWindowProc(hWnd, message, wParam, lParam));
  1053.  
  1054.           case WM_DRAWITEM:
  1055.           hdc = GetDC(hWnd);
  1056.           dis = (DRAWITEMSTRUCT *) lParam;
  1057.           disabled = (dis->itemState & ODS_DISABLED) == ODS_DISABLED;
  1058.           selected = (dis->itemState & ODS_SELECTED) == ODS_SELECTED;
  1059.  
  1060.           switch (dis->CtlType) {
  1061.  
  1062.           case ODT_BUTTON:
  1063.           if (dis->hwndItem == openbut)
  1064.             if (selected)
  1065.                     DrawIcon(hdc, 5, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_9)));
  1066.             else
  1067.                 DrawIcon(hdc, 5, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_12)));
  1068.           else if (dis->hwndItem == playbut)
  1069.             if (disabled)
  1070.                 DrawIcon(hdc, 45, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_14)));
  1071.             else
  1072.                 if (selected)
  1073.                     DrawIcon(hdc, 45, 5, LoadIcon(hInst,MAKEINTRESOURCE(ICON_18)));
  1074.                 else
  1075.                     DrawIcon(hdc, 45, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_13)));
  1076.           else if (dis->hwndItem == pausebut)
  1077.             if (disabled)
  1078.               DrawIcon(hdc, 69, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_4)));
  1079.             else
  1080.                 if (selected)
  1081.                   DrawIcon(hdc, 69, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_24)));
  1082.                 else
  1083.                   DrawIcon(hdc, 69, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_6)));
  1084.           else if (dis->hwndItem == stopbut)
  1085.             if (disabled)
  1086.               DrawIcon(hdc, 93, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_3)));
  1087.             else
  1088.               if (selected)
  1089.                   DrawIcon(hdc, 93, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_10)));
  1090.               else
  1091.                   DrawIcon(hdc, 93, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_5)));
  1092.           else if (dis->hwndItem == aboutbut)
  1093.               if (selected)
  1094.                 DrawIcon(hdc, 245, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_21)));
  1095.               else
  1096.                 DrawIcon(hdc, 245, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_15)));
  1097.           else if (dis->hwndItem == rewbut)
  1098.             if (disabled)
  1099.                 DrawIcon(hdc, 157, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_8)));
  1100.             else
  1101.                 if (selected)
  1102.                     DrawIcon(hdc, 157, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_22)));
  1103.                 else
  1104.                     DrawIcon(hdc, 157, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_7)));
  1105.           else if (dis->hwndItem == ffbut)
  1106.             if (disabled)
  1107.                 DrawIcon(hdc, 181, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_17)));
  1108.             else
  1109.                 if (selected)
  1110.                     DrawIcon(hdc, 181, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_23)));
  1111.                 else
  1112.                     DrawIcon(hdc, 181, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_16)));
  1113.  
  1114.           else if (dis->hwndItem == prevbut)
  1115.             if (disabled)
  1116.                 DrawIcon(hdc, 133, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_26)));
  1117.             else
  1118.                 if (selected)
  1119.                     DrawIcon(hdc, 133, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_27)));
  1120.                 else
  1121.                     DrawIcon(hdc, 133, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_20)));
  1122.           else if (dis->hwndItem == nextbut)
  1123.             if (disabled)
  1124.                 DrawIcon(hdc, 205, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_29)));
  1125.             else
  1126.                 if (selected)
  1127.                     DrawIcon(hdc, 205, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_30)));
  1128.                 else
  1129.                     DrawIcon(hdc, 205, 5, LoadIcon(hInst, MAKEINTRESOURCE(ICON_28)));
  1130.           break;
  1131.           }
  1132.  
  1133.           ReleaseDC(hWnd, hdc);
  1134.           return(DefWindowProc(hWnd, message, wParam, lParam));
  1135.  
  1136.           case WM_COMMAND:
  1137.           switch (GET_WM_COMMAND_ID(wParam, lParam))
  1138.             {
  1139.                  case CM_FILEOPEN:
  1140.                  file_open();
  1141.                  break;
  1142.  
  1143.                  case CM_FILEEXIT:
  1144.                  leave();
  1145.                  break;
  1146.  
  1147.                  case CM_AUDIOPLAY:
  1148.                  audio_play();
  1149.                  break;
  1150.  
  1151.                  case CM_AUDIOPAUSE:
  1152.                  audio_pause();
  1153.                  break;
  1154.  
  1155.                  case CM_AUDIOSTOP:
  1156.                  audio_stop();
  1157.                  break;
  1158.  
  1159.                  case CM_AUDIOREWIND:
  1160.                  CMDLINE   = FALSE;
  1161.                  scrolling = TRUE;
  1162.  
  1163.                  new_pos = SendMessage(tracker, TBM_GETPOS, 0, 0);
  1164.                  if ((new_pos -= line_size) < 0)
  1165.                         new_pos = 0;
  1166.  
  1167.                  WaitForSingleObject(args->mutex, INFINITE);
  1168.                  args->desired_position = new_pos;
  1169.  
  1170.                  if (!args->position_change) {
  1171.                     args->position_change = TRUE;
  1172.                     if (!paused && playing)
  1173.                         PostMessage(status_bar,SB_SETTEXT, 0,
  1174.                                  (LPARAM) "Seeking...");
  1175.                  }
  1176.                  ReleaseMutex(args->mutex);
  1177.  
  1178.                  SendMessage(tracker, TBM_SETPOS, (WPARAM) TRUE, new_pos);
  1179.                  break;
  1180.  
  1181.                  case CM_AUDIOFAST_FORWARD:
  1182.                  CMDLINE   = FALSE;
  1183.  
  1184.                  new_pos = SendMessage(tracker, TBM_GETPOS, 0, 0);
  1185.                  if ((new_pos += line_size) < scroll_range) {
  1186.  
  1187.                  scrolling = TRUE;
  1188.                     WaitForSingleObject(args->mutex, INFINITE);
  1189.                      args->desired_position = new_pos;
  1190.                 scrolling = TRUE;
  1191.  
  1192.                      if (!args->position_change) {
  1193.                     args->position_change = TRUE;
  1194.  
  1195.                           if (!paused && playing)
  1196.                                 PostMessage(status_bar,SB_SETTEXT, 0,
  1197.                                         (LPARAM) "Seeking...");
  1198.                 }
  1199.                      ReleaseMutex(args->mutex);
  1200.  
  1201.                      SendMessage(tracker, TBM_SETPOS, (WPARAM) TRUE, new_pos);
  1202.              }
  1203.                  break;
  1204.  
  1205.  
  1206.                  case CM_AUDIOREPEAT:
  1207.                  CMDLINE = FALSE;
  1208.                  // Beautiful C++ style, but Borland doesn't like this:
  1209.  
  1210.                  if (Repeat = !Repeat) {
  1211.                      CheckMenuItem(mainmenu, CM_AUDIOREPEAT, MF_CHECKED);
  1212.                      SendMessage(status_bar,SB_SETTEXT, 3,(LPARAM) "R");
  1213.                  } else {
  1214.                      CheckMenuItem(mainmenu, CM_AUDIOREPEAT, MF_UNCHECKED);
  1215.                      SendMessage(status_bar,SB_SETTEXT, 3,(LPARAM) "");
  1216.                  }
  1217.                  break;
  1218.  
  1219.                  case CM_OPTIONS:
  1220.                  if (DialogBox(hInst, MAKEINTRESOURCE(OPTIONS), hWnd,
  1221.                                Options) == -1)
  1222.                  MessageBox(hWnd, "Unable to open options dialog box.",
  1223.                                "Error Opening Dialog Box", MB_OK);
  1224.                  break;
  1225.  
  1226.                  case CM_AUDIOPROPERTIES:
  1227.                  audio_properties();
  1228.                  break;
  1229.  
  1230.                  case CM_LISTPREV:
  1231.                  gotop_List(-2);
  1232.                  break;
  1233.  
  1234.                  case CM_LISTREPEAT:
  1235.                  gotop_List(-1);
  1236.                  break;
  1237.  
  1238.                  case CM_LISTNEXT:
  1239.                  gotop_List(0);
  1240.                  break;
  1241.  
  1242.                  case CM_HELPABOUT:
  1243.                  about();
  1244.                  break;
  1245.  
  1246.                  default:
  1247.                  break;
  1248.           }
  1249.           break;
  1250.  
  1251.           case WM_HSCROLL:
  1252.             // Process scroll messages by sending notification to
  1253.           // appropriate thread.
  1254.           LRESULT new_pos;
  1255.  
  1256.           switch (LOWORD(wParam)) {
  1257.                   case TB_LINEUP:
  1258.                   case TB_LINEDOWN:
  1259.                   case TB_PAGEDOWN:
  1260.                   case TB_PAGEUP:
  1261.                   CMDLINE = FALSE;
  1262.                   new_pos = SendMessage(tracker, TBM_GETPOS, 0, 0);
  1263.  
  1264.                   if ((new_pos  <= scroll_range) && (new_pos >= 0)) {
  1265.                       scrolling = TRUE;
  1266.                WaitForSingleObject(args->mutex, INFINITE);
  1267.                       args->desired_position = new_pos;
  1268.  
  1269.                       if (!args->position_change) {
  1270.                           args->position_change = TRUE;
  1271.                           if (!paused && playing)
  1272.                               SendMessage(status_bar,SB_SETTEXT, 0,
  1273.                                  (LPARAM) "Seeking...");
  1274.                }
  1275.                     ReleaseMutex(args->mutex);
  1276.             }
  1277.                 break;
  1278.  
  1279.                 case TB_THUMBTRACK:
  1280.                 scrolling = TRUE;        // We are scrolling, don't allow
  1281.                                             // scroll position changes by threads.
  1282.                 new_pos = SendMessage(tracker, TBM_GETPOS, 0, 0);
  1283.                 update_timewin((int32) new_pos);
  1284.                 break;
  1285.  
  1286.             case TB_THUMBPOSITION:    // Scroll box placed somewhere
  1287.             WaitForSingleObject(args->mutex, INFINITE);
  1288.                  args->desired_position = SendMessage(tracker, TBM_GETPOS, 0, 0);
  1289.  
  1290.                 if(!args->position_change) {
  1291.                     args->position_change = TRUE;
  1292.                     if (!paused && playing)
  1293.                         SendMessage(status_bar,SB_SETTEXT, 0,
  1294.                                     (LPARAM) "Seeking...");
  1295.                 }
  1296.                 ReleaseMutex(args->mutex);
  1297.                 break;
  1298.         }
  1299.           return(0);
  1300.  
  1301.           case SCROLL_POS:    // Process new position data from threads.
  1302.           if (!scrolling && (wParam <=scroll_range) && playing) {
  1303.                 SendMessage(tracker, TBM_SETPOS, TRUE, wParam);
  1304.                 update_timewin((int32) wParam);
  1305.           }
  1306.           return(0);
  1307.  
  1308.           case SEEK_ACK:        // Seek completed, allow scroll changes.
  1309.         if (playing) {
  1310.               SendMessage(status_bar, SB_SETTEXT, 0, (LPARAM) "Playing...");
  1311.               scrolling = FALSE;
  1312.         }
  1313.           return(0);
  1314.  
  1315.           case MM_MCINOTIFY:
  1316.                 switch (wParam) {
  1317.                     case MCI_NOTIFY_SUCCESSFUL:
  1318.                     clear_sound();
  1319.  
  1320.                     if (ListMode) {
  1321.                         Next_Song();
  1322.                         return(0);
  1323.                     }
  1324.  
  1325.                     reinit_MCI();
  1326.                     ok_play();
  1327.                     no_stop();
  1328.  
  1329.                     if (Repeat) {
  1330.                         no_play();
  1331.                         MCI_play();
  1332.                         SendMessage(status_bar, SB_SETTEXT, 0, (LPARAM) "Playing...");
  1333.                     } else {
  1334.                         playing=FALSE;
  1335.                         if (CMDLINE)
  1336.                             leave();
  1337.                         SendMessage(status_bar, SB_SETTEXT, 0, (LPARAM) "Stopped");
  1338.                     }
  1339.                     break;
  1340.                 }
  1341.           break;
  1342.  
  1343.         case WM_DROPFILES:
  1344.         CMDLINE = FALSE;
  1345.  
  1346.         DragAcceptFiles(hWnd, TRUE);
  1347.         DragQueryFile((HDROP) wParam, 0, szName, MAX_PATH);
  1348.           DragFinish((HDROP) wParam);
  1349.  
  1350.         if (file_load())
  1351.             audio_play();
  1352.         break;
  1353.  
  1354.           case WM_DESTROY:
  1355.           PostQuitMessage(0);   // this is the end...
  1356.           break;
  1357.  
  1358.           case WM_CLOSE:
  1359.           // Tell windows to destroy our window.
  1360.           leave();
  1361.           break;
  1362.  
  1363.           case WM_THREADEND:
  1364.           clear_sound();
  1365.  
  1366.           if (ListMode) {
  1367.               Next_Song();
  1368.               return(0);
  1369.           }
  1370.  
  1371.         if (CMDLINE)
  1372.            leave();
  1373.           else {
  1374.                playing = FALSE;
  1375.               reinit_MPEG(); // We know file is ok already.
  1376.  
  1377.               if (Repeat) {
  1378.                 MPEG_play();
  1379.              SendMessage(status_bar,SB_SETTEXT, 0,(LPARAM) "Playing...");
  1380.               } else {
  1381.                 ok_play();
  1382.                 no_stop();
  1383.                 SendMessage(status_bar,SB_SETTEXT, 0,(LPARAM) "Stopped");
  1384.               }
  1385.         }
  1386.           break;
  1387.  
  1388.           case WM_CMDLINEFILE:
  1389.           lstrcpy(szName, (LPSTR) lParam);
  1390.  
  1391.           if (wParam == 2) {
  1392.  
  1393.              ListMode = TRUE;
  1394.                 Init_List();
  1395.                 Get_File_List(szName);
  1396.             DisplayName(szName);
  1397.                 lstrcpy(szName, PlayList[0]);
  1398.                 File_Init();
  1399.             ok_play();
  1400.                 audio_play();
  1401.  
  1402.           } else {
  1403.  
  1404.               if (wParam == 0) {
  1405.                     playing=TRUE;
  1406.                     no_play();
  1407.                     reinit_MCI();
  1408.                     MCI_play();
  1409.               } else {
  1410.                   clear_sound();
  1411.                   if (!reinit_MPEG())
  1412.                         return(1);
  1413.                   playing=FALSE;
  1414.                   no_play();
  1415.                   MPEG_play();
  1416.               }
  1417.               SendMessage(status_bar,SB_SETTEXT, 0,(LPARAM) "Playing...");
  1418.            DisplayName(szName);
  1419.           }
  1420.  
  1421.  
  1422.           EnableWindow(rewbut, TRUE);
  1423.           EnableMenuItem(mainmenu, CM_AUDIOREWIND, MF_ENABLED);
  1424.           EnableWindow(ffbut, TRUE);
  1425.           EnableMenuItem(mainmenu, CM_AUDIOFAST_FORWARD, MF_ENABLED);
  1426.           break;
  1427.  
  1428.           case WM_CHAR:
  1429.             switch(wParam) {
  1430.                 case 'o':
  1431.                 file_open();
  1432.                 break;
  1433.  
  1434.                 case ' ':
  1435.                 audio_play();
  1436.                 break;
  1437.  
  1438.                 case 's':
  1439.                 audio_stop();
  1440.                 break;
  1441.  
  1442.                 case '"':
  1443.                 case 'p':
  1444.                 audio_pause();
  1445.                 break;
  1446.  
  1447.                 case '?':
  1448.                 about();
  1449.                 break;
  1450.  
  1451.                 case 'x':
  1452.                 case 'q':
  1453.                 leave();
  1454.                 break;
  1455.             }
  1456.           break;
  1457.  
  1458.           case 312:        // CTLCOLOR message for trackbar
  1459.           if ((HWND) lParam == tracker)
  1460.               return((DWORD) GetStockObject(LTGRAY_BRUSH));
  1461.  
  1462.           default:
  1463.           // Let windows handle all messages we choose to ignore.
  1464.           return(DefWindowProc(hWnd, message, wParam, lParam));
  1465.      }
  1466.      return(0);
  1467. }
  1468.  
  1469. void leave_options(HWND hDlg, BOOL save)
  1470. {
  1471.     enum e_channels new_mode;
  1472.  
  1473.    if (save) {
  1474.  
  1475.  
  1476.         if (IsDlgButtonChecked(hDlg, IDC_STEREO))
  1477.             new_mode = both;
  1478.         else if (IsDlgButtonChecked(hDlg, IDC_LEFT))
  1479.             new_mode = left;
  1480.         else if (IsDlgButtonChecked(hDlg, IDC_RIGHT))
  1481.             new_mode = right;
  1482.       else
  1483.           new_mode = downmix;
  1484.  
  1485.         if (mode != new_mode) {
  1486.  
  1487.             if (!(playing || paused)) {
  1488.  
  1489.             mode = new_mode;
  1490.             reinit_MPEG();
  1491.  
  1492.             } else {
  1493.                 MessageBox(hDlg, "You must stop the stream before modifying the \
  1494. decoding options.", "Options error", MB_ICONEXCLAMATION | MB_OK);
  1495.             }
  1496.         }
  1497.    }
  1498.  
  1499.       EndDialog(hDlg, TRUE);
  1500.  
  1501.     return;
  1502. }
  1503.  
  1504. #pragma argsused
  1505. BOOL WINAPI Options(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1506. {
  1507.      switch (message) {
  1508.  
  1509.         case WM_INITDIALOG:
  1510.  
  1511.         switch (mode) {
  1512.             case both:
  1513.             CheckRadioButton(hDlg, IDC_STEREO, IDC_DOWNMIX, IDC_STEREO);
  1514.             break;
  1515.  
  1516.             case left:
  1517.             CheckRadioButton(hDlg, IDC_STEREO, IDC_DOWNMIX, IDC_LEFT);
  1518.             break;
  1519.  
  1520.             case right:
  1521.             CheckRadioButton(hDlg, IDC_STEREO, IDC_DOWNMIX, IDC_RIGHT);
  1522.          break;
  1523.  
  1524.          case downmix:
  1525.          CheckRadioButton(hDlg, IDC_STEREO, IDC_DOWNMIX, IDC_DOWNMIX);
  1526.             break;
  1527.         }
  1528.         return(TRUE);
  1529.  
  1530.         case WM_CLOSE:
  1531.         leave_options(hDlg, TRUE);
  1532.         return(TRUE);
  1533.  
  1534.         case WM_COMMAND:
  1535.         {
  1536.             switch (GET_WM_COMMAND_ID(wParam, lParam))  {
  1537.  
  1538.               case IDC_STEREO:
  1539.               CheckRadioButton(hDlg, IDC_STEREO, IDC_DOWNMIX, IDC_STEREO);
  1540.               return(TRUE);
  1541.  
  1542.               case IDC_LEFT:
  1543.               CheckRadioButton(hDlg, IDC_STEREO, IDC_DOWNMIX, IDC_LEFT);
  1544.               return(TRUE);
  1545.  
  1546.               case IDC_RIGHT:
  1547.               CheckRadioButton(hDlg, IDC_STEREO, IDC_DOWNMIX, IDC_RIGHT);
  1548.               return(TRUE);
  1549.  
  1550.            case IDC_DOWNMIX:
  1551.               CheckRadioButton(hDlg, IDC_STEREO, IDC_DOWNMIX, IDC_DOWNMIX);
  1552.            return(TRUE);
  1553.  
  1554.               case IDOK:
  1555.               leave_options(hDlg, TRUE);
  1556.               return(TRUE);
  1557.  
  1558.            case IDCANCEL:
  1559.            leave_options(hDlg, FALSE);
  1560.  
  1561.               default:
  1562.               return(FALSE);
  1563.             }
  1564.         }
  1565.  
  1566.         default:
  1567.         return(FALSE);
  1568.      }
  1569. }
  1570.  
  1571.