home *** CD-ROM | disk | FTP | other *** search
/ PC Shareware 1997 June / PC_Shareware-1997-06.iso / manga / mp2win95 / _setup.1 / OBUFFER5.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-30  |  9.8 KB  |  386 lines

  1. /*
  2.  *  @(#) obuffer.cc 1.15, last edit: 6/23/94 13:04:36
  3.  *  @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
  4.  *  @(#) Berlin University of Technology
  5.  *
  6.  *  Idea and first implementation for u-law output with fast downsampling by
  7.  *  Jim Boucher (jboucher@flash.bu.edu)
  8.  *
  9.  *  LinuxObuffer class written by
  10.  *  Louis P. Kruger (lpkruger@phoenix.princeton.edu)
  11.  *
  12.  *  This program is free software; you can redistribute it and/or modify
  13.  *  it under the terms of the GNU General Public License as published by
  14.  *  the Free Software Foundation; either version 2 of the License, or
  15.  *  (at your option) any later version.
  16.  *
  17.  *  This program is distributed in the hope that it will be useful,
  18.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  *  GNU General Public License for more details.
  21.  *
  22.  *  You should have received a copy of the GNU General Public License
  23.  *  along with this program; if not, write to the Free Software
  24.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  */
  26.  
  27. /*
  28.  *  Changes from version 1.1 to 1.2:
  29.  *    - new LinuxObuffer class, which works with 16 bit soundcards
  30.  *      like Gravis Ultrasound, SoundBlaster 16 or Pro Audio Spectrum 16,
  31.  *      if attached to /dev/dsp
  32.  *    - ShortObuffer renamed to FileObuffer
  33.  *    - If ULAW is defined:
  34.  *      - SparcObuffer feeds mono u-law output to an amd device (u-law format).
  35.  *        The required downsampling to 8 kHz in done in the synthesis filter.
  36.  *      - FileObuffer creates u-law output at 8 kHz instead of 16 bit PCM samples.
  37.  *    - O_NDELAY flag is cleared now after a successful open syscall
  38.  *      on /dev/audio (caused problems under Solaris)
  39.  *    - options -us, -uh and -ul should work now
  40.  *    - FileObuffer can handle incomplete write syscalls now
  41.  */
  42.  
  43. /* MCIbuffer class added by Jeff Tsay (last edit: 05/18/96)
  44.     Writing to Windows multimedia system with such a small
  45.     buffer won't do, so we increase buffer size, and ignore
  46.     most of the writes. Also we need to have a queue of 3 wave
  47.     headers for smooth playback. The last header and the oldest
  48.     header play while the current one is being filled in.
  49.  
  50.     Note that this does not support 8-bit soundcards yet! I don't
  51.     know what the data format is to that */
  52.  
  53. /* Changes since last version: changed GMEM_MOVEABLE to GMEM_FIXED
  54.     which is a bit faster, according to the suggestions of Paul Forgey.
  55.     clear_buffer() added for seeking. Changes int16 parameter to int32
  56.     for minor speed improvement. Last edit: 06/29/96. */
  57.  
  58. /* More changes: eliminated GlobalLock on the fixed memory, which
  59.    is unnecessary.
  60.  
  61.    Added a function clear_buffer(), which clears the audio data
  62.    when a seek is made by the user.
  63.  
  64.    Also added a function set_stop_flag() which
  65.    sets a flag when playback is interrupted by the user. Then
  66.    no attempt is made to unprepare headers after waveReset() is
  67.    called by the main thread.
  68.  
  69.    Last edit: 10/12/96. */
  70.  
  71. /* Replaced usage of the PCMWAVEFORMAT structure with the more up
  72.    to date WAVEFORMATEX structure.
  73.  
  74.    According to the suggestions of Sergey Kuzmin, replaced
  75.    GlobalAlloc and GlobalFree with new and delete, which should
  76.    eliminate memory leaks.
  77.  
  78.    Last edit: 12/31/96. */
  79.  
  80. #define STRICT
  81. #define WIN32_LEAN_AND_MEAN
  82. #define NOMCX
  83. #define NOIME
  84. #define NOGDI
  85. #define NOUSER
  86. #define NOSOUND
  87. #define NOCOMM
  88. #define NODRIVERS
  89. #define OEMRESOURCE
  90. #define NONLS
  91. #define NOSERVICE
  92. #define NOKANJI
  93. #define NOMINMAX
  94. #define NOLOGERROR
  95. #define NOPROFILER
  96. #define NOMEMMGR
  97. #define NOLFILEIO
  98. #define NOOPENFILE
  99. #define NORESOURCE
  100. #define NOATOM
  101. #define NOLANGUAGE
  102. #define NOLSTRING
  103. #define NODBCS
  104. #define NOKEYBOARDINFO
  105. #define NOGDICAPMASKS
  106. #define NOCOLOR
  107. #define NOGDIOBJ
  108. #define NODRAWTEXT
  109. #define NOTEXTMETRIC
  110. #define NOSCALABLEFONT
  111. #define NOBITMAP
  112. #define NORASTEROPS
  113. #define NOMETAFILE
  114. #define NOSYSMETRICS
  115. #define NOSYSTEMPARAMSINFO
  116. #define NOMSG
  117. #define NOWINSTYLES
  118. #define NOWINOFFSETS
  119. #define NOSHOWWINDOW
  120. #define NODEFERWINDOWPOS
  121. #define NOVIRTUALKEYCODES
  122. #define NOKEYSTATES
  123. #define NOWH
  124. #define NOMENUS
  125. #define NOSCROLL
  126. #define NOCLIPBOARD
  127. #define NOICONS
  128. #define NOMB
  129. #define NOSYSCOMMANDS
  130. #define NOMDI
  131. #define NOCTLMGR
  132. #define NOWINMESSAGES
  133. #define NOHELP
  134. #define _WINUSER_
  135. #define __oleidl_h__
  136. #define _OLE2_H_
  137. #include <windows.h>
  138.  
  139. #include "obuffer.h"
  140. #include "obuffer5.h"  // Windows addition
  141. #include "header.h"
  142.  
  143. MCIbuffer::MCIbuffer (uint32 number_of_channels,
  144.                              Header *header,
  145.                              HWAVEOUT *phwo0)
  146. {
  147.   int32 i;
  148.   LPWAVEHDR temp;
  149.   channels= number_of_channels;
  150.   data_size= channels * BUFFERSIZE;
  151.  
  152.   hdr_size= sizeof(WAVEHDR);
  153.   lpwavehdr_arr=new LPWAVEHDR[3];
  154.   phwo=phwo0;
  155.   fillup=0;
  156.  
  157.   lpwf = (tWAVEFORMATEX *) new WAVEFORMATEX;
  158.  
  159.   lpwf->wBitsPerSample=16;  // No 8-bit support yet
  160.   lpwf->wFormatTag=WAVE_FORMAT_PCM;
  161.   lpwf->nChannels=(WORD) channels;
  162.   lpwf->nSamplesPerSec=(DWORD) header->frequency ();
  163.   lpwf->nAvgBytesPerSec=(DWORD) channels * header->frequency() << 1;
  164.   lpwf->nBlockAlign=(WORD) (channels << 1);
  165.   lpwf->cbSize = 0;
  166.  
  167.   if (waveOutOpen(phwo, WAVE_MAPPER, (const tWAVEFORMATEX *) lpwf,
  168.                      NULL, NULL, WAVE_ALLOWSYNC))
  169.         ExitThread(1L);
  170.  
  171.   buffer_count=0;
  172.  
  173.   for(i=0; i<3; i++) {
  174.       lpwavehdr_arr[i] = (LPWAVEHDR) new WAVEHDR;
  175.  
  176.       temp = lpwavehdr_arr[i];
  177.       if(!temp) ExitThread(1L);
  178.  
  179.       temp->lpData=(LPSTR) new char[data_size];
  180.  
  181.       if(!temp->lpData) ExitThread(1L);
  182.       temp->dwBufferLength=data_size;
  183.       temp->dwBytesRecorded=0L;
  184.       temp->dwUser=0L;  // If played, dwUser = 1
  185.       temp->dwLoops=0L;
  186.       temp->dwFlags=NULL;
  187.   }
  188.  
  189.   for(i=0; i<channels; i++)
  190.     bufferp[i]=i * channels;
  191.  
  192.   user_stop = 0;
  193. }
  194.  
  195. void MCIbuffer::append (uint32 channel, int32 value)
  196. {
  197.   // Need to break up the 32-bit integer into 2 8-bit bytes.
  198.   // (ignore the first two bytes - either 0x0000 or 0xffff)
  199.   // Note that Intel byte order is backwards!!!
  200.  
  201.   LPSTR temp=lpwavehdr_arr[2]->lpData;
  202.   temp[bufferp[channel]]= (char) (value & 0xff);
  203.   temp[bufferp[channel]+1] = (char) (value >> 8);
  204.   bufferp[channel]+= channels << 1;
  205.  
  206.   return;
  207. }
  208.  
  209. #pragma argsused
  210. void MCIbuffer::write_buffer (int fd)
  211. {
  212.     // Actually write only when buffer is actually full.
  213.     if ((++buffer_count & BIT_SELECT)==0) {
  214.  
  215.         int32 i;
  216.  
  217.         buffer_count=0;
  218.  
  219.         // Wait for 2 completed headers
  220.         if (fillup>1) {
  221.  
  222.             // Prepare+write newest header
  223.             while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[2],
  224.                         hdr_size))
  225.                 Sleep(SLEEPTIME);
  226.  
  227.             while(waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size))
  228.                 Sleep(SLEEPTIME);
  229.  
  230.             // Header has now been sent
  231.             lpwavehdr_arr[2]->dwUser=1L;
  232.  
  233.             wave_swap();
  234.  
  235.             // Unprepare oldest header
  236.             if (lpwavehdr_arr[2]->dwUser) {
  237.  
  238.                 while(waveOutUnprepareHeader(*phwo, lpwavehdr_arr[2],
  239.                     hdr_size)==WAVERR_STILLPLAYING)
  240.                     Sleep(SLEEPTIME);
  241.             }
  242.  
  243.         } else {
  244.  
  245.             if (++fillup == 2) {
  246.  
  247.                     // Write the previously calculated 2 headers
  248.                     while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[0],
  249.                         hdr_size))
  250.                         Sleep(SLEEPTIME);
  251.  
  252.                     while(waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size))
  253.                         Sleep(SLEEPTIME);
  254.  
  255.                     // Header has now been sent
  256.                     lpwavehdr_arr[0]->dwUser=1L;
  257.  
  258.                     wave_swap();
  259.  
  260.                     while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[0],
  261.                         hdr_size))
  262.                         Sleep(SLEEPTIME);
  263.  
  264.                     while(waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size))
  265.                         Sleep(SLEEPTIME);
  266.  
  267.                     // Header has now been sent
  268.                     lpwavehdr_arr[0]->dwUser=1L;
  269.  
  270.             } else
  271.                 wave_swap();
  272.         }
  273.  
  274.         for(i=0; i<channels; i++)
  275.           bufferp[i]=i * channels;
  276.     }
  277.     return;
  278. }
  279.  
  280. void MCIbuffer::wave_swap(void)
  281. {
  282.     int32 i;
  283.     LPWAVEHDR temp=lpwavehdr_arr[2];
  284.  
  285.     for(i=2;i>0; i--)
  286.         lpwavehdr_arr[i]=lpwavehdr_arr[i-1];
  287.  
  288.     lpwavehdr_arr[0]=temp;
  289.     return;
  290. }
  291.  
  292. void MCIbuffer::clear_buffer(void)
  293. // Clear all the data in the buffers
  294. {
  295.     int32 i, j;
  296.     LPWAVEHDR temp;
  297.  
  298.     waveOutReset(*phwo);
  299.  
  300.     for(i=0; i<3; i++) {
  301.  
  302.         temp = lpwavehdr_arr[i];
  303.  
  304.         if (temp->dwUser)
  305.             waveOutUnprepareHeader(*phwo, temp, hdr_size);
  306.  
  307.         temp->dwUser = 0;
  308.  
  309.         for(j=0; j<data_size; j++)
  310.             temp->lpData[j] = (char) 0;
  311.     }
  312.  
  313.     // Reset buffer pointers
  314.     for(i=0; i<channels; i++)
  315.         bufferp[i]=i * channels;
  316.  
  317.     // Force the buffers to fillup before playing.
  318.     fillup = buffer_count = 0;
  319. }
  320.  
  321. void MCIbuffer::set_stop_flag(void)
  322. // Set the flag to avoid unpreparing non-existent headers
  323. {
  324.     user_stop = 1;
  325.    return;
  326. }
  327.  
  328.  
  329. MCIbuffer::~MCIbuffer(void)
  330. {
  331.     int32 i, j;
  332.  
  333.     if ((fillup==1) && !user_stop) {
  334.  
  335.         // Write the last header calculated (at the top of the array).
  336.         while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size))
  337.             Sleep(SLEEPTIME);
  338.  
  339.         while(waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size))
  340.             Sleep(SLEEPTIME);
  341.  
  342.         // Header has been written.
  343.         lpwavehdr_arr[0]->dwUser=1L;
  344.     }
  345.  
  346.     if (buffer_count && !user_stop) {
  347.  
  348.     /* Write the last wave header (probably not be written due to buffer size
  349.          increase.) */
  350.  
  351.         for(i= bufferp[channels-1]; i< data_size; i++)
  352.              lpwavehdr_arr[2]->lpData[i]= (char) 0;
  353.  
  354.         while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[2], hdr_size))
  355.             Sleep(SLEEPTIME);
  356.  
  357.         while(waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size))
  358.             Sleep(SLEEPTIME);
  359.  
  360.         // Header has been written.
  361.         lpwavehdr_arr[2]->dwUser=1L;
  362.  
  363.         wave_swap();
  364.     }
  365.  
  366.     // Unprepare and free the header memory.
  367.     for (j=2; j>=0; j--) {
  368.         if (lpwavehdr_arr[j]->dwUser && !user_stop)
  369.             while (waveOutUnprepareHeader(*phwo, lpwavehdr_arr[j], hdr_size)
  370.                   ==WAVERR_STILLPLAYING)
  371.                 Sleep(SLEEPTIME);
  372.  
  373.       delete [] lpwavehdr_arr[j]->lpData;
  374.       delete lpwavehdr_arr[j];
  375.     }
  376.  
  377.    delete [] lpwavehdr_arr;
  378.     delete lpwf;
  379.  
  380.    if (!user_stop)    // Wave device already closed if user_stop
  381.         while(waveOutClose(*phwo))
  382.             Sleep(SLEEPTIME);
  383.  
  384.     return;
  385. }
  386.