00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <math.h>
00022 #include "output_ds.hpp"
00023 #include "debug.hpp"
00024 #include "input.hpp"
00025
00026
00027 static const int DS_DefaultBufferLength = 1000;
00028
00029
00030
00031
00032 inline int Volume_AudiereToDirectSound(int volume) {
00033
00034 double fv = volume / 255.0;
00035 double attenuate = pow(1 - fv, 3);
00036 return int(-10000 * attenuate);
00037 }
00038
00039
00041
00042 DSOutputContext::DSOutputContext()
00043 {
00044 m_DirectSound = NULL;
00045 m_BufferLength = DS_DefaultBufferLength;
00046 m_AnonymousWindow = NULL;
00047 }
00048
00050
00051 DSOutputContext::~DSOutputContext()
00052 {
00053 ADR_ASSERT(m_OpenStreams.size() == 0,
00054 "DirectSound output context should not die with open streams");
00055
00056
00057 if (m_AnonymousWindow) {
00058 DestroyWindow(m_AnonymousWindow);
00059 m_AnonymousWindow = NULL;
00060 }
00061
00062
00063 if (m_DirectSound) {
00064 m_DirectSound->Release();
00065 m_DirectSound = NULL;
00066 }
00067 }
00068
00070
00071 bool
00072 DSOutputContext::Initialize(const char* parameters)
00073 {
00074 ADR_GUARD("DSOutputContext::Initialize");
00075
00076
00077 ParameterList pl;
00078 ParseParameters(parameters, pl);
00079
00080 ParameterList::iterator i = pl.begin();
00081 while (i != pl.end()) {
00082
00083 if (i->first.c_str() == "buffer") {
00084 m_BufferLength = atoi(i->second.c_str());
00085 if (m_BufferLength == 0) {
00086 m_BufferLength = DS_DefaultBufferLength;
00087 }
00088 }
00089
00090 ++i;
00091 }
00092
00093
00094 HRESULT rv = CoInitialize(NULL);
00095 if (FAILED(rv)) {
00096 return false;
00097 }
00098
00099 ADR_LOG("COM initialized properly");
00100
00101
00102
00103 WNDCLASS wc;
00104 wc.style = 0;
00105 wc.lpfnWndProc = DefWindowProc;
00106 wc.cbClsExtra = 0;
00107 wc.cbWndExtra = 0;
00108 wc.hInstance = GetModuleHandle(NULL);
00109 wc.hIcon = NULL;
00110 wc.hCursor = NULL;
00111 wc.hbrBackground = NULL;
00112 wc.lpszMenuName = NULL;
00113 wc.lpszClassName = "AudiereHiddenWindow";
00114 RegisterClass(&wc);
00115
00116
00117 m_AnonymousWindow = CreateWindow(
00118 "AudiereHiddenWindow", "", WS_POPUP,
00119 0, 0, 0, 0,
00120 NULL, NULL, GetModuleHandle(NULL), NULL);
00121 if (!m_AnonymousWindow) {
00122 return false;
00123 }
00124
00125 ADR_LOG("Anonymous window created successfully");
00126
00127
00128 rv = CoCreateInstance(
00129 GetCLSID(),
00130 NULL,
00131 CLSCTX_INPROC_SERVER,
00132 IID_IDirectSound,
00133 (void**)&m_DirectSound);
00134 if (FAILED(rv) || !m_DirectSound) {
00135 DestroyWindow(m_AnonymousWindow);
00136 m_AnonymousWindow = NULL;
00137 return false;
00138 }
00139
00140 ADR_LOG("Created DS object");
00141
00142
00143 rv = m_DirectSound->Initialize(NULL);
00144 if (FAILED(rv)) {
00145 DestroyWindow(m_AnonymousWindow);
00146 m_AnonymousWindow = NULL;
00147 m_DirectSound->Release();
00148 m_DirectSound = NULL;
00149 return false;
00150 }
00151
00152 ADR_LOG("Initialized DS object");
00153
00154
00155 rv = m_DirectSound->SetCooperativeLevel(
00156 m_AnonymousWindow,
00157 GetCooperativeLevel());
00158 if (FAILED(rv)) {
00159 DestroyWindow(m_AnonymousWindow);
00160 m_AnonymousWindow = NULL;
00161 m_DirectSound->Release();
00162 m_DirectSound = NULL;
00163 return false;
00164 }
00165
00166 ADR_LOG("Set cooperative level");
00167
00168 if (!CreatePrimarySoundBuffer(m_DirectSound)) {
00169
00170 ADR_LOG("CreatePrimarySoundBuffer failed");
00171
00172 DestroyWindow(m_AnonymousWindow);
00173 m_AnonymousWindow = NULL;
00174 m_DirectSound->Release();
00175 m_DirectSound = NULL;
00176 return false;
00177 }
00178
00179 ADR_LOG("Primary sound buffer created");
00180
00181 return true;
00182 }
00183
00185
00186 void
00187 DSOutputContext::Update()
00188 {
00189 ADR_GUARD("DSOutputContext::Update");
00190
00191
00192 StreamList::iterator i = m_OpenStreams.begin();
00193 while (i != m_OpenStreams.end()) {
00194 DSOutputStream* s = *i++;
00195 s->Update();
00196 }
00197
00198 Sleep(50);
00199 }
00200
00202
00203 IOutputStream*
00204 DSOutputContext::OpenStream(ISampleSource* source)
00205 {
00206 ADR_GUARD("DSOutputContext::OpenStream");
00207
00208 int channel_count, sample_rate, bits_per_sample;
00209 source->GetFormat(channel_count, sample_rate, bits_per_sample);
00210
00211 int sample_size = channel_count * bits_per_sample / 8;
00212
00213
00214 int buffer_length = sample_rate * m_BufferLength / 1000;
00215
00216
00217 WAVEFORMATEX wfx;
00218 memset(&wfx, 0, sizeof(wfx));
00219 wfx.wFormatTag = WAVE_FORMAT_PCM;
00220 wfx.nChannels = channel_count;
00221 wfx.nSamplesPerSec = sample_rate;
00222 wfx.nAvgBytesPerSec = sample_rate * sample_size;
00223 wfx.nBlockAlign = sample_size;
00224 wfx.wBitsPerSample = bits_per_sample;
00225 wfx.cbSize = sizeof(wfx);
00226
00227
00228 #if DIRECTSOUND_VERSION >= 0x0700
00229 DSBUFFERDESC1 dsbd;
00230 #else
00231 DSBUFFERDESC dsbd;
00232 #endif
00233 memset(&dsbd, 0, sizeof(dsbd));
00234 dsbd.dwSize = sizeof(dsbd);
00235 dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN |
00236 DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS;
00237 dsbd.dwBufferBytes = sample_size * buffer_length;
00238 dsbd.lpwfxFormat = &wfx;
00239
00240
00241 IDirectSoundBuffer* buffer;
00242 HRESULT result = m_DirectSound->CreateSoundBuffer(
00243 (DSBUFFERDESC*)&dsbd,
00244 &buffer,
00245 NULL);
00246 if (FAILED(result) || !buffer) {
00247 return 0;
00248 }
00249
00250 ADR_LOG("CreateSoundBuffer succeeded");
00251
00252 DSOutputStream* stream = new DSOutputStream(
00253 this, buffer, sample_size, buffer_length, source);
00254
00255
00256 m_OpenStreams.push_back(stream);
00257 return stream;
00258 }
00259
00261
00262 void
00263 DSOutputContext::RemoveStream(DSOutputStream* stream)
00264 {
00265 m_OpenStreams.remove(stream);
00266 }
00267
00269
00270 DSOutputStream::DSOutputStream(
00271 DSOutputContext* context,
00272 IDirectSoundBuffer* buffer,
00273 int sample_size,
00274 int buffer_length,
00275 ISampleSource* source)
00276 {
00277 ADR_GUARD("DSOutputStream::DSOutputStream");
00278
00279 m_Context = context;
00280 m_Buffer = buffer;
00281 m_NextRead = 0;
00282 m_BufferLength = buffer_length;
00283
00284 m_Source = source;
00285
00286 m_SampleSize = sample_size;
00287 m_LastSample = new BYTE[sample_size];
00288
00289 SetVolume(ADR_VOLUME_MAX);
00290
00291
00292 FillStream();
00293 }
00294
00296
00297 DSOutputStream::~DSOutputStream()
00298 {
00299 ADR_GUARD("DSOutputStream::~DSOutputStream");
00300
00301 m_Context->RemoveStream(this);
00302
00303
00304 m_Buffer->Release();
00305 delete[] m_LastSample;
00306 }
00307
00309
00310 void
00311 DSOutputStream::FillStream()
00312 {
00313 ADR_GUARD("DSOutputStream::FillStream");
00314
00315
00316
00317 void* buffer = NULL;
00318 DWORD buffer_length = 0;
00319
00320
00321 HRESULT result = m_Buffer->Lock(
00322 0,
00323 m_BufferLength * m_SampleSize,
00324 &buffer,
00325 &buffer_length,
00326 NULL,
00327 NULL,
00328 0);
00329 if (FAILED(result) || !buffer) {
00330 ADR_LOG("FillStream failed!");
00331 return;
00332 }
00333
00334 ADR_IF_DEBUG {
00335 char str[80];
00336 sprintf(str, "Buffer Length = %d", buffer_length);
00337 ADR_LOG(str);
00338 }
00339
00340
00341 int samples_to_read = buffer_length / m_SampleSize;
00342 int samples_read = StreamRead(samples_to_read, buffer);
00343 if (samples_read != samples_to_read) {
00344 m_NextRead = samples_read;
00345 } else {
00346 m_NextRead = 0;
00347 }
00348
00349
00350 m_Buffer->Unlock(buffer, buffer_length, NULL, 0);
00351 }
00352
00354
00355 void
00356 DSOutputStream::Update()
00357 {
00358 ADR_GUARD("DSOutputStream::Update");
00359
00360
00361 if (!IsPlaying()) {
00362 return;
00363 }
00364
00365
00366
00367
00368 DWORD play;
00369 DWORD write;
00370 HRESULT result = m_Buffer->GetCurrentPosition(&play, &write);
00371 if (FAILED(result)) {
00372 ADR_LOG("GetCurrentPosition failed");
00373 return;
00374 }
00375
00376 ADR_IF_DEBUG {
00377 char str[160];
00378 sprintf(str, "play: %d write: %d", play, write);
00379 ADR_LOG(str);
00380 }
00381
00382
00383 play /= m_SampleSize;
00384 write /= m_SampleSize;
00385
00386
00387 int read_length = play - m_NextRead;
00388 if (read_length < 0) {
00389 read_length += m_BufferLength;
00390 }
00391
00392 if (read_length == 0) {
00393 return;
00394 }
00395
00396
00397 void* buffer1;
00398 void* buffer2;
00399 DWORD buffer1_length;
00400 DWORD buffer2_length;
00401 result = m_Buffer->Lock(
00402 m_NextRead * m_SampleSize,
00403 read_length * m_SampleSize,
00404 &buffer1,
00405 &buffer1_length,
00406 &buffer2,
00407 &buffer2_length,
00408 0
00409 );
00410 if (FAILED(result)) {
00411 ADR_LOG("Lock() failed!");
00412 return;
00413 }
00414
00415 ADR_IF_DEBUG {
00416 char str[160];
00417 sprintf(str, "buffer1: %d buffer2: %d", buffer1_length, buffer2_length);
00418 ADR_LOG(str);
00419 }
00420
00421
00422 int length1 = buffer1_length / m_SampleSize;
00423 int length2 = buffer2_length / m_SampleSize;
00424 int read = StreamRead(length1, buffer1);
00425 if (length1 == read) {
00426 read += StreamRead(length2, buffer2);
00427 }
00428
00429 ADR_IF_DEBUG {
00430 char str[80];
00431 sprintf(str, "read: %d", read);
00432 ADR_LOG(str);
00433 }
00434
00435 m_NextRead = (m_NextRead + read) % m_BufferLength;
00436
00437
00438 m_Buffer->Unlock(buffer1, buffer1_length, buffer2, buffer2_length);
00439
00440
00441
00442
00443 if (read == 0 && IsBetween(m_NextRead, play, write)) {
00444
00445 ADR_LOG("Stopping stream!");
00446
00447 m_Buffer->Stop();
00448 m_Buffer->SetCurrentPosition(0);
00449
00450 m_Source->Reset();
00451
00452 m_NextRead = 0;
00453 FillStream();
00454
00455 return;
00456 }
00457 }
00458
00460
00461
00462 int
00463 DSOutputStream::StreamRead(int sample_count, void* samples)
00464 {
00465 ADR_GUARD("StreamRead");
00466
00467
00468 int samples_read = m_Source->Read(sample_count, samples);
00469
00470
00471 if (samples_read > 0) {
00472 memcpy(
00473 m_LastSample,
00474 (BYTE*)samples + (samples_read - 1) * m_SampleSize,
00475 m_SampleSize);
00476 }
00477
00478
00479 BYTE* out = (BYTE*)samples + m_SampleSize * samples_read;
00480 int c = sample_count - samples_read;
00481 while (c--) {
00482 memcpy(out, m_LastSample, m_SampleSize);
00483 out += m_SampleSize;
00484 }
00485
00486 return samples_read;
00487 }
00488
00490
00491 bool
00492 DSOutputStream::IsBetween(int position, int start, int end)
00493 {
00494 if (start < end) {
00495 return (position >= start && position < end);
00496 } else {
00497 return (position >= start || position < end);
00498 }
00499 }
00500
00502
00503 void
00504 DSOutputStream::Play()
00505 {
00506 m_Buffer->Play(0, 0, DSBPLAY_LOOPING);
00507 }
00508
00510
00511 void
00512 DSOutputStream::Stop()
00513 {
00514 m_Buffer->Stop();
00515 }
00516
00518
00519 void
00520 DSOutputStream::Reset()
00521 {
00522 ADR_GUARD("DSOutputStream::Reset");
00523
00524
00525 bool is_playing = IsPlaying();
00526
00527
00528 if (is_playing) {
00529 m_Buffer->Stop();
00530 }
00531
00532 m_Buffer->SetCurrentPosition(0);
00533 m_Source->Reset();
00534 m_NextRead = 0;
00535 FillStream();
00536
00537
00538 if (is_playing) {
00539 m_Buffer->Play(0, 0, DSBPLAY_LOOPING);
00540 }
00541 }
00542
00544
00545 bool
00546 DSOutputStream::IsPlaying()
00547 {
00548 DWORD status;
00549 HRESULT rv = m_Buffer->GetStatus(&status);
00550 return (SUCCEEDED(rv) && status & DSBSTATUS_PLAYING);
00551 }
00552
00554
00555 void
00556 DSOutputStream::SetVolume(int volume)
00557 {
00558 m_Volume = volume;
00559 m_Buffer->SetVolume(Volume_AudiereToDirectSound(volume));
00560 }
00561
00563
00564 int
00565 DSOutputStream::GetVolume()
00566 {
00567 return m_Volume;
00568 }
00569