DirectXAudioDevice.cxx

Go to the documentation of this file.
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 

Generated on Tue Aug 12 22:33:42 2008 for CLAM by  doxygen 1.5.5