blob: 0e0b352b70cb683f87e940fc47ea29cf686b4ed2 [file] [log] [blame] [raw]
#include "AudioWinmm.h"
#include <mmsystem.h>
#include "tedmem.h"
#include "cpu.h"
// some good values for block size and count
#define BLOCK_SIZE 8192
#define BLOCK_COUNT 20
static CRITICAL_SECTION waveCriticalSection;
static WAVEHDR* waveBlocks;
static volatile int waveFreeBlockCount;
static int waveCurrentBlock;
HWAVEOUT hWaveOut; /* device handle */
HANDLE hFile;/* file handle */
WAVEFORMATEX wfx; /* look this up in your documentation */
char buffer[1024]; /* intermediate buffer for reading */
//struct WaveProcData{
TED *ted;
HANDLE semaph;
//};
//static WaveProcData wpd;
static WAVEHDR *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 = (unsigned char *) HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, totalBufferSize)) == NULL) {
fprintf(stderr, "Memory allocation error\n");
ExitProcess(1);
}
// 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 = (LPSTR) buffer;
buffer += size;
}
return blocks;
}
static void freeBlocks(WAVEHDR* blockArray)
{
// and this is why allocateBlocks works the way it does
HeapFree(GetProcessHeap(), 0, blockArray);
}
void CALLBACK AudioWinmm::sndCallbackFunc(HANDLE wout, UINT msg,
DWORD user, DWORD dw1, DWORD dw2)
{
//pointer to free block counter
DWORD *freeBlockCounter = (DWORD *) user;
if (msg == WOM_DONE) {
EnterCriticalSection(&waveCriticalSection);
(*freeBlockCounter)++;
LeaveCriticalSection(&waveCriticalSection);
if (ted) {
//ted->ted_process((short*) stream, len / 2);
}
}
}
AudioWinmm::AudioWinmm(void *userData, unsigned int sampleFrq_) : Audio(sampleFrq_)
{
MMRESULT mRes;
unsigned int i;
ted = reinterpret_cast<TED *>(userData);
// Find a usable waveOut device and open it
for(i = 0; i < waveOutGetNumDevs(); i++) {
if(i == waveOutGetNumDevs()) {// Error (very probably no free devices found)
// MessageBox(NULL,L"No audio device found!",L"ERROR",MB_OK);
return;
}
}
// initialise the module variables
waveBlocks = allocateBlocks(BLOCK_SIZE, BLOCK_COUNT);
waveFreeBlockCount = BLOCK_COUNT;
waveCurrentBlock = 0;
InitializeCriticalSection(&waveCriticalSection);
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 1;
wfx.nSamplesPerSec = sampleFrq_;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = 0;
if ( (mRes = waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx,
(DWORD_PTR) sndCallbackFunc, (DWORD_PTR)&waveFreeBlockCount, CALLBACK_FUNCTION))
!= MMSYSERR_NOERROR) {
TCHAR errMsg[100];
//wsprintf(errMsg, TEXT("Cannot open waveout device.\rError code: %0X."),mRes);
// MessageBox(NULL,errMsg,L"ERROR",MB_OK);
return;
}
play();
}
void AudioWinmm::reset()
{
if (hWaveOut)
waveOutReset(hWaveOut);
}
void AudioWinmm::pause()
{
paused = true;
if (hWaveOut) {
waveOutPause(hWaveOut);
}
}
void AudioWinmm::play()
{
paused = false;
if (hWaveOut) {
waveOutRestart(hWaveOut);
}
}
void AudioWinmm::stop()
{
paused = true;
if (hWaveOut) {
waveOutReset(hWaveOut);
waveOutPause(hWaveOut);
}
}
void AudioWinmm::write(HWAVEOUT hWaveOut, LPSTR data, int size)
{
WAVEHDR *current;
int remain;
current = &waveBlocks[waveCurrentBlock];
while(size > 0) {
// first make sure the header we're going to use is unprepared
if(current->dwFlags & WHDR_PREPARED)
waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR));
if(size < (int)(BLOCK_SIZE - current->dwUser)) {
memcpy(current->lpData + current->dwUser, data, size);
current->dwUser += size;
break;
}
remain = BLOCK_SIZE - current->dwUser;
memcpy(current->lpData + current->dwUser, data, remain);
size -= remain;
data += remain;
current->dwBufferLength = BLOCK_SIZE;
waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));
EnterCriticalSection(&waveCriticalSection);
waveFreeBlockCount--;
LeaveCriticalSection(&waveCriticalSection);
// wait for a block to become free
while(!waveFreeBlockCount)
Sleep(0);
// point to the next block
waveCurrentBlock++;
waveCurrentBlock %= BLOCK_COUNT;
current = &waveBlocks[waveCurrentBlock];
current->dwUser = 0;
}
}
AudioWinmm::~AudioWinmm()
{
// unprepare any blocks that are still prepared
for(int i = 0; i < waveFreeBlockCount; i++)
if(waveBlocks[i].dwFlags & WHDR_PREPARED)
waveOutUnprepareHeader(hWaveOut, &waveBlocks[i], sizeof(WAVEHDR));
DeleteCriticalSection(&waveCriticalSection);
if (hWaveOut) {
waveOutReset(hWaveOut);
waveOutClose(hWaveOut);
hWaveOut = NULL;
}
freeBlocks(waveBlocks);
}