00001
00002
00003
00004
00005
00006 #ifdef WIN32
00007 #pragma warning (disable:4786)
00008 #endif
00009
00010 #include "directsound.h"
00011 #include <API/Core/System/error.h>
00012 #include <API/Core/System/cl_assert.h>
00013 #include <Core/System/Win32/init_win32.h>
00014 #include <iostream>
00015
00016 extern LONG WINAPI MainMessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
00017
00018 bool has_sound = true;
00019
00020 CL_CSOutput::CL_CSOutput()
00021 : directsound(NULL), soundbuffer(NULL), sleep_event(NULL)
00022 {
00023 HRESULT err;
00024 err = DirectSoundCreate(NULL, &directsound, NULL);
00025
00026 if (err != DS_OK)
00027 {
00028
00029 frag_size = 22050/2;
00030 has_sound = false;
00031 return;
00032 }
00033
00034
00035 HWND hwnd = NULL;
00036
00037 if (hwnd == NULL)
00038 {
00039 WNDCLASS wndclass;
00040
00041 wndclass.style = 0;
00042 wndclass.lpfnWndProc = (WNDPROC) MainMessageHandler;
00043 wndclass.cbClsExtra = 0;
00044 wndclass.cbWndExtra = 0;
00045 wndclass.hInstance = CL_System_Win32::hInstance;
00046 wndclass.hIcon = NULL;
00047 wndclass.hCursor = LoadCursor (NULL,IDC_ARROW);
00048 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
00049 wndclass.lpszMenuName = "ClanSound";
00050 wndclass.lpszClassName = "ClanSound";
00051
00052 RegisterClass(&wndclass);
00053
00054 hwnd = CreateWindow(
00055 "ClanSound",
00056 "ClanSound",
00057 0,
00058 0,
00059 0,
00060 1,
00061 1,
00062 NULL,
00063 NULL,
00064 CL_System_Win32::hInstance,
00065 NULL);
00066 }
00067 cl_assert(hwnd != NULL);
00068
00069 err = directsound->SetCooperativeLevel(hwnd, DSSCL_NORMAL);
00070 cl_assert(err == DS_OK);
00071
00072
00073
00074 WAVEFORMATEX format;
00075 format.wFormatTag = WAVE_FORMAT_PCM;
00076 format.nChannels = 2;
00077 format.nSamplesPerSec = 22050;
00078 format.wBitsPerSample = 16;
00079 format.nBlockAlign = format.wBitsPerSample * format.nChannels / 8;
00080 format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
00081 format.cbSize = 0;
00082
00083 bytes_per_sample = format.nBlockAlign;
00084
00085 frag_size = 2500;
00086 int num_fragments = 8;
00087
00088 DSBUFFERDESC desc;
00089 desc.dwSize = sizeof(DSBUFFERDESC);
00090 desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS;
00091
00092 desc.dwBufferBytes = frag_size * bytes_per_sample * num_fragments;
00093 desc.dwReserved = 0;
00094 desc.lpwfxFormat = &format;
00095
00096 err = directsound->CreateSoundBuffer(&desc, &soundbuffer, NULL);
00097 if (err != DS_OK) throw CL_Error("Cannot get primary sound buffer.");
00098
00099
00100
00101 DSBCAPS caps;
00102 memset(&caps, 0, sizeof(DSBCAPS));
00103 caps.dwSize = sizeof(DSBCAPS);
00104
00105 err = soundbuffer->GetCaps(&caps);
00106 cl_assert(err == DS_OK);
00107
00108 buffer_size = caps.dwBufferBytes;
00109 cl_assert(buffer_size == frag_size * bytes_per_sample * num_fragments);
00110
00111
00112 DWORD size1, size2;
00113 void *ptr1;
00114 void *ptr2;
00115 err = soundbuffer->Lock(0, buffer_size, &ptr1, &size1, &ptr2, &size2, 0);
00116 cl_assert(err == DS_OK);
00117
00118 memset(ptr1, 0, size1);
00119 if (ptr2 != NULL) memset(ptr2, 0, size2);
00120
00121 soundbuffer->Unlock(ptr1, size1, ptr2, size2);
00122
00123
00124 sleep_event = CreateEvent(NULL, TRUE, FALSE, NULL);
00125
00126 err = soundbuffer->QueryInterface(IID_IDirectSoundNotify, (void **) ¬ify);
00127
00128 if (err != DS_OK)
00129 {
00130
00131 frag_size = 22050/2;
00132 has_sound = false;
00133 return;
00134 }
00135
00136 DSBPOSITIONNOTIFY *notify_pos = new DSBPOSITIONNOTIFY[num_fragments];
00137 for (int i=0; i<num_fragments; i++)
00138 {
00139 notify_pos[i].dwOffset = i*frag_size*bytes_per_sample;
00140 notify_pos[i].hEventNotify = sleep_event;
00141 }
00142 notify->SetNotificationPositions(num_fragments, notify_pos);
00143 delete[] notify_pos;
00144
00145 err = soundbuffer->Play(0, 0, DSBPLAY_LOOPING);
00146 cl_assert(err == DS_OK);
00147 }
00148
00149 CL_CSOutput::~CL_CSOutput()
00150 {
00151 if (soundbuffer != NULL) soundbuffer->Release();
00152 if (directsound != NULL) directsound->Release();
00153 if (sleep_event != NULL) CloseHandle(sleep_event);
00154 }
00155
00156 void CL_CSOutput::silence()
00157 {
00158 }
00159
00160 bool CL_CSOutput::is_full()
00161 {
00162 if (!has_sound) return false;
00163
00164 cl_info(info_sound, "CL_CSOutput::is_full() is not implemented! Program will assert now.");
00165 cl_assert(false);
00166 return false;
00167 }
00168
00169 void CL_CSOutput::write_fragment(short *data)
00170 {
00171 if (!has_sound) return;
00172
00173 HRESULT err;
00174
00175 DWORD play, write;
00176 err = soundbuffer->GetCurrentPosition(&play, &write);
00177 cl_assert(err == DS_OK);
00178
00179 int frag_bytes = frag_size*bytes_per_sample;
00180
00181 int pos = (write / frag_bytes + 1) * frag_bytes;
00182 if (pos >= buffer_size) pos -= buffer_size;
00183
00184 DWORD size1, size2;
00185 void *ptr1 = NULL, *ptr2 = NULL;
00186 err = soundbuffer->Lock(
00187 pos,
00188 frag_bytes,
00189 (void **) &ptr1,
00190 &size1,
00191 (void **) &ptr2,
00192 &size2,
00193 0);
00194 cl_assert(err == DS_OK);
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 char *_data = (char *) data;
00206 if (ptr1 != NULL) memcpy(ptr1, _data, size1);
00207 if (ptr2 != NULL) memcpy(ptr2, _data+size1, size2);
00208
00209 err = soundbuffer->Unlock(ptr1, size1, ptr2, size2);
00210 cl_assert(err == DS_OK);
00211 }
00212
00213 void CL_CSOutput::wait()
00214 {
00215 if(!has_sound)
00216 {
00217 CL_System::sleep(100);
00218 return;
00219 }
00220
00221 WaitForSingleObject(sleep_event, INFINITE);
00222 ResetEvent(sleep_event);
00223 }