CLAM-Development
1.1
|
00001 /* 00002 * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG) 00003 * UNIVERSITAT POMPEU FABRA 00004 * 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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 // :TODO: Alert! This is a kludge... 00145 // mDXFullDuplex->Stop(); 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