home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Zodiac Super OZ
/
MEDIADEPOT.ISO
/
FILES
/
39
/
MPW32-5S.ZIP
/
OBUFFER5.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-30
|
9KB
|
348 lines
/*
* @(#) obuffer.cc 1.15, last edit: 6/23/94 13:04:36
* @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
* @(#) Berlin University of Technology
*
* Idea and first implementation for u-law output with fast downsampling by
* Jim Boucher (jboucher@flash.bu.edu)
*
* LinuxObuffer class written by
* Louis P. Kruger (lpkruger@phoenix.princeton.edu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Changes from version 1.1 to 1.2:
* - new LinuxObuffer class, which works with 16 bit soundcards
* like Gravis Ultrasound, SoundBlaster 16 or Pro Audio Spectrum 16,
* if attached to /dev/dsp
* - ShortObuffer renamed to FileObuffer
* - If ULAW is defined:
* - SparcObuffer feeds mono u-law output to an amd device (u-law format).
* The required downsampling to 8 kHz in done in the synthesis filter.
* - FileObuffer creates u-law output at 8 kHz instead of 16 bit PCM samples.
* - O_NDELAY flag is cleared now after a successful open syscall
* on /dev/audio (caused problems under Solaris)
* - options -us, -uh and -ul should work now
* - FileObuffer can handle incomplete write syscalls now
*/
/* MCIbuffer class added by Jeff Tsay (last edit: 05/18/96)
Writing to Windows multimedia system with such a small
buffer won't do, so we increase buffer size, and ignore
most of the writes. Also we need to have a queue of 3 wave
headers for smooth playback. The last header and the oldest
header play while the current one is being filled in.
Note that this does not support 8-bit soundcards yet! I don't
know what the data format is to that */
/* Changes since last version: changed GMEM_MOVEABLE to GMEM_FIXED
which is a bit faster, according to the suggestions of Paul Forgey.
clear_buffer() added for seeking. Changes int16 parameter to int32
for minor speed improvement. Last edit: 06/29/96. */
#define STRICT
#define WIN32_LEAN_AND_MEAN
#define NOMCX
#define NOIME
#define NOGDI
#define NOUSER
#define NOSOUND
#define NOCOMM
#define NODRIVERS
#define OEMRESOURCE
#define NONLS
#define NOSERVICE
#define NOKANJI
#define NOMINMAX
#define NOLOGERROR
#define NOPROFILER
#define NOMEMMGR
#define NOLFILEIO
#define NOOPENFILE
#define NORESOURCE
#define NOATOM
#define NOLANGUAGE
#define NOLSTRING
#define NODBCS
#define NOKEYBOARDINFO
#define NOGDICAPMASKS
#define NOCOLOR
#define NOGDIOBJ
#define NODRAWTEXT
#define NOTEXTMETRIC
#define NOSCALABLEFONT
#define NOBITMAP
#define NORASTEROPS
#define NOMETAFILE
#define NOSYSMETRICS
#define NOSYSTEMPARAMSINFO
#define NOMSG
#define NOWINSTYLES
#define NOWINOFFSETS
#define NOSHOWWINDOW
#define NODEFERWINDOWPOS
#define NOVIRTUALKEYCODES
#define NOKEYSTATES
#define NOWH
#define NOMENUS
#define NOSCROLL
#define NOCLIPBOARD
#define NOICONS
#define NOMB
#define NOSYSCOMMANDS
#define NOMDI
#define NOCTLMGR
#define NOWINMESSAGES
#define NOHELP
#define _WINUSER_
#define __oleidl_h__
#define _OLE2_H_
#include <windows.h>
#include "obuffer.h"
#include "obuffer5.h" // Windows addition
#include "header.h"
MCIbuffer::MCIbuffer (uint32 number_of_channels,
Header *header,
HWAVEOUT *phwo0)
{
int i;
LPWAVEHDR temp;
channels= number_of_channels;
data_size= channels * BUFFERSIZE;
hdr_size= sizeof(WAVEHDR);
lpwavehdr_arr=new LPWAVEHDR[3];
phwo=phwo0;
fillup=0;
lpwf=(LPPCMWAVEFORMAT) new PCMWAVEFORMAT;
lpwf->wBitsPerSample=16; // No 8-bit support yet
lpwf->wf.wFormatTag=WAVE_FORMAT_PCM;
lpwf->wf.nChannels=(WORD) channels;
lpwf->wf.nSamplesPerSec=(DWORD) header->frequency ();
lpwf->wf.nAvgBytesPerSec=(DWORD) channels * header->frequency() << 1;
lpwf->wf.nBlockAlign=(WORD) (channels << 1);
if (waveOutOpen(phwo, WAVE_MAPPER, (const tWAVEFORMATEX *) lpwf,
NULL, NULL, WAVE_ALLOWSYNC))
ExitThread(1L);
buffer_count=0;
for(i=0; i<3; i++) {
lpwavehdr_arr[i]=(LPWAVEHDR) GlobalLock(GlobalAlloc(GMEM_FIXED,
hdr_size));
temp = lpwavehdr_arr[i];
if(!temp) ExitThread(1L);
temp->lpData=(LPSTR) GlobalLock(GlobalAlloc(GMEM_FIXED,
data_size));
if(!temp->lpData) ExitThread(1L);
temp->dwBufferLength=data_size;
temp->dwBytesRecorded=0L;
temp->dwUser=0L; // If played, dwUser = 1
temp->dwLoops=0L;
temp->dwFlags=NULL;
}
for(i=0; i<channels; i++)
bufferp[i]=i * channels;
}
void MCIbuffer::append (uint32 channel, int32 value)
{
// Need to break up the 32-bit integer into 2 8-bit bytes.
// (ignore the first two bytes - either 0x0000 or 0xffff)
// Note that Intel byte order is backwards!!!
LPSTR temp=lpwavehdr_arr[2]->lpData;
temp[bufferp[channel]]= (char) (value & 0xff);
temp[bufferp[channel]+1] = (char) (value >> 8);
bufferp[channel]+= channels << 1;
return;
}
#pragma argsused
void MCIbuffer::write_buffer (int fd)
{
// Actually write only when buffer is actually full.
if ((++buffer_count & BIT_SELECT)==0) {
int i;
buffer_count=0;
// Wait for 2 completed headers
if (fillup>1) {
// Prepare+write newest header
while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[2],
hdr_size))
Sleep(1);
while(waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size))
Sleep(1);
// Header has now been sent
lpwavehdr_arr[2]->dwUser=1L;
wave_swap();
// Unprepare oldest header
if (lpwavehdr_arr[2]->dwUser) {
while(waveOutUnprepareHeader(*phwo, lpwavehdr_arr[2],
hdr_size)==WAVERR_STILLPLAYING)
Sleep(1);
}
} else {
if (++fillup == 2) {
// Write the previously calculated 2 headers
while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[0],
hdr_size))
Sleep(1);
while(waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size))
Sleep(1);
// Header has now been sent
lpwavehdr_arr[0]->dwUser=1L;
wave_swap();
while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[0],
hdr_size))
Sleep(1);
while(waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size))
Sleep(1);
// Header has now been sent
lpwavehdr_arr[0]->dwUser=1L;
} else
wave_swap();
}
for(i=0; i<channels; i++)
bufferp[i]=i * channels;
}
return;
}
void MCIbuffer::wave_swap(void)
{
int i;
LPWAVEHDR temp=lpwavehdr_arr[2];
for(i=2;i>0; i--)
lpwavehdr_arr[i]=lpwavehdr_arr[i-1];
lpwavehdr_arr[0]=temp;
return;
}
void MCIbuffer::clear_buffer(void)
// Clear all the data in the buffers
{
int i, j;
LPWAVEHDR temp;
waveOutReset(*phwo);
for(i=0; i<3; i++) {
temp = lpwavehdr_arr[i];
if (temp->dwUser)
waveOutUnprepareHeader(*phwo, temp, hdr_size);
temp->dwUser = 0;
for(j=0; j<data_size; j++)
temp->lpData[j] = 0;
}
// Reset buffer pointers
for(i=0; i<channels; i++)
bufferp[i]=i * channels;
// Force the buffers to fillup before playing.
fillup = buffer_count = 0;
}
MCIbuffer::~MCIbuffer(void)
{
int i, j;
if (fillup==1) {
// Write the last header calculated (at the top of the array).
while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size))
Sleep(1);
while(waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size))
Sleep(1);
// Header has been written.
lpwavehdr_arr[0]->dwUser=1L;
}
if (buffer_count) {
/* Write the last wave header (probably not be written due to buffer size
increase.) */
for(i= bufferp[channels-1]; i< data_size; i++)
lpwavehdr_arr[2]->lpData[i]= (char) 0;
while (waveOutPrepareHeader(*phwo, lpwavehdr_arr[2], hdr_size))
Sleep(1);
while(waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size))
Sleep(1);
// Header has been written.
lpwavehdr_arr[2]->dwUser=1L;
wave_swap();
}
// Unprepare and free the header memory.
for (j=2; j>=0; j--) {
if (lpwavehdr_arr[j]->dwUser)
while (waveOutUnprepareHeader(*phwo, lpwavehdr_arr[j], hdr_size))
Sleep(1);
GlobalFree(lpwavehdr_arr[j]->lpData);
GlobalFree(lpwavehdr_arr[j]);
}
delete lpwf;
while(waveOutClose(*phwo))
Sleep(1);
return;
}