home *** CD-ROM | disk | FTP | other *** search
/ The Best of Windows 95.com 1996 September / WIN95_09964.iso / sound / mpw32-5s.zip / OBUFFER5.CPP < prev    next >
C/C++ Source or Header  |  1996-06-30  |  9KB  |  348 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. #define STRICT
  59. #define WIN32_LEAN_AND_MEAN
  60. #define NOMCX
  61. #define NOIME
  62. #define NOGDI
  63. #define NOUSER
  64. #define NOSOUND
  65. #define NOCOMM
  66. #define NODRIVERS
  67. #define OEMRESOURCE
  68. #define NONLS
  69. #define NOSERVICE
  70. #define NOKANJI
  71. #define NOMINMAX
  72. #define NOLOGERROR
  73. #define NOPROFILER
  74. #define NOMEMMGR
  75. #define NOLFILEIO
  76. #define NOOPENFILE
  77. #define NORESOURCE
  78. #define NOATOM
  79. #define NOLANGUAGE
  80. #define NOLSTRING
  81. #define NODBCS
  82. #define NOKEYBOARDINFO
  83. #define NOGDICAPMASKS
  84. #define NOCOLOR
  85. #define NOGDIOBJ
  86. #define NODRAWTEXT
  87. #define NOTEXTMETRIC
  88. #define NOSCALABLEFONT
  89. #define NOBITMAP
  90. #define NORASTEROPS
  91. #define NOMETAFILE
  92. #define NOSYSMETRICS
  93. #define NOSYSTEMPARAMSINFO
  94. #define NOMSG
  95. #define NOWINSTYLES
  96. #define NOWINOFFSETS
  97. #define NOSHOWWINDOW
  98. #define NODEFERWINDOWPOS
  99. #define NOVIRTUALKEYCODES
  100. #define NOKEYSTATES
  101. #define NOWH
  102. #define NOMENUS
  103. #define NOSCROLL
  104. #define NOCLIPBOARD
  105. #define NOICONS
  106. #define NOMB
  107. #define NOSYSCOMMANDS
  108. #define NOMDI
  109. #define NOCTLMGR
  110. #define NOWINMESSAGES
  111. #define NOHELP
  112. #define _WINUSER_
  113. #define __oleidl_h__
  114. #define _OLE2_H_
  115. #include <windows.h>
  116.  
  117. #include "obuffer.h"
  118. #include "obuffer5.h"  // Windows addition
  119. #include "header.h"
  120.  
  121. MCIbuffer::MCIbuffer (uint32 number_of_channels,
  122.                              Header *header,
  123.                              HWAVEOUT *phwo0)
  124. {
  125.   int i;
  126.   LPWAVEHDR temp;
  127.   channels= number_of_channels;
  128.   data_size= channels * BUFFERSIZE;
  129.  
  130.   hdr_size= sizeof(WAVEHDR);
  131.   lpwavehdr_arr=new LPWAVEHDR[3];
  132.   phwo=phwo0;
  133.   fillup=0;
  134.  
  135.   lpwf=(LPPCMWAVEFORMAT) new PCMWAVEFORMAT;
  136.   lpwf->wBitsPerSample=16;  // No 8-bit support yet
  137.  
  138.   lpwf->wf.wFormatTag=WAVE_FORMAT_PCM;
  139.   lpwf->wf.nChannels=(WORD) channels;
  140.   lpwf->wf.nSamplesPerSec=(DWORD) header->frequency ();
  141.   lpwf->wf.nAvgBytesPerSec=(DWORD) channels * header->frequency() << 1;
  142.   lpwf->wf.nBlockAlign=(WORD) (channels << 1);
  143.  
  144.   if (waveOutOpen(phwo, WAVE_MAPPER, (const tWAVEFORMATEX *) lpwf,
  145.                      NULL, NULL, WAVE_ALLOWSYNC))
  146.         ExitThread(1L);
  147.  
  148.   buffer_count=0;
  149.  
  150.   for(i=0; i<3; i++) {
  151.       lpwavehdr_arr[i]=(LPWAVEHDR) GlobalLock(GlobalAlloc(GMEM_FIXED,
  152.                                                   hdr_size));
  153.       temp = lpwavehdr_arr[i];
  154.       if(!temp) ExitThread(1L);
  155.       temp->lpData=(LPSTR) GlobalLock(GlobalAlloc(GMEM_FIXED,
  156.                                                          data_size));
  157.       if(!temp->lpData) ExitThread(1L);
  158.       temp->dwBufferLength=data_size;
  159.       temp->dwBytesRecorded=0L;
  160.       temp->dwUser=0L;  // If played, dwUser = 1
  161.       temp->dwLoops=0L;
  162.       temp->dwFlags=NULL;
  163.   }
  164.  
  165.   for(i=0; i<channels; i++)
  166.     bufferp[i]=i * channels;
  167.  
  168. }
  169.  
  170. void MCIbuffer::append (uint32 channel, int32 value)
  171. {
  172.   // Need to break up the 32-bit integer into 2 8-bit bytes.
  173.   // (ignore the first two bytes - either 0x0000 or 0xffff)
  174.   // Note that Intel byte order is backwards!!!
  175.  
  176.   LPSTR temp=lpwavehdr_arr[2]->lpData;
  177.   temp[bufferp[channel]]= (char) (value & 0xff);
  178.   temp[bufferp[channel]+1] = (char) (value >> 8);
  179.   bufferp[channel]+= channels << 1;
  180.  
  181.   return;
  182. }
  183.  
  184. #pragma argsused
  185. void MCIbuffer::write_buffer (int fd)
  186. {
  187.     // Actually write only when buffer is actually full.
  188.     if ((++buffer_count & BIT_SELECT)==0) {
  189.  
  190.         int i;
  191.  
  192.         buffer_count=0;
  193.  
  194.         // Wait for 2 completed headers
  195.         if (fillup>1) {
  196.  
  197.             // Prepare+write newest header
  198.             while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[2],
  199.                         hdr_size))
  200.                 Sleep(1);
  201.  
  202.             while(waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size))
  203.                 Sleep(1);
  204.  
  205.             // Header has now been sent
  206.             lpwavehdr_arr[2]->dwUser=1L;
  207.  
  208.             wave_swap();
  209.  
  210.             // Unprepare oldest header
  211.             if (lpwavehdr_arr[2]->dwUser) {
  212.  
  213.                 while(waveOutUnprepareHeader(*phwo, lpwavehdr_arr[2],
  214.                     hdr_size)==WAVERR_STILLPLAYING)
  215.                     Sleep(1);
  216.             }
  217.  
  218.         } else {
  219.  
  220.             if (++fillup == 2) {
  221.  
  222.                     // Write the previously calculated 2 headers
  223.                     while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[0],
  224.                         hdr_size))
  225.                         Sleep(1);
  226.  
  227.                     while(waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size))
  228.                         Sleep(1);
  229.  
  230.                     // Header has now been sent
  231.                     lpwavehdr_arr[0]->dwUser=1L;
  232.  
  233.                     wave_swap();
  234.  
  235.                     while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[0],
  236.                         hdr_size))
  237.                         Sleep(1);
  238.  
  239.                     while(waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size))
  240.                         Sleep(1);
  241.  
  242.                     // Header has now been sent
  243.                     lpwavehdr_arr[0]->dwUser=1L;
  244.  
  245.             } else
  246.                 wave_swap();
  247.         }
  248.  
  249.         for(i=0; i<channels; i++)
  250.           bufferp[i]=i * channels;
  251.     }
  252.     return;
  253. }
  254.  
  255. void MCIbuffer::wave_swap(void)
  256. {
  257.     int i;
  258.     LPWAVEHDR temp=lpwavehdr_arr[2];
  259.  
  260.     for(i=2;i>0; i--)
  261.         lpwavehdr_arr[i]=lpwavehdr_arr[i-1];
  262.     lpwavehdr_arr[0]=temp;
  263.     return;
  264. }
  265.  
  266. void MCIbuffer::clear_buffer(void)
  267. // Clear all the data in the buffers
  268. {
  269.     int i, j;
  270.     LPWAVEHDR temp;
  271.  
  272.     waveOutReset(*phwo);
  273.  
  274.     for(i=0; i<3; i++) {
  275.  
  276.         temp = lpwavehdr_arr[i];
  277.  
  278.         if (temp->dwUser)
  279.             waveOutUnprepareHeader(*phwo, temp, hdr_size);
  280.  
  281.         temp->dwUser = 0;
  282.  
  283.         for(j=0; j<data_size; j++)
  284.             temp->lpData[j] = 0;
  285.     }
  286.  
  287.     // Reset buffer pointers
  288.     for(i=0; i<channels; i++)
  289.         bufferp[i]=i * channels;
  290.  
  291.     // Force the buffers to fillup before playing.
  292.     fillup = buffer_count = 0;
  293. }
  294.  
  295. MCIbuffer::~MCIbuffer(void)
  296. {
  297.     int i, j;
  298.  
  299.     if (fillup==1) {
  300.  
  301.         // Write the last header calculated (at the top of the array).
  302.         while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size))
  303.             Sleep(1);
  304.  
  305.         while(waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size))
  306.             Sleep(1);
  307.  
  308.         // Header has been written.
  309.         lpwavehdr_arr[0]->dwUser=1L;
  310.     }
  311.  
  312.     if (buffer_count) {
  313.  
  314.     /* Write the last wave header (probably not be written due to buffer size
  315.          increase.) */
  316.  
  317.         for(i= bufferp[channels-1]; i< data_size; i++)
  318.              lpwavehdr_arr[2]->lpData[i]= (char) 0;
  319.  
  320.         while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[2], hdr_size))
  321.             Sleep(1);
  322.  
  323.         while(waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size))
  324.             Sleep(1);
  325.  
  326.         // Header has been written.
  327.         lpwavehdr_arr[2]->dwUser=1L;
  328.  
  329.         wave_swap();
  330.     }
  331.  
  332.     // Unprepare and free the header memory.
  333.     for (j=2; j>=0; j--) {
  334.         if (lpwavehdr_arr[j]->dwUser)
  335.             while (waveOutUnprepareHeader(*phwo, lpwavehdr_arr[j], hdr_size))
  336.                 Sleep(1);
  337.  
  338.         GlobalFree(lpwavehdr_arr[j]->lpData);
  339.         GlobalFree(lpwavehdr_arr[j]);
  340.     }
  341.  
  342.     delete lpwf;
  343.  
  344.     while(waveOutClose(*phwo))
  345.         Sleep(1);
  346.     return;
  347. }
  348.