blob: 689f1eb02c0868dc5ac5942e2e26d322cc211db2 [file] [log] [blame] [raw]
#include "stdafx.h"
#include <mmsystem.h>
#include "AudioDirectSound.h"
#include "Tedmem.h"
#define DIVISOR 2
CRITICAL_SECTION AudioDirectSound::cs;
void CALLBACK TimerProcess(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
AudioDirectSound *pDDS = (AudioDirectSound *)dwUser;
pDDS->TimerCallback();
}
HRESULT WINAPI AudioDirectSound::cb(LPBYTE lpDesBuf, const DWORD dwRequiredSamples, DWORD &dwRetSamples, LPVOID lpData)
{
//EnterCriticalSection(&cs);
TED *ted = reinterpret_cast<TED *>(lpData);
if (ted) {
ted->ted_process((short*) lpDesBuf, dwRequiredSamples);
}
//LeaveCriticalSection(&cs);
dwRetSamples = dwRequiredSamples;
return 0;
}
AudioDirectSound::AudioDirectSound(void *userData, unsigned int sampleFrq_) : Audio(sampleFrq_)
{
InitializeCriticalSection(&cs);
//<DirectSound>
ZeroMemory(&m_WFE, sizeof(m_WFE));
m_lpDS = NULL;
m_lpDSB = NULL;
m_pHEvent[0] = CreateEvent(NULL, FALSE, FALSE, _T("Direct_Sound_Buffer_Notify_0"));
m_pHEvent[1] = CreateEvent(NULL, FALSE, FALSE, _T("Direct_Sound_Buffer_Notify_1"));
//</DirectSound>
//<Audio Buffer>
m_lpAudioBuf = NULL;
m_lpGETAUDIOSAMPLES = NULL;
m_lpData = NULL;
//</Audio Buffer>
//<Playing>
m_dwCircles1 = 0;
m_dwCircles2 = 0;
//</Playing>
// Initialize
m_WFE.wFormatTag = WAVE_FORMAT_PCM;
m_WFE.nChannels = 1;
m_WFE.nSamplesPerSec = sampleFrq_;
m_WFE.wBitsPerSample = 16;
m_WFE.nBlockAlign = m_WFE.nChannels * m_WFE.wBitsPerSample / 8;
m_WFE.nAvgBytesPerSec = m_WFE.nSamplesPerSec * m_WFE.nBlockAlign;
m_WFE.cbSize = 0;
SetFormat(m_WFE);
SetCallback( cb, userData);
}
//</AudioDirectSound>
AudioDirectSound::~AudioDirectSound()
{
if (NULL != m_lpAudioBuf) {
delete []m_lpAudioBuf;
m_lpAudioBuf = NULL;
}
}
//</~AudioDirectSound>
void AudioDirectSound::SetFormat(WAVEFORMATEX WFE)
{
m_WFE = WFE;
//Create DirectSound
if ( FAILED(DirectSoundCreate(NULL, &m_lpDS, NULL)) ) {
OutputDebugString(_T("Create DirectSound Failed!"));
m_strLastError = _T("MyDirectSound SetFormat Failed!");
return;
}
//Set Cooperative Level
HWND hWnd = GetForegroundWindow();
if (hWnd == NULL) {
hWnd = GetDesktopWindow();
}
if ( FAILED(m_lpDS->SetCooperativeLevel(hWnd, DSSCL_PRIORITY)) ) {
OutputDebugString(_T("SetCooperativeLevel Failed"));
m_strLastError = _T("MyDirectSound SetFormat Failed!");
return;
}
//Create Primary Buffer
DSBUFFERDESC dsbd;
ZeroMemory(&dsbd, sizeof(dsbd));
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = NULL;
LPDIRECTSOUNDBUFFER lpDSB = NULL;
if ( FAILED(m_lpDS->CreateSoundBuffer(&dsbd, &lpDSB, NULL)) ) {
OutputDebugString(_T("Create Primary Sound Buffer Failed!"));
m_strLastError = _T("MyDirectSound SetFormat Failed!");
return;
}
//Set Primary Buffer Format
if ( FAILED(lpDSB->SetFormat(&m_WFE)) ) {
OutputDebugString(_T("Set Primary Format Failed!"));
m_strLastError = _T("MyDirectSound SetFormat Failed!");
return;
}
//Create Second Sound Buffer
dsbd.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS;
//dsbd.dwBufferBytes = 2*m_WFE.nAvgBytesPerSec; //2 Seconds Buffer
dsbd.dwBufferBytes = 2 * m_WFE.nAvgBytesPerSec / DIVISOR; //2 Seconds Buffer
dsbd.lpwfxFormat = &m_WFE;
if ( FAILED(m_lpDS->CreateSoundBuffer(&dsbd, &m_lpDSB, NULL)) ) {
OutputDebugString(_T("Create Second Sound Buffer Failed!"));
m_strLastError = _T("MyDirectSound SetFormat Failed!");
return;
}
//Query DirectSoundNotify
LPDIRECTSOUNDNOTIFY lpDSBNotify;
if ( FAILED(m_lpDSB->QueryInterface(IID_IDirectSoundNotify, (LPVOID *)&lpDSBNotify)) ) {
OutputDebugString(_T("QueryInterface DirectSoundNotify Failed!"));
m_strLastError = _T("MyDirectSound SetFormat Failed!");
return;
}
//Set Direct Sound Buffer Notify Position
DSBPOSITIONNOTIFY pPosNotify[2];
pPosNotify[0].dwOffset = m_WFE.nAvgBytesPerSec/2 / DIVISOR - 1;
pPosNotify[1].dwOffset = 3 * m_WFE.nAvgBytesPerSec/2 / DIVISOR - 1;
pPosNotify[0].hEventNotify = m_pHEvent[0];
pPosNotify[1].hEventNotify = m_pHEvent[1];
if ( FAILED(lpDSBNotify->SetNotificationPositions(2, pPosNotify)) ) {
OutputDebugString(_T("Set NotificationPosition Failed!"));
m_strLastError = _T("MyDirectSound SetFormat Failed!");
return;
}
//New audio buffer
if (NULL != m_lpAudioBuf) {
delete []m_lpAudioBuf;
m_lpAudioBuf = NULL;
}
m_lpAudioBuf = new unsigned char[m_WFE.nAvgBytesPerSec];
//Init Audio Buffer
memset(m_lpAudioBuf, 0, m_WFE.nAvgBytesPerSec);
}
//</SetFormat>
void AudioDirectSound::play()
{
paused = false;
//Check if the DirectSound was created successfully
if (NULL == m_lpDS) {
m_strLastError = _T("DirectSound was not created!");
OutputDebugString(m_strLastError);
return;
}
//Check if the callback function is valid
if (NULL == m_lpGETAUDIOSAMPLES) {
m_strLastError = _T("Callback Function is NULL!");
OutputDebugString(m_strLastError);
return;
}
//Check if SetFormat successfully
if ( !m_strLastError.CompareNoCase(_T("MyDirectSound SetFormat Failed!")) ) {
OutputDebugString(m_strLastError);
return;
}
if (0 == m_dwCircles1) {
////Get audio data by callback function
//DWORD dwRetSamples = 0, dwRetBytes = 0;
//m_lpGETAUDIOSAMPLES(m_lpAudioBuf, m_WFE.nSamplesPerSec / DIVISOR, dwRetSamples, m_lpData);
//dwRetBytes = dwRetSamples*m_WFE.nBlockAlign;
////Write the audio data to DirectSoundBuffer
//LPVOID lpvAudio1 = NULL, lpvAudio2 = NULL;
//DWORD dwBytesAudio1 = 0, dwBytesAudio2 = 0;
////Lock DirectSoundBuffer
//HRESULT hr = m_lpDSB->Lock(0, m_WFE.nAvgBytesPerSec / DIVISOR, &lpvAudio1, &dwBytesAudio1, &lpvAudio2, &dwBytesAudio2, 0);
//if ( FAILED(hr) ) {
// m_strLastError = _T("Lock DirectSoundBuffer Failed!");
// OutputDebugString(m_strLastError);
// return;
//}
////Init lpvAudio1
//if (NULL != lpvAudio1) {
// memset(lpvAudio1, 0, dwBytesAudio1);
//}
////Init lpvAudio2
//if (NULL != lpvAudio2) {
// memset(lpvAudio2, 0, dwBytesAudio2);
//}
////Copy Audio Buffer to DirectSoundBuffer
//if (NULL == lpvAudio2) {
// memcpy(lpvAudio1, m_lpAudioBuf, dwRetBytes);
//}
//else {
// memcpy(lpvAudio1, m_lpAudioBuf, dwBytesAudio1);
// memcpy(lpvAudio2, m_lpAudioBuf + dwBytesAudio1, dwBytesAudio2);
//}
////Unlock DirectSoundBuffer
//m_lpDSB->Unlock(lpvAudio1, dwBytesAudio1, lpvAudio2, dwBytesAudio2);
}
//Begin Play
m_lpDSB->Play(0, 0, DSBPLAY_LOOPING);
//timeSetEvent (300, 100)
m_timerID = timeSetEvent(200, 50, TimerProcess, (DWORD)this, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
}
//</Play>
void AudioDirectSound::pause()
{
paused = true;
if (NULL != m_lpDSB) {
m_lpDSB->Stop();
timeKillEvent(m_timerID);
}
}
//</Pause>
void AudioDirectSound::stop()
{
paused = true;
if (NULL != m_lpDSB) {
m_lpDSB->Stop();
timeKillEvent(m_timerID);
//Empty the buffer
LPVOID lpvAudio1 = NULL;
DWORD dwBytesAudio1 = 0;
HRESULT hr = m_lpDSB->Lock(0, 0, &lpvAudio1, &dwBytesAudio1, NULL, NULL, DSBLOCK_ENTIREBUFFER);
if ( FAILED(hr) ) {
m_strLastError = _T("Lock entirebuffer failed! Stop Failed!");
OutputDebugString(m_strLastError);
return;
}
memset(lpvAudio1, 0, dwBytesAudio1);
m_lpDSB->Unlock(lpvAudio1, dwBytesAudio1, NULL, NULL);
//Move the current play position to begin
m_lpDSB->SetCurrentPosition(0);
//Reset Event
ResetEvent(m_pHEvent[0]);
ResetEvent(m_pHEvent[1]);
//Set Circles1 and Circles2 0
m_dwCircles1 = 0;
m_dwCircles2 = 0;
}
//::Sleep(500);
}
//</Stop>
DWORD AudioDirectSound::GetSamplesPlayed()
{
if (NULL == m_lpDSB) {
return 0;
}
//Get current play position
DWORD dwCurPlayPos = 0, dwCurPlaySample = 0;
m_lpDSB->GetCurrentPosition(&dwCurPlayPos, NULL);
dwCurPlaySample = dwCurPlayPos/m_WFE.nBlockAlign;
//Caculate the samples played
DWORD dwSamplesPlayed = 0;
if (m_dwCircles2 < 1) {
return dwCurPlaySample;
}
dwSamplesPlayed = (m_dwCircles2-1)*2*m_WFE.nSamplesPerSec + 3*m_WFE.nSamplesPerSec/2;
if (dwCurPlaySample > (3*m_WFE.nSamplesPerSec/2)) {
if (m_dwCircles2 < m_dwCircles1) {
dwSamplesPlayed = (m_dwCircles1-1)*2*m_WFE.nSamplesPerSec + 3*m_WFE.nSamplesPerSec/2;
}
dwSamplesPlayed += dwCurPlaySample - 3*m_WFE.nSamplesPerSec/2 + 1;
}
else {
dwSamplesPlayed += dwCurPlaySample + m_WFE.nSamplesPerSec/2;
}
CString strSamplesPlayed;
strSamplesPlayed.Format(_T("Samples Played: %d \n"), dwSamplesPlayed);
OutputDebugString(strSamplesPlayed);
return dwSamplesPlayed;
}
//</GetSamplePlaying>
void AudioDirectSound::SetCallback(LPGETAUDIOSAMPLES_PROGRESS Function_Callback, LPVOID lpData)
{
m_lpGETAUDIOSAMPLES = Function_Callback;
m_lpData = lpData;
}
//</SetCallback>
void AudioDirectSound::TimerCallback()
{
LPVOID lpvAudio1 = NULL, lpvAudio2 = NULL;
DWORD dwBytesAudio1 = 0, dwBytesAudio2 = 0;
DWORD dwRetSamples = 0, dwRetBytes = 0;
HRESULT hr = WaitForMultipleObjects(2, m_pHEvent, FALSE, 0);
if(WAIT_OBJECT_0 == hr) {
m_dwCircles1++;
//Lock DirectSoundBuffer Second Part
HRESULT hr = m_lpDSB->Lock(m_WFE.nAvgBytesPerSec / DIVISOR, m_WFE.nAvgBytesPerSec / DIVISOR,
&lpvAudio1, &dwBytesAudio1, &lpvAudio2, &dwBytesAudio2, 0);
if ( FAILED(hr) ) {
m_strLastError = _T("Lock DirectSoundBuffer Failed!");
OutputDebugString(m_strLastError);
return;
}
} else if (WAIT_OBJECT_0 + 1 == hr) {
m_dwCircles2++;
//Lock DirectSoundBuffer First Part
HRESULT hr = m_lpDSB->Lock(0, m_WFE.nAvgBytesPerSec / DIVISOR, &lpvAudio1, &dwBytesAudio1,
&lpvAudio2, &dwBytesAudio2, 0);
if ( FAILED(hr) ) {
m_strLastError = _T("Lock DirectSoundBuffer Failed!");
OutputDebugString(m_strLastError);
return;
}
} else {
return;
}
//Get 1 Second Audio Buffer
m_lpGETAUDIOSAMPLES(m_lpAudioBuf, m_WFE.nSamplesPerSec / DIVISOR, dwRetSamples, m_lpData);
dwRetBytes = dwRetSamples*m_WFE.nBlockAlign;
//If near the end of the audio data
if (dwRetSamples < m_WFE.nSamplesPerSec / DIVISOR) {
DWORD dwRetBytes = dwRetSamples*m_WFE.nBlockAlign;
memset(m_lpAudioBuf+dwRetBytes, 0, m_WFE.nAvgBytesPerSec / DIVISOR - dwRetBytes);
}
//Copy AudioBuffer to DirectSoundBuffer
if (NULL == lpvAudio2) {
memcpy(lpvAudio1, m_lpAudioBuf, dwBytesAudio1);
}
else {
memcpy(lpvAudio1, m_lpAudioBuf, dwBytesAudio1);
memcpy(lpvAudio2, m_lpAudioBuf + dwBytesAudio1, dwBytesAudio2);
}
//Unlock DirectSoundBuffer
m_lpDSB->Unlock(lpvAudio1, dwBytesAudio1, lpvAudio2, dwBytesAudio2);
}
//</TimerCallback>