00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "AudioManager.hxx"
00023
00024 #define STRICT
00025 #include "CLAM_windows.h"
00026 #undef GetClassName
00027 #include <dxerr8.h>
00028 #include <dsound.h>
00029 #include <dinput.h>
00030
00031 #include "DXFullDuplex.hxx"
00032 #include "AudioDeviceList.hxx"
00033
00034 namespace CLAM {
00035
00036 class ErrDirectX:public Err
00037 {
00038 public:
00039 ErrDirectX(char* str,HRESULT hr) throw();
00040 };
00041
00042 ErrDirectX::ErrDirectX(char* str,HRESULT hr):Err()
00043 {
00044 const char* dxErrStr = DXGetErrorString8(hr);
00045 mMsg = (char*) malloc(strlen(str)+strlen(dxErrStr)+1);
00046 strcpy(mMsg,str);
00047 strcat(mMsg,dxErrStr);
00048 }
00049
00050 class DirectXAudioDevice: public AudioDevice
00051 {
00052 private:
00053 int mNChannelsWritten;
00054 bool mChannelsWritten[256];
00055
00056 int mNChannelsRead;
00057 bool mChannelsRead[256];
00058
00059 int mWriteBufSize;
00060 short mWriteBuf[8192];
00061
00062 int mReadBufSize;
00063 short mReadBuf[8192];
00064
00065 DXFullDuplex* mDXFullDuplex;
00066 LPGUID mGUID;
00067
00068 public:
00069 DirectXAudioDevice(const std::string& name,const LPGUID& guid);
00070 ~DirectXAudioDevice(void);
00071 void Start(void) throw(Err);
00072 void Stop(void) throw(Err);
00073 void Read(Audio& audio,const int channelID);
00074 void Write(const Audio& audio,const int channelID);
00075
00076 virtual void GetInfo( AudioDevice::TInfo& );
00077 };
00078
00079 DirectXAudioDevice::DirectXAudioDevice(const std::string& name,const LPGUID& guid)
00080 :AudioDevice(name)
00081 {
00082 int i;
00083
00084 mNChannelsWritten = 0;
00085 for (i=0;i<256;i++)
00086 {
00087 mChannelsWritten[i] = false;
00088 }
00089
00090 mNChannelsRead = 0;
00091 for (i=0;i<256;i++)
00092 {
00093 mChannelsRead[i] = false;
00094 }
00095
00096 mDXFullDuplex = 0;
00097 mGUID = guid;
00098 }
00099
00100
00101 DirectXAudioDevice::~DirectXAudioDevice(void)
00102 {
00103 if (mDXFullDuplex)
00104 {
00105 delete mDXFullDuplex;
00106 }
00107 }
00108
00109 void DirectXAudioDevice::Start(void) throw(Err)
00110 {
00111 if (mOutputs.size() && mInputs.size())
00112 {
00113 if (mOutputs.size() != mInputs.size())
00114 {
00115 throw(Err("DirectXAudioDevice::Start(): "
00116 "need identical number of inputs and outputs "
00117 "for full-duplex operation"));
00118 }
00119 mNChannels = mOutputs.size();
00120 if (mDXFullDuplex==0)
00121 {
00122 try {
00123 mDXFullDuplex = new DXFullDuplex(SampleRate(),mNChannels,Latency(),mGUID);
00124 }
00125 catch (ErrDXFullDuplex e) {
00126 Err ne("DirectXAudioDevice::Start(): Failed to create DirectX device.");
00127 ne.Embed(e);
00128 throw(ne);
00129 }
00130
00131 mWriteBufSize = mReadBufSize = 0;
00132
00133 mDXFullDuplex->Start();
00134 }
00135 }else{
00136 throw Err("currently only full-duplex implemented");
00137 }
00138
00139
00140 }
00141
00142 void DirectXAudioDevice::Stop()
00143 {
00144
00145
00146 }
00147
00148 void DirectXAudioDevice::GetInfo( AudioDevice::TInfo &info )
00149 {
00150 AudioDevice::GetInfo( info );
00151 }
00152
00153 void DirectXAudioDevice::Read(Audio& audio,const int channelID)
00154 {
00155 TData* ptrA = audio.GetBuffer().GetPtr();
00156 short* ptrB = mReadBuf + channelID;
00157 int n;
00158
00159 if (mChannelsRead[channelID])
00160 throw Err("DirectXAudioDevice::Read(): Tried to read "
00161 "twice from a channel in a single time frame!");
00162 if (!mDXFullDuplex)
00163 throw Err("DirectXAudioDevice::Read(): Device not configured.");
00164
00165 if (mReadBufSize==0) mReadBufSize=audio.GetSize();
00166 else if (mReadBufSize!=audio.GetSize())
00167 throw Err("Inconsistent Audio size");
00168 if (mReadBufSize>mDXFullDuplex->mLatency)
00169 throw Err("You are trying to read audio in blocks bigger than the latency");
00170
00171 if (mNChannelsRead == 0)
00172 {
00173 mDXFullDuplex->Poll();
00174 mDXFullDuplex->Read(mReadBuf,mReadBufSize);
00175 }
00176
00177 n = mReadBufSize;
00178 while (n--)
00179 {
00180 *ptrA++ = TData(*ptrB) / TData(32767.);
00181 ptrB += mNChannels;
00182 }
00183
00184 mChannelsRead[channelID] = true;
00185 mNChannelsRead++;
00186
00187 if (mNChannelsRead==mNChannels)
00188 {
00189 mNChannelsRead = 0;
00190 for (int i=0;i<mNChannels;i++)
00191 mChannelsRead[i] = false;
00192 }
00193 }
00194
00195 void DirectXAudioDevice::Write(const Audio& audio,const int channelID)
00196 {
00197 TData* ptrA = audio.GetBuffer().GetPtr();
00198 short* ptrB = mWriteBuf + channelID;
00199 int i,n;
00200
00201 if (mWriteBufSize==0) mWriteBufSize=audio.GetSize();
00202 else if (mWriteBufSize!=audio.GetSize())
00203 throw Err("Inconsistent Audio size");
00204
00205
00206 if (mChannelsWritten[channelID])
00207 throw Err("DirectXAudioDevice::Write(): Tried to write "
00208 "twice into a channel in a single time frame.");
00209 if (!mDXFullDuplex)
00210 throw Err("DirectXAudioDevice::Write(): Device not configured.");
00211 if (mWriteBufSize>mDXFullDuplex->mLatency)
00212 throw Err("You are trying to write audio in blocks bigger than the latency");
00213
00214 n = mWriteBufSize;
00215 while (n--)
00216 {
00217 *ptrB = (short) (32767.*(*ptrA++));
00218 ptrB += mNChannels;
00219 }
00220
00221 mChannelsWritten[channelID] = true;
00222 mNChannelsWritten++;
00223
00224 if (mNChannelsWritten==mNChannels)
00225 {
00226 mDXFullDuplex->Write(mWriteBuf,mWriteBufSize);
00227
00228 mNChannelsWritten = 0;
00229 for (i=0;i<mNChannels;i++)
00230 mChannelsWritten[i] = false;
00231 }
00232 }
00233
00234
00235
00236
00237 class DirectXAudioDeviceList: public AudioDeviceList
00238 {
00239 static DirectXAudioDeviceList sDevices;
00240 private:
00241 DirectXAudioDeviceList()
00242 :AudioDeviceList(std::string("directx"))
00243 {
00244 HRESULT hr;
00245
00246 if( FAILED( hr = DirectSoundEnumerate(DSEnumCallback,this ) ) )
00247 throw(ErrDirectX( TEXT("DirectSoundEnumerate"), hr ));
00248
00249 AddMe();
00250 }
00251 public:
00252 std::vector<LPGUID> mGuids;
00253
00254 static BOOL CALLBACK DSEnumCallback(
00255 LPGUID lpGuid,
00256 LPCSTR lpcstrDescription,
00257 LPCSTR lpcstrModule,
00258 LPVOID lpContext
00259 )
00260 {
00261 DirectXAudioDeviceList* list = (DirectXAudioDeviceList*) lpContext;
00262 list->mAvailableDevices.push_back(lpcstrDescription);
00263 list->mGuids.push_back(lpGuid);
00264 return true;
00265 }
00266
00267 std::string DefaultDevice(void)
00268 {
00269 return mAvailableDevices[0];
00270 }
00271
00272 AudioDevice* Create(
00273 const std::string& name, const std::string& device)
00274 {
00275 int i = 0;
00276 for (i=0;i<mAvailableDevices.size();i++)
00277 {
00278 if (device == mAvailableDevices[i])
00279 return new DirectXAudioDevice(name,mGuids[i]);
00280 }
00281 return 0;
00282 }
00283 };
00284
00285 DirectXAudioDeviceList DirectXAudioDeviceList::sDevices;
00286
00287 }
00288