/*********************************************************************************
SoundServer - Written by Arnaud Carré (aka Leonard / OXYGENE)
Part of the "Leonard Homepage Articles".
http://leonard.oxg.free.fr
Read the complete article on my web page:
PART 1: Using WaveOut API.
How to make a SoundServer under windows, to play various sound.
WARNING: This sample plays a 44.1Khz, 16bits, mono sound. Should be quite easy to modify ! :-)
arnaud.carre@freesurf.fr
WARNING: You have to link this with the Windows MultiMedia library. (WINMM.LIB)
*********************************************************************************/
#include <windows.h>
#include "SoundServer.h"
// Internal WaveOut API callback function. We just call our sound handler ("playNextBuffer")
static void CALLBACK waveOutProc(HWAVEOUT hwo,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2)
{
if (uMsg == WOM_DONE)
{
CSoundServer *pServer = (CSoundServer*)dwInstance;
if (pServer) pServer->fillNextBuffer();
}
}
CSoundServer::CSoundServer()
{
m_pUserCallback = NULL;
m_bServerRunning = FALSE;
m_currentBuffer = 0;
}
CSoundServer::~CSoundServer()
{
close();
}
BOOL CSoundServer::open(USER_CALLBACK pUserCallback,long totalBufferedSoundLen)
{
m_pUserCallback = pUserCallback;
m_bufferSize = ((totalBufferedSoundLen * REPLAY_RATE) / 1000) * REPLAY_SAMPLELEN;
m_bufferSize /= REPLAY_NBSOUNDBUFFER;
WAVEFORMATEX wfx;
wfx.wFormatTag = 1; // PCM standart.
wfx.nChannels = 1; // Mono
wfx.nSamplesPerSec = REPLAY_RATE;
wfx.nAvgBytesPerSec = REPLAY_RATE*REPLAY_SAMPLELEN;
wfx.nBlockAlign = REPLAY_SAMPLELEN;
wfx.wBitsPerSample = REPLAY_DEPTH;
wfx.cbSize = 0;
MMRESULT errCode = waveOutOpen( &m_hWaveOut,
WAVE_MAPPER,
&wfx,
(DWORD)waveOutProc,
(DWORD)this, // User data.
(DWORD)CALLBACK_FUNCTION);
if (errCode != MMSYSERR_NOERROR) return FALSE;
// Alloc the sample buffers.
for (int i=0;i<REPLAY_NBSOUNDBUFFER;i++)
{
m_pSoundBuffer[i] = malloc(m_bufferSize);
memset(&m_waveHeader[i],0,sizeof(WAVEHDR));
}
// Fill all the sound buffers
m_currentBuffer = 0;
for (i=0;i<REPLAY_NBSOUNDBUFFER;i++)
fillNextBuffer();
m_bServerRunning = TRUE;
return TRUE;
}
void CSoundServer::close(void)
{
if (m_bServerRunning)
{
m_pUserCallback = NULL;
waveOutReset(m_hWaveOut); // Reset tout.
for (int i=0;i<REPLAY_NBSOUNDBUFFER;i++)
{
if (m_waveHeader[m_currentBuffer].dwFlags & WHDR_PREPARED)
waveOutUnprepareHeader(m_hWaveOut,&m_waveHeader[i],sizeof(WAVEHDR));
free(m_pSoundBuffer[i]);
}
waveOutClose(m_hWaveOut);
m_bServerRunning = FALSE;
}
}
void CSoundServer::fillNextBuffer(void)
{
// check if the buffer is already prepared (should not !)
if (m_waveHeader[m_currentBuffer].dwFlags&WHDR_PREPARED)
waveOutUnprepareHeader(m_hWaveOut,&m_waveHeader[m_currentBuffer],sizeof(WAVEHDR));
// Call the user function to fill the buffer with anything you want ! :-)
if (m_pUserCallback)
m_pUserCallback(m_pSoundBuffer[m_currentBuffer],m_bufferSize);
// Prepare the buffer to be sent to the WaveOut API
m_waveHeader[m_currentBuffer].lpData = (char*)m_pSoundBuffer[m_currentBuffer];
m_waveHeader[m_currentBuffer].dwBufferLength = m_bufferSize;
waveOutPrepareHeader(m_hWaveOut,&m_waveHeader[m_currentBuffer],sizeof(WAVEHDR));
// Send the buffer the the WaveOut queue
waveOutWrite(m_hWaveOut,&m_waveHeader[m_currentBuffer],sizeof(WAVEHDR));
m_currentBuffer++;
if (m_currentBuffer >= REPLAY_NBSOUNDBUFFER) m_currentBuffer = 0;
}
|