Home   Class/Enum List   File List   Compound Members  

RtAudio.h

Go to the documentation of this file.
00001 /************************************************************************/
00039 /************************************************************************/
00040 
00045 // RtAudio: Version 4.0.7
00046 
00047 #ifndef __RTAUDIO_H
00048 #define __RTAUDIO_H
00049 
00050 #include <string>
00051 #include <vector>
00052 #include "RtError.h"
00053 
00070 typedef unsigned long RtAudioFormat;
00071 static const RtAudioFormat RTAUDIO_SINT8 = 0x1;    // 8-bit signed integer.
00072 static const RtAudioFormat RTAUDIO_SINT16 = 0x2;   // 16-bit signed integer.
00073 static const RtAudioFormat RTAUDIO_SINT24 = 0x4;   // Lower 3 bytes of 32-bit signed integer.
00074 static const RtAudioFormat RTAUDIO_SINT32 = 0x8;   // 32-bit signed integer.
00075 static const RtAudioFormat RTAUDIO_FLOAT32 = 0x10; // Normalized between plus/minus 1.0.
00076 static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/minus 1.0.
00077 
00115 typedef unsigned int RtAudioStreamFlags;
00116 static const RtAudioStreamFlags RTAUDIO_NONINTERLEAVED = 0x1;    // Use non-interleaved buffers (default = interleaved).
00117 static const RtAudioStreamFlags RTAUDIO_MINIMIZE_LATENCY = 0x2;  // Attempt to set stream parameters for lowest possible latency.
00118 static const RtAudioStreamFlags RTAUDIO_HOG_DEVICE = 0x4;        // Attempt grab device and prevent use by others.
00119 static const RtAudioStreamFlags RTAUDIO_SCHEDULE_REALTIME = 0x8; // Try to select realtime scheduling for callback thread.
00120 
00132 typedef unsigned int RtAudioStreamStatus;
00133 static const RtAudioStreamStatus RTAUDIO_INPUT_OVERFLOW = 0x1;    // Input data was discarded because of an overflow condition at the driver.
00134 static const RtAudioStreamStatus RTAUDIO_OUTPUT_UNDERFLOW = 0x2;  // The output buffer ran low, likely causing a gap in the output sound.
00135 
00137 
00175 typedef int (*RtAudioCallback)( void *outputBuffer, void *inputBuffer,
00176                                 unsigned int nFrames,
00177                                 double streamTime,
00178                                 RtAudioStreamStatus status,
00179                                 void *userData );
00180 
00181 
00182 // **************************************************************** //
00183 //
00184 // RtAudio class declaration.
00185 //
00186 // RtAudio is a "controller" used to select an available audio i/o
00187 // interface.  It presents a common API for the user to call but all
00188 // functionality is implemented by the class RtApi and its
00189 // subclasses.  RtAudio creates an instance of an RtApi subclass
00190 // based on the user's API choice.  If no choice is made, RtAudio
00191 // attempts to make a "logical" API selection.
00192 //
00193 // **************************************************************** //
00194 
00195 class RtApi;
00196 
00197 class RtAudio
00198 {
00199  public:
00200 
00202   enum Api {
00203     UNSPECIFIED,    
00204     LINUX_ALSA,     
00205     LINUX_OSS,      
00206     UNIX_JACK,      
00207     MACOSX_CORE,    
00208     WINDOWS_ASIO,   
00209     WINDOWS_DS,     
00210     RTAUDIO_DUMMY   
00211   };
00212 
00214   struct DeviceInfo {
00215     bool probed;                  
00216     std::string name;             
00217     unsigned int outputChannels;  
00218     unsigned int inputChannels;   
00219     unsigned int duplexChannels;  
00220     bool isDefaultOutput;         
00221     bool isDefaultInput;          
00222     std::vector<unsigned int> sampleRates; 
00223     RtAudioFormat nativeFormats;  
00225     // Default constructor.
00226     DeviceInfo()
00227       :probed(false), outputChannels(0), inputChannels(0), duplexChannels(0),
00228        isDefaultOutput(false), isDefaultInput(false), nativeFormats(0) {}
00229   };
00230 
00232   struct StreamParameters {
00233     unsigned int deviceId;     
00234     unsigned int nChannels;    
00235     unsigned int firstChannel; 
00237     // Default constructor.
00238     StreamParameters()
00239       : deviceId(0), nChannels(0), firstChannel(0) {}
00240   };
00241 
00243 
00294   struct StreamOptions {
00295     RtAudioStreamFlags flags;      
00296     unsigned int numberOfBuffers;  
00297     std::string streamName;        
00298     int priority;                  
00300     // Default constructor.
00301     StreamOptions()
00302     : flags(0), numberOfBuffers(0), priority(0) {}
00303   };
00304 
00306 
00311   static void getCompiledApi( std::vector<RtAudio::Api> &apis ) throw();
00312 
00314 
00322   RtAudio( RtAudio::Api api=UNSPECIFIED ) throw();
00323 
00325 
00329   ~RtAudio() throw();
00330 
00332   RtAudio::Api getCurrentApi( void ) throw();
00333 
00335 
00340   unsigned int getDeviceCount( void ) throw();
00341 
00343 
00353   RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
00354 
00356 
00363   unsigned int getDefaultOutputDevice( void ) throw();
00364 
00366 
00373   unsigned int getDefaultInputDevice( void ) throw();
00374 
00376 
00413   void openStream( RtAudio::StreamParameters *outputParameters,
00414                    RtAudio::StreamParameters *inputParameters,
00415                    RtAudioFormat format, unsigned int sampleRate,
00416                    unsigned int *bufferFrames, RtAudioCallback callback,
00417                    void *userData = NULL, RtAudio::StreamOptions *options = NULL );
00418 
00420 
00424   void closeStream( void ) throw();
00425 
00427 
00433   void startStream( void );
00434 
00436 
00442   void stopStream( void );
00443 
00445 
00451   void abortStream( void );
00452 
00454   bool isStreamOpen( void ) const throw();
00455 
00457   bool isStreamRunning( void ) const throw();
00458 
00460 
00463   double getStreamTime( void );
00464 
00466 
00474   long getStreamLatency( void );
00475 
00477 
00482   unsigned int getStreamSampleRate( void );
00483 
00485   void showWarnings( bool value = true ) throw();
00486 
00487  protected:
00488 
00489   void openRtApi( RtAudio::Api api );
00490   RtApi *rtapi_;
00491 };
00492 
00493 // Operating system dependent thread functionality.
00494 #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)
00495   #include <windows.h>
00496   #include <process.h>
00497 
00498   typedef unsigned long ThreadHandle;
00499   typedef CRITICAL_SECTION StreamMutex;
00500 
00501 #elif defined(__LINUX_ALSA__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
00502   // Using pthread library for various flavors of unix.
00503   #include <pthread.h>
00504 
00505   typedef pthread_t ThreadHandle;
00506   typedef pthread_mutex_t StreamMutex;
00507 
00508 #else // Setup for "dummy" behavior
00509 
00510   #define __RTAUDIO_DUMMY__
00511   typedef int ThreadHandle;
00512   typedef int StreamMutex;
00513 
00514 #endif
00515 
00516 // This global structure type is used to pass callback information
00517 // between the private RtAudio stream structure and global callback
00518 // handling functions.
00519 struct CallbackInfo {
00520   void *object;    // Used as a "this" pointer.
00521   ThreadHandle thread;
00522   void *callback;
00523   void *userData;
00524   void *apiInfo;   // void pointer for API specific callback information
00525   bool isRunning;
00526 
00527   // Default constructor.
00528   CallbackInfo()
00529     :object(0), callback(0), userData(0), apiInfo(0), isRunning(false) {}
00530 };
00531 
00532 // **************************************************************** //
00533 //
00534 // RtApi class declaration.
00535 //
00536 // Subclasses of RtApi contain all API- and OS-specific code necessary
00537 // to fully implement the RtAudio API.
00538 //
00539 // Note that RtApi is an abstract base class and cannot be
00540 // explicitly instantiated.  The class RtAudio will create an
00541 // instance of an RtApi subclass (RtApiOss, RtApiAlsa,
00542 // RtApiJack, RtApiCore, RtApiAl, RtApiDs, or RtApiAsio).
00543 //
00544 // **************************************************************** //
00545 
00546 #if defined( HAVE_GETTIMEOFDAY )
00547   #include <sys/time.h>
00548 #endif
00549 
00550 #include <sstream>
00551 
00552 class RtApi
00553 {
00554 public:
00555 
00556   RtApi();
00557   virtual ~RtApi();
00558   virtual RtAudio::Api getCurrentApi( void ) = 0;
00559   virtual unsigned int getDeviceCount( void ) = 0;
00560   virtual RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) = 0;
00561   virtual unsigned int getDefaultInputDevice( void );
00562   virtual unsigned int getDefaultOutputDevice( void );
00563   void openStream( RtAudio::StreamParameters *outputParameters,
00564                    RtAudio::StreamParameters *inputParameters,
00565                    RtAudioFormat format, unsigned int sampleRate,
00566                    unsigned int *bufferFrames, RtAudioCallback callback,
00567                    void *userData, RtAudio::StreamOptions *options );
00568   virtual void closeStream( void );
00569   virtual void startStream( void ) = 0;
00570   virtual void stopStream( void ) = 0;
00571   virtual void abortStream( void ) = 0;
00572   long getStreamLatency( void );
00573   unsigned int getStreamSampleRate( void );
00574   virtual double getStreamTime( void );
00575   bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; };
00576   bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; };
00577   void showWarnings( bool value ) { showWarnings_ = value; };
00578 
00579 
00580 protected:
00581 
00582   static const unsigned int MAX_SAMPLE_RATES;
00583   static const unsigned int SAMPLE_RATES[];
00584 
00585   enum { FAILURE, SUCCESS };
00586 
00587   enum StreamState {
00588     STREAM_STOPPED,
00589     STREAM_RUNNING,
00590     STREAM_CLOSED = -50
00591   };
00592 
00593   enum StreamMode {
00594     OUTPUT,
00595     INPUT,
00596     DUPLEX,
00597     UNINITIALIZED = -75
00598   };
00599 
00600   // A protected structure used for buffer conversion.
00601   struct ConvertInfo {
00602     int channels;
00603     int inJump, outJump;
00604     RtAudioFormat inFormat, outFormat;
00605     std::vector<int> inOffset;
00606     std::vector<int> outOffset;
00607   };
00608 
00609   // A protected structure for audio streams.
00610   struct RtApiStream {
00611     unsigned int device[2];    // Playback and record, respectively.
00612     void *apiHandle;           // void pointer for API specific stream handle information
00613     StreamMode mode;           // OUTPUT, INPUT, or DUPLEX.
00614     StreamState state;         // STOPPED, RUNNING, or CLOSED
00615     char *userBuffer[2];       // Playback and record, respectively.
00616     char *deviceBuffer;
00617     bool doConvertBuffer[2];   // Playback and record, respectively.
00618     bool userInterleaved;
00619     bool deviceInterleaved[2]; // Playback and record, respectively.
00620     bool doByteSwap[2];        // Playback and record, respectively.
00621     unsigned int sampleRate;
00622     unsigned int bufferSize;
00623     unsigned int nBuffers;
00624     unsigned int nUserChannels[2];    // Playback and record, respectively.
00625     unsigned int nDeviceChannels[2];  // Playback and record channels, respectively.
00626     unsigned int channelOffset[2];    // Playback and record, respectively.
00627     unsigned long latency[2];         // Playback and record, respectively.
00628     RtAudioFormat userFormat;
00629     RtAudioFormat deviceFormat[2];    // Playback and record, respectively.
00630     StreamMutex mutex;
00631     CallbackInfo callbackInfo;
00632     ConvertInfo convertInfo[2];
00633     double streamTime;         // Number of elapsed seconds since the stream started.
00634 
00635 #if defined(HAVE_GETTIMEOFDAY)
00636     struct timeval lastTickTimestamp;
00637 #endif
00638 
00639     RtApiStream()
00640       :apiHandle(0), deviceBuffer(0) { device[0] = 11111; device[1] = 11111; }
00641   };
00642 
00643   typedef signed short Int16;
00644   typedef signed int Int32;
00645   typedef float Float32;
00646   typedef double Float64;
00647 
00648   std::ostringstream errorStream_;
00649   std::string errorText_;
00650   bool showWarnings_;
00651   RtApiStream stream_;
00652 
00660   virtual bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
00661                                 unsigned int firstChannel, unsigned int sampleRate,
00662                                 RtAudioFormat format, unsigned int *bufferSize,
00663                                 RtAudio::StreamOptions *options );
00664 
00666   void tickStreamTime( void );
00667 
00669   void clearStreamInfo();
00670 
00675   void verifyStream( void );
00676 
00678   void error( RtError::Type type );
00679 
00684   void convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info );
00685 
00687   void byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format );
00688 
00690   unsigned int formatBytes( RtAudioFormat format );
00691 
00693   void setConvertInfo( StreamMode mode, unsigned int firstChannel );
00694 };
00695 
00696 // **************************************************************** //
00697 //
00698 // Inline RtAudio definitions.
00699 //
00700 // **************************************************************** //
00701 
00702 inline RtAudio::Api RtAudio :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
00703 inline unsigned int RtAudio :: getDeviceCount( void ) throw() { return rtapi_->getDeviceCount(); }
00704 inline RtAudio::DeviceInfo RtAudio :: getDeviceInfo( unsigned int device ) { return rtapi_->getDeviceInfo( device ); }
00705 inline unsigned int RtAudio :: getDefaultInputDevice( void ) throw() { return rtapi_->getDefaultInputDevice(); }
00706 inline unsigned int RtAudio :: getDefaultOutputDevice( void ) throw() { return rtapi_->getDefaultOutputDevice(); }
00707 inline void RtAudio :: closeStream( void ) throw() { return rtapi_->closeStream(); }
00708 inline void RtAudio :: startStream( void ) { return rtapi_->startStream(); }
00709 inline void RtAudio :: stopStream( void )  { return rtapi_->stopStream(); }
00710 inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); }
00711 inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); }
00712 inline bool RtAudio :: isStreamRunning( void ) const throw() { return rtapi_->isStreamRunning(); }
00713 inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); }
00714 inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); };
00715 inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); }
00716 inline void RtAudio :: showWarnings( bool value ) throw() { rtapi_->showWarnings( value ); }
00717 
00718 // RtApi Subclass prototypes.
00719 
00720 #if defined(__MACOSX_CORE__)
00721 
00722 #include <CoreAudio/AudioHardware.h>
00723 
00724 class RtApiCore: public RtApi
00725 {
00726 public:
00727 
00728   RtApiCore();
00729   ~RtApiCore();
00730   RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; };
00731   unsigned int getDeviceCount( void );
00732   RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
00733   unsigned int getDefaultOutputDevice( void );
00734   unsigned int getDefaultInputDevice( void );
00735   void closeStream( void );
00736   void startStream( void );
00737   void stopStream( void );
00738   void abortStream( void );
00739   long getStreamLatency( void );
00740 
00741   // This function is intended for internal use only.  It must be
00742   // public because it is called by the internal callback handler,
00743   // which is not a member of RtAudio.  External use of this function
00744   // will most likely produce highly undesireable results!
00745   bool callbackEvent( AudioDeviceID deviceId,
00746                       const AudioBufferList *inBufferList,
00747                       const AudioBufferList *outBufferList );
00748 
00749   private:
00750 
00751   bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
00752                         unsigned int firstChannel, unsigned int sampleRate,
00753                         RtAudioFormat format, unsigned int *bufferSize,
00754                         RtAudio::StreamOptions *options );
00755   static const char* getErrorCode( OSStatus code );
00756 };
00757 
00758 #endif
00759 
00760 #if defined(__UNIX_JACK__)
00761 
00762 class RtApiJack: public RtApi
00763 {
00764 public:
00765 
00766   RtApiJack();
00767   ~RtApiJack();
00768   RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; };
00769   unsigned int getDeviceCount( void );
00770   RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
00771   void closeStream( void );
00772   void startStream( void );
00773   void stopStream( void );
00774   void abortStream( void );
00775   long getStreamLatency( void );
00776 
00777   // This function is intended for internal use only.  It must be
00778   // public because it is called by the internal callback handler,
00779   // which is not a member of RtAudio.  External use of this function
00780   // will most likely produce highly undesireable results!
00781   bool callbackEvent( unsigned long nframes );
00782 
00783   private:
00784 
00785   bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
00786                         unsigned int firstChannel, unsigned int sampleRate,
00787                         RtAudioFormat format, unsigned int *bufferSize,
00788                         RtAudio::StreamOptions *options );
00789 };
00790 
00791 #endif
00792 
00793 #if defined(__WINDOWS_ASIO__)
00794 
00795 class RtApiAsio: public RtApi
00796 {
00797 public:
00798 
00799   RtApiAsio();
00800   ~RtApiAsio();
00801   RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; };
00802   unsigned int getDeviceCount( void );
00803   RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
00804   void closeStream( void );
00805   void startStream( void );
00806   void stopStream( void );
00807   void abortStream( void );
00808   long getStreamLatency( void );
00809 
00810   // This function is intended for internal use only.  It must be
00811   // public because it is called by the internal callback handler,
00812   // which is not a member of RtAudio.  External use of this function
00813   // will most likely produce highly undesireable results!
00814   bool callbackEvent( long bufferIndex );
00815 
00816   private:
00817 
00818   std::vector<RtAudio::DeviceInfo> devices_;
00819   void saveDeviceInfo( void );
00820   bool coInitialized_;
00821   bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
00822                         unsigned int firstChannel, unsigned int sampleRate,
00823                         RtAudioFormat format, unsigned int *bufferSize,
00824                         RtAudio::StreamOptions *options );
00825 };
00826 
00827 #endif
00828 
00829 #if defined(__WINDOWS_DS__)
00830 
00831 class RtApiDs: public RtApi
00832 {
00833 public:
00834 
00835   RtApiDs();
00836   ~RtApiDs();
00837   RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; };
00838   unsigned int getDeviceCount( void );
00839   unsigned int getDefaultOutputDevice( void );
00840   unsigned int getDefaultInputDevice( void );
00841   RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
00842   void closeStream( void );
00843   void startStream( void );
00844   void stopStream( void );
00845   void abortStream( void );
00846   long getStreamLatency( void );
00847 
00848   // This function is intended for internal use only.  It must be
00849   // public because it is called by the internal callback handler,
00850   // which is not a member of RtAudio.  External use of this function
00851   // will most likely produce highly undesireable results!
00852   void callbackEvent( void );
00853 
00854   private:
00855 
00856   bool coInitialized_;
00857   bool buffersRolling;
00858   long duplexPrerollBytes;
00859   bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
00860                         unsigned int firstChannel, unsigned int sampleRate,
00861                         RtAudioFormat format, unsigned int *bufferSize,
00862                         RtAudio::StreamOptions *options );
00863 };
00864 
00865 #endif
00866 
00867 #if defined(__LINUX_ALSA__)
00868 
00869 class RtApiAlsa: public RtApi
00870 {
00871 public:
00872 
00873   RtApiAlsa();
00874   ~RtApiAlsa();
00875   RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; };
00876   unsigned int getDeviceCount( void );
00877   RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
00878   void closeStream( void );
00879   void startStream( void );
00880   void stopStream( void );
00881   void abortStream( void );
00882 
00883   // This function is intended for internal use only.  It must be
00884   // public because it is called by the internal callback handler,
00885   // which is not a member of RtAudio.  External use of this function
00886   // will most likely produce highly undesireable results!
00887   void callbackEvent( void );
00888 
00889   private:
00890 
00891   std::vector<RtAudio::DeviceInfo> devices_;
00892   void saveDeviceInfo( void );
00893   bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
00894                         unsigned int firstChannel, unsigned int sampleRate,
00895                         RtAudioFormat format, unsigned int *bufferSize,
00896                         RtAudio::StreamOptions *options );
00897 };
00898 
00899 #endif
00900 
00901 #if defined(__LINUX_OSS__)
00902 
00903 class RtApiOss: public RtApi
00904 {
00905 public:
00906 
00907   RtApiOss();
00908   ~RtApiOss();
00909   RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; };
00910   unsigned int getDeviceCount( void );
00911   RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
00912   void closeStream( void );
00913   void startStream( void );
00914   void stopStream( void );
00915   void abortStream( void );
00916 
00917   // This function is intended for internal use only.  It must be
00918   // public because it is called by the internal callback handler,
00919   // which is not a member of RtAudio.  External use of this function
00920   // will most likely produce highly undesireable results!
00921   void callbackEvent( void );
00922 
00923   private:
00924 
00925   bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
00926                         unsigned int firstChannel, unsigned int sampleRate,
00927                         RtAudioFormat format, unsigned int *bufferSize,
00928                         RtAudio::StreamOptions *options );
00929 };
00930 
00931 #endif
00932 
00933 #if defined(__RTAUDIO_DUMMY__)
00934 
00935 class RtApiDummy: public RtApi
00936 {
00937 public:
00938 
00939   RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtError::WARNING ); };
00940   RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; };
00941   unsigned int getDeviceCount( void ) { return 0; };
00942   RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; return info; };
00943   void closeStream( void ) {};
00944   void startStream( void ) {};
00945   void stopStream( void ) {};
00946   void abortStream( void ) {};
00947 
00948   private:
00949 
00950   bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 
00951                         unsigned int firstChannel, unsigned int sampleRate,
00952                         RtAudioFormat format, unsigned int *bufferSize,
00953                         RtAudio::StreamOptions *options ) { return false; };
00954 };
00955 
00956 #endif
00957 
00958 #endif
00959 
00960 // Indentation settings for Vim and Emacs
00961 //
00962 // Local Variables:
00963 // c-basic-offset: 2
00964 // indent-tabs-mode: nil
00965 // End:
00966 //
00967 // vim: et sts=2 sw=2

©2001-2010 Gary P. Scavone, McGill University. All Rights Reserved.
Maintained by Gary P. Scavone.