Windows/RtAAudioDevice.cxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 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 "AudioDevice.hxx"
00023 #include "AudioDeviceList.hxx"
00024 #include "RtAudio.h"
00025 #include "RtAudioUtils.hxx"
00026 
00027 #include "CLAM_windows.h"
00028 #undef GetClassName
00029 #include <iostream>
00030 
00031 using std::cout;
00032 using std::endl;
00033 
00034 namespace CLAM
00035 {
00036 
00037         class RtAAudioDevice : public AudioDevice
00038         {
00039                 enum IOModalities
00040                 {
00041                         eFullDuplex=0,
00042                         eHalfDuplexIn,
00043                         eHalfDuplexOut,
00044                         eNoneYet
00045                 };
00046 
00047         public:
00048 
00049                 RtAAudioDevice( const std::string& str, int devID );
00050                 ~RtAAudioDevice( );
00051 
00052                 void Start() throw( ErrRtAudio );
00053                 void Stop() throw ( ErrRtAudio );
00054                 void Read( Audio& samples, const int channelID );
00055                 void Write( const Audio& samples, const  int channelID );
00056 
00057                 virtual void GetInfo( AudioDevice::TInfo& );
00058 
00059         protected:
00060 
00061                 void SetupMonoOutputStream() throw( ErrRtAudio );
00062                 void SetupStereoOutputStream() throw( ErrRtAudio );
00063                 void SetupMultiOutputStream() throw( ErrRtAudio );
00064                 void SetupMonoInputStream() throw( ErrRtAudio );
00065                 void SetupStereoInputStream() throw( ErrRtAudio );
00066                 void SetupMultiInputStream() throw( ErrRtAudio );
00067                 void SetupStereoFullDuplexStream() throw( ErrRtAudio );
00068 
00069         private:
00070 
00071                 unsigned                 mNChannelsWritten;
00072                 bool                     mChannelsWritten[256];
00073 
00074                 unsigned                 mNChannelsRead;
00075                 bool                     mChannelsRead[256];
00076 
00077                 int                      mFramesPerBuffer;
00078 
00079                 int                      mDevID;
00080 
00081                 short*                   mInputSamples;
00082                 short*                   mOutputSamples;
00083 
00084                 int                      mInputStreamId;
00085                 int                      mOutputStreamId;
00086 
00087                 IOModalities             mIOModel;
00088                 RtAudio*                 mDevice;
00089 
00090                 bool                     mStarted;
00091         };
00092 
00093 
00094         class RtAAudioDeviceList : public AudioDeviceList
00095         {
00096         private:
00097                 static RtAAudioDeviceList sDevices;
00098 
00099                 RtAAudioDeviceList();
00100 
00101                 std::vector< int > mDevIDs;
00102 
00103         protected:
00104 
00105                 void EnumerateAvailableDevices() throw ( ErrRtAudio );
00106 
00107         public:
00108 
00109                 virtual ~RtAAudioDeviceList();
00110 
00111                 inline std::string DefaultDevice()
00112                 {
00113                         return mAvailableDevices[0];
00114                 }
00115 
00116                 AudioDevice* Create( const std::string& name, const std::string& device );
00117 
00118         };
00119         
00120         RtAAudioDevice::RtAAudioDevice( const std::string& name, int devID )
00121                 : AudioDevice(name), mDevID( devID ), 
00122                   mIOModel( eNoneYet ),mStarted(false), mDevice( NULL ), 
00123                   mInputSamples( NULL ), mOutputSamples( NULL ), mInputStreamId( -1 ), mOutputStreamId( -1)
00124         {
00125 
00126                 // MRJ: Read/Written Channel Masks initialization
00127                 int i;
00128 
00129                 mNChannelsWritten = 0;
00130                 for (i=0;i<256;i++)
00131                 {
00132                         mChannelsWritten[i] = false;
00133                 }
00134 
00135                 mNChannelsRead = 0;
00136                 for (i=0;i<256;i++)
00137                 {
00138                         mChannelsRead[i] = false;
00139                 }
00140 
00141         }
00142 
00143         RtAAudioDevice::~RtAAudioDevice( )
00144         {
00145                 if ( mDevice )
00146                         delete mDevice;
00147         }
00148 
00149         void RtAAudioDevice::Start() throw( ErrRtAudio )
00150         {
00151                 if ( mStarted )
00152                         return;
00153 
00154                 unsigned outChannels = mOutputs.size();
00155                 unsigned inChannels = mInputs.size();
00156 
00157                 try
00158                 {
00159                         // Check for Full Duplex I/O
00160                         if ( (outChannels > 0) && (inChannels > 0) && (outChannels==inChannels) )
00161                                 {
00162                                         // both outChannels and inChannels have the same value
00163                                         // and are above zero
00164                                         mIOModel = eFullDuplex;
00165                                         mNChannels = outChannels;
00166                                         mFramesPerBuffer = Latency();
00167 
00168                                         mDevice = new RtAudio();
00169                                         mOutputStreamId= mDevice->openStream( mDevID,mNChannels, 0, 0, 
00170                                                                                    RtAudio::RTAUDIO_SINT16, SampleRate(), &mFramesPerBuffer, NumberOfInternalBuffers() );
00171                                         mInputStreamId= mDevice->openStream( 0, 0, mDevID, mNChannels, RtAudio::RTAUDIO_SINT16,
00172                                                                                          SampleRate(), &mFramesPerBuffer, NumberOfInternalBuffers() );
00173 
00174                                         mOutputSamples = (short*) mDevice->getStreamBuffer( mOutputStreamId );
00175                                         mDevice->startStream( mOutputStreamId );
00176                                         mInputSamples = (short*) mDevice->getStreamBuffer( mInputStreamId );
00177                                         mDevice->startStream( mInputStreamId );
00178 
00179                                 }
00180                         // Check for Half Duplex Ouput
00181                         else if ( (inChannels == 0) && (outChannels > 0))
00182                                 {
00183                                         mIOModel = eHalfDuplexOut;
00184                                         mNChannels = outChannels;
00185                                         // depending on outChannels value
00186                                         mFramesPerBuffer = Latency();
00187                                         mDevice = new RtAudio();
00188                                         mOutputStreamId= mDevice->openStream( mDevID,mNChannels, 0, 0, 
00189                                                                                    RtAudio::RTAUDIO_SINT16, SampleRate(), &mFramesPerBuffer, NumberOfInternalBuffers() );
00190                                         mOutputSamples = (short*) mDevice->getStreamBuffer( mOutputStreamId );
00191                                         mDevice->startStream( mOutputStreamId );
00192                                                                 
00193                                 }
00194                         // Check for Half Duplex Input
00195                         else if ( (outChannels == 0) && (inChannels > 0))
00196                                 {
00197                                         mIOModel = eHalfDuplexIn;
00198                                         // depending on the value of inChannels
00199                                         mNChannels = inChannels;
00200                                         mFramesPerBuffer = Latency();
00201                                         mDevice = new RtAudio();
00202                                         mInputStreamId= mDevice->openStream( 0, 0, mDevID, mNChannels, RtAudio::RTAUDIO_SINT16,
00203                                                                                          SampleRate(), &mFramesPerBuffer, NumberOfInternalBuffers());
00204                                         mInputSamples = (short*) mDevice->getStreamBuffer( mInputStreamId );
00205                                         mDevice->startStream( mInputStreamId );
00206                                 
00207                                 }
00208                         else
00209                                 {
00210                                         // Error. None of the supported I/O modalities.
00211                                         CLAM_ASSERT( false, "Check the number of AudioIn's and AudioOut's in your system.\n"
00212                                                                                 "I have detected a input output mismatch( either you have none input and some outputs or\n"
00213                                                                                 " some input or none output or just the same number of inputs and outputs)");
00214                                 }
00215                         mStarted = true;
00216                 }
00217                 catch( RtError& e )
00218                 {
00219                         ErrRtAudio new_e( e );
00220                         throw ( new_e );
00221                 }
00222         }
00223 
00224         void RtAAudioDevice::Stop() throw( ErrRtAudio )
00225         {
00226                 switch ( mIOModel )
00227                         {
00228                         case eFullDuplex:
00229                                 mDevice->stopStream( mOutputStreamId );
00230                                 mDevice->stopStream( mInputStreamId );
00231                                 mDevice->closeStream( mOutputStreamId );
00232                                 mDevice->closeStream( mInputStreamId );
00233                                 delete mDevice;
00234                                 mDevice=NULL;
00235                                 mInputSamples = NULL;
00236                                 mOutputSamples = NULL;
00237                                 mOutputStreamId = -1;
00238                                 mInputStreamId = -1;
00239                                 break;
00240                         case eHalfDuplexIn:
00241                                 mDevice->stopStream( mInputStreamId );
00242                                 mDevice->closeStream( mInputStreamId );
00243                                 delete mDevice;
00244                                 mDevice=NULL;
00245                                 mInputSamples = NULL;
00246                                 mInputStreamId = -1;
00247                                 break;
00248                         case eHalfDuplexOut:
00249                                 mDevice->stopStream( mOutputStreamId );
00250                                 mDevice->closeStream( mOutputStreamId );
00251                                 delete mDevice;
00252                                 mDevice=NULL;
00253                                 mOutputSamples = NULL;
00254                                 mOutputStreamId = -1;
00255                                 break;
00256                         case eNoneYet:
00257                                 CLAM_ASSERT( false, "You cannot stop what hasn't been started" );
00258                                 break;
00259                         }
00260                 mStarted = false;
00261         }
00262 
00263         void RtAAudioDevice::GetInfo( AudioDevice::TInfo& nfo )
00264         {
00265                 AudioDevice::GetInfo( nfo );
00266         }
00267 
00268         void RtAAudioDevice::Read( Audio& samples, const int channelID )
00269         {
00270                 TData* dst = samples.GetBuffer().GetPtr();
00271                 short* src = NULL;
00272                 unsigned samples_to_read = mFramesPerBuffer;
00273 
00274                 // Some error checking - proof of concepts
00275                 CLAM_ASSERT( mInputStreamId!=-1, "No Input stream over the device has been created yet!" );                      
00276                 CLAM_ASSERT( samples_to_read == samples.GetSize(), "Inconsistent Audio size" );
00277 
00278                 static TData inv_2_15 = 1 / TData(32767.);
00279 
00280                 src = mInputSamples + channelID;
00281 
00282                 while ( samples_to_read-- )
00283                         {
00284                                 *dst++ = TData(*src)*inv_2_15;
00285                                 src+=mNChannels;
00286                         }
00287 
00288 
00289                 mChannelsRead[channelID] = true;
00290                 mNChannelsRead++;
00291 
00292                 if (mNChannelsRead==mNChannels)
00293                 {
00294                         mNChannelsRead = 0;
00295                         for (int i=0;i<mNChannels;i++)
00296                                 mChannelsRead[i] = false;
00297                         mDevice->tickStream( mInputStreamId );
00298                 }
00299 
00300 
00301         }
00302         
00303         void RtAAudioDevice::Write( const Audio& samples, const int channelID )
00304         {
00305                 unsigned samples_to_write = mFramesPerBuffer;
00306 
00307                 CLAM_ASSERT( mOutputStreamId!=-1, "No Output stream over the device has been created yet!" );                    
00308                 CLAM_ASSERT( samples_to_write == samples.GetSize(), "Inconsistent Audio size" );
00309 
00310                 short* dst = mOutputSamples + channelID;
00311                 TData* src = samples.GetBuffer().GetPtr();
00312 
00313                 while ( samples_to_write-- )
00314                         {
00315                                 *dst = (short) ( 32767. * (*src++));
00316                                 dst+=mNChannels;
00317                         }
00318                 mChannelsWritten[channelID] = true;
00319                 mNChannelsWritten++;
00320 
00321                 if (mNChannelsWritten==mNChannels)
00322                 {
00323                 
00324                         
00325                         mNChannelsWritten = 0;
00326                         for (int i=0;i<mNChannels;i++)
00327                                 mChannelsWritten[i] = false;
00328 
00329                         mDevice->tickStream( mOutputStreamId );
00330                 }
00331 
00332 
00333         }
00334 
00335         RtAAudioDeviceList::RtAAudioDeviceList()
00336                 : AudioDeviceList( std::string("rtaudio") )
00337         {
00338 
00339                 EnumerateAvailableDevices();
00340 
00341                 AddMe();
00342         }
00343 
00344         RtAAudioDeviceList::~RtAAudioDeviceList()
00345         {
00346         }
00347 
00348         void RtAAudioDeviceList::EnumerateAvailableDevices() throw ( ErrRtAudio )
00349         {
00350                 RtAudio* instance = NULL;
00351                 
00352                 try
00353                         {
00354                                 instance = new RtAudio();
00355                                 
00356                                 int numDevs = instance->getDeviceCount();
00357                                 int k = 0;
00358                                 RtAudio::RTAUDIO_DEVICE devnfo;
00359                                 
00360                                 for ( k = 0; k < numDevs; k++ )
00361                                         {
00362                                                 instance->getDeviceInfo( k, &devnfo );
00363                                                 mAvailableDevices.push_back( devnfo.name );
00364                                                 mDevIDs.push_back( k );
00365                                         }
00366                                 delete instance;
00367                         }
00368                 catch( RtError& err )
00369                         {
00370                                 if ( instance )
00371                                         delete instance;
00372                                 ErrRtAudio new_err( err );
00373                                 throw ( new_err );
00374                         }
00375 
00376         }
00377 
00378         AudioDevice* RtAAudioDeviceList::Create( const std::string& name, const std::string& device )
00379         {
00380                 int i = 0;
00381 
00382                 for ( i=0; i < mAvailableDevices.size(); i++ )
00383                         {
00384                                 if ( device == mAvailableDevices[i] )
00385                                         return new RtAAudioDevice( name, mDevIDs[i] );
00386                         }
00387                 
00388                 return 0;
00389         }
00390 
00391         RtAAudioDeviceList RtAAudioDeviceList::sDevices;
00392 
00393 }
00394 

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