📄 wavebox.cpp
字号:
// WaveBox.cpp: implementation of the CWave class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "WaveBox.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CWaveBox::CWaveBox()
{
// init wave(s) counter
wload = 0;
// thread suspended < used for resuming thread at first play >
run = 0;
// create suspended player thread
thread = CreateThread( NULL,
0,
(LPTHREAD_START_ROUTINE)PlayThread,
(LPVOID)this,
CREATE_SUSPENDED,
NULL );
// alloc mem for interface(s)
for( unsigned int i = 0; i < SUPPORT_INTERFACES; i++ )
{
I[i].wblock = allocateBlocks( BLOCK_SIZE, BLOCK_COUNT );
I[i].wfreeblock = BLOCK_COUNT;
I[i].wcurrblock = 0;
I[i].state = INT_FREE;
I[i].wpos = 0;
}
// init msg
for( unsigned int i = 0; i < SUPPORT_WAVES; i++ ) W[i].WMSG = WMSG_WAIT;
// init cs
InitializeCriticalSection( &cs );
}
CWaveBox::~CWaveBox()
{
unsigned long exit = 0;
if( run ) // thread resumed
{
// set thread close message
EnterCriticalSection( &cs );
TMSG = TMSG_CLOSE;
LeaveCriticalSection( &cs );
do // wait for soft close
{
GetExitCodeThread( thread, &exit );
Sleep( 10 );
}while( exit != THREAD_EXIT );
}else // thread suspended
{
// hard close
GetExitCodeThread( thread, &exit );
TerminateThread( thread, exit );
}
// release wave(s)
for( unsigned int i = 0; i < wload; i++ )
free( W[i].data );
// release interface(s)
for( unsigned int i = 0; i < SUPPORT_INTERFACES; i++ )
freeBlocks( I[i].wblock );
// del cs
DeleteCriticalSection( &cs );
}
WAVEHDR* CWaveBox::allocateBlocks(int size, int count)
{
unsigned char* buffer;
int i;
WAVEHDR* blocks;
DWORD totalBufferSize = (size + sizeof(WAVEHDR)) * count;
// allocate memory for the entire set in one go
if((buffer = ( UCHAR*) HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
totalBufferSize )) == NULL) return NULL;
// and set up the pointers to each bit
blocks = (WAVEHDR*)buffer;
buffer += sizeof(WAVEHDR) * count;
for(i = 0; i < count; i++)
{
blocks[i].dwBufferLength = size;
blocks[i].lpData = (CHAR *)buffer;
buffer += size;
}
return blocks;
}
void CWaveBox::freeBlocks(WAVEHDR* blockArray)
{
// and this is why allocateBlocks works the way it does
HeapFree(GetProcessHeap(), 0, blockArray);
}
int CWaveBox::Load( TCHAR *file )
{
if( wload == SUPPORT_WAVES )
return -1;
HANDLE hFile;
// open file
if((hFile = CreateFile( file,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL )) == INVALID_HANDLE_VALUE) return -1;
// read wave header
char header[HEADER_SIZE];
unsigned long rbytes = 0;
if( !ReadFile(hFile, header, sizeof(header), &rbytes, NULL) )
{ CloseHandle(hFile); return -1; }
if( !rbytes || rbytes < sizeof(header) )
{ CloseHandle(hFile); return -1; }
/// check if this is a wave file
if( strncmp( header, WAVE_FILE_MARK, strlen( WAVE_FILE_MARK )) )
{ CloseHandle(hFile); return -1; }
if( strncmp( header + OFFSET_HEAD_MARK, WAVE_HEAD_MARK, strlen( WAVE_HEAD_MARK )) )
{ CloseHandle(hFile); return -1; }
/// check if wave is uncompressed PCM format
if ( ((*(DWORD*)(header + OFFSET_WAVE_PCM1)) != WAVE_PCM_16 )
|| ((*(WORD *)(header + OFFSET_WAVE_PCM2)) != WAVE_PCM_1 ))
{CloseHandle(hFile); return -1; }
/// check for 'data' mark
if( !strncmp( header + OFFSET_DATA_MARK, WAVE_DATA_MARK, strlen( WAVE_DATA_MARK )) )
W[wload].size = *((DWORD*)(header + OFFSET_DATA_SIZE )); /* size of data */
else
{ /// if data block size cant be read
/// try to predict data block without extra info
/// this is unusualy case
W[wload].size = *((DWORD*)(header + OFFSET_FILE_LEFT ));
W[wload].size -= ( HEADER_SIZE - EOF_EXTRA_INFO ); /* size of data */
}
// fill WAVEFORMATEX from wave header
W[wload].wfx.nSamplesPerSec = *((DWORD*)(header + OFFSET_SAMPLESPERSEC )); /* sample rate */
W[wload].wfx.wBitsPerSample = *((WORD *)(header + OFFSET_BITSPERSAMPLE )); /* sample size */
W[wload].wfx.nChannels = *((WORD *)(header + OFFSET_CHANNELS )); /* channels */
W[wload].wfx.cbSize = 0; /* size of _extra_ info */
W[wload].wfx.wFormatTag = WAVE_FORMAT_PCM;
W[wload].wfx.nBlockAlign = *((WORD *)(header + OFFSET_BLOCKALIGN ));
W[wload].wfx.nAvgBytesPerSec = *((DWORD*)(header + OFFSET_AVGBYTESPERSEC));
// get mem for wave data block
if((W[wload].data = ( char *) calloc( W[wload].size, sizeof( char ))) == NULL)
{ CloseHandle(hFile); return -1; }
char buffer[READ_BLOCK];
unsigned long size = W[wload].size;
unsigned long read_block = 0;
rbytes = 0;
do /// copy uncompressed PCM wave data block
{
if( ( size -= rbytes ) >= READ_BLOCK ) read_block = READ_BLOCK;
else
if( size && size < READ_BLOCK ) read_block = size;
else break;
if( !ReadFile(hFile, buffer, read_block, &rbytes, NULL) )
break;
if( rbytes == 0 )
break;
if( rbytes < sizeof(buffer) )
memset(buffer + rbytes, 0, sizeof(buffer) - rbytes);
memcpy( &W[wload].data[W[wload].size - size], buffer, rbytes );
}while( 1 );
// close file handle
CloseHandle(hFile);
// return current wave count
return ++wload;
}
int CWaveBox::Play( unsigned int wave )
{
// check wave id
if( wave < 0 || wave >= wload )
return -1;
// set play message
EnterCriticalSection(&cs);
W[wave].WMSG = WMSG_START;
LeaveCriticalSection(&cs);
// resume thread < at first play >
if( !run ){ run = 1; TMSG = TMSG_ALIVE; ResumeThread( thread ); }
return 1;
}
int CWaveBox::AddInterface( HWAVEOUT *dev,
WAVEFORMATEX *wfx,
volatile int *wfreeblock )
{
// check for free device
if( !waveOutGetNumDevs() )
return -1;
// try to open the default wave device. WAVE_MAPPER is
// a constant defined in mmsystem.h, it always points to the
// default wave device on the system (some people have 2 or
// more sound cards).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -