📄 soundoutput_directsound.cpp
字号:
/* $Id: soundoutput_directsound.cpp,v 1.9 2003/11/06 08:38:24 sphair Exp $
**
** ClanLib Game SDK
** Copyright (C) 2003 The ClanLib Team
** For a total list of contributers see the file CREDITS.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
**
*/
#include "Sound/precomp.h"
#include "soundoutput_directsound.h"
#include "API/Core/System/error.h"
#include "API/Core/System/cl_assert.h"
#include "API/Core/System/log.h"
#include "Core/System/Win32/init_win32.h"
/////////////////////////////////////////////////////////////////////////////
// CL_SoundOutput_DirectSound construction:
CL_SoundOutput_DirectSound::CL_SoundOutput_DirectSound(int mixing_frequency) :
CL_SoundOutput_Generic(mixing_frequency),
directsound(0), soundbuffer(0),
frag_size(0), buffer_size(0), bytes_per_sample(0),
sleep_event(0), notify(0), has_sound(true)
{
HRESULT err;
err = DirectSoundCreate(NULL, &directsound, NULL);
if (FAILED(err))
{
// throw CL_Error("Cannot open sound device.");
frag_size = mixing_frequency/2;
has_sound = false;
return;
}
// We need a hwnd for our directsound interface:
HWND hwnd = NULL;
// if (CL_Display::cards.size() > 0) hwnd = ((CL_DisplayCard_Win32Compatible *) CL_Display::cards[0])->get_hwnd();
if (hwnd == NULL)
{
WNDCLASS wndclass;
wndclass.style = 0;
wndclass.lpfnWndProc = DefWindowProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = CL_System_Win32::hInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = LoadCursor (NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wndclass.lpszMenuName = "ClanSound";
wndclass.lpszClassName = "ClanSound";
RegisterClass(&wndclass);
hwnd = CreateWindow(
"ClanSound",
"ClanSound",
0, // WS_POPUP,
0,
0,
1,
1,
NULL,
NULL,
CL_System_Win32::hInstance,
NULL);
}
cl_assert(hwnd != NULL);
err = directsound->SetCooperativeLevel(hwnd, DSSCL_NORMAL);
cl_assert(SUCCEEDED(err));
// Create mixing buffer.
WAVEFORMATEX format;
format.wFormatTag = WAVE_FORMAT_PCM;
format.nChannels = 2;
format.nSamplesPerSec = mixing_frequency;
format.wBitsPerSample = 16;
format.nBlockAlign = format.wBitsPerSample * format.nChannels / 8;
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
format.cbSize = 0;
bytes_per_sample = format.nBlockAlign;
frag_size = 2500; // 0.12 sec latency
int num_fragments = 8;
DSBUFFERDESC desc;
desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS;
desc.dwBufferBytes = frag_size * bytes_per_sample * num_fragments;
desc.dwReserved = 0;
desc.lpwfxFormat = &format;
err = directsound->CreateSoundBuffer(&desc, &soundbuffer, NULL);
if (FAILED(err)) throw CL_Error("Cannot get primary sound buffer.");
// Find size of buffer:
DSBCAPS caps;
memset(&caps, 0, sizeof(DSBCAPS));
caps.dwSize = sizeof(DSBCAPS);
err = soundbuffer->GetCaps(&caps);
cl_assert(SUCCEEDED(err));
buffer_size = caps.dwBufferBytes;
cl_assert(buffer_size == frag_size * bytes_per_sample * num_fragments);
// Clear buffer at beginning (good for debugging):
DWORD size1, size2;
void *ptr1;
void *ptr2;
err = soundbuffer->Lock(0, buffer_size, &ptr1, &size1, &ptr2, &size2, 0);
cl_assert(SUCCEEDED(err));
memset(ptr1, 0, size1);
if (ptr2 != NULL) memset(ptr2, 0, size2);
soundbuffer->Unlock(ptr1, size1, ptr2, size2);
// Setup some sleeping :)
sleep_event = CreateEvent(NULL, TRUE, FALSE, NULL);
err = soundbuffer->QueryInterface(IID_IDirectSoundNotify, (void **) ¬ify);
// cl_assert(SUCCEEDED(err));
if (FAILED(err)) // directsoundnotify doesnt exist on nt4 with dx3. No sound avail.
{
// throw CL_Error("Cannot open sound device.");
frag_size = mixing_frequency/2;
has_sound = false;
return;
}
DSBPOSITIONNOTIFY *notify_pos = new DSBPOSITIONNOTIFY[num_fragments];
for (int i=0; i<num_fragments; i++)
{
notify_pos[i].dwOffset = i*frag_size*bytes_per_sample;
notify_pos[i].hEventNotify = sleep_event;
}
notify->SetNotificationPositions(num_fragments, notify_pos);
delete[] notify_pos;
err = soundbuffer->Play(0, 0, DSBPLAY_LOOPING);
cl_assert(SUCCEEDED(err));
}
CL_SoundOutput_DirectSound::~CL_SoundOutput_DirectSound()
{
if (notify) notify->Release();
if (soundbuffer) soundbuffer->Release();
if (directsound) directsound->Release();
if (sleep_event) CloseHandle(sleep_event);
}
/////////////////////////////////////////////////////////////////////////////
// CL_SoundOutput_DirectSound attributes:
/////////////////////////////////////////////////////////////////////////////
// CL_SoundOutput_DirectSound operations:
void CL_SoundOutput_DirectSound::silence()
{
}
int CL_SoundOutput_DirectSound::get_fragment_size()
{
return frag_size;
}
void CL_SoundOutput_DirectSound::write_fragment(short *data)
{
if (!has_sound) return;
HRESULT err;
DWORD play, write;
err = soundbuffer->GetCurrentPosition(&play, &write);
cl_assert(SUCCEEDED(err));
int frag_bytes = frag_size*bytes_per_sample;
int pos = (write / frag_bytes + 1) * frag_bytes;
if (pos >= buffer_size) pos -= buffer_size;
DWORD size1, size2;
void *ptr1 = NULL, *ptr2 = NULL;
err = soundbuffer->Lock(
pos,
frag_bytes,
(void **) &ptr1,
&size1,
(void **) &ptr2,
&size2,
0);
cl_assert(SUCCEEDED(err));
/*
CL_Log::log(
"debug", "#%1 play ptr: %2, write ptr: %3, pos: %4, size1: %5, size2: %6",
pos / frag_bytes, play, write, pos, size1, size2);
*/
char *_data = (char *) data;
if (ptr1 != NULL) memcpy(ptr1, _data, size1);
if (ptr2 != NULL) memcpy(ptr2, _data+size1, size2);
err = soundbuffer->Unlock(ptr1, size1, ptr2, size2);
cl_assert(SUCCEEDED(err));
}
void CL_SoundOutput_DirectSound::wait()
{
if(!has_sound)
{
CL_System::sleep(100);
return;
}
WaitForSingleObject(sleep_event, INFINITE);
ResetEvent(sleep_event);
}
/////////////////////////////////////////////////////////////////////////////
// CL_SoundOutput_DirectSound implementation:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -