Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

device_ds.cpp

Go to the documentation of this file.
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;  // one second
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     // initialize COM
00024     HRESULT rv = CoInitialize(NULL);
00025     if (FAILED(rv)) {
00026       return 0;
00027     }
00028 
00029     ADR_LOG("COM initialized properly");
00030 
00031     // register anonymous window class
00032     // don't worry about failure, if it fails, the window creation will fail
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     // create anonymous window
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     // create the DirectSound object
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     // initialize the DirectSound device
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     // set the cooperative level
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     // if the anonymous window is open, close it
00112     if (m_anonymous_window) {
00113       DestroyWindow(m_anonymous_window);
00114       m_anonymous_window = NULL;
00115     }
00116 
00117     // shut down DirectSound
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     // enumerate all open streams
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     // calculate an ideal buffer size
00157     int buffer_length = sample_rate * m_buffer_length / 1000;
00158 
00159     // define the wave format
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     // create the DirectSound buffer
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     // add ourselves to the list of streams and return
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     // The proper math doesn't sound right at all, so here is something that
00260     // sounds about right.
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 }

Generated on Sat Oct 12 01:43:01 2002 for audiere by doxygen1.2.17