00001 #include <math.h>
00002 #include "device_ds.h"
00003 #include "device_ds_stream.h"
00004 #include "device_ds_buffer.h"
00005 #include "debug.h"
00006 #include "utility.h"
00007
00008
00009 namespace audiere {
00010
00011 static const int DEFAULT_BUFFER_LENGTH = 1000;
00012
00013
00014 DSAudioDevice*
00015 DSAudioDevice::create(const ParameterList& parameters) {
00016 ADR_GUARD("DSAudioDevice::create");
00017
00018 int buffer_length = atoi(parameters.getValue("buffer", "").c_str());
00019 if (buffer_length == 0) {
00020 buffer_length = DEFAULT_BUFFER_LENGTH;
00021 }
00022
00023
00024 HRESULT rv = CoInitialize(NULL);
00025 if (FAILED(rv)) {
00026 return 0;
00027 }
00028
00029 ADR_LOG("COM initialized properly");
00030
00031
00032
00033 WNDCLASS wc;
00034 wc.style = 0;
00035 wc.lpfnWndProc = DefWindowProc;
00036 wc.cbClsExtra = 0;
00037 wc.cbWndExtra = 0;
00038 wc.hInstance = GetModuleHandle(NULL);
00039 wc.hIcon = NULL;
00040 wc.hCursor = NULL;
00041 wc.hbrBackground = NULL;
00042 wc.lpszMenuName = NULL;
00043 wc.lpszClassName = "AudiereHiddenWindow";
00044 RegisterClass(&wc);
00045
00046
00047 HWND anonymous_window = CreateWindow(
00048 "AudiereHiddenWindow", "", WS_POPUP,
00049 0, 0, 0, 0,
00050 NULL, NULL, GetModuleHandle(NULL), NULL);
00051 if (!anonymous_window) {
00052 return false;
00053 }
00054
00055 ADR_LOG("Anonymous window created successfully");
00056
00057
00058 IDirectSound* direct_sound;
00059 rv = CoCreateInstance(
00060 CLSID_DirectSound,
00061 NULL,
00062 CLSCTX_INPROC_SERVER,
00063 IID_IDirectSound,
00064 (void**)&direct_sound);
00065 if (FAILED(rv) || !direct_sound) {
00066 DestroyWindow(anonymous_window);
00067 return 0;
00068 }
00069
00070 ADR_LOG("Created DS object");
00071
00072
00073 rv = direct_sound->Initialize(NULL);
00074 if (FAILED(rv)) {
00075 DestroyWindow(anonymous_window);
00076 direct_sound->Release();
00077 return 0;
00078 }
00079
00080 ADR_LOG("Initialized DS object");
00081
00082
00083 rv = direct_sound->SetCooperativeLevel(anonymous_window, DSSCL_NORMAL);
00084 if (FAILED(rv)) {
00085 DestroyWindow(anonymous_window);
00086 direct_sound->Release();
00087 return 0;
00088 }
00089
00090 ADR_LOG("Set cooperative level");
00091
00092 return new DSAudioDevice(buffer_length, anonymous_window, direct_sound);
00093 }
00094
00095
00096 DSAudioDevice::DSAudioDevice(
00097 int buffer_length,
00098 HWND anonymous_window,
00099 IDirectSound* direct_sound)
00100 {
00101 m_buffer_length = buffer_length;
00102 m_anonymous_window = anonymous_window;
00103 m_direct_sound = direct_sound;
00104 }
00105
00106
00107 DSAudioDevice::~DSAudioDevice() {
00108 ADR_ASSERT(m_open_streams.size() == 0,
00109 "DirectSound output context should not die with open streams");
00110
00111
00112 if (m_anonymous_window) {
00113 DestroyWindow(m_anonymous_window);
00114 m_anonymous_window = NULL;
00115 }
00116
00117
00118 if (m_direct_sound) {
00119 m_direct_sound->Release();
00120 m_direct_sound = NULL;
00121 }
00122 }
00123
00124
00125 void
00126 DSAudioDevice::update() {
00127 ADR_GUARD("DSAudioDevice::update");
00128 SYNCHRONIZED(this);
00129
00130
00131 StreamList::iterator i = m_open_streams.begin();
00132 while (i != m_open_streams.end()) {
00133 DSOutputStream* s = *i++;
00134 s->update();
00135 }
00136
00137 Sleep(50);
00138 }
00139
00140
00141 OutputStream*
00142 DSAudioDevice::openStream(SampleSource* source) {
00143 if (!source) {
00144 return 0;
00145 }
00146
00147 ADR_GUARD("DSAudioDevice::openStream");
00148 SYNCHRONIZED(this);
00149
00150 int channel_count, sample_rate;
00151 SampleFormat sample_format;
00152 source->getFormat(channel_count, sample_rate, sample_format);
00153
00154 int frame_size = channel_count * GetSampleSize(sample_format);
00155
00156
00157 int buffer_length = sample_rate * m_buffer_length / 1000;
00158
00159
00160 WAVEFORMATEX wfx;
00161 memset(&wfx, 0, sizeof(wfx));
00162 wfx.wFormatTag = WAVE_FORMAT_PCM;
00163 wfx.nChannels = channel_count;
00164 wfx.nSamplesPerSec = sample_rate;
00165 wfx.nAvgBytesPerSec = sample_rate * frame_size;
00166 wfx.nBlockAlign = frame_size;
00167 wfx.wBitsPerSample = GetSampleSize(sample_format) * 8;
00168 wfx.cbSize = sizeof(wfx);
00169
00170 DSBUFFERDESC dsbd;
00171 memset(&dsbd, 0, sizeof(dsbd));
00172 dsbd.dwSize = sizeof(dsbd);
00173 dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN |
00174 DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY |
00175 DSBCAPS_GLOBALFOCUS;
00176 dsbd.dwBufferBytes = frame_size * buffer_length;
00177 dsbd.lpwfxFormat = &wfx;
00178
00179
00180 IDirectSoundBuffer* buffer;
00181 HRESULT result = m_direct_sound->CreateSoundBuffer(
00182 &dsbd, &buffer, NULL);
00183 if (FAILED(result) || !buffer) {
00184 return 0;
00185 }
00186
00187 ADR_LOG("CreateSoundBuffer succeeded");
00188
00189 DSOutputStream* stream = new DSOutputStream(
00190 this, buffer, buffer_length, source);
00191
00192
00193 m_open_streams.push_back(stream);
00194 return stream;
00195 }
00196
00197
00198 OutputStream*
00199 DSAudioDevice::openBuffer(
00200 void* samples, int frame_count,
00201 int channel_count, int sample_rate, SampleFormat sample_format)
00202 {
00203 ADR_GUARD("DSAudioDevice::openBuffer");
00204 SYNCHRONIZED(this);
00205
00206 int frame_size = channel_count * GetSampleSize(sample_format);
00207 int buffer_size = frame_count * frame_size;
00208
00209 WAVEFORMATEX wfx;
00210 memset(&wfx, 0, sizeof(wfx));
00211 wfx.wFormatTag = WAVE_FORMAT_PCM;
00212 wfx.nChannels = channel_count;
00213 wfx.nSamplesPerSec = sample_rate;
00214 wfx.nAvgBytesPerSec = sample_rate * frame_size;
00215 wfx.nBlockAlign = frame_size;
00216 wfx.wBitsPerSample = GetSampleSize(sample_format) * 8;
00217 wfx.cbSize = sizeof(wfx);
00218
00219 DSBUFFERDESC dsbd;
00220 memset(&dsbd, 0, sizeof(dsbd));
00221 dsbd.dwSize = sizeof(dsbd);
00222 dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN |
00223 DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY |
00224 DSBCAPS_GLOBALFOCUS | DSBCAPS_STATIC;
00225 dsbd.dwBufferBytes = buffer_size;
00226 dsbd.lpwfxFormat = &wfx;
00227
00228 IDirectSoundBuffer* buffer;
00229 HRESULT result = m_direct_sound->CreateSoundBuffer(
00230 &dsbd, &buffer, NULL);
00231 if (FAILED(result) || !buffer) {
00232 return 0;
00233 }
00234
00235 void* data;
00236 DWORD data_size;
00237 result = buffer->Lock(0, buffer_size, &data, &data_size, 0, 0, 0);
00238 if (FAILED(result)) {
00239 buffer->Release();
00240 return 0;
00241 }
00242
00243 memcpy(data, samples, data_size);
00244 buffer->Unlock(data, data_size, 0, 0);
00245
00246 return new DSOutputBuffer(this, buffer, frame_count, frame_size);
00247 }
00248
00249
00250 void
00251 DSAudioDevice::removeStream(DSOutputStream* stream) {
00252 SYNCHRONIZED(this);
00253 m_open_streams.remove(stream);
00254 }
00255
00256
00257 int
00258 DSAudioDevice::Volume_AudiereToDirectSound(float volume) {
00259
00260
00261 double attenuate = pow(1 - volume, 3);
00262 return int(-10000 * attenuate);
00263 }
00264
00265
00266 int
00267 DSAudioDevice::Pan_AudiereToDirectSound(float pan) {
00268 if (pan < 0) {
00269 return -Pan_AudiereToDirectSound(-pan);
00270 } else {
00271 return -Volume_AudiereToDirectSound(1 - pan);
00272 }
00273 }
00274
00275 }