home *** CD-ROM | disk | FTP | other *** search
/ Windows 95 Secrets / Secrets2.iso / Audio / WAV / MaplayP / _SETUP.1 / mci_obuf.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-06-05  |  8.5 KB  |  333 lines

  1. /* mci_obuf.cpp
  2.  
  3.     Output buffer class for Win32 multimedia system written by
  4.    Jeff Tsay (ctsay@pasteur.eecs.berkeley.edu
  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.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
  19.  
  20. /* Writing to Windows multimedia system with such a small
  21.     buffer won't do, so we increase buffer size, and ignore
  22.     most of the writes. Also we need to have a queue of 3 wave
  23.     headers for smooth playback. The last header and the oldest
  24.     header play while the current one is being filled in.
  25.  
  26.     Note that this does not support 8-bit soundcards yet! I don't
  27.     know what the data format is to that */
  28.  
  29. /* Changes since last version: changed GMEM_MOVEABLE to GMEM_FIXED
  30.     which is a bit faster, according to the suggestions of Paul Forgey.
  31.     clear_buffer() added for seeking. Changes int16 parameter to int32
  32.     for minor speed improvement. Last edit: 06/29/96. */
  33.  
  34. /* More changes: eliminated GlobalLock on the fixed memory, which
  35.    is unnecessary.
  36.  
  37.    Added a function clear_buffer(), which clears the audio data
  38.    when a seek is made by the user.
  39.  
  40.    Also added a function set_stop_flag() which
  41.    sets a flag when playback is interrupted by the user. Then
  42.    no attempt is made to unprepare headers after waveReset() is
  43.    called by the main thread.
  44.  
  45.    Last edit: 10/12/96. */
  46.  
  47. /* Replaced usage of the PCMWAVEFORMAT structure with the more up
  48.    to date WAVEFORMATEX structure.
  49.  
  50.    According to the suggestions of Sergey Kuzmin, replaced
  51.    GlobalAlloc and GlobalFree with new and delete, which should
  52.    eliminate memory leaks.
  53.  
  54.    Last edit: 12/31/96. */
  55.  
  56. #ifdef  __WIN32__
  57. #define STRICT
  58. #include <windows.h>
  59.  
  60. #ifndef WIN32GUI
  61. #include <iostream.h>
  62. #endif
  63.  
  64. #include "all.h"
  65. #include "header.h"
  66. #include "args.h"
  67. #include "obuffer.h"
  68. #include "mci_obuf.h"
  69.  
  70. MCIbuffer::MCIbuffer(uint32 number_of_channels,
  71.                             MPEG_Args *maplay_args)
  72. {
  73.   channels  = number_of_channels;
  74.   data_size = channels * BUFFERSIZE;
  75.  
  76.   if (maplay_args->MPEGheader->version() == MPEG2_LSF)
  77.           data_size >>= 1;
  78.  
  79.   if (maplay_args->MPEGheader->layer() == 1)
  80.           data_size /= 3;
  81.  
  82.   hdr_size      = sizeof(WAVEHDR);
  83.   lpwavehdr_arr = new LPWAVEHDR[3];
  84.   phwo          = maplay_args->phwo;
  85.   fillup        = 0;
  86.  
  87.   lpwf = (tWAVEFORMATEX *) new WAVEFORMATEX;
  88.  
  89.   lpwf->wBitsPerSample  = 16;  // No 8-bit support yet
  90.   lpwf->wFormatTag      = WAVE_FORMAT_PCM;
  91.   lpwf->nChannels       = (WORD) channels;
  92.   lpwf->nSamplesPerSec  = (DWORD) maplay_args->MPEGheader->frequency();
  93.   lpwf->nAvgBytesPerSec = (DWORD) channels *
  94.                                                maplay_args->MPEGheader->frequency() << 1;
  95.   lpwf->nBlockAlign     = (WORD) (channels << 1);
  96.   lpwf->cbSize          = 0;
  97.  
  98.   if (waveOutOpen(phwo, WAVE_MAPPER, (const tWAVEFORMATEX *) lpwf,
  99.                        NULL, NULL, WAVE_ALLOWSYNC) != MMSYSERR_NOERROR)
  100.   {
  101. #ifdef WIN32GUI
  102.          MessageBox(maplay_args->hWnd, "Could not open wave device.",
  103. "Audio playback error", MB_ICONSTOP | MB_OK);
  104.         ExitProcess(-1);
  105. #else
  106.         cerr << endl << "Could not open wave device." << endl;
  107. #endif
  108.         return;
  109.   }
  110.  
  111.   buffer_count = 0;
  112.  
  113.   uint32 i;
  114.  
  115.   for(i=0; i<3; i++) {
  116.       lpwavehdr_arr[i] = (LPWAVEHDR) new WAVEHDR;
  117.  
  118.      LPWAVEHDR temp = lpwavehdr_arr[i];
  119.  
  120.       if(!temp) return;
  121.  
  122.       temp->lpData = (LPSTR) new char[data_size];
  123.  
  124.       if(!temp->lpData) return;
  125.       temp->dwBufferLength  = data_size;
  126.       temp->dwBytesRecorded = 0;
  127.       temp->dwUser          = 0;  // If played, dwUser = 1
  128.       temp->dwLoops         = 0;
  129.       temp->dwFlags         = NULL;
  130.   }
  131.  
  132.   for(i=0; i<channels; i++)
  133.        bufferp[i] = i * channels;
  134.  
  135.   user_stop = 0;
  136. }
  137.  
  138. void MCIbuffer::append(uint32 channel, int16 value)
  139. {
  140.   // Need to break up the 32-bit integer into 2 8-bit bytes.
  141.   // (ignore the first two bytes - either 0x0000 or 0xffff)
  142.   // Note that Intel byte order is backwards!!!
  143.  
  144.   LPSTR temp = lpwavehdr_arr[2]->lpData;
  145.  
  146.   temp[bufferp[channel]]   = (char) (value & 0xff);
  147.   temp[bufferp[channel]+1] = (char) (value >> 8);
  148.  
  149.   bufferp[channel] += channels << 1;
  150.  
  151.   return;
  152. }
  153.  
  154. #pragma argsused
  155. void MCIbuffer::write_buffer(int32 fd)
  156. {
  157.     // Actually write only when buffer is actually full.
  158.     if ((++buffer_count & BIT_SELECT) == 0) {
  159.  
  160.         buffer_count = 0;
  161.  
  162.         // Wait for 2 completed headers
  163.         if (fillup > 1) {
  164.  
  165.             // Prepare & write newest header
  166.             waveOutPrepareHeader(*phwo, lpwavehdr_arr[2], hdr_size);
  167.             waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size);
  168.  
  169.             // Header has now been sent
  170.             lpwavehdr_arr[2]->dwUser = 1;
  171.  
  172.             wave_swap();
  173.  
  174.             // Unprepare oldest header
  175.             if (lpwavehdr_arr[2]->dwUser) {
  176.  
  177.                 while(waveOutUnprepareHeader(*phwo, lpwavehdr_arr[2],
  178.                        hdr_size) == WAVERR_STILLPLAYING)
  179.                     Sleep(SLEEPTIME);
  180.             }
  181.  
  182.         } else {
  183.  
  184.             if (++fillup == 2) {
  185.  
  186.                     // Write the previously calculated 2 headers
  187.                     waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size);
  188.                     waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size);
  189.  
  190.                     // Header has now been sent
  191.                     lpwavehdr_arr[0]->dwUser = 1;
  192.  
  193.                     wave_swap();
  194.  
  195.                     waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size);
  196.                     waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size);
  197.  
  198.                     // Header has now been sent
  199.                     lpwavehdr_arr[0]->dwUser = 1;
  200.  
  201.             } else {
  202.                 wave_swap();
  203.          }
  204.         }
  205.  
  206.         for(uint32 i=0; i<channels; i++)
  207.           bufferp[i] = i * channels;
  208.     }
  209.     return;
  210. }
  211.  
  212. void MCIbuffer::wave_swap()
  213. {
  214.     LPWAVEHDR temp   = lpwavehdr_arr[2];
  215.    lpwavehdr_arr[2] = lpwavehdr_arr[1];
  216.    lpwavehdr_arr[1] = lpwavehdr_arr[0];
  217.     lpwavehdr_arr[0] = temp;
  218.  
  219.     return;
  220. }
  221.  
  222. #ifdef SEEK_STOP
  223. void MCIbuffer::clear_buffer()
  224. // Clear all the data in the buffers
  225. {
  226.  
  227.     waveOutReset(*phwo);
  228.  
  229.    unsigned int i;
  230.  
  231.     for(i=0; i<3; i++) {
  232.  
  233.         LPWAVEHDR temp = lpwavehdr_arr[i];
  234.  
  235.         if (temp->dwUser)
  236.             waveOutUnprepareHeader(*phwo, temp, hdr_size);
  237.  
  238.         temp->dwUser = 0;
  239.  
  240.         for(unsigned int j=0; j<data_size; j++)
  241.             temp->lpData[j] = (char) 0;
  242.     }
  243.  
  244.     // Reset buffer pointers
  245.     for(i=0; i<channels; i++)
  246.         bufferp[i] = i * channels;
  247.  
  248.     // Force the buffers to fillup before playing.
  249.     fillup = buffer_count = 0;
  250. }
  251.  
  252. void MCIbuffer::set_stop_flag()
  253. // Set the flag to avoid unpreparing non-existent headers
  254. {
  255.     user_stop = 1;
  256.    return;
  257. }
  258. #endif
  259.  
  260.  
  261. MCIbuffer::~MCIbuffer()
  262. {
  263.    if (user_stop) {
  264.  
  265.      waveOutReset(*phwo);
  266.  
  267.    } else {
  268.  
  269.        if (fillup == 1) {
  270.  
  271.            // Write the last header calculated (at the top of the array).
  272.            waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size);
  273.              waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size);
  274.  
  275.          // Header has been written.
  276.            lpwavehdr_arr[0]->dwUser = 1;
  277.       }
  278.  
  279.       if (buffer_count) {
  280.  
  281.           // Write the last wave header (probably not be written due to buffer
  282.          //    size increase.)
  283.  
  284.          for(unsigned int i = bufferp[channels-1]; i < data_size; i++)
  285.                  lpwavehdr_arr[2]->lpData[i] = (char) 0;
  286.  
  287.            waveOutPrepareHeader(*phwo, lpwavehdr_arr[2], hdr_size);
  288.             waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size);
  289.  
  290.            // Header has been written.
  291.          lpwavehdr_arr[2]->dwUser = 1;
  292.          wave_swap();
  293.          }
  294.    }
  295.  
  296.     // Unprepare and free the header memory.
  297.     for (int j=2; j>=0; j--) {
  298.           if (lpwavehdr_arr[j]->dwUser && !user_stop)
  299.             while (waveOutUnprepareHeader(*phwo, lpwavehdr_arr[j], hdr_size)
  300.                   == WAVERR_STILLPLAYING)
  301.                 Sleep(SLEEPTIME);
  302.  
  303.       delete [] lpwavehdr_arr[j]->lpData;
  304.       delete lpwavehdr_arr[j];
  305.     }
  306.  
  307.    delete [] lpwavehdr_arr;
  308.     delete lpwf;
  309.  
  310.  
  311.     while(waveOutClose(*phwo) == WAVERR_STILLPLAYING);
  312.         Sleep(SLEEPTIME);
  313.  
  314.     return;
  315. }
  316.  
  317. Obuffer *create_obuffer(MPEG_Args *maplay_args)
  318. {
  319.     Obuffer *buffer;
  320.  
  321.     enum e_mode mode = maplay_args->MPEGheader->mode();
  322.    enum e_channels which_channels = maplay_args->which_c;
  323.  
  324.     if ((mode == single_channel) || (which_channels != both))
  325.         buffer = new MCIbuffer(1, maplay_args);    // mono
  326.    else
  327.         buffer = new MCIbuffer(2, maplay_args);    // stereo
  328.  
  329.    return(buffer);
  330. }
  331.  
  332. #endif // __WIN32__
  333.