Blame tools/wave_out.c

Packit 664db3
/* Copyright (c) 2002, John Edwards
Packit 664db3

Packit 664db3
   Redistribution and use in source and binary forms, with or without
Packit 664db3
   modification, are permitted provided that the following conditions
Packit 664db3
   are met:
Packit 664db3

Packit 664db3
   - Redistributions of source code must retain the above copyright
Packit 664db3
   notice, this list of conditions and the following disclaimer.
Packit 664db3

Packit 664db3
   - Redistributions in binary form must reproduce the above copyright
Packit 664db3
   notice, this list of conditions and the following disclaimer in the
Packit 664db3
   documentation and/or other materials provided with the distribution.
Packit 664db3

Packit 664db3
   - Neither the name of the Xiph.org Foundation nor the names of its
Packit 664db3
   contributors may be used to endorse or promote products derived from
Packit 664db3
   this software without specific prior written permission.
Packit 664db3

Packit 664db3
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 664db3
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 664db3
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 664db3
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
Packit 664db3
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
Packit 664db3
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
Packit 664db3
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
Packit 664db3
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
Packit 664db3
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
Packit 664db3
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
Packit 664db3
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 664db3
*/
Packit 664db3

Packit 664db3
#ifdef HAVE_CONFIG_H
Packit 664db3
# include "config.h"
Packit 664db3
#endif
Packit 664db3

Packit 664db3
/* Set TABS = 4 */
Packit 664db3
/********************************************************************
Packit 664db3

Packit 664db3
 function: To provide playback of 16 bit PCM wave data in Win32
Packit 664db3
           environments from decoded compressed files.
Packit 664db3

Packit 664db3
 ********************************************************************/
Packit 664db3

Packit 664db3
#if defined WIN32 || defined _WIN32
Packit 664db3

Packit 664db3
#include <string.h>
Packit 664db3
#include <errno.h>
Packit 664db3
#include "wave_out.h"
Packit 664db3

Packit 664db3
#define MAXWAVESIZE     4294967040LU
Packit 664db3
#define MAX_WAVEBLOCKS    32
Packit 664db3

Packit 664db3
// This is modified for USE_WIN_AUDIO - ONLY 2002-02-27
Packit 664db3

Packit 664db3

Packit 664db3
static CRITICAL_SECTION  cs;
Packit 664db3
static HWAVEOUT          dev                    = NULL;
Packit 664db3
static int               ScheduledBlocks        = 0;
Packit 664db3
static int               PlayedWaveHeadersCount = 0;          // free index
Packit 664db3
static WAVEHDR*          PlayedWaveHeaders [MAX_WAVEBLOCKS];
Packit 664db3

Packit 664db3
static int
Packit 664db3
Box ( const char* msg )
Packit 664db3
{
Packit 664db3
	MessageBox ( NULL, msg, " "VERSION_STRING": Error Message . . .", MB_OK | MB_ICONEXCLAMATION );
Packit 664db3
	return -1;
Packit 664db3
}
Packit 664db3

Packit 664db3

Packit 664db3
/*
Packit 664db3
 *  This function registers already played WAVE chunks. Freeing is done by free_memory(),
Packit 664db3
 */
Packit 664db3

Packit 664db3
static void CALLBACK
Packit 664db3
wave_callback ( HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
Packit 664db3
{
Packit 664db3
	if ( uMsg == WOM_DONE ) {
Packit 664db3
		EnterCriticalSection ( &cs );
Packit 664db3
		PlayedWaveHeaders [PlayedWaveHeadersCount++] = (WAVEHDR*) dwParam1;
Packit 664db3
		LeaveCriticalSection ( &cs );
Packit 664db3
	}
Packit 664db3
}
Packit 664db3

Packit 664db3

Packit 664db3
static void
Packit 664db3
free_memory ( void )
Packit 664db3
{
Packit 664db3
	WAVEHDR*  wh;
Packit 664db3
	HGLOBAL   hg;
Packit 664db3

Packit 664db3
	EnterCriticalSection ( &cs );
Packit 664db3
	wh = PlayedWaveHeaders [--PlayedWaveHeadersCount];
Packit 664db3
	ScheduledBlocks--;                               // decrease the number of USED blocks
Packit 664db3
	LeaveCriticalSection ( &cs );
Packit 664db3

Packit 664db3
	waveOutUnprepareHeader ( dev, wh, sizeof (WAVEHDR) );
Packit 664db3

Packit 664db3
	hg = GlobalHandle ( wh -> lpData );       // Deallocate the buffer memory
Packit 664db3
	GlobalUnlock (hg);
Packit 664db3
	GlobalFree   (hg);
Packit 664db3

Packit 664db3
	hg = GlobalHandle ( wh );                 // Deallocate the header memory
Packit 664db3
	GlobalUnlock (hg);
Packit 664db3
	GlobalFree   (hg);
Packit 664db3
}
Packit 664db3

Packit 664db3

Packit 664db3
Int
Packit 664db3
Set_WIN_Params ( FILE_T   dummyFile ,
Packit 664db3
                 Ldouble  SampleFreq,
Packit 664db3
                 Uint     BitsPerSample,
Packit 664db3
                 Uint     Channels )
Packit 664db3
{
Packit 664db3
	WAVEFORMATEX  outFormat;
Packit 664db3
	UINT          deviceID = WAVE_MAPPER;
Packit 664db3

Packit 664db3
	(void) dummyFile;
Packit 664db3

Packit 664db3
	if ( waveOutGetNumDevs () == 0 )
Packit 664db3
		return Box ( "No audio device present." );
Packit 664db3

Packit 664db3
	outFormat.wFormatTag      = WAVE_FORMAT_PCM;
Packit 664db3
	outFormat.wBitsPerSample  = BitsPerSample;
Packit 664db3
	outFormat.nChannels       = Channels;
Packit 664db3
	outFormat.nSamplesPerSec  = (unsigned long)(SampleFreq + 0.5);
Packit 664db3
	outFormat.nBlockAlign     = (outFormat.wBitsPerSample + 7) / 8 * outFormat.nChannels;
Packit 664db3
	outFormat.nAvgBytesPerSec = outFormat.nSamplesPerSec * outFormat.nBlockAlign;
Packit 664db3

Packit 664db3
	switch ( waveOutOpen ( &dev, deviceID, &outFormat, (DWORD)wave_callback, 0, CALLBACK_FUNCTION ) )
Packit 664db3
	{
Packit 664db3
		case MMSYSERR_ALLOCATED:   return Box ( "Device is already open." );
Packit 664db3
		case MMSYSERR_BADDEVICEID: return Box ( "The specified device is out of range." );
Packit 664db3
		case MMSYSERR_NODRIVER:    return Box ( "There is no audio driver in this system." );
Packit 664db3
		case MMSYSERR_NOMEM:       return Box ( "Unable to allocate sound memory." );
Packit 664db3
		case WAVERR_BADFORMAT:     return Box ( "This audio format is not supported." );
Packit 664db3
		case WAVERR_SYNC:          return Box ( "The device is synchronous." );
Packit 664db3
		default:                   return Box ( "Unknown media error." );
Packit 664db3
		case MMSYSERR_NOERROR:     break;
Packit 664db3
	}
Packit 664db3

Packit 664db3
	waveOutReset ( dev );
Packit 664db3
	InitializeCriticalSection ( &cs );
Packit 664db3
	SetPriorityClass ( GetCurrentProcess (), HIGH_PRIORITY_CLASS );
Packit 664db3
	return 0;
Packit 664db3
}
Packit 664db3

Packit 664db3

Packit 664db3
int
Packit 664db3
WIN_Play_Samples ( const void* data, size_t len )
Packit 664db3
{
Packit 664db3
	HGLOBAL    hg;
Packit 664db3
	HGLOBAL    hg2;
Packit 664db3
	LPWAVEHDR  wh;
Packit 664db3
	void*      allocptr;
Packit 664db3

Packit 664db3
	do {
Packit 664db3
		while ( PlayedWaveHeadersCount > 0 )                // free used blocks ...
Packit 664db3
			free_memory ();
Packit 664db3

Packit 664db3
		if ( ScheduledBlocks < sizeof(PlayedWaveHeaders)/sizeof(*PlayedWaveHeaders) ) // wait for a free block ...
Packit 664db3
			break;
Packit 664db3
		Sleep (26);
Packit 664db3
	} while (1);
Packit 664db3

Packit 664db3
	if ( (hg2 = GlobalAlloc ( GMEM_MOVEABLE, len )) == NULL )   // allocate some memory for a copy of the buffer
Packit 664db3
		return Box ( "GlobalAlloc failed." );
Packit 664db3

Packit 664db3
	allocptr = GlobalLock (hg2);
Packit 664db3
	CopyMemory ( allocptr, data, len );                         // Here we can call any modification output functions we want....
Packit 664db3

Packit 664db3
	if ( (hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR))) == NULL ) // now make a header and WRITE IT!
Packit 664db3
		return -1;
Packit 664db3

Packit 664db3
	wh                   = GlobalLock (hg);
Packit 664db3
	wh -> dwBufferLength = len;
Packit 664db3
	wh -> lpData         = allocptr;
Packit 664db3

Packit 664db3
	if ( waveOutPrepareHeader ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {
Packit 664db3
		GlobalUnlock (hg);
Packit 664db3
		GlobalFree   (hg);
Packit 664db3
		return -1;
Packit 664db3
	}
Packit 664db3

Packit 664db3
	if ( waveOutWrite ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {
Packit 664db3
		GlobalUnlock (hg);
Packit 664db3
		GlobalFree   (hg);
Packit 664db3
		return -1;
Packit 664db3
	}
Packit 664db3

Packit 664db3
	EnterCriticalSection ( &cs );
Packit 664db3
	ScheduledBlocks++;
Packit 664db3
	LeaveCriticalSection ( &cs );
Packit 664db3

Packit 664db3
	return len;
Packit 664db3
}
Packit 664db3

Packit 664db3

Packit 664db3
int
Packit 664db3
WIN_Audio_close ( void )
Packit 664db3
{
Packit 664db3
	if ( dev != NULL ) {
Packit 664db3

Packit 664db3
		while ( ScheduledBlocks > 0 ) {
Packit 664db3
			Sleep (ScheduledBlocks);
Packit 664db3
			while ( PlayedWaveHeadersCount > 0 )         // free used blocks ...
Packit 664db3
				free_memory ();
Packit 664db3
		}
Packit 664db3

Packit 664db3
		waveOutReset (dev);      // reset the device
Packit 664db3
		waveOutClose (dev);      // close the device
Packit 664db3
		dev = NULL;
Packit 664db3
	}
Packit 664db3

Packit 664db3
	DeleteCriticalSection ( &cs );
Packit 664db3
	ScheduledBlocks = 0;
Packit 664db3
	return 0;
Packit 664db3
}
Packit 664db3

Packit 664db3
#endif
Packit 664db3

Packit 664db3
/* end of wave_out.c */