├── README.md └── trunk ├── Bull-Record-Everything.pro ├── doc └── attach │ ├── bre_preview_1.png │ └── bre_v0.1_windows.7z ├── external ├── libRtAudio │ ├── RtAudio.cpp │ ├── RtAudio.h │ ├── RtError.h │ └── include │ │ ├── asio.cpp │ │ ├── asio.h │ │ ├── asiodrivers.cpp │ │ ├── asiodrivers.h │ │ ├── asiodrvr.h │ │ ├── asiolist.cpp │ │ ├── asiolist.h │ │ ├── asiosys.h │ │ ├── dsound.h │ │ ├── ginclude.h │ │ ├── iasiodrv.h │ │ ├── iasiothiscallresolver.cpp │ │ ├── iasiothiscallresolver.h │ │ └── soundcard.h └── libmux │ ├── SDL2.dll │ ├── avcodec-57.dll │ ├── avdevice-57.dll │ ├── avfilter-6.dll │ ├── avformat-57.dll │ ├── avutil-55.dll │ ├── libgcc_s_dw2-1.dll │ ├── libmux.dll │ ├── libwinpthread-1.dll │ ├── libx264-148.dll │ ├── postproc-54.dll │ ├── swresample-2.dll │ └── swscale-4.dll └── src ├── MainWindow.cpp ├── MainWindow.h ├── MainWindow.ui ├── main.cpp ├── mux ├── MuxApi.cpp ├── MuxApi.h ├── MuxThread.cpp ├── MuxThread.h └── libmux.h ├── pages ├── Page_GrabCamera.cpp ├── Page_GrabCamera.h ├── Page_GrabCamera.ui ├── Page_GrabDesktopArea.cpp ├── Page_GrabDesktopArea.h ├── Page_GrabDesktopArea.ui ├── Page_GrabScrollArea.cpp ├── Page_GrabScrollArea.h ├── Page_GrabScrollArea.ui ├── Page_GrabWindow.cpp ├── Page_GrabWindow.h └── Page_GrabWindow.ui ├── scene ├── Scene_GrabScreen.cpp ├── Scene_GrabScreen.h ├── Scene_GrabScreen.ui ├── Scene_RecordAudio.cpp ├── Scene_RecordAudio.h ├── Scene_RecordAudio.ui ├── Scene_RecordVideo.cpp ├── Scene_RecordVideo.h └── Scene_RecordVideo.ui ├── source ├── AudioSource.cpp ├── AudioSource.h ├── VideoSurface.cpp └── VideoSurface.h └── widgets ├── MenuButton.cpp ├── MenuButton.h ├── NavWidget.cpp ├── NavWidget.h └── NavWidget.ui /README.md: -------------------------------------------------------------------------------- 1 | # Bull-Record-Everything 2 | Bull-Record-Everything is a convenient tool which can be used to record everything, eg : desktop, camera, window , and it also has capacities to mix speaker or microphone to a media file. 3 | 4 | # Download 5 | 1:windows: [https://github.com/wenjiegit/Bull-Record-Everything/raw/master/trunk/doc/attach/bre_v0.1_windows.7z](https://github.com/wenjiegit/Bull-Record-Everything/raw/master/trunk/doc/attach/bre_v0.1_windows.7z) 6 | 7 | # Build 8 | windows: 9 | Qt 5.7.0 (msvc2013) 32bit 10 | 11 | # Preview 12 | ![](https://github.com/wenjiegit/Bull-Record-Everything/blob/master/trunk/doc/attach/bre_preview_1.png) 13 | 14 | # History 15 | v0.1, 2017-12-17, add scene files 16 | 17 | v0.1, 2017-09-07, support ingest from camera and micor-phone, support mix to media file(mp4,mkv,wmv,rm...) 18 | -------------------------------------------------------------------------------- /trunk/Bull-Record-Everything.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2017-09-05T17:50:11 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui multimedia 8 | 9 | DESTDIR += $$PWD/bin 10 | INCLUDEPATH += $$PWD/libRtAudio/ 11 | 12 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 13 | 14 | TARGET = bre 15 | TEMPLATE = app 16 | DEFINES += __WINDOWS_DS__ 17 | LIBS += -ldsound -luser32 -lole32 18 | 19 | INCLUDEPATH += $$PWD/src $$PWD/src/mux $$PWD/src/source \ 20 | $$PWD/external/libRtAudio $$PWD/src/widgets $$PWD/src/scene 21 | 22 | SOURCES += src/main.cpp\ 23 | src/MainWindow.cpp \ 24 | src/source/AudioSource.cpp \ 25 | src/mux/MuxApi.cpp \ 26 | src/mux/MuxThread.cpp \ 27 | src/source/VideoSurface.cpp \ 28 | external/libRtAudio/RtAudio.cpp \ 29 | src/scene/Scene_RecordVideo.cpp \ 30 | src/scene/Scene_GrabScreen.cpp \ 31 | src/scene/Scene_RecordAudio.cpp \ 32 | src/widgets/NavWidget.cpp 33 | 34 | HEADERS += src/MainWindow.h \ 35 | src/source/AudioSource.h \ 36 | src/mux/MuxApi.h \ 37 | src/mux/MuxThread.h \ 38 | src/source/VideoSurface.h \ 39 | external/libRtAudio/RtAudio.h \ 40 | external/libRtAudio/RtError.h \ 41 | src/scene/Scene_RecordVideo.h \ 42 | src/scene/Scene_GrabScreen.h \ 43 | src/scene/Scene_RecordAudio.h \ 44 | src/widgets/NavWidget.h 45 | 46 | FORMS += src/MainWindow.ui \ 47 | src/scene/Scene_RecordVideo.ui \ 48 | src/scene/Scene_GrabScreen.ui \ 49 | src/scene/Scene_RecordAudio.ui \ 50 | src/widgets/NavWidget.ui 51 | -------------------------------------------------------------------------------- /trunk/doc/attach/bre_preview_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/doc/attach/bre_preview_1.png -------------------------------------------------------------------------------- /trunk/doc/attach/bre_v0.1_windows.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/doc/attach/bre_v0.1_windows.7z -------------------------------------------------------------------------------- /trunk/external/libRtAudio/RtAudio.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /*! \class RtAudio 3 | \brief Realtime audio i/o C++ classes. 4 | 5 | RtAudio provides a common API (Application Programming Interface) 6 | for realtime audio input/output across Linux (native ALSA, Jack, 7 | and OSS), Macintosh OS X (CoreAudio and Jack), and Windows 8 | (DirectSound and ASIO) operating systems. 9 | 10 | RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/ 11 | 12 | RtAudio: realtime audio i/o C++ classes 13 | Copyright (c) 2001-2013 Gary P. Scavone 14 | 15 | Permission is hereby granted, free of charge, to any person 16 | obtaining a copy of this software and associated documentation files 17 | (the "Software"), to deal in the Software without restriction, 18 | including without limitation the rights to use, copy, modify, merge, 19 | publish, distribute, sublicense, and/or sell copies of the Software, 20 | and to permit persons to whom the Software is furnished to do so, 21 | subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be 24 | included in all copies or substantial portions of the Software. 25 | 26 | Any person wishing to distribute modifications to the Software is 27 | asked to send the modifications to the original developer so that 28 | they can be incorporated into the canonical version. This is, 29 | however, not a binding provision of this license. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 32 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 33 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 34 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 35 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 36 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 37 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 38 | */ 39 | /************************************************************************/ 40 | 41 | /*! 42 | \file RtAudio.h 43 | */ 44 | 45 | #ifndef __RTAUDIO_H 46 | #define __RTAUDIO_H 47 | 48 | #include 49 | #include 50 | #include "RtError.h" 51 | 52 | // RtAudio version 53 | static const std::string VERSION( "4.0.12" ); 54 | 55 | /*! \typedef typedef unsigned long RtAudioFormat; 56 | \brief RtAudio data format type. 57 | 58 | Support for signed integers and floats. Audio data fed to/from an 59 | RtAudio stream is assumed to ALWAYS be in host byte order. The 60 | internal routines will automatically take care of any necessary 61 | byte-swapping between the host format and the soundcard. Thus, 62 | endian-ness is not a concern in the following format definitions. 63 | 64 | - \e RTAUDIO_SINT8: 8-bit signed integer. 65 | - \e RTAUDIO_SINT16: 16-bit signed integer. 66 | - \e RTAUDIO_SINT24: 24-bit signed integer. 67 | - \e RTAUDIO_SINT32: 32-bit signed integer. 68 | - \e RTAUDIO_FLOAT32: Normalized between plus/minus 1.0. 69 | - \e RTAUDIO_FLOAT64: Normalized between plus/minus 1.0. 70 | */ 71 | typedef unsigned long RtAudioFormat; 72 | static const RtAudioFormat RTAUDIO_SINT8 = 0x1; // 8-bit signed integer. 73 | static const RtAudioFormat RTAUDIO_SINT16 = 0x2; // 16-bit signed integer. 74 | static const RtAudioFormat RTAUDIO_SINT24 = 0x4; // 24-bit signed integer. 75 | static const RtAudioFormat RTAUDIO_SINT32 = 0x8; // 32-bit signed integer. 76 | static const RtAudioFormat RTAUDIO_FLOAT32 = 0x10; // Normalized between plus/minus 1.0. 77 | static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/minus 1.0. 78 | 79 | /*! \typedef typedef unsigned long RtAudioStreamFlags; 80 | \brief RtAudio stream option flags. 81 | 82 | The following flags can be OR'ed together to allow a client to 83 | make changes to the default stream behavior: 84 | 85 | - \e RTAUDIO_NONINTERLEAVED: Use non-interleaved buffers (default = interleaved). 86 | - \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency. 87 | - \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use. 88 | - \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only). 89 | 90 | By default, RtAudio streams pass and receive audio data from the 91 | client in an interleaved format. By passing the 92 | RTAUDIO_NONINTERLEAVED flag to the openStream() function, audio 93 | data will instead be presented in non-interleaved buffers. In 94 | this case, each buffer argument in the RtAudioCallback function 95 | will point to a single array of data, with \c nFrames samples for 96 | each channel concatenated back-to-back. For example, the first 97 | sample of data for the second channel would be located at index \c 98 | nFrames (assuming the \c buffer pointer was recast to the correct 99 | data type for the stream). 100 | 101 | Certain audio APIs offer a number of parameters that influence the 102 | I/O latency of a stream. By default, RtAudio will attempt to set 103 | these parameters internally for robust (glitch-free) performance 104 | (though some APIs, like Windows Direct Sound, make this difficult). 105 | By passing the RTAUDIO_MINIMIZE_LATENCY flag to the openStream() 106 | function, internal stream settings will be influenced in an attempt 107 | to minimize stream latency, though possibly at the expense of stream 108 | performance. 109 | 110 | If the RTAUDIO_HOG_DEVICE flag is set, RtAudio will attempt to 111 | open the input and/or output stream device(s) for exclusive use. 112 | Note that this is not possible with all supported audio APIs. 113 | 114 | If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt 115 | to select realtime scheduling (round-robin) for the callback thread. 116 | 117 | If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to 118 | open the "default" PCM device when using the ALSA API. Note that this 119 | will override any specified input or output device id. 120 | */ 121 | typedef unsigned int RtAudioStreamFlags; 122 | static const RtAudioStreamFlags RTAUDIO_NONINTERLEAVED = 0x1; // Use non-interleaved buffers (default = interleaved). 123 | static const RtAudioStreamFlags RTAUDIO_MINIMIZE_LATENCY = 0x2; // Attempt to set stream parameters for lowest possible latency. 124 | static const RtAudioStreamFlags RTAUDIO_HOG_DEVICE = 0x4; // Attempt grab device and prevent use by others. 125 | static const RtAudioStreamFlags RTAUDIO_SCHEDULE_REALTIME = 0x8; // Try to select realtime scheduling for callback thread. 126 | static const RtAudioStreamFlags RTAUDIO_ALSA_USE_DEFAULT = 0x10; // Use the "default" PCM device (ALSA only). 127 | 128 | /*! \typedef typedef unsigned long RtAudioStreamStatus; 129 | \brief RtAudio stream status (over- or underflow) flags. 130 | 131 | Notification of a stream over- or underflow is indicated by a 132 | non-zero stream \c status argument in the RtAudioCallback function. 133 | The stream status can be one of the following two options, 134 | depending on whether the stream is open for output and/or input: 135 | 136 | - \e RTAUDIO_INPUT_OVERFLOW: Input data was discarded because of an overflow condition at the driver. 137 | - \e RTAUDIO_OUTPUT_UNDERFLOW: The output buffer ran low, likely producing a break in the output sound. 138 | */ 139 | typedef unsigned int RtAudioStreamStatus; 140 | static const RtAudioStreamStatus RTAUDIO_INPUT_OVERFLOW = 0x1; // Input data was discarded because of an overflow condition at the driver. 141 | static const RtAudioStreamStatus RTAUDIO_OUTPUT_UNDERFLOW = 0x2; // The output buffer ran low, likely causing a gap in the output sound. 142 | 143 | //! RtAudio callback function prototype. 144 | /*! 145 | All RtAudio clients must create a function of type RtAudioCallback 146 | to read and/or write data from/to the audio stream. When the 147 | underlying audio system is ready for new input or output data, this 148 | function will be invoked. 149 | 150 | \param outputBuffer For output (or duplex) streams, the client 151 | should write \c nFrames of audio sample frames into this 152 | buffer. This argument should be recast to the datatype 153 | specified when the stream was opened. For input-only 154 | streams, this argument will be NULL. 155 | 156 | \param inputBuffer For input (or duplex) streams, this buffer will 157 | hold \c nFrames of input audio sample frames. This 158 | argument should be recast to the datatype specified when the 159 | stream was opened. For output-only streams, this argument 160 | will be NULL. 161 | 162 | \param nFrames The number of sample frames of input or output 163 | data in the buffers. The actual buffer size in bytes is 164 | dependent on the data type and number of channels in use. 165 | 166 | \param streamTime The number of seconds that have elapsed since the 167 | stream was started. 168 | 169 | \param status If non-zero, this argument indicates a data overflow 170 | or underflow condition for the stream. The particular 171 | condition can be determined by comparison with the 172 | RtAudioStreamStatus flags. 173 | 174 | \param userData A pointer to optional data provided by the client 175 | when opening the stream (default = NULL). 176 | 177 | To continue normal stream operation, the RtAudioCallback function 178 | should return a value of zero. To stop the stream and drain the 179 | output buffer, the function should return a value of one. To abort 180 | the stream immediately, the client should return a value of two. 181 | */ 182 | typedef int (*RtAudioCallback)( void *outputBuffer, void *inputBuffer, 183 | unsigned int nFrames, 184 | double streamTime, 185 | RtAudioStreamStatus status, 186 | void *userData ); 187 | 188 | //! RtAudio error callback function prototype. 189 | /*! 190 | \param type Type of error. 191 | \param errorText Error description. 192 | */ 193 | typedef void (*RtAudioErrorCallback)( RtError::Type type, const std::string &errorText, void *userData ); 194 | 195 | // **************************************************************** // 196 | // 197 | // RtAudio class declaration. 198 | // 199 | // RtAudio is a "controller" used to select an available audio i/o 200 | // interface. It presents a common API for the user to call but all 201 | // functionality is implemented by the class RtApi and its 202 | // subclasses. RtAudio creates an instance of an RtApi subclass 203 | // based on the user's API choice. If no choice is made, RtAudio 204 | // attempts to make a "logical" API selection. 205 | // 206 | // **************************************************************** // 207 | 208 | class RtApi; 209 | 210 | class RtAudio 211 | { 212 | public: 213 | 214 | //! Audio API specifier arguments. 215 | enum Api { 216 | UNSPECIFIED, /*!< Search for a working compiled API. */ 217 | LINUX_ALSA, /*!< The Advanced Linux Sound Architecture API. */ 218 | LINUX_PULSE, /*!< The Linux PulseAudio API. */ 219 | LINUX_OSS, /*!< The Linux Open Sound System API. */ 220 | UNIX_JACK, /*!< The Jack Low-Latency Audio Server API. */ 221 | MACOSX_CORE, /*!< Macintosh OS-X Core Audio API. */ 222 | WINDOWS_ASIO, /*!< The Steinberg Audio Stream I/O API. */ 223 | WINDOWS_DS, /*!< The Microsoft Direct Sound API. */ 224 | RTAUDIO_DUMMY /*!< A compilable but non-functional API. */ 225 | }; 226 | 227 | //! The public device information structure for returning queried values. 228 | struct DeviceInfo { 229 | bool probed; /*!< true if the device capabilities were successfully probed. */ 230 | std::string name; /*!< Character string device identifier. */ 231 | unsigned int outputChannels; /*!< Maximum output channels supported by device. */ 232 | unsigned int inputChannels; /*!< Maximum input channels supported by device. */ 233 | unsigned int duplexChannels; /*!< Maximum simultaneous input/output channels supported by device. */ 234 | bool isDefaultOutput; /*!< true if this is the default output device. */ 235 | bool isDefaultInput; /*!< true if this is the default input device. */ 236 | std::vector sampleRates; /*!< Supported sample rates (queried from list of standard rates). */ 237 | RtAudioFormat nativeFormats; /*!< Bit mask of supported data formats. */ 238 | 239 | // Default constructor. 240 | DeviceInfo() 241 | :probed(false), outputChannels(0), inputChannels(0), duplexChannels(0), 242 | isDefaultOutput(false), isDefaultInput(false), nativeFormats(0) {} 243 | }; 244 | 245 | //! The structure for specifying input or ouput stream parameters. 246 | struct StreamParameters { 247 | unsigned int deviceId; /*!< Device index (0 to getDeviceCount() - 1). */ 248 | unsigned int nChannels; /*!< Number of channels. */ 249 | unsigned int firstChannel; /*!< First channel index on device (default = 0). */ 250 | 251 | // Default constructor. 252 | StreamParameters() 253 | : deviceId(0), nChannels(0), firstChannel(0) {} 254 | }; 255 | 256 | //! The structure for specifying stream options. 257 | /*! 258 | The following flags can be OR'ed together to allow a client to 259 | make changes to the default stream behavior: 260 | 261 | - \e RTAUDIO_NONINTERLEAVED: Use non-interleaved buffers (default = interleaved). 262 | - \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency. 263 | - \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use. 264 | - \e RTAUDIO_SCHEDULE_REALTIME: Attempt to select realtime scheduling for callback thread. 265 | - \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only). 266 | 267 | By default, RtAudio streams pass and receive audio data from the 268 | client in an interleaved format. By passing the 269 | RTAUDIO_NONINTERLEAVED flag to the openStream() function, audio 270 | data will instead be presented in non-interleaved buffers. In 271 | this case, each buffer argument in the RtAudioCallback function 272 | will point to a single array of data, with \c nFrames samples for 273 | each channel concatenated back-to-back. For example, the first 274 | sample of data for the second channel would be located at index \c 275 | nFrames (assuming the \c buffer pointer was recast to the correct 276 | data type for the stream). 277 | 278 | Certain audio APIs offer a number of parameters that influence the 279 | I/O latency of a stream. By default, RtAudio will attempt to set 280 | these parameters internally for robust (glitch-free) performance 281 | (though some APIs, like Windows Direct Sound, make this difficult). 282 | By passing the RTAUDIO_MINIMIZE_LATENCY flag to the openStream() 283 | function, internal stream settings will be influenced in an attempt 284 | to minimize stream latency, though possibly at the expense of stream 285 | performance. 286 | 287 | If the RTAUDIO_HOG_DEVICE flag is set, RtAudio will attempt to 288 | open the input and/or output stream device(s) for exclusive use. 289 | Note that this is not possible with all supported audio APIs. 290 | 291 | If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt 292 | to select realtime scheduling (round-robin) for the callback thread. 293 | The \c priority parameter will only be used if the RTAUDIO_SCHEDULE_REALTIME 294 | flag is set. It defines the thread's realtime priority. 295 | 296 | If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to 297 | open the "default" PCM device when using the ALSA API. Note that this 298 | will override any specified input or output device id. 299 | 300 | The \c numberOfBuffers parameter can be used to control stream 301 | latency in the Windows DirectSound, Linux OSS, and Linux Alsa APIs 302 | only. A value of two is usually the smallest allowed. Larger 303 | numbers can potentially result in more robust stream performance, 304 | though likely at the cost of stream latency. The value set by the 305 | user is replaced during execution of the RtAudio::openStream() 306 | function by the value actually used by the system. 307 | 308 | The \c streamName parameter can be used to set the client name 309 | when using the Jack API. By default, the client name is set to 310 | RtApiJack. However, if you wish to create multiple instances of 311 | RtAudio with Jack, each instance must have a unique client name. 312 | */ 313 | struct StreamOptions { 314 | RtAudioStreamFlags flags; /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE, RTAUDIO_ALSA_USE_DEFAULT). */ 315 | unsigned int numberOfBuffers; /*!< Number of stream buffers. */ 316 | std::string streamName; /*!< A stream name (currently used only in Jack). */ 317 | int priority; /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */ 318 | 319 | // Default constructor. 320 | StreamOptions() 321 | : flags(0), numberOfBuffers(0), priority(0) {} 322 | }; 323 | 324 | //! A static function to determine the current RtAudio version. 325 | static std::string getVersion( void ) { return VERSION; } 326 | 327 | //! A static function to determine the available compiled audio APIs. 328 | /*! 329 | The values returned in the std::vector can be compared against 330 | the enumerated list values. Note that there can be more than one 331 | API compiled for certain operating systems. 332 | */ 333 | static void getCompiledApi( std::vector &apis ) throw(); 334 | 335 | //! The class constructor. 336 | /*! 337 | The constructor performs minor initialization tasks. No exceptions 338 | can be thrown. 339 | 340 | If no API argument is specified and multiple API support has been 341 | compiled, the default order of use is JACK, ALSA, OSS (Linux 342 | systems) and ASIO, DS (Windows systems). 343 | */ 344 | RtAudio( RtAudio::Api api=UNSPECIFIED ) throw(); 345 | 346 | //! The destructor. 347 | /*! 348 | If a stream is running or open, it will be stopped and closed 349 | automatically. 350 | */ 351 | ~RtAudio() throw(); 352 | 353 | //! Returns the audio API specifier for the current instance of RtAudio. 354 | RtAudio::Api getCurrentApi( void ) throw(); 355 | 356 | //! A public function that queries for the number of audio devices available. 357 | /*! 358 | This function performs a system query of available devices each time it 359 | is called, thus supporting devices connected \e after instantiation. If 360 | a system error occurs during processing, a warning will be issued. 361 | */ 362 | unsigned int getDeviceCount( void ) throw(); 363 | 364 | //! Return an RtAudio::DeviceInfo structure for a specified device number. 365 | /*! 366 | 367 | Any device integer between 0 and getDeviceCount() - 1 is valid. 368 | If an invalid argument is provided, an RtError (type = INVALID_USE) 369 | will be thrown. If a device is busy or otherwise unavailable, the 370 | structure member "probed" will have a value of "false" and all 371 | other members are undefined. If the specified device is the 372 | current default input or output device, the corresponding 373 | "isDefault" member will have a value of "true". 374 | */ 375 | RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); 376 | 377 | //! A function that returns the index of the default output device. 378 | /*! 379 | If the underlying audio API does not provide a "default 380 | device", or if no devices are available, the return value will be 381 | 0. Note that this is a valid device identifier and it is the 382 | client's responsibility to verify that a device is available 383 | before attempting to open a stream. 384 | */ 385 | unsigned int getDefaultOutputDevice( void ) throw(); 386 | 387 | //! A function that returns the index of the default input device. 388 | /*! 389 | If the underlying audio API does not provide a "default 390 | device", or if no devices are available, the return value will be 391 | 0. Note that this is a valid device identifier and it is the 392 | client's responsibility to verify that a device is available 393 | before attempting to open a stream. 394 | */ 395 | unsigned int getDefaultInputDevice( void ) throw(); 396 | 397 | //! A public function for opening a stream with the specified parameters. 398 | /*! 399 | An RtError (type = SYSTEM_ERROR) is thrown if a stream cannot be 400 | opened with the specified parameters or an error occurs during 401 | processing. An RtError (type = INVALID_USE) is thrown if any 402 | invalid device ID or channel number parameters are specified. 403 | 404 | \param outputParameters Specifies output stream parameters to use 405 | when opening a stream, including a device ID, number of channels, 406 | and starting channel number. For input-only streams, this 407 | argument should be NULL. The device ID is an index value between 408 | 0 and getDeviceCount() - 1. 409 | \param inputParameters Specifies input stream parameters to use 410 | when opening a stream, including a device ID, number of channels, 411 | and starting channel number. For output-only streams, this 412 | argument should be NULL. The device ID is an index value between 413 | 0 and getDeviceCount() - 1. 414 | \param format An RtAudioFormat specifying the desired sample data format. 415 | \param sampleRate The desired sample rate (sample frames per second). 416 | \param *bufferFrames A pointer to a value indicating the desired 417 | internal buffer size in sample frames. The actual value 418 | used by the device is returned via the same pointer. A 419 | value of zero can be specified, in which case the lowest 420 | allowable value is determined. 421 | \param callback A client-defined function that will be invoked 422 | when input data is available and/or output data is needed. 423 | \param userData An optional pointer to data that can be accessed 424 | from within the callback function. 425 | \param options An optional pointer to a structure containing various 426 | global stream options, including a list of OR'ed RtAudioStreamFlags 427 | and a suggested number of stream buffers that can be used to 428 | control stream latency. More buffers typically result in more 429 | robust performance, though at a cost of greater latency. If a 430 | value of zero is specified, a system-specific median value is 431 | chosen. If the RTAUDIO_MINIMIZE_LATENCY flag bit is set, the 432 | lowest allowable value is used. The actual value used is 433 | returned via the structure argument. The parameter is API dependent. 434 | \param errorCallback A client-defined function that will be invoked 435 | when an error has occured. 436 | */ 437 | void openStream( RtAudio::StreamParameters *outputParameters, 438 | RtAudio::StreamParameters *inputParameters, 439 | RtAudioFormat format, unsigned int sampleRate, 440 | unsigned int *bufferFrames, RtAudioCallback callback, 441 | void *userData = NULL, RtAudio::StreamOptions *options = NULL, RtAudioErrorCallback errorCallback = NULL ); 442 | 443 | //! A function that closes a stream and frees any associated stream memory. 444 | /*! 445 | If a stream is not open, this function issues a warning and 446 | returns (no exception is thrown). 447 | */ 448 | void closeStream( void ) throw(); 449 | 450 | //! A function that starts a stream. 451 | /*! 452 | An RtError (type = SYSTEM_ERROR) is thrown if an error occurs 453 | during processing. An RtError (type = INVALID_USE) is thrown if a 454 | stream is not open. A warning is issued if the stream is already 455 | running. 456 | */ 457 | void startStream( void ); 458 | 459 | //! Stop a stream, allowing any samples remaining in the output queue to be played. 460 | /*! 461 | An RtError (type = SYSTEM_ERROR) is thrown if an error occurs 462 | during processing. An RtError (type = INVALID_USE) is thrown if a 463 | stream is not open. A warning is issued if the stream is already 464 | stopped. 465 | */ 466 | void stopStream( void ); 467 | 468 | //! Stop a stream, discarding any samples remaining in the input/output queue. 469 | /*! 470 | An RtError (type = SYSTEM_ERROR) is thrown if an error occurs 471 | during processing. An RtError (type = INVALID_USE) is thrown if a 472 | stream is not open. A warning is issued if the stream is already 473 | stopped. 474 | */ 475 | void abortStream( void ); 476 | 477 | //! Returns true if a stream is open and false if not. 478 | bool isStreamOpen( void ) const throw(); 479 | 480 | //! Returns true if the stream is running and false if it is stopped or not open. 481 | bool isStreamRunning( void ) const throw(); 482 | 483 | //! Returns the number of elapsed seconds since the stream was started. 484 | /*! 485 | If a stream is not open, an RtError (type = INVALID_USE) will be thrown. 486 | */ 487 | double getStreamTime( void ); 488 | 489 | //! Returns the internal stream latency in sample frames. 490 | /*! 491 | The stream latency refers to delay in audio input and/or output 492 | caused by internal buffering by the audio system and/or hardware. 493 | For duplex streams, the returned value will represent the sum of 494 | the input and output latencies. If a stream is not open, an 495 | RtError (type = INVALID_USE) will be thrown. If the API does not 496 | report latency, the return value will be zero. 497 | */ 498 | long getStreamLatency( void ); 499 | 500 | //! Returns actual sample rate in use by the stream. 501 | /*! 502 | On some systems, the sample rate used may be slightly different 503 | than that specified in the stream parameters. If a stream is not 504 | open, an RtError (type = INVALID_USE) will be thrown. 505 | */ 506 | unsigned int getStreamSampleRate( void ); 507 | 508 | //! Specify whether warning messages should be printed to stderr. 509 | void showWarnings( bool value = true ) throw(); 510 | 511 | protected: 512 | 513 | void openRtApi( RtAudio::Api api ); 514 | RtApi *rtapi_; 515 | }; 516 | 517 | // Operating system dependent thread functionality. 518 | #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) 519 | #include 520 | #include 521 | 522 | typedef unsigned long ThreadHandle; 523 | typedef CRITICAL_SECTION StreamMutex; 524 | 525 | #elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) 526 | // Using pthread library for various flavors of unix. 527 | #include 528 | 529 | typedef pthread_t ThreadHandle; 530 | typedef pthread_mutex_t StreamMutex; 531 | 532 | #else // Setup for "dummy" behavior 533 | 534 | #define __RTAUDIO_DUMMY__ 535 | typedef int ThreadHandle; 536 | typedef int StreamMutex; 537 | 538 | #endif 539 | 540 | // This global structure type is used to pass callback information 541 | // between the private RtAudio stream structure and global callback 542 | // handling functions. 543 | struct CallbackInfo { 544 | void *object; // Used as a "this" pointer. 545 | ThreadHandle thread; 546 | void *callback; 547 | void *userData; 548 | void *errorCallback; 549 | void *apiInfo; // void pointer for API specific callback information 550 | bool isRunning; 551 | bool doRealtime; 552 | int priority; 553 | 554 | // Default constructor. 555 | CallbackInfo() 556 | :object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false) {} 557 | }; 558 | 559 | // **************************************************************** // 560 | // 561 | // RtApi class declaration. 562 | // 563 | // Subclasses of RtApi contain all API- and OS-specific code necessary 564 | // to fully implement the RtAudio API. 565 | // 566 | // Note that RtApi is an abstract base class and cannot be 567 | // explicitly instantiated. The class RtAudio will create an 568 | // instance of an RtApi subclass (RtApiOss, RtApiAlsa, 569 | // RtApiJack, RtApiCore, RtApiDs, or RtApiAsio). 570 | // 571 | // **************************************************************** // 572 | 573 | #pragma pack(push, 1) 574 | class S24 { 575 | 576 | protected: 577 | unsigned char c3[3]; 578 | 579 | public: 580 | S24() {} 581 | 582 | S24& operator = ( const int& i ) { 583 | c3[0] = (i & 0x000000ff); 584 | c3[1] = (i & 0x0000ff00) >> 8; 585 | c3[2] = (i & 0x00ff0000) >> 16; 586 | return *this; 587 | } 588 | 589 | S24( const S24& v ) { *this = v; } 590 | S24( const double& d ) { *this = (int) d; } 591 | S24( const float& f ) { *this = (int) f; } 592 | S24( const signed short& s ) { *this = (int) s; } 593 | S24( const char& c ) { *this = (int) c; } 594 | 595 | int asInt() { 596 | int i = c3[0] | (c3[1] << 8) | (c3[2] << 16); 597 | if (i & 0x800000) i |= ~0xffffff; 598 | return i; 599 | } 600 | }; 601 | #pragma pack(pop) 602 | 603 | #if defined( HAVE_GETTIMEOFDAY ) 604 | #include 605 | #endif 606 | 607 | #include 608 | 609 | class RtApi 610 | { 611 | public: 612 | 613 | RtApi(); 614 | virtual ~RtApi(); 615 | virtual RtAudio::Api getCurrentApi( void ) = 0; 616 | virtual unsigned int getDeviceCount( void ) = 0; 617 | virtual RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) = 0; 618 | virtual unsigned int getDefaultInputDevice( void ); 619 | virtual unsigned int getDefaultOutputDevice( void ); 620 | void openStream( RtAudio::StreamParameters *outputParameters, 621 | RtAudio::StreamParameters *inputParameters, 622 | RtAudioFormat format, unsigned int sampleRate, 623 | unsigned int *bufferFrames, RtAudioCallback callback, 624 | void *userData, RtAudio::StreamOptions *options, 625 | RtAudioErrorCallback errorCallback ); 626 | virtual void closeStream( void ); 627 | virtual void startStream( void ) = 0; 628 | virtual void stopStream( void ) = 0; 629 | virtual void abortStream( void ) = 0; 630 | long getStreamLatency( void ); 631 | unsigned int getStreamSampleRate( void ); 632 | virtual double getStreamTime( void ); 633 | bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; } 634 | bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; } 635 | void showWarnings( bool value ) { showWarnings_ = value; } 636 | 637 | 638 | protected: 639 | 640 | static const unsigned int MAX_SAMPLE_RATES; 641 | static const unsigned int SAMPLE_RATES[]; 642 | 643 | enum { FAILURE, SUCCESS }; 644 | 645 | enum StreamState { 646 | STREAM_STOPPED, 647 | STREAM_STOPPING, 648 | STREAM_RUNNING, 649 | STREAM_CLOSED = -50 650 | }; 651 | 652 | enum StreamMode { 653 | OUTPUT, 654 | INPUT, 655 | DUPLEX, 656 | UNINITIALIZED = -75 657 | }; 658 | 659 | // A protected structure used for buffer conversion. 660 | struct ConvertInfo { 661 | int channels; 662 | int inJump, outJump; 663 | RtAudioFormat inFormat, outFormat; 664 | std::vector inOffset; 665 | std::vector outOffset; 666 | }; 667 | 668 | // A protected structure for audio streams. 669 | struct RtApiStream { 670 | unsigned int device[2]; // Playback and record, respectively. 671 | void *apiHandle; // void pointer for API specific stream handle information 672 | StreamMode mode; // OUTPUT, INPUT, or DUPLEX. 673 | StreamState state; // STOPPED, RUNNING, or CLOSED 674 | char *userBuffer[2]; // Playback and record, respectively. 675 | char *deviceBuffer; 676 | bool doConvertBuffer[2]; // Playback and record, respectively. 677 | bool userInterleaved; 678 | bool deviceInterleaved[2]; // Playback and record, respectively. 679 | bool doByteSwap[2]; // Playback and record, respectively. 680 | unsigned int sampleRate; 681 | unsigned int bufferSize; 682 | unsigned int nBuffers; 683 | unsigned int nUserChannels[2]; // Playback and record, respectively. 684 | unsigned int nDeviceChannels[2]; // Playback and record channels, respectively. 685 | unsigned int channelOffset[2]; // Playback and record, respectively. 686 | unsigned long latency[2]; // Playback and record, respectively. 687 | RtAudioFormat userFormat; 688 | RtAudioFormat deviceFormat[2]; // Playback and record, respectively. 689 | StreamMutex mutex; 690 | CallbackInfo callbackInfo; 691 | ConvertInfo convertInfo[2]; 692 | double streamTime; // Number of elapsed seconds since the stream started. 693 | 694 | #if defined(HAVE_GETTIMEOFDAY) 695 | struct timeval lastTickTimestamp; 696 | #endif 697 | 698 | RtApiStream() 699 | :apiHandle(0), deviceBuffer(0) { device[0] = 11111; device[1] = 11111; } 700 | }; 701 | 702 | typedef S24 Int24; 703 | typedef signed short Int16; 704 | typedef signed int Int32; 705 | typedef float Float32; 706 | typedef double Float64; 707 | 708 | std::ostringstream errorStream_; 709 | std::string errorText_; 710 | bool showWarnings_; 711 | RtApiStream stream_; 712 | 713 | /*! 714 | Protected, api-specific method that attempts to open a device 715 | with the given parameters. This function MUST be implemented by 716 | all subclasses. If an error is encountered during the probe, a 717 | "warning" message is reported and FAILURE is returned. A 718 | successful probe is indicated by a return value of SUCCESS. 719 | */ 720 | virtual bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 721 | unsigned int firstChannel, unsigned int sampleRate, 722 | RtAudioFormat format, unsigned int *bufferSize, 723 | RtAudio::StreamOptions *options ); 724 | 725 | //! A protected function used to increment the stream time. 726 | void tickStreamTime( void ); 727 | 728 | //! Protected common method to clear an RtApiStream structure. 729 | void clearStreamInfo(); 730 | 731 | /*! 732 | Protected common method that throws an RtError (type = 733 | INVALID_USE) if a stream is not open. 734 | */ 735 | void verifyStream( void ); 736 | 737 | //! Protected common error method to allow global control over error handling. 738 | void error( RtError::Type type ); 739 | 740 | /*! 741 | Protected method used to perform format, channel number, and/or interleaving 742 | conversions between the user and device buffers. 743 | */ 744 | void convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info ); 745 | 746 | //! Protected common method used to perform byte-swapping on buffers. 747 | void byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format ); 748 | 749 | //! Protected common method that returns the number of bytes for a given format. 750 | unsigned int formatBytes( RtAudioFormat format ); 751 | 752 | //! Protected common method that sets up the parameters for buffer conversion. 753 | void setConvertInfo( StreamMode mode, unsigned int firstChannel ); 754 | }; 755 | 756 | // **************************************************************** // 757 | // 758 | // Inline RtAudio definitions. 759 | // 760 | // **************************************************************** // 761 | 762 | inline RtAudio::Api RtAudio :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); } 763 | inline unsigned int RtAudio :: getDeviceCount( void ) throw() { return rtapi_->getDeviceCount(); } 764 | inline RtAudio::DeviceInfo RtAudio :: getDeviceInfo( unsigned int device ) { return rtapi_->getDeviceInfo( device ); } 765 | inline unsigned int RtAudio :: getDefaultInputDevice( void ) throw() { return rtapi_->getDefaultInputDevice(); } 766 | inline unsigned int RtAudio :: getDefaultOutputDevice( void ) throw() { return rtapi_->getDefaultOutputDevice(); } 767 | inline void RtAudio :: closeStream( void ) throw() { return rtapi_->closeStream(); } 768 | inline void RtAudio :: startStream( void ) { return rtapi_->startStream(); } 769 | inline void RtAudio :: stopStream( void ) { return rtapi_->stopStream(); } 770 | inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); } 771 | inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); } 772 | inline bool RtAudio :: isStreamRunning( void ) const throw() { return rtapi_->isStreamRunning(); } 773 | inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); } 774 | inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); } 775 | inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); } 776 | inline void RtAudio :: showWarnings( bool value ) throw() { rtapi_->showWarnings( value ); } 777 | 778 | // RtApi Subclass prototypes. 779 | 780 | #if defined(__MACOSX_CORE__) 781 | 782 | #include 783 | 784 | class RtApiCore: public RtApi 785 | { 786 | public: 787 | 788 | RtApiCore(); 789 | ~RtApiCore(); 790 | RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; } 791 | unsigned int getDeviceCount( void ); 792 | RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); 793 | unsigned int getDefaultOutputDevice( void ); 794 | unsigned int getDefaultInputDevice( void ); 795 | void closeStream( void ); 796 | void startStream( void ); 797 | void stopStream( void ); 798 | void abortStream( void ); 799 | long getStreamLatency( void ); 800 | 801 | // This function is intended for internal use only. It must be 802 | // public because it is called by the internal callback handler, 803 | // which is not a member of RtAudio. External use of this function 804 | // will most likely produce highly undesireable results! 805 | bool callbackEvent( AudioDeviceID deviceId, 806 | const AudioBufferList *inBufferList, 807 | const AudioBufferList *outBufferList ); 808 | 809 | private: 810 | 811 | bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 812 | unsigned int firstChannel, unsigned int sampleRate, 813 | RtAudioFormat format, unsigned int *bufferSize, 814 | RtAudio::StreamOptions *options ); 815 | static const char* getErrorCode( OSStatus code ); 816 | }; 817 | 818 | #endif 819 | 820 | #if defined(__UNIX_JACK__) 821 | 822 | class RtApiJack: public RtApi 823 | { 824 | public: 825 | 826 | RtApiJack(); 827 | ~RtApiJack(); 828 | RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; } 829 | unsigned int getDeviceCount( void ); 830 | RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); 831 | void closeStream( void ); 832 | void startStream( void ); 833 | void stopStream( void ); 834 | void abortStream( void ); 835 | long getStreamLatency( void ); 836 | 837 | // This function is intended for internal use only. It must be 838 | // public because it is called by the internal callback handler, 839 | // which is not a member of RtAudio. External use of this function 840 | // will most likely produce highly undesireable results! 841 | bool callbackEvent( unsigned long nframes ); 842 | 843 | private: 844 | 845 | bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 846 | unsigned int firstChannel, unsigned int sampleRate, 847 | RtAudioFormat format, unsigned int *bufferSize, 848 | RtAudio::StreamOptions *options ); 849 | }; 850 | 851 | #endif 852 | 853 | #if defined(__WINDOWS_ASIO__) 854 | 855 | class RtApiAsio: public RtApi 856 | { 857 | public: 858 | 859 | RtApiAsio(); 860 | ~RtApiAsio(); 861 | RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; } 862 | unsigned int getDeviceCount( void ); 863 | RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); 864 | void closeStream( void ); 865 | void startStream( void ); 866 | void stopStream( void ); 867 | void abortStream( void ); 868 | long getStreamLatency( void ); 869 | 870 | // This function is intended for internal use only. It must be 871 | // public because it is called by the internal callback handler, 872 | // which is not a member of RtAudio. External use of this function 873 | // will most likely produce highly undesireable results! 874 | bool callbackEvent( long bufferIndex ); 875 | 876 | private: 877 | 878 | std::vector devices_; 879 | void saveDeviceInfo( void ); 880 | bool coInitialized_; 881 | bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 882 | unsigned int firstChannel, unsigned int sampleRate, 883 | RtAudioFormat format, unsigned int *bufferSize, 884 | RtAudio::StreamOptions *options ); 885 | }; 886 | 887 | #endif 888 | 889 | #if defined(__WINDOWS_DS__) 890 | 891 | class RtApiDs: public RtApi 892 | { 893 | public: 894 | 895 | RtApiDs(); 896 | ~RtApiDs(); 897 | RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; } 898 | unsigned int getDeviceCount( void ); 899 | unsigned int getDefaultOutputDevice( void ); 900 | unsigned int getDefaultInputDevice( void ); 901 | RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); 902 | void closeStream( void ); 903 | void startStream( void ); 904 | void stopStream( void ); 905 | void abortStream( void ); 906 | long getStreamLatency( void ); 907 | 908 | // This function is intended for internal use only. It must be 909 | // public because it is called by the internal callback handler, 910 | // which is not a member of RtAudio. External use of this function 911 | // will most likely produce highly undesireable results! 912 | void callbackEvent( void ); 913 | 914 | private: 915 | 916 | bool coInitialized_; 917 | bool buffersRolling; 918 | long duplexPrerollBytes; 919 | std::vector dsDevices; 920 | bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 921 | unsigned int firstChannel, unsigned int sampleRate, 922 | RtAudioFormat format, unsigned int *bufferSize, 923 | RtAudio::StreamOptions *options ); 924 | }; 925 | 926 | #endif 927 | 928 | #if defined(__LINUX_ALSA__) 929 | 930 | class RtApiAlsa: public RtApi 931 | { 932 | public: 933 | 934 | RtApiAlsa(); 935 | ~RtApiAlsa(); 936 | RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; } 937 | unsigned int getDeviceCount( void ); 938 | RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); 939 | void closeStream( void ); 940 | void startStream( void ); 941 | void stopStream( void ); 942 | void abortStream( void ); 943 | 944 | // This function is intended for internal use only. It must be 945 | // public because it is called by the internal callback handler, 946 | // which is not a member of RtAudio. External use of this function 947 | // will most likely produce highly undesireable results! 948 | void callbackEvent( void ); 949 | 950 | private: 951 | 952 | std::vector devices_; 953 | void saveDeviceInfo( void ); 954 | bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 955 | unsigned int firstChannel, unsigned int sampleRate, 956 | RtAudioFormat format, unsigned int *bufferSize, 957 | RtAudio::StreamOptions *options ); 958 | }; 959 | 960 | #endif 961 | 962 | #if defined(__LINUX_PULSE__) 963 | 964 | class RtApiPulse: public RtApi 965 | { 966 | public: 967 | ~RtApiPulse(); 968 | RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; } 969 | unsigned int getDeviceCount( void ); 970 | RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); 971 | void closeStream( void ); 972 | void startStream( void ); 973 | void stopStream( void ); 974 | void abortStream( void ); 975 | 976 | // This function is intended for internal use only. It must be 977 | // public because it is called by the internal callback handler, 978 | // which is not a member of RtAudio. External use of this function 979 | // will most likely produce highly undesireable results! 980 | void callbackEvent( void ); 981 | 982 | private: 983 | 984 | std::vector devices_; 985 | void saveDeviceInfo( void ); 986 | bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 987 | unsigned int firstChannel, unsigned int sampleRate, 988 | RtAudioFormat format, unsigned int *bufferSize, 989 | RtAudio::StreamOptions *options ); 990 | }; 991 | 992 | #endif 993 | 994 | #if defined(__LINUX_OSS__) 995 | 996 | class RtApiOss: public RtApi 997 | { 998 | public: 999 | 1000 | RtApiOss(); 1001 | ~RtApiOss(); 1002 | RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; } 1003 | unsigned int getDeviceCount( void ); 1004 | RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); 1005 | void closeStream( void ); 1006 | void startStream( void ); 1007 | void stopStream( void ); 1008 | void abortStream( void ); 1009 | 1010 | // This function is intended for internal use only. It must be 1011 | // public because it is called by the internal callback handler, 1012 | // which is not a member of RtAudio. External use of this function 1013 | // will most likely produce highly undesireable results! 1014 | void callbackEvent( void ); 1015 | 1016 | private: 1017 | 1018 | bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, 1019 | unsigned int firstChannel, unsigned int sampleRate, 1020 | RtAudioFormat format, unsigned int *bufferSize, 1021 | RtAudio::StreamOptions *options ); 1022 | }; 1023 | 1024 | #endif 1025 | 1026 | #if defined(__RTAUDIO_DUMMY__) 1027 | 1028 | class RtApiDummy: public RtApi 1029 | { 1030 | public: 1031 | 1032 | RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtError::WARNING ); } 1033 | RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; } 1034 | unsigned int getDeviceCount( void ) { return 0; } 1035 | RtAudio::DeviceInfo getDeviceInfo( unsigned int /*device*/ ) { RtAudio::DeviceInfo info; return info; } 1036 | void closeStream( void ) {} 1037 | void startStream( void ) {} 1038 | void stopStream( void ) {} 1039 | void abortStream( void ) {} 1040 | 1041 | private: 1042 | 1043 | bool probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/, 1044 | unsigned int /*firstChannel*/, unsigned int /*sampleRate*/, 1045 | RtAudioFormat /*format*/, unsigned int * /*bufferSize*/, 1046 | RtAudio::StreamOptions * /*options*/ ) { return false; } 1047 | }; 1048 | 1049 | #endif 1050 | 1051 | #endif 1052 | 1053 | // Indentation settings for Vim and Emacs 1054 | // 1055 | // Local Variables: 1056 | // c-basic-offset: 2 1057 | // indent-tabs-mode: nil 1058 | // End: 1059 | // 1060 | // vim: et sts=2 sw=2 1061 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/RtError.h: -------------------------------------------------------------------------------- 1 | /************************************************************************/ 2 | /*! \class RtError 3 | \brief Exception handling class for RtAudio & RtMidi. 4 | 5 | The RtError class is quite simple but it does allow errors to be 6 | "caught" by RtError::Type. See the RtAudio and RtMidi 7 | documentation to know which methods can throw an RtError. 8 | 9 | */ 10 | /************************************************************************/ 11 | 12 | #ifndef RTERROR_H 13 | #define RTERROR_H 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | class RtError : public std::exception 20 | { 21 | public: 22 | //! Defined RtError types. 23 | enum Type { 24 | WARNING, /*!< A non-critical error. */ 25 | DEBUG_WARNING, /*!< A non-critical error which might be useful for debugging. */ 26 | UNSPECIFIED, /*!< The default, unspecified error type. */ 27 | NO_DEVICES_FOUND, /*!< No devices found on system. */ 28 | INVALID_DEVICE, /*!< An invalid device ID was specified. */ 29 | MEMORY_ERROR, /*!< An error occured during memory allocation. */ 30 | INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */ 31 | INVALID_USE, /*!< The function was called incorrectly. */ 32 | DRIVER_ERROR, /*!< A system driver error occured. */ 33 | SYSTEM_ERROR, /*!< A system error occured. */ 34 | THREAD_ERROR /*!< A thread error occured. */ 35 | }; 36 | 37 | //! The constructor. 38 | RtError( const std::string& message, Type type = RtError::UNSPECIFIED ) throw() : message_(message), type_(type) {} 39 | 40 | //! The destructor. 41 | virtual ~RtError( void ) throw() {} 42 | 43 | //! Prints thrown error message to stderr. 44 | virtual void printMessage( void ) const throw() { std::cerr << '\n' << message_ << "\n\n"; } 45 | 46 | //! Returns the thrown error message type. 47 | virtual const Type& getType(void) const throw() { return type_; } 48 | 49 | //! Returns the thrown error message string. 50 | virtual const std::string& getMessage(void) const throw() { return message_; } 51 | 52 | //! Returns the thrown error message as a c-style string. 53 | virtual const char* what( void ) const throw() { return message_.c_str(); } 54 | 55 | protected: 56 | std::string message_; 57 | Type type_; 58 | }; 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/include/asio.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Steinberg Audio Stream I/O API 3 | (c) 1996, Steinberg Soft- und Hardware GmbH 4 | 5 | asio.cpp 6 | 7 | asio functions entries which translate the 8 | asio interface to the asiodrvr class methods 9 | */ 10 | 11 | #include 12 | #include "asiosys.h" // platform definition 13 | #include "asio.h" 14 | 15 | #if MAC 16 | #include "asiodrvr.h" 17 | 18 | #pragma export on 19 | 20 | AsioDriver *theAsioDriver = 0; 21 | 22 | extern "C" 23 | { 24 | 25 | long main() 26 | { 27 | return 'ASIO'; 28 | } 29 | 30 | #elif WINDOWS 31 | 32 | #include "windows.h" 33 | #include "iasiodrv.h" 34 | #include "asiodrivers.h" 35 | 36 | IASIO *theAsioDriver = 0; 37 | extern AsioDrivers *asioDrivers; 38 | 39 | #elif SGI || SUN || BEOS || LINUX 40 | #include "asiodrvr.h" 41 | static AsioDriver *theAsioDriver = 0; 42 | #endif 43 | 44 | //----------------------------------------------------------------------------------------------------- 45 | ASIOError ASIOInit(ASIODriverInfo *info) 46 | { 47 | #if MAC || SGI || SUN || BEOS || LINUX 48 | if(theAsioDriver) 49 | { 50 | delete theAsioDriver; 51 | theAsioDriver = 0; 52 | } 53 | info->driverVersion = 0; 54 | strcpy(info->name, "No ASIO Driver"); 55 | theAsioDriver = getDriver(); 56 | if(!theAsioDriver) 57 | { 58 | strcpy(info->errorMessage, "Not enough memory for the ASIO driver!"); 59 | return ASE_NotPresent; 60 | } 61 | if(!theAsioDriver->init(info->sysRef)) 62 | { 63 | theAsioDriver->getErrorMessage(info->errorMessage); 64 | delete theAsioDriver; 65 | theAsioDriver = 0; 66 | return ASE_NotPresent; 67 | } 68 | strcpy(info->errorMessage, "No ASIO Driver Error"); 69 | theAsioDriver->getDriverName(info->name); 70 | info->driverVersion = theAsioDriver->getDriverVersion(); 71 | return ASE_OK; 72 | 73 | #else 74 | 75 | info->driverVersion = 0; 76 | strcpy(info->name, "No ASIO Driver"); 77 | if(theAsioDriver) // must be loaded! 78 | { 79 | if(!theAsioDriver->init(info->sysRef)) 80 | { 81 | theAsioDriver->getErrorMessage(info->errorMessage); 82 | theAsioDriver = 0; 83 | return ASE_NotPresent; 84 | } 85 | 86 | strcpy(info->errorMessage, "No ASIO Driver Error"); 87 | theAsioDriver->getDriverName(info->name); 88 | info->driverVersion = theAsioDriver->getDriverVersion(); 89 | return ASE_OK; 90 | } 91 | return ASE_NotPresent; 92 | 93 | #endif // !MAC 94 | } 95 | 96 | ASIOError ASIOExit(void) 97 | { 98 | if(theAsioDriver) 99 | { 100 | #if WINDOWS 101 | asioDrivers->removeCurrentDriver(); 102 | #else 103 | delete theAsioDriver; 104 | #endif 105 | } 106 | theAsioDriver = 0; 107 | return ASE_OK; 108 | } 109 | 110 | ASIOError ASIOStart(void) 111 | { 112 | if(!theAsioDriver) 113 | return ASE_NotPresent; 114 | return theAsioDriver->start(); 115 | } 116 | 117 | ASIOError ASIOStop(void) 118 | { 119 | if(!theAsioDriver) 120 | return ASE_NotPresent; 121 | return theAsioDriver->stop(); 122 | } 123 | 124 | ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels) 125 | { 126 | if(!theAsioDriver) 127 | { 128 | *numInputChannels = *numOutputChannels = 0; 129 | return ASE_NotPresent; 130 | } 131 | return theAsioDriver->getChannels(numInputChannels, numOutputChannels); 132 | } 133 | 134 | ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency) 135 | { 136 | if(!theAsioDriver) 137 | { 138 | *inputLatency = *outputLatency = 0; 139 | return ASE_NotPresent; 140 | } 141 | return theAsioDriver->getLatencies(inputLatency, outputLatency); 142 | } 143 | 144 | ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity) 145 | { 146 | if(!theAsioDriver) 147 | { 148 | *minSize = *maxSize = *preferredSize = *granularity = 0; 149 | return ASE_NotPresent; 150 | } 151 | return theAsioDriver->getBufferSize(minSize, maxSize, preferredSize, granularity); 152 | } 153 | 154 | ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate) 155 | { 156 | if(!theAsioDriver) 157 | return ASE_NotPresent; 158 | return theAsioDriver->canSampleRate(sampleRate); 159 | } 160 | 161 | ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate) 162 | { 163 | if(!theAsioDriver) 164 | return ASE_NotPresent; 165 | return theAsioDriver->getSampleRate(currentRate); 166 | } 167 | 168 | ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate) 169 | { 170 | if(!theAsioDriver) 171 | return ASE_NotPresent; 172 | return theAsioDriver->setSampleRate(sampleRate); 173 | } 174 | 175 | ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources) 176 | { 177 | if(!theAsioDriver) 178 | { 179 | *numSources = 0; 180 | return ASE_NotPresent; 181 | } 182 | return theAsioDriver->getClockSources(clocks, numSources); 183 | } 184 | 185 | ASIOError ASIOSetClockSource(long reference) 186 | { 187 | if(!theAsioDriver) 188 | return ASE_NotPresent; 189 | return theAsioDriver->setClockSource(reference); 190 | } 191 | 192 | ASIOError ASIOGetSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) 193 | { 194 | if(!theAsioDriver) 195 | return ASE_NotPresent; 196 | return theAsioDriver->getSamplePosition(sPos, tStamp); 197 | } 198 | 199 | ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info) 200 | { 201 | if(!theAsioDriver) 202 | { 203 | info->channelGroup = -1; 204 | info->type = ASIOSTInt16MSB; 205 | strcpy(info->name, "None"); 206 | return ASE_NotPresent; 207 | } 208 | return theAsioDriver->getChannelInfo(info); 209 | } 210 | 211 | ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, 212 | long bufferSize, ASIOCallbacks *callbacks) 213 | { 214 | if(!theAsioDriver) 215 | { 216 | ASIOBufferInfo *info = bufferInfos; 217 | for(long i = 0; i < numChannels; i++, info++) 218 | info->buffers[0] = info->buffers[1] = 0; 219 | return ASE_NotPresent; 220 | } 221 | return theAsioDriver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks); 222 | } 223 | 224 | ASIOError ASIODisposeBuffers(void) 225 | { 226 | if(!theAsioDriver) 227 | return ASE_NotPresent; 228 | return theAsioDriver->disposeBuffers(); 229 | } 230 | 231 | ASIOError ASIOControlPanel(void) 232 | { 233 | if(!theAsioDriver) 234 | return ASE_NotPresent; 235 | return theAsioDriver->controlPanel(); 236 | } 237 | 238 | ASIOError ASIOFuture(long selector, void *opt) 239 | { 240 | if(!theAsioDriver) 241 | return ASE_NotPresent; 242 | return theAsioDriver->future(selector, opt); 243 | } 244 | 245 | ASIOError ASIOOutputReady(void) 246 | { 247 | if(!theAsioDriver) 248 | return ASE_NotPresent; 249 | return theAsioDriver->outputReady(); 250 | } 251 | 252 | #if MAC 253 | } // extern "C" 254 | #pragma export off 255 | #endif 256 | 257 | 258 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/include/asio.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------------------- 2 | //--------------------------------------------------------------------------------------------------- 3 | 4 | /* 5 | Steinberg Audio Stream I/O API 6 | (c) 1997 - 2005, Steinberg Media Technologies GmbH 7 | 8 | ASIO Interface Specification v 2.1 9 | 10 | 2005 - Added support for DSD sample data (in cooperation with Sony) 11 | 12 | 13 | basic concept is an i/o synchronous double-buffer scheme: 14 | 15 | on bufferSwitch(index == 0), host will read/write: 16 | 17 | after ASIOStart(), the 18 | read first input buffer A (index 0) 19 | | will be invalid (empty) 20 | * ------------------------ 21 | |------------------------|-----------------------| 22 | | | | 23 | | Input Buffer A (0) | Input Buffer B (1) | 24 | | | | 25 | |------------------------|-----------------------| 26 | | | | 27 | | Output Buffer A (0) | Output Buffer B (1) | 28 | | | | 29 | |------------------------|-----------------------| 30 | * ------------------------- 31 | | before calling ASIOStart(), 32 | write host will have filled output 33 | buffer B (index 1) already 34 | 35 | *please* take special care of proper statement of input 36 | and output latencies (see ASIOGetLatencies()), these 37 | control sequencer sync accuracy 38 | 39 | */ 40 | 41 | //--------------------------------------------------------------------------------------------------- 42 | //--------------------------------------------------------------------------------------------------- 43 | 44 | /* 45 | 46 | prototypes summary: 47 | 48 | ASIOError ASIOInit(ASIODriverInfo *info); 49 | ASIOError ASIOExit(void); 50 | ASIOError ASIOStart(void); 51 | ASIOError ASIOStop(void); 52 | ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels); 53 | ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency); 54 | ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); 55 | ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); 56 | ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); 57 | ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); 58 | ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources); 59 | ASIOError ASIOSetClockSource(long reference); 60 | ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); 61 | ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); 62 | ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, 63 | long bufferSize, ASIOCallbacks *callbacks); 64 | ASIOError ASIODisposeBuffers(void); 65 | ASIOError ASIOControlPanel(void); 66 | void *ASIOFuture(long selector, void *params); 67 | ASIOError ASIOOutputReady(void); 68 | 69 | */ 70 | 71 | //--------------------------------------------------------------------------------------------------- 72 | //--------------------------------------------------------------------------------------------------- 73 | 74 | #ifndef __ASIO_H 75 | #define __ASIO_H 76 | 77 | // force 4 byte alignment 78 | #if defined(_MSC_VER) && !defined(__MWERKS__) 79 | #pragma pack(push,4) 80 | #elif PRAGMA_ALIGN_SUPPORTED 81 | #pragma options align = native 82 | #endif 83 | 84 | //- - - - - - - - - - - - - - - - - - - - - - - - - 85 | // Type definitions 86 | //- - - - - - - - - - - - - - - - - - - - - - - - - 87 | 88 | // number of samples data type is 64 bit integer 89 | #if NATIVE_INT64 90 | typedef long long int ASIOSamples; 91 | #else 92 | typedef struct ASIOSamples { 93 | unsigned long hi; 94 | unsigned long lo; 95 | } ASIOSamples; 96 | #endif 97 | 98 | // Timestamp data type is 64 bit integer, 99 | // Time format is Nanoseconds. 100 | #if NATIVE_INT64 101 | typedef long long int ASIOTimeStamp ; 102 | #else 103 | typedef struct ASIOTimeStamp { 104 | unsigned long hi; 105 | unsigned long lo; 106 | } ASIOTimeStamp; 107 | #endif 108 | 109 | // Samplerates are expressed in IEEE 754 64 bit double float, 110 | // native format as host computer 111 | #if IEEE754_64FLOAT 112 | typedef double ASIOSampleRate; 113 | #else 114 | typedef struct ASIOSampleRate { 115 | char ieee[8]; 116 | } ASIOSampleRate; 117 | #endif 118 | 119 | // Boolean values are expressed as long 120 | typedef long ASIOBool; 121 | enum { 122 | ASIOFalse = 0, 123 | ASIOTrue = 1 124 | }; 125 | 126 | // Sample Types are expressed as long 127 | typedef long ASIOSampleType; 128 | enum { 129 | ASIOSTInt16MSB = 0, 130 | ASIOSTInt24MSB = 1, // used for 20 bits as well 131 | ASIOSTInt32MSB = 2, 132 | ASIOSTFloat32MSB = 3, // IEEE 754 32 bit float 133 | ASIOSTFloat64MSB = 4, // IEEE 754 64 bit double float 134 | 135 | // these are used for 32 bit data buffer, with different alignment of the data inside 136 | // 32 bit PCI bus systems can be more easily used with these 137 | ASIOSTInt32MSB16 = 8, // 32 bit data with 16 bit alignment 138 | ASIOSTInt32MSB18 = 9, // 32 bit data with 18 bit alignment 139 | ASIOSTInt32MSB20 = 10, // 32 bit data with 20 bit alignment 140 | ASIOSTInt32MSB24 = 11, // 32 bit data with 24 bit alignment 141 | 142 | ASIOSTInt16LSB = 16, 143 | ASIOSTInt24LSB = 17, // used for 20 bits as well 144 | ASIOSTInt32LSB = 18, 145 | ASIOSTFloat32LSB = 19, // IEEE 754 32 bit float, as found on Intel x86 architecture 146 | ASIOSTFloat64LSB = 20, // IEEE 754 64 bit double float, as found on Intel x86 architecture 147 | 148 | // these are used for 32 bit data buffer, with different alignment of the data inside 149 | // 32 bit PCI bus systems can more easily used with these 150 | ASIOSTInt32LSB16 = 24, // 32 bit data with 18 bit alignment 151 | ASIOSTInt32LSB18 = 25, // 32 bit data with 18 bit alignment 152 | ASIOSTInt32LSB20 = 26, // 32 bit data with 20 bit alignment 153 | ASIOSTInt32LSB24 = 27, // 32 bit data with 24 bit alignment 154 | 155 | // ASIO DSD format. 156 | ASIOSTDSDInt8LSB1 = 32, // DSD 1 bit data, 8 samples per byte. First sample in Least significant bit. 157 | ASIOSTDSDInt8MSB1 = 33, // DSD 1 bit data, 8 samples per byte. First sample in Most significant bit. 158 | ASIOSTDSDInt8NER8 = 40, // DSD 8 bit data, 1 sample per byte. No Endianness required. 159 | 160 | ASIOSTLastEntry 161 | }; 162 | 163 | /*----------------------------------------------------------------------------- 164 | // DSD operation and buffer layout 165 | // Definition by Steinberg/Sony Oxford. 166 | // 167 | // We have tried to treat DSD as PCM and so keep a consistant structure across 168 | // the ASIO interface. 169 | // 170 | // DSD's sample rate is normally referenced as a multiple of 44.1Khz, so 171 | // the standard sample rate is refered to as 64Fs (or 2.8224Mhz). We looked 172 | // at making a special case for DSD and adding a field to the ASIOFuture that 173 | // would allow the user to select the Over Sampleing Rate (OSR) as a seperate 174 | // entity but decided in the end just to treat it as a simple value of 175 | // 2.8224Mhz and use the standard interface to set it. 176 | // 177 | // The second problem was the "word" size, in PCM the word size is always a 178 | // greater than or equal to 8 bits (a byte). This makes life easy as we can 179 | // then pack the samples into the "natural" size for the machine. 180 | // In DSD the "word" size is 1 bit. This is not a major problem and can easily 181 | // be dealt with if we ensure that we always deal with a multiple of 8 samples. 182 | // 183 | // DSD brings with it another twist to the Endianness religion. How are the 184 | // samples packed into the byte. It would be nice to just say the most significant 185 | // bit is always the first sample, however there would then be a performance hit 186 | // on little endian machines. Looking at how some of the processing goes... 187 | // Little endian machines like the first sample to be in the Least Significant Bit, 188 | // this is because when you write it to memory the data is in the correct format 189 | // to be shifted in and out of the words. 190 | // Big endian machine prefer the first sample to be in the Most Significant Bit, 191 | // again for the same reasion. 192 | // 193 | // And just when things were looking really muddy there is a proposed extension to 194 | // DSD that uses 8 bit word sizes. It does not care what endianness you use. 195 | // 196 | // Switching the driver between DSD and PCM mode 197 | // ASIOFuture allows for extending the ASIO API quite transparently. 198 | // See kAsioSetIoFormat, kAsioGetIoFormat, kAsioCanDoIoFormat 199 | // 200 | //-----------------------------------------------------------------------------*/ 201 | 202 | 203 | //- - - - - - - - - - - - - - - - - - - - - - - - - 204 | // Error codes 205 | //- - - - - - - - - - - - - - - - - - - - - - - - - 206 | 207 | typedef long ASIOError; 208 | enum { 209 | ASE_OK = 0, // This value will be returned whenever the call succeeded 210 | ASE_SUCCESS = 0x3f4847a0, // unique success return value for ASIOFuture calls 211 | ASE_NotPresent = -1000, // hardware input or output is not present or available 212 | ASE_HWMalfunction, // hardware is malfunctioning (can be returned by any ASIO function) 213 | ASE_InvalidParameter, // input parameter invalid 214 | ASE_InvalidMode, // hardware is in a bad mode or used in a bad mode 215 | ASE_SPNotAdvancing, // hardware is not running when sample position is inquired 216 | ASE_NoClock, // sample clock or rate cannot be determined or is not present 217 | ASE_NoMemory // not enough memory for completing the request 218 | }; 219 | 220 | //--------------------------------------------------------------------------------------------------- 221 | //--------------------------------------------------------------------------------------------------- 222 | 223 | //- - - - - - - - - - - - - - - - - - - - - - - - - 224 | // Time Info support 225 | //- - - - - - - - - - - - - - - - - - - - - - - - - 226 | 227 | typedef struct ASIOTimeCode 228 | { 229 | double speed; // speed relation (fraction of nominal speed) 230 | // optional; set to 0. or 1. if not supported 231 | ASIOSamples timeCodeSamples; // time in samples 232 | unsigned long flags; // some information flags (see below) 233 | char future[64]; 234 | } ASIOTimeCode; 235 | 236 | typedef enum ASIOTimeCodeFlags 237 | { 238 | kTcValid = 1, 239 | kTcRunning = 1 << 1, 240 | kTcReverse = 1 << 2, 241 | kTcOnspeed = 1 << 3, 242 | kTcStill = 1 << 4, 243 | 244 | kTcSpeedValid = 1 << 8 245 | } ASIOTimeCodeFlags; 246 | 247 | typedef struct AsioTimeInfo 248 | { 249 | double speed; // absolute speed (1. = nominal) 250 | ASIOTimeStamp systemTime; // system time related to samplePosition, in nanoseconds 251 | // on mac, must be derived from Microseconds() (not UpTime()!) 252 | // on windows, must be derived from timeGetTime() 253 | ASIOSamples samplePosition; 254 | ASIOSampleRate sampleRate; // current rate 255 | unsigned long flags; // (see below) 256 | char reserved[12]; 257 | } AsioTimeInfo; 258 | 259 | typedef enum AsioTimeInfoFlags 260 | { 261 | kSystemTimeValid = 1, // must always be valid 262 | kSamplePositionValid = 1 << 1, // must always be valid 263 | kSampleRateValid = 1 << 2, 264 | kSpeedValid = 1 << 3, 265 | 266 | kSampleRateChanged = 1 << 4, 267 | kClockSourceChanged = 1 << 5 268 | } AsioTimeInfoFlags; 269 | 270 | typedef struct ASIOTime // both input/output 271 | { 272 | long reserved[4]; // must be 0 273 | struct AsioTimeInfo timeInfo; // required 274 | struct ASIOTimeCode timeCode; // optional, evaluated if (timeCode.flags & kTcValid) 275 | } ASIOTime; 276 | 277 | /* 278 | 279 | using time info: 280 | it is recommended to use the new method with time info even if the asio 281 | device does not support timecode; continuous calls to ASIOGetSamplePosition 282 | and ASIOGetSampleRate are avoided, and there is a more defined relationship 283 | between callback time and the time info. 284 | 285 | see the example below. 286 | to initiate time info mode, after you have received the callbacks pointer in 287 | ASIOCreateBuffers, you will call the asioMessage callback with kAsioSupportsTimeInfo 288 | as the argument. if this returns 1, host has accepted time info mode. 289 | now host expects the new callback bufferSwitchTimeInfo to be used instead 290 | of the old bufferSwitch method. the ASIOTime structure is assumed to be valid 291 | and accessible until the callback returns. 292 | 293 | using time code: 294 | if the device supports reading time code, it will call host's asioMessage callback 295 | with kAsioSupportsTimeCode as the selector. it may then fill the according 296 | fields and set the kTcValid flag. 297 | host will call the future method with the kAsioEnableTimeCodeRead selector when 298 | it wants to enable or disable tc reading by the device. you should also support 299 | the kAsioCanTimeInfo and kAsioCanTimeCode selectors in ASIOFuture (see example). 300 | 301 | note: 302 | the AsioTimeInfo/ASIOTimeCode pair is supposed to work in both directions. 303 | as a matter of convention, the relationship between the sample 304 | position counter and the time code at buffer switch time is 305 | (ignoring offset between tc and sample pos when tc is running): 306 | 307 | on input: sample 0 -> input buffer sample 0 -> time code 0 308 | on output: sample 0 -> output buffer sample 0 -> time code 0 309 | 310 | this means that for 'real' calculations, one has to take into account 311 | the according latencies. 312 | 313 | example: 314 | 315 | ASIOTime asioTime; 316 | 317 | in createBuffers() 318 | { 319 | memset(&asioTime, 0, sizeof(ASIOTime)); 320 | AsioTimeInfo* ti = &asioTime.timeInfo; 321 | ti->sampleRate = theSampleRate; 322 | ASIOTimeCode* tc = &asioTime.timeCode; 323 | tc->speed = 1.; 324 | timeInfoMode = false; 325 | canTimeCode = false; 326 | if(callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0) == 1) 327 | { 328 | timeInfoMode = true; 329 | #if kCanTimeCode 330 | if(callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0) == 1) 331 | canTimeCode = true; 332 | #endif 333 | } 334 | } 335 | 336 | void switchBuffers(long doubleBufferIndex, bool processNow) 337 | { 338 | if(timeInfoMode) 339 | { 340 | AsioTimeInfo* ti = &asioTime.timeInfo; 341 | ti->flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid; 342 | ti->systemTime = theNanoSeconds; 343 | ti->samplePosition = theSamplePosition; 344 | if(ti->sampleRate != theSampleRate) 345 | ti->flags |= kSampleRateChanged; 346 | ti->sampleRate = theSampleRate; 347 | 348 | #if kCanTimeCode 349 | if(canTimeCode && timeCodeEnabled) 350 | { 351 | ASIOTimeCode* tc = &asioTime.timeCode; 352 | tc->timeCodeSamples = tcSamples; // tc in samples 353 | tc->flags = kTcValid | kTcRunning | kTcOnspeed; // if so... 354 | } 355 | ASIOTime* bb = callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); 356 | #else 357 | callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); 358 | #endif 359 | } 360 | else 361 | callbacks->bufferSwitch(doubleBufferIndex, ASIOFalse); 362 | } 363 | 364 | ASIOError ASIOFuture(long selector, void *params) 365 | { 366 | switch(selector) 367 | { 368 | case kAsioEnableTimeCodeRead: 369 | timeCodeEnabled = true; 370 | return ASE_SUCCESS; 371 | case kAsioDisableTimeCodeRead: 372 | timeCodeEnabled = false; 373 | return ASE_SUCCESS; 374 | case kAsioCanTimeInfo: 375 | return ASE_SUCCESS; 376 | #if kCanTimeCode 377 | case kAsioCanTimeCode: 378 | return ASE_SUCCESS; 379 | #endif 380 | } 381 | return ASE_NotPresent; 382 | }; 383 | 384 | */ 385 | 386 | //- - - - - - - - - - - - - - - - - - - - - - - - - 387 | // application's audio stream handler callbacks 388 | //- - - - - - - - - - - - - - - - - - - - - - - - - 389 | 390 | typedef struct ASIOCallbacks 391 | { 392 | void (*bufferSwitch) (long doubleBufferIndex, ASIOBool directProcess); 393 | // bufferSwitch indicates that both input and output are to be processed. 394 | // the current buffer half index (0 for A, 1 for B) determines 395 | // - the output buffer that the host should start to fill. the other buffer 396 | // will be passed to output hardware regardless of whether it got filled 397 | // in time or not. 398 | // - the input buffer that is now filled with incoming data. Note that 399 | // because of the synchronicity of i/o, the input always has at 400 | // least one buffer latency in relation to the output. 401 | // directProcess suggests to the host whether it should immedeately 402 | // start processing (directProcess == ASIOTrue), or whether its process 403 | // should be deferred because the call comes from a very low level 404 | // (for instance, a high level priority interrupt), and direct processing 405 | // would cause timing instabilities for the rest of the system. If in doubt, 406 | // directProcess should be set to ASIOFalse. 407 | // Note: bufferSwitch may be called at interrupt time for highest efficiency. 408 | 409 | void (*sampleRateDidChange) (ASIOSampleRate sRate); 410 | // gets called when the AudioStreamIO detects a sample rate change 411 | // If sample rate is unknown, 0 is passed (for instance, clock loss 412 | // when externally synchronized). 413 | 414 | long (*asioMessage) (long selector, long value, void* message, double* opt); 415 | // generic callback for various purposes, see selectors below. 416 | // note this is only present if the asio version is 2 or higher 417 | 418 | ASIOTime* (*bufferSwitchTimeInfo) (ASIOTime* params, long doubleBufferIndex, ASIOBool directProcess); 419 | // new callback with time info. makes ASIOGetSamplePosition() and various 420 | // calls to ASIOGetSampleRate obsolete, 421 | // and allows for timecode sync etc. to be preferred; will be used if 422 | // the driver calls asioMessage with selector kAsioSupportsTimeInfo. 423 | } ASIOCallbacks; 424 | 425 | // asioMessage selectors 426 | enum 427 | { 428 | kAsioSelectorSupported = 1, // selector in , returns 1L if supported, 429 | // 0 otherwise 430 | kAsioEngineVersion, // returns engine (host) asio implementation version, 431 | // 2 or higher 432 | kAsioResetRequest, // request driver reset. if accepted, this 433 | // will close the driver (ASIO_Exit() ) and 434 | // re-open it again (ASIO_Init() etc). some 435 | // drivers need to reconfigure for instance 436 | // when the sample rate changes, or some basic 437 | // changes have been made in ASIO_ControlPanel(). 438 | // returns 1L; note the request is merely passed 439 | // to the application, there is no way to determine 440 | // if it gets accepted at this time (but it usually 441 | // will be). 442 | kAsioBufferSizeChange, // not yet supported, will currently always return 0L. 443 | // for now, use kAsioResetRequest instead. 444 | // once implemented, the new buffer size is expected 445 | // in , and on success returns 1L 446 | kAsioResyncRequest, // the driver went out of sync, such that 447 | // the timestamp is no longer valid. this 448 | // is a request to re-start the engine and 449 | // slave devices (sequencer). returns 1 for ok, 450 | // 0 if not supported. 451 | kAsioLatenciesChanged, // the drivers latencies have changed. The engine 452 | // will refetch the latencies. 453 | kAsioSupportsTimeInfo, // if host returns true here, it will expect the 454 | // callback bufferSwitchTimeInfo to be called instead 455 | // of bufferSwitch 456 | kAsioSupportsTimeCode, // 457 | kAsioMMCCommand, // unused - value: number of commands, message points to mmc commands 458 | kAsioSupportsInputMonitor, // kAsioSupportsXXX return 1 if host supports this 459 | kAsioSupportsInputGain, // unused and undefined 460 | kAsioSupportsInputMeter, // unused and undefined 461 | kAsioSupportsOutputGain, // unused and undefined 462 | kAsioSupportsOutputMeter, // unused and undefined 463 | kAsioOverload, // driver detected an overload 464 | 465 | kAsioNumMessageSelectors 466 | }; 467 | 468 | //--------------------------------------------------------------------------------------------------- 469 | //--------------------------------------------------------------------------------------------------- 470 | 471 | //- - - - - - - - - - - - - - - - - - - - - - - - - 472 | // (De-)Construction 473 | //- - - - - - - - - - - - - - - - - - - - - - - - - 474 | 475 | typedef struct ASIODriverInfo 476 | { 477 | long asioVersion; // currently, 2 478 | long driverVersion; // driver specific 479 | char name[32]; 480 | char errorMessage[124]; 481 | void *sysRef; // on input: system reference 482 | // (Windows: application main window handle, Mac & SGI: 0) 483 | } ASIODriverInfo; 484 | 485 | ASIOError ASIOInit(ASIODriverInfo *info); 486 | /* Purpose: 487 | Initialize the AudioStreamIO. 488 | Parameter: 489 | info: pointer to an ASIODriver structure: 490 | - asioVersion: 491 | - on input, the host version. *** Note *** this is 0 for earlier asio 492 | implementations, and the asioMessage callback is implemeted 493 | only if asioVersion is 2 or greater. sorry but due to a design fault 494 | the driver doesn't have access to the host version in ASIOInit :-( 495 | added selector for host (engine) version in the asioMessage callback 496 | so we're ok from now on. 497 | - on return, asio implementation version. 498 | older versions are 1 499 | if you support this version (namely, ASIO_outputReady() ) 500 | this should be 2 or higher. also see the note in 501 | ASIO_getTimeStamp() ! 502 | - version: on return, the driver version (format is driver specific) 503 | - name: on return, a null-terminated string containing the driver's name 504 | - error message: on return, should contain a user message describing 505 | the type of error that occured during ASIOInit(), if any. 506 | - sysRef: platform specific 507 | Returns: 508 | If neither input nor output is present ASE_NotPresent 509 | will be returned. 510 | ASE_NoMemory, ASE_HWMalfunction are other possible error conditions 511 | */ 512 | 513 | ASIOError ASIOExit(void); 514 | /* Purpose: 515 | Terminates the AudioStreamIO. 516 | Parameter: 517 | None. 518 | Returns: 519 | If neither input nor output is present ASE_NotPresent 520 | will be returned. 521 | Notes: this implies ASIOStop() and ASIODisposeBuffers(), 522 | meaning that no host callbacks must be accessed after ASIOExit(). 523 | */ 524 | 525 | //- - - - - - - - - - - - - - - - - - - - - - - - - 526 | // Start/Stop 527 | //- - - - - - - - - - - - - - - - - - - - - - - - - 528 | 529 | ASIOError ASIOStart(void); 530 | /* Purpose: 531 | Start input and output processing synchronously. 532 | This will 533 | - reset the sample counter to zero 534 | - start the hardware (both input and output) 535 | The first call to the hosts' bufferSwitch(index == 0) then tells 536 | the host to read from input buffer A (index 0), and start 537 | processing to output buffer A while output buffer B (which 538 | has been filled by the host prior to calling ASIOStart()) 539 | is possibly sounding (see also ASIOGetLatencies()) 540 | Parameter: 541 | None. 542 | Returns: 543 | If neither input nor output is present, ASE_NotPresent 544 | will be returned. 545 | If the hardware fails to start, ASE_HWMalfunction will be returned. 546 | Notes: 547 | There is no restriction on the time that ASIOStart() takes 548 | to perform (that is, it is not considered a realtime trigger). 549 | */ 550 | 551 | ASIOError ASIOStop(void); 552 | /* Purpose: 553 | Stops input and output processing altogether. 554 | Parameter: 555 | None. 556 | Returns: 557 | If neither input nor output is present ASE_NotPresent 558 | will be returned. 559 | Notes: 560 | On return from ASIOStop(), the driver must in no 561 | case call the hosts' bufferSwitch() routine. 562 | */ 563 | 564 | //- - - - - - - - - - - - - - - - - - - - - - - - - 565 | // Inquiry methods and sample rate 566 | //- - - - - - - - - - - - - - - - - - - - - - - - - 567 | 568 | ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels); 569 | /* Purpose: 570 | Returns number of individual input/output channels. 571 | Parameter: 572 | numInputChannels will hold the number of available input channels 573 | numOutputChannels will hold the number of available output channels 574 | Returns: 575 | If no input/output is present ASE_NotPresent will be returned. 576 | If only inputs, or only outputs are available, the according 577 | other parameter will be zero, and ASE_OK is returned. 578 | */ 579 | 580 | ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency); 581 | /* Purpose: 582 | Returns the input and output latencies. This includes 583 | device specific delays, like FIFOs etc. 584 | Parameter: 585 | inputLatency will hold the 'age' of the first sample frame 586 | in the input buffer when the hosts reads it in bufferSwitch() 587 | (this is theoretical, meaning it does not include the overhead 588 | and delay between the actual physical switch, and the time 589 | when bufferSitch() enters). 590 | This will usually be the size of one block in sample frames, plus 591 | device specific latencies. 592 | 593 | outputLatency will specify the time between the buffer switch, 594 | and the time when the next play buffer will start to sound. 595 | The next play buffer is defined as the one the host starts 596 | processing after (or at) bufferSwitch(), indicated by the 597 | index parameter (0 for buffer A, 1 for buffer B). 598 | It will usually be either one block, if the host writes directly 599 | to a dma buffer, or two or more blocks if the buffer is 'latched' by 600 | the driver. As an example, on ASIOStart(), the host will have filled 601 | the play buffer at index 1 already; when it gets the callback (with 602 | the parameter index == 0), this tells it to read from the input 603 | buffer 0, and start to fill the play buffer 0 (assuming that now 604 | play buffer 1 is already sounding). In this case, the output 605 | latency is one block. If the driver decides to copy buffer 1 606 | at that time, and pass it to the hardware at the next slot (which 607 | is most commonly done, but should be avoided), the output latency 608 | becomes two blocks instead, resulting in a total i/o latency of at least 609 | 3 blocks. As memory access is the main bottleneck in native dsp processing, 610 | and to acheive less latency, it is highly recommended to try to avoid 611 | copying (this is also why the driver is the owner of the buffers). To 612 | summarize, the minimum i/o latency can be acheived if the input buffer 613 | is processed by the host into the output buffer which will physically 614 | start to sound on the next time slice. Also note that the host expects 615 | the bufferSwitch() callback to be accessed for each time slice in order 616 | to retain sync, possibly recursively; if it fails to process a block in 617 | time, it will suspend its operation for some time in order to recover. 618 | Returns: 619 | If no input/output is present ASE_NotPresent will be returned. 620 | */ 621 | 622 | ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); 623 | /* Purpose: 624 | Returns min, max, and preferred buffer sizes for input/output 625 | Parameter: 626 | minSize will hold the minimum buffer size 627 | maxSize will hold the maxium possible buffer size 628 | preferredSize will hold the preferred buffer size (a size which 629 | best fits performance and hardware requirements) 630 | granularity will hold the granularity at which buffer sizes 631 | may differ. Usually, the buffer size will be a power of 2; 632 | in this case, granularity will hold -1 on return, signalling 633 | possible buffer sizes starting from minSize, increased in 634 | powers of 2 up to maxSize. 635 | Returns: 636 | If no input/output is present ASE_NotPresent will be returned. 637 | Notes: 638 | When minimum and maximum buffer size are equal, 639 | the preferred buffer size has to be the same value as well; granularity 640 | should be 0 in this case. 641 | */ 642 | 643 | ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); 644 | /* Purpose: 645 | Inquires the hardware for the available sample rates. 646 | Parameter: 647 | sampleRate is the rate in question. 648 | Returns: 649 | If the inquired sample rate is not supported, ASE_NoClock will be returned. 650 | If no input/output is present ASE_NotPresent will be returned. 651 | */ 652 | ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); 653 | /* Purpose: 654 | Get the current sample Rate. 655 | Parameter: 656 | currentRate will hold the current sample rate on return. 657 | Returns: 658 | If sample rate is unknown, sampleRate will be 0 and ASE_NoClock will be returned. 659 | If no input/output is present ASE_NotPresent will be returned. 660 | Notes: 661 | */ 662 | 663 | ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); 664 | /* Purpose: 665 | Set the hardware to the requested sample Rate. If sampleRate == 0, 666 | enable external sync. 667 | Parameter: 668 | sampleRate: on input, the requested rate 669 | Returns: 670 | If sampleRate is unknown ASE_NoClock will be returned. 671 | If the current clock is external, and sampleRate is != 0, 672 | ASE_InvalidMode will be returned 673 | If no input/output is present ASE_NotPresent will be returned. 674 | Notes: 675 | */ 676 | 677 | typedef struct ASIOClockSource 678 | { 679 | long index; // as used for ASIOSetClockSource() 680 | long associatedChannel; // for instance, S/PDIF or AES/EBU 681 | long associatedGroup; // see channel groups (ASIOGetChannelInfo()) 682 | ASIOBool isCurrentSource; // ASIOTrue if this is the current clock source 683 | char name[32]; // for user selection 684 | } ASIOClockSource; 685 | 686 | ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources); 687 | /* Purpose: 688 | Get the available external audio clock sources 689 | Parameter: 690 | clocks points to an array of ASIOClockSource structures: 691 | - index: this is used to identify the clock source 692 | when ASIOSetClockSource() is accessed, should be 693 | an index counting from zero 694 | - associatedInputChannel: the first channel of an associated 695 | input group, if any. 696 | - associatedGroup: the group index of that channel. 697 | groups of channels are defined to seperate for 698 | instance analog, S/PDIF, AES/EBU, ADAT connectors etc, 699 | when present simultaniously. Note that associated channel 700 | is enumerated according to numInputs/numOutputs, means it 701 | is independant from a group (see also ASIOGetChannelInfo()) 702 | inputs are associated to a clock if the physical connection 703 | transfers both data and clock (like S/PDIF, AES/EBU, or 704 | ADAT inputs). if there is no input channel associated with 705 | the clock source (like Word Clock, or internal oscillator), both 706 | associatedChannel and associatedGroup should be set to -1. 707 | - isCurrentSource: on exit, ASIOTrue if this is the current clock 708 | source, ASIOFalse else 709 | - name: a null-terminated string for user selection of the available sources. 710 | numSources: 711 | on input: the number of allocated array members 712 | on output: the number of available clock sources, at least 713 | 1 (internal clock generator). 714 | Returns: 715 | If no input/output is present ASE_NotPresent will be returned. 716 | Notes: 717 | */ 718 | 719 | ASIOError ASIOSetClockSource(long index); 720 | /* Purpose: 721 | Set the audio clock source 722 | Parameter: 723 | index as obtained from an inquiry to ASIOGetClockSources() 724 | Returns: 725 | If no input/output is present ASE_NotPresent will be returned. 726 | If the clock can not be selected because an input channel which 727 | carries the current clock source is active, ASE_InvalidMode 728 | *may* be returned (this depends on the properties of the driver 729 | and/or hardware). 730 | Notes: 731 | Should *not* return ASE_NoClock if there is no clock signal present 732 | at the selected source; this will be inquired via ASIOGetSampleRate(). 733 | It should call the host callback procedure sampleRateHasChanged(), 734 | if the switch causes a sample rate change, or if no external clock 735 | is present at the selected source. 736 | */ 737 | 738 | ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); 739 | /* Purpose: 740 | Inquires the sample position/time stamp pair. 741 | Parameter: 742 | sPos will hold the sample position on return. The sample 743 | position is reset to zero when ASIOStart() gets called. 744 | tStamp will hold the system time when the sample position 745 | was latched. 746 | Returns: 747 | If no input/output is present, ASE_NotPresent will be returned. 748 | If there is no clock, ASE_SPNotAdvancing will be returned. 749 | Notes: 750 | 751 | in order to be able to synchronise properly, 752 | the sample position / time stamp pair must refer to the current block, 753 | that is, the engine will call ASIOGetSamplePosition() in its bufferSwitch() 754 | callback and expect the time for the current block. thus, when requested 755 | in the very first bufferSwitch after ASIO_Start(), the sample position 756 | should be zero, and the time stamp should refer to the very time where 757 | the stream was started. it also means that the sample position must be 758 | block aligned. the driver must ensure proper interpolation if the system 759 | time can not be determined for the block position. the driver is responsible 760 | for precise time stamps as it usually has most direct access to lower 761 | level resources. proper behaviour of ASIO_GetSamplePosition() and ASIO_GetLatencies() 762 | are essential for precise media synchronization! 763 | */ 764 | 765 | typedef struct ASIOChannelInfo 766 | { 767 | long channel; // on input, channel index 768 | ASIOBool isInput; // on input 769 | ASIOBool isActive; // on exit 770 | long channelGroup; // dto 771 | ASIOSampleType type; // dto 772 | char name[32]; // dto 773 | } ASIOChannelInfo; 774 | 775 | ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); 776 | /* Purpose: 777 | retreive information about the nature of a channel 778 | Parameter: 779 | info: pointer to a ASIOChannelInfo structure with 780 | - channel: on input, the channel index of the channel in question. 781 | - isInput: on input, ASIOTrue if info for an input channel is 782 | requested, else output 783 | - channelGroup: on return, the channel group that the channel 784 | belongs to. For drivers which support different types of 785 | channels, like analog, S/PDIF, AES/EBU, ADAT etc interfaces, 786 | there should be a reasonable grouping of these types. Groups 787 | are always independant form a channel index, that is, a channel 788 | index always counts from 0 to numInputs/numOutputs regardless 789 | of the group it may belong to. 790 | There will always be at least one group (group 0). Please 791 | also note that by default, the host may decide to activate 792 | channels 0 and 1; thus, these should belong to the most 793 | useful type (analog i/o, if present). 794 | - type: on return, contains the sample type of the channel 795 | - isActive: on return, ASIOTrue if channel is active as it was 796 | installed by ASIOCreateBuffers(), ASIOFalse else 797 | - name: describing the type of channel in question. Used to allow 798 | for user selection, and enabling of specific channels. examples: 799 | "Analog In", "SPDIF Out" etc 800 | Returns: 801 | If no input/output is present ASE_NotPresent will be returned. 802 | Notes: 803 | If possible, the string should be organised such that the first 804 | characters are most significantly describing the nature of the 805 | port, to allow for identification even if the view showing the 806 | port name is too small to display more than 8 characters, for 807 | instance. 808 | */ 809 | 810 | //- - - - - - - - - - - - - - - - - - - - - - - - - 811 | // Buffer preparation 812 | //- - - - - - - - - - - - - - - - - - - - - - - - - 813 | 814 | typedef struct ASIOBufferInfo 815 | { 816 | ASIOBool isInput; // on input: ASIOTrue: input, else output 817 | long channelNum; // on input: channel index 818 | void *buffers[2]; // on output: double buffer addresses 819 | } ASIOBufferInfo; 820 | 821 | ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, 822 | long bufferSize, ASIOCallbacks *callbacks); 823 | 824 | /* Purpose: 825 | Allocates input/output buffers for all input and output channels to be activated. 826 | Parameter: 827 | bufferInfos is a pointer to an array of ASIOBufferInfo structures: 828 | - isInput: on input, ASIOTrue if the buffer is to be allocated 829 | for an input, output buffer else 830 | - channelNum: on input, the index of the channel in question 831 | (counting from 0) 832 | - buffers: on exit, 2 pointers to the halves of the channels' double-buffer. 833 | the size of the buffer(s) of course depend on both the ASIOSampleType 834 | as obtained from ASIOGetChannelInfo(), and bufferSize 835 | numChannels is the sum of all input and output channels to be created; 836 | thus bufferInfos is a pointer to an array of numChannels ASIOBufferInfo 837 | structures. 838 | bufferSize selects one of the possible buffer sizes as obtained from 839 | ASIOGetBufferSizes(). 840 | callbacks is a pointer to an ASIOCallbacks structure. 841 | Returns: 842 | If not enough memory is available ASE_NoMemory will be returned. 843 | If no input/output is present ASE_NotPresent will be returned. 844 | If bufferSize is not supported, or one or more of the bufferInfos elements 845 | contain invalid settings, ASE_InvalidMode will be returned. 846 | Notes: 847 | If individual channel selection is not possible but requested, 848 | the driver has to handle this. namely, bufferSwitch() will only 849 | have filled buffers of enabled outputs. If possible, processing 850 | and buss activities overhead should be avoided for channels which 851 | were not enabled here. 852 | */ 853 | 854 | ASIOError ASIODisposeBuffers(void); 855 | /* Purpose: 856 | Releases all buffers for the device. 857 | Parameter: 858 | None. 859 | Returns: 860 | If no buffer were ever prepared, ASE_InvalidMode will be returned. 861 | If no input/output is present ASE_NotPresent will be returned. 862 | Notes: 863 | This implies ASIOStop(). 864 | */ 865 | 866 | ASIOError ASIOControlPanel(void); 867 | /* Purpose: 868 | request the driver to start a control panel component 869 | for device specific user settings. This will not be 870 | accessed on some platforms (where the component is accessed 871 | instead). 872 | Parameter: 873 | None. 874 | Returns: 875 | If no panel is available ASE_NotPresent will be returned. 876 | Actually, the return code is ignored. 877 | Notes: 878 | if the user applied settings which require a re-configuration 879 | of parts or all of the enigine and/or driver (such as a change of 880 | the block size), the asioMessage callback can be used (see 881 | ASIO_Callbacks). 882 | */ 883 | 884 | ASIOError ASIOFuture(long selector, void *params); 885 | /* Purpose: 886 | various 887 | Parameter: 888 | selector: operation Code as to be defined. zero is reserved for 889 | testing purposes. 890 | params: depends on the selector; usually pointer to a structure 891 | for passing and retreiving any type and amount of parameters. 892 | Returns: 893 | the return value is also selector dependant. if the selector 894 | is unknown, ASE_InvalidParameter should be returned to prevent 895 | further calls with this selector. on success, ASE_SUCCESS 896 | must be returned (note: ASE_OK is *not* sufficient!) 897 | Notes: 898 | see selectors defined below. 899 | */ 900 | 901 | enum 902 | { 903 | kAsioEnableTimeCodeRead = 1, // no arguments 904 | kAsioDisableTimeCodeRead, // no arguments 905 | kAsioSetInputMonitor, // ASIOInputMonitor* in params 906 | kAsioTransport, // ASIOTransportParameters* in params 907 | kAsioSetInputGain, // ASIOChannelControls* in params, apply gain 908 | kAsioGetInputMeter, // ASIOChannelControls* in params, fill meter 909 | kAsioSetOutputGain, // ASIOChannelControls* in params, apply gain 910 | kAsioGetOutputMeter, // ASIOChannelControls* in params, fill meter 911 | kAsioCanInputMonitor, // no arguments for kAsioCanXXX selectors 912 | kAsioCanTimeInfo, 913 | kAsioCanTimeCode, 914 | kAsioCanTransport, 915 | kAsioCanInputGain, 916 | kAsioCanInputMeter, 917 | kAsioCanOutputGain, 918 | kAsioCanOutputMeter, 919 | 920 | // DSD support 921 | // The following extensions are required to allow switching 922 | // and control of the DSD subsystem. 923 | kAsioSetIoFormat = 0x23111961, /* ASIOIoFormat * in params. */ 924 | kAsioGetIoFormat = 0x23111983, /* ASIOIoFormat * in params. */ 925 | kAsioCanDoIoFormat = 0x23112004, /* ASIOIoFormat * in params. */ 926 | }; 927 | 928 | typedef struct ASIOInputMonitor 929 | { 930 | long input; // this input was set to monitor (or off), -1: all 931 | long output; // suggested output for monitoring the input (if so) 932 | long gain; // suggested gain, ranging 0 - 0x7fffffffL (-inf to +12 dB) 933 | ASIOBool state; // ASIOTrue => on, ASIOFalse => off 934 | long pan; // suggested pan, 0 => all left, 0x7fffffff => right 935 | } ASIOInputMonitor; 936 | 937 | typedef struct ASIOChannelControls 938 | { 939 | long channel; // on input, channel index 940 | ASIOBool isInput; // on input 941 | long gain; // on input, ranges 0 thru 0x7fffffff 942 | long meter; // on return, ranges 0 thru 0x7fffffff 943 | char future[32]; 944 | } ASIOChannelControls; 945 | 946 | typedef struct ASIOTransportParameters 947 | { 948 | long command; // see enum below 949 | ASIOSamples samplePosition; 950 | long track; 951 | long trackSwitches[16]; // 512 tracks on/off 952 | char future[64]; 953 | } ASIOTransportParameters; 954 | 955 | enum 956 | { 957 | kTransStart = 1, 958 | kTransStop, 959 | kTransLocate, // to samplePosition 960 | kTransPunchIn, 961 | kTransPunchOut, 962 | kTransArmOn, // track 963 | kTransArmOff, // track 964 | kTransMonitorOn, // track 965 | kTransMonitorOff, // track 966 | kTransArm, // trackSwitches 967 | kTransMonitor // trackSwitches 968 | }; 969 | 970 | /* 971 | // DSD support 972 | // Some notes on how to use ASIOIoFormatType. 973 | // 974 | // The caller will fill the format with the request types. 975 | // If the board can do the request then it will leave the 976 | // values unchanged. If the board does not support the 977 | // request then it will change that entry to Invalid (-1) 978 | // 979 | // So to request DSD then 980 | // 981 | // ASIOIoFormat NeedThis={kASIODSDFormat}; 982 | // 983 | // if(ASE_SUCCESS != ASIOFuture(kAsioSetIoFormat,&NeedThis) ){ 984 | // // If the board did not accept one of the parameters then the 985 | // // whole call will fail and the failing parameter will 986 | // // have had its value changes to -1. 987 | // } 988 | // 989 | // Note: Switching between the formats need to be done before the "prepared" 990 | // state (see ASIO 2 documentation) is entered. 991 | */ 992 | typedef long int ASIOIoFormatType; 993 | enum ASIOIoFormatType_e 994 | { 995 | kASIOFormatInvalid = -1, 996 | kASIOPCMFormat = 0, 997 | kASIODSDFormat = 1, 998 | }; 999 | 1000 | typedef struct ASIOIoFormat_s 1001 | { 1002 | ASIOIoFormatType FormatType; 1003 | char future[512-sizeof(ASIOIoFormatType)]; 1004 | } ASIOIoFormat; 1005 | 1006 | 1007 | ASIOError ASIOOutputReady(void); 1008 | /* Purpose: 1009 | this tells the driver that the host has completed processing 1010 | the output buffers. if the data format required by the hardware 1011 | differs from the supported asio formats, but the hardware 1012 | buffers are DMA buffers, the driver will have to convert 1013 | the audio stream data; as the bufferSwitch callback is 1014 | usually issued at dma block switch time, the driver will 1015 | have to convert the *previous* host buffer, which increases 1016 | the output latency by one block. 1017 | when the host finds out that ASIOOutputReady() returns 1018 | true, it will issue this call whenever it completed 1019 | output processing. then the driver can convert the 1020 | host data directly to the dma buffer to be played next, 1021 | reducing output latency by one block. 1022 | another way to look at it is, that the buffer switch is called 1023 | in order to pass the *input* stream to the host, so that it can 1024 | process the input into the output, and the output stream is passed 1025 | to the driver when the host has completed its process. 1026 | Parameter: 1027 | None 1028 | Returns: 1029 | only if the above mentioned scenario is given, and a reduction 1030 | of output latency can be acheived by this mechanism, should 1031 | ASE_OK be returned. otherwise (and usually), ASE_NotPresent 1032 | should be returned in order to prevent further calls to this 1033 | function. note that the host may want to determine if it is 1034 | to use this when the system is not yet fully initialized, so 1035 | ASE_OK should always be returned if the mechanism makes sense. 1036 | Notes: 1037 | please remeber to adjust ASIOGetLatencies() according to 1038 | whether ASIOOutputReady() was ever called or not, if your 1039 | driver supports this scenario. 1040 | also note that the engine may fail to call ASIO_OutputReady() 1041 | in time in overload cases. as already mentioned, bufferSwitch 1042 | should be called for every block regardless of whether a block 1043 | could be processed in time. 1044 | */ 1045 | 1046 | // restore old alignment 1047 | #if defined(_MSC_VER) && !defined(__MWERKS__) 1048 | #pragma pack(pop) 1049 | #elif PRAGMA_ALIGN_SUPPORTED 1050 | #pragma options align = reset 1051 | #endif 1052 | 1053 | #endif 1054 | 1055 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/include/asiodrivers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "asiodrivers.h" 3 | 4 | AsioDrivers* asioDrivers = 0; 5 | 6 | bool loadAsioDriver(char *name); 7 | 8 | bool loadAsioDriver(char *name) 9 | { 10 | if(!asioDrivers) 11 | asioDrivers = new AsioDrivers(); 12 | if(asioDrivers) 13 | return asioDrivers->loadDriver(name); 14 | return false; 15 | } 16 | 17 | //------------------------------------------------------------------------------------ 18 | 19 | #if MAC 20 | 21 | bool resolveASIO(unsigned long aconnID); 22 | 23 | AsioDrivers::AsioDrivers() : CodeFragments("ASIO Drivers", 'AsDr', 'Asio') 24 | { 25 | connID = -1; 26 | curIndex = -1; 27 | } 28 | 29 | AsioDrivers::~AsioDrivers() 30 | { 31 | removeCurrentDriver(); 32 | } 33 | 34 | bool AsioDrivers::getCurrentDriverName(char *name) 35 | { 36 | if(curIndex >= 0) 37 | return getName(curIndex, name); 38 | return false; 39 | } 40 | 41 | long AsioDrivers::getDriverNames(char **names, long maxDrivers) 42 | { 43 | for(long i = 0; i < getNumFragments() && i < maxDrivers; i++) 44 | getName(i, names[i]); 45 | return getNumFragments() < maxDrivers ? getNumFragments() : maxDrivers; 46 | } 47 | 48 | bool AsioDrivers::loadDriver(char *name) 49 | { 50 | char dname[64]; 51 | unsigned long newID; 52 | 53 | for(long i = 0; i < getNumFragments(); i++) 54 | { 55 | if(getName(i, dname) && !strcmp(name, dname)) 56 | { 57 | if(newInstance(i, &newID)) 58 | { 59 | if(resolveASIO(newID)) 60 | { 61 | if(connID != -1) 62 | removeInstance(curIndex, connID); 63 | curIndex = i; 64 | connID = newID; 65 | return true; 66 | } 67 | } 68 | break; 69 | } 70 | } 71 | return false; 72 | } 73 | 74 | void AsioDrivers::removeCurrentDriver() 75 | { 76 | if(connID != -1) 77 | removeInstance(curIndex, connID); 78 | connID = -1; 79 | curIndex = -1; 80 | } 81 | 82 | //------------------------------------------------------------------------------------ 83 | 84 | #elif WINDOWS 85 | 86 | #include "iasiodrv.h" 87 | 88 | extern IASIO* theAsioDriver; 89 | 90 | AsioDrivers::AsioDrivers() : AsioDriverList() 91 | { 92 | curIndex = -1; 93 | } 94 | 95 | AsioDrivers::~AsioDrivers() 96 | { 97 | } 98 | 99 | bool AsioDrivers::getCurrentDriverName(char *name) 100 | { 101 | if(curIndex >= 0) 102 | return asioGetDriverName(curIndex, name, 32) == 0 ? true : false; 103 | name[0] = 0; 104 | return false; 105 | } 106 | 107 | long AsioDrivers::getDriverNames(char **names, long maxDrivers) 108 | { 109 | for(long i = 0; i < asioGetNumDev() && i < maxDrivers; i++) 110 | asioGetDriverName(i, names[i], 32); 111 | return asioGetNumDev() < maxDrivers ? asioGetNumDev() : maxDrivers; 112 | } 113 | 114 | bool AsioDrivers::loadDriver(char *name) 115 | { 116 | char dname[64]; 117 | char curName[64]; 118 | 119 | for(long i = 0; i < asioGetNumDev(); i++) 120 | { 121 | if(!asioGetDriverName(i, dname, 32) && !strcmp(name, dname)) 122 | { 123 | curName[0] = 0; 124 | getCurrentDriverName(curName); // in case we fail... 125 | removeCurrentDriver(); 126 | 127 | if(!asioOpenDriver(i, (void **)&theAsioDriver)) 128 | { 129 | curIndex = i; 130 | return true; 131 | } 132 | else 133 | { 134 | theAsioDriver = 0; 135 | if(curName[0] && strcmp(dname, curName)) 136 | loadDriver(curName); // try restore 137 | } 138 | break; 139 | } 140 | } 141 | return false; 142 | } 143 | 144 | void AsioDrivers::removeCurrentDriver() 145 | { 146 | if(curIndex != -1) 147 | asioCloseDriver(curIndex); 148 | curIndex = -1; 149 | } 150 | 151 | #elif SGI || BEOS 152 | 153 | #include "asiolist.h" 154 | 155 | AsioDrivers::AsioDrivers() 156 | : AsioDriverList() 157 | { 158 | curIndex = -1; 159 | } 160 | 161 | AsioDrivers::~AsioDrivers() 162 | { 163 | } 164 | 165 | bool AsioDrivers::getCurrentDriverName(char *name) 166 | { 167 | return false; 168 | } 169 | 170 | long AsioDrivers::getDriverNames(char **names, long maxDrivers) 171 | { 172 | return 0; 173 | } 174 | 175 | bool AsioDrivers::loadDriver(char *name) 176 | { 177 | return false; 178 | } 179 | 180 | void AsioDrivers::removeCurrentDriver() 181 | { 182 | } 183 | 184 | #else 185 | #error implement me 186 | #endif 187 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/include/asiodrivers.h: -------------------------------------------------------------------------------- 1 | #ifndef __AsioDrivers__ 2 | #define __AsioDrivers__ 3 | 4 | #include "ginclude.h" 5 | 6 | #if MAC 7 | #include "CodeFragments.hpp" 8 | 9 | class AsioDrivers : public CodeFragments 10 | 11 | #elif WINDOWS 12 | #include 13 | #include "asiolist.h" 14 | 15 | class AsioDrivers : public AsioDriverList 16 | 17 | #elif SGI || BEOS 18 | #include "asiolist.h" 19 | 20 | class AsioDrivers : public AsioDriverList 21 | 22 | #else 23 | #error implement me 24 | #endif 25 | 26 | { 27 | public: 28 | AsioDrivers(); 29 | ~AsioDrivers(); 30 | 31 | bool getCurrentDriverName(char *name); 32 | long getDriverNames(char **names, long maxDrivers); 33 | bool loadDriver(char *name); 34 | void removeCurrentDriver(); 35 | long getCurrentDriverIndex() {return curIndex;} 36 | protected: 37 | unsigned long connID; 38 | long curIndex; 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/include/asiodrvr.h: -------------------------------------------------------------------------------- 1 | /* 2 | Steinberg Audio Stream I/O API 3 | (c) 1996, Steinberg Soft- und Hardware GmbH 4 | charlie (May 1996) 5 | 6 | asiodrvr.h 7 | c++ superclass to implement asio functionality. from this, 8 | you can derive whatever required 9 | */ 10 | 11 | #ifndef _asiodrvr_ 12 | #define _asiodrvr_ 13 | 14 | // cpu and os system we are running on 15 | #include "asiosys.h" 16 | // basic "C" interface 17 | #include "asio.h" 18 | 19 | class AsioDriver; 20 | extern AsioDriver *getDriver(); // for generic constructor 21 | 22 | #if WINDOWS 23 | #include 24 | #include "combase.h" 25 | #include "iasiodrv.h" 26 | class AsioDriver : public IASIO ,public CUnknown 27 | { 28 | public: 29 | AsioDriver(LPUNKNOWN pUnk, HRESULT *phr); 30 | 31 | DECLARE_IUNKNOWN 32 | // Factory method 33 | static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); 34 | // IUnknown 35 | virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject); 36 | 37 | #else 38 | 39 | class AsioDriver 40 | { 41 | public: 42 | AsioDriver(); 43 | #endif 44 | virtual ~AsioDriver(); 45 | 46 | virtual ASIOBool init(void* sysRef); 47 | virtual void getDriverName(char *name); // max 32 bytes incl. terminating zero 48 | virtual long getDriverVersion(); 49 | virtual void getErrorMessage(char *string); // max 124 bytes incl. 50 | 51 | virtual ASIOError start(); 52 | virtual ASIOError stop(); 53 | 54 | virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels); 55 | virtual ASIOError getLatencies(long *inputLatency, long *outputLatency); 56 | virtual ASIOError getBufferSize(long *minSize, long *maxSize, 57 | long *preferredSize, long *granularity); 58 | 59 | virtual ASIOError canSampleRate(ASIOSampleRate sampleRate); 60 | virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate); 61 | virtual ASIOError setSampleRate(ASIOSampleRate sampleRate); 62 | virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); 63 | virtual ASIOError setClockSource(long reference); 64 | 65 | virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); 66 | virtual ASIOError getChannelInfo(ASIOChannelInfo *info); 67 | 68 | virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, 69 | long bufferSize, ASIOCallbacks *callbacks); 70 | virtual ASIOError disposeBuffers(); 71 | 72 | virtual ASIOError controlPanel(); 73 | virtual ASIOError future(long selector, void *opt); 74 | virtual ASIOError outputReady(); 75 | }; 76 | #endif 77 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/include/asiolist.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "iasiodrv.h" 3 | #include "asiolist.h" 4 | 5 | #define ASIODRV_DESC "description" 6 | #define INPROC_SERVER "InprocServer32" 7 | #define ASIO_PATH "software\\asio" 8 | #define COM_CLSID "clsid" 9 | 10 | // ****************************************************************** 11 | // Local Functions 12 | // ****************************************************************** 13 | static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize) 14 | { 15 | HKEY hkEnum,hksub,hkpath; 16 | char databuf[512]; 17 | LONG cr,rc = -1; 18 | DWORD datatype,datasize; 19 | DWORD index; 20 | OFSTRUCT ofs; 21 | HFILE hfile; 22 | BOOL found = FALSE; 23 | 24 | #ifdef UNICODE 25 | CharLowerBuffA(clsidstr,strlen(clsidstr)); 26 | if ((cr = RegOpenKeyA(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) { 27 | 28 | index = 0; 29 | while (cr == ERROR_SUCCESS && !found) { 30 | cr = RegEnumKeyA(hkEnum,index++,databuf,512); 31 | if (cr == ERROR_SUCCESS) { 32 | CharLowerBuffA(databuf,strlen(databuf)); 33 | if (!(strcmp(databuf,clsidstr))) { 34 | if ((cr = RegOpenKeyExA(hkEnum,databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { 35 | if ((cr = RegOpenKeyExA(hksub,INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) { 36 | datatype = REG_SZ; datasize = (DWORD)dllpathsize; 37 | cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize); 38 | if (cr == ERROR_SUCCESS) { 39 | memset(&ofs,0,sizeof(OFSTRUCT)); 40 | ofs.cBytes = sizeof(OFSTRUCT); 41 | hfile = OpenFile(dllpath,&ofs,OF_EXIST); 42 | if (hfile) rc = 0; 43 | } 44 | RegCloseKey(hkpath); 45 | } 46 | RegCloseKey(hksub); 47 | } 48 | found = TRUE; // break out 49 | } 50 | } 51 | } 52 | RegCloseKey(hkEnum); 53 | } 54 | #else 55 | CharLowerBuff(clsidstr,strlen(clsidstr)); 56 | if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) { 57 | 58 | index = 0; 59 | while (cr == ERROR_SUCCESS && !found) { 60 | cr = RegEnumKey(hkEnum,index++,databuf,512); 61 | if (cr == ERROR_SUCCESS) { 62 | CharLowerBuff(databuf,strlen(databuf)); 63 | if (!(strcmp(databuf,clsidstr))) { 64 | if ((cr = RegOpenKeyEx(hkEnum,databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { 65 | if ((cr = RegOpenKeyEx(hksub,INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) { 66 | datatype = REG_SZ; datasize = (DWORD)dllpathsize; 67 | cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize); 68 | if (cr == ERROR_SUCCESS) { 69 | memset(&ofs,0,sizeof(OFSTRUCT)); 70 | ofs.cBytes = sizeof(OFSTRUCT); 71 | hfile = OpenFile(dllpath,&ofs,OF_EXIST); 72 | if (hfile) rc = 0; 73 | } 74 | RegCloseKey(hkpath); 75 | } 76 | RegCloseKey(hksub); 77 | } 78 | found = TRUE; // break out 79 | } 80 | } 81 | } 82 | RegCloseKey(hkEnum); 83 | } 84 | #endif 85 | return rc; 86 | } 87 | 88 | 89 | static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv) 90 | { 91 | HKEY hksub; 92 | char databuf[256]; 93 | char dllpath[MAXPATHLEN]; 94 | WORD wData[100]; 95 | CLSID clsid; 96 | DWORD datatype,datasize; 97 | LONG cr,rc; 98 | 99 | if (!lpdrv) { 100 | if ((cr = RegOpenKeyExA(hkey,keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { 101 | 102 | datatype = REG_SZ; datasize = 256; 103 | cr = RegQueryValueExA(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize); 104 | if (cr == ERROR_SUCCESS) { 105 | rc = findDrvPath (databuf,dllpath,MAXPATHLEN); 106 | if (rc == 0) { 107 | lpdrv = new ASIODRVSTRUCT[1]; 108 | if (lpdrv) { 109 | memset(lpdrv,0,sizeof(ASIODRVSTRUCT)); 110 | lpdrv->drvID = drvID; 111 | MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100); 112 | if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) { 113 | memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID)); 114 | } 115 | 116 | datatype = REG_SZ; datasize = 256; 117 | cr = RegQueryValueExA(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize); 118 | if (cr == ERROR_SUCCESS) { 119 | strcpy(lpdrv->drvname,databuf); 120 | } 121 | else strcpy(lpdrv->drvname,keyname); 122 | } 123 | } 124 | } 125 | RegCloseKey(hksub); 126 | } 127 | } 128 | else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next); 129 | 130 | return lpdrv; 131 | } 132 | 133 | static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv) 134 | { 135 | IASIO *iasio; 136 | 137 | if (lpdrv != 0) { 138 | deleteDrvStruct(lpdrv->next); 139 | if (lpdrv->asiodrv) { 140 | iasio = (IASIO *)lpdrv->asiodrv; 141 | iasio->Release(); 142 | } 143 | delete lpdrv; 144 | } 145 | } 146 | 147 | 148 | static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv) 149 | { 150 | while (lpdrv) { 151 | if (lpdrv->drvID == drvID) return lpdrv; 152 | lpdrv = lpdrv->next; 153 | } 154 | return 0; 155 | } 156 | // ****************************************************************** 157 | 158 | 159 | // ****************************************************************** 160 | // AsioDriverList 161 | // ****************************************************************** 162 | AsioDriverList::AsioDriverList () 163 | { 164 | HKEY hkEnum = 0; 165 | char keyname[MAXDRVNAMELEN]; 166 | LPASIODRVSTRUCT pdl; 167 | LONG cr; 168 | DWORD index = 0; 169 | BOOL fin = FALSE; 170 | 171 | numdrv = 0; 172 | lpdrvlist = 0; 173 | 174 | #ifdef UNICODE 175 | cr = RegOpenKeyA(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum); 176 | #else 177 | cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum); 178 | #endif 179 | while (cr == ERROR_SUCCESS) { 180 | #ifdef UNICODE 181 | if ((cr = RegEnumKeyA(hkEnum,index++,keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) { 182 | #else 183 | if ((cr = RegEnumKey(hkEnum,index++,keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) { 184 | #endif 185 | lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist); 186 | } 187 | else fin = TRUE; 188 | } 189 | if (hkEnum) RegCloseKey(hkEnum); 190 | 191 | pdl = lpdrvlist; 192 | while (pdl) { 193 | numdrv++; 194 | pdl = pdl->next; 195 | } 196 | 197 | if (numdrv) CoInitialize(0); // initialize COM 198 | } 199 | 200 | AsioDriverList::~AsioDriverList () 201 | { 202 | if (numdrv) { 203 | deleteDrvStruct(lpdrvlist); 204 | CoUninitialize(); 205 | } 206 | } 207 | 208 | 209 | LONG AsioDriverList::asioGetNumDev (VOID) 210 | { 211 | return (LONG)numdrv; 212 | } 213 | 214 | 215 | LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv) 216 | { 217 | LPASIODRVSTRUCT lpdrv = 0; 218 | long rc; 219 | 220 | if (!asiodrv) return DRVERR_INVALID_PARAM; 221 | 222 | if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { 223 | if (!lpdrv->asiodrv) { 224 | rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv); 225 | if (rc == S_OK) { 226 | lpdrv->asiodrv = *asiodrv; 227 | return 0; 228 | } 229 | // else if (rc == REGDB_E_CLASSNOTREG) 230 | // strcpy (info->messageText, "Driver not registered in the Registration Database!"); 231 | } 232 | else rc = DRVERR_DEVICE_ALREADY_OPEN; 233 | } 234 | else rc = DRVERR_DEVICE_NOT_FOUND; 235 | 236 | return rc; 237 | } 238 | 239 | 240 | LONG AsioDriverList::asioCloseDriver (int drvID) 241 | { 242 | LPASIODRVSTRUCT lpdrv = 0; 243 | IASIO *iasio; 244 | 245 | if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { 246 | if (lpdrv->asiodrv) { 247 | iasio = (IASIO *)lpdrv->asiodrv; 248 | iasio->Release(); 249 | lpdrv->asiodrv = 0; 250 | } 251 | } 252 | 253 | return 0; 254 | } 255 | 256 | LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize) 257 | { 258 | LPASIODRVSTRUCT lpdrv = 0; 259 | 260 | if (!drvname) return DRVERR_INVALID_PARAM; 261 | 262 | if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { 263 | if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) { 264 | strcpy(drvname,lpdrv->drvname); 265 | } 266 | else { 267 | memcpy(drvname,lpdrv->drvname,drvnamesize-4); 268 | drvname[drvnamesize-4] = '.'; 269 | drvname[drvnamesize-3] = '.'; 270 | drvname[drvnamesize-2] = '.'; 271 | drvname[drvnamesize-1] = 0; 272 | } 273 | return 0; 274 | } 275 | return DRVERR_DEVICE_NOT_FOUND; 276 | } 277 | 278 | LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize) 279 | { 280 | LPASIODRVSTRUCT lpdrv = 0; 281 | 282 | if (!dllpath) return DRVERR_INVALID_PARAM; 283 | 284 | if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { 285 | if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) { 286 | strcpy(dllpath,lpdrv->dllpath); 287 | return 0; 288 | } 289 | dllpath[0] = 0; 290 | return DRVERR_INVALID_PARAM; 291 | } 292 | return DRVERR_DEVICE_NOT_FOUND; 293 | } 294 | 295 | LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid) 296 | { 297 | LPASIODRVSTRUCT lpdrv = 0; 298 | 299 | if (!clsid) return DRVERR_INVALID_PARAM; 300 | 301 | if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { 302 | memcpy(clsid,&lpdrv->clsid,sizeof(CLSID)); 303 | return 0; 304 | } 305 | return DRVERR_DEVICE_NOT_FOUND; 306 | } 307 | 308 | 309 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/include/asiolist.h: -------------------------------------------------------------------------------- 1 | #ifndef __asiolist__ 2 | #define __asiolist__ 3 | 4 | #define DRVERR -5000 5 | #define DRVERR_INVALID_PARAM DRVERR-1 6 | #define DRVERR_DEVICE_ALREADY_OPEN DRVERR-2 7 | #define DRVERR_DEVICE_NOT_FOUND DRVERR-3 8 | 9 | #define MAXPATHLEN 512 10 | #define MAXDRVNAMELEN 128 11 | 12 | struct asiodrvstruct 13 | { 14 | int drvID; 15 | CLSID clsid; 16 | char dllpath[MAXPATHLEN]; 17 | char drvname[MAXDRVNAMELEN]; 18 | LPVOID asiodrv; 19 | struct asiodrvstruct *next; 20 | }; 21 | 22 | typedef struct asiodrvstruct ASIODRVSTRUCT; 23 | typedef ASIODRVSTRUCT *LPASIODRVSTRUCT; 24 | 25 | class AsioDriverList { 26 | public: 27 | AsioDriverList(); 28 | ~AsioDriverList(); 29 | 30 | LONG asioOpenDriver (int,VOID **); 31 | LONG asioCloseDriver (int); 32 | 33 | // nice to have 34 | LONG asioGetNumDev (VOID); 35 | LONG asioGetDriverName (int,char *,int); 36 | LONG asioGetDriverPath (int,char *,int); 37 | LONG asioGetDriverCLSID (int,CLSID *); 38 | 39 | // or use directly access 40 | LPASIODRVSTRUCT lpdrvlist; 41 | int numdrv; 42 | }; 43 | 44 | typedef class AsioDriverList *LPASIODRIVERLIST; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/include/asiosys.h: -------------------------------------------------------------------------------- 1 | #ifndef __asiosys__ 2 | #define __asiosys__ 3 | 4 | #ifdef WIN32 5 | #undef MAC 6 | #define PPC 0 7 | #define WINDOWS 1 8 | #define SGI 0 9 | #define SUN 0 10 | #define LINUX 0 11 | #define BEOS 0 12 | 13 | #define NATIVE_INT64 0 14 | #define IEEE754_64FLOAT 1 15 | 16 | #elif BEOS 17 | #define MAC 0 18 | #define PPC 0 19 | #define WINDOWS 0 20 | #define PC 0 21 | #define SGI 0 22 | #define SUN 0 23 | #define LINUX 0 24 | 25 | #define NATIVE_INT64 0 26 | #define IEEE754_64FLOAT 1 27 | 28 | #ifndef DEBUG 29 | #define DEBUG 0 30 | #if DEBUG 31 | void DEBUGGERMESSAGE(char *string); 32 | #else 33 | #define DEBUGGERMESSAGE(a) 34 | #endif 35 | #endif 36 | 37 | #elif SGI 38 | #define MAC 0 39 | #define PPC 0 40 | #define WINDOWS 0 41 | #define PC 0 42 | #define SUN 0 43 | #define LINUX 0 44 | #define BEOS 0 45 | 46 | #define NATIVE_INT64 0 47 | #define IEEE754_64FLOAT 1 48 | 49 | #ifndef DEBUG 50 | #define DEBUG 0 51 | #if DEBUG 52 | void DEBUGGERMESSAGE(char *string); 53 | #else 54 | #define DEBUGGERMESSAGE(a) 55 | #endif 56 | #endif 57 | 58 | #else // MAC 59 | 60 | #define MAC 1 61 | #define PPC 1 62 | #define WINDOWS 0 63 | #define PC 0 64 | #define SGI 0 65 | #define SUN 0 66 | #define LINUX 0 67 | #define BEOS 0 68 | 69 | #define NATIVE_INT64 0 70 | #define IEEE754_64FLOAT 1 71 | 72 | #ifndef DEBUG 73 | #define DEBUG 0 74 | #if DEBUG 75 | void DEBUGGERMESSAGE(char *string); 76 | #else 77 | #define DEBUGGERMESSAGE(a) 78 | #endif 79 | #endif 80 | #endif 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/include/ginclude.h: -------------------------------------------------------------------------------- 1 | #ifndef __gInclude__ 2 | #define __gInclude__ 3 | 4 | #if SGI 5 | #undef BEOS 6 | #undef MAC 7 | #undef WINDOWS 8 | // 9 | #define ASIO_BIG_ENDIAN 1 10 | #define ASIO_CPU_MIPS 1 11 | #elif defined WIN32 12 | #undef BEOS 13 | #undef MAC 14 | #undef SGI 15 | #define WINDOWS 1 16 | #define ASIO_LITTLE_ENDIAN 1 17 | #define ASIO_CPU_X86 1 18 | #elif BEOS 19 | #undef MAC 20 | #undef SGI 21 | #undef WINDOWS 22 | #define ASIO_LITTLE_ENDIAN 1 23 | #define ASIO_CPU_X86 1 24 | // 25 | #else 26 | #define MAC 1 27 | #undef BEOS 28 | #undef WINDOWS 29 | #undef SGI 30 | #define ASIO_BIG_ENDIAN 1 31 | #define ASIO_CPU_PPC 1 32 | #endif 33 | 34 | // always 35 | #define NATIVE_INT64 0 36 | #define IEEE754_64FLOAT 1 37 | 38 | #endif // __gInclude__ 39 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/include/iasiodrv.h: -------------------------------------------------------------------------------- 1 | #include "asiosys.h" 2 | #include "asio.h" 3 | 4 | /* Forward Declarations */ 5 | 6 | #ifndef __ASIODRIVER_FWD_DEFINED__ 7 | #define __ASIODRIVER_FWD_DEFINED__ 8 | typedef interface IASIO IASIO; 9 | #endif /* __ASIODRIVER_FWD_DEFINED__ */ 10 | 11 | interface IASIO : public IUnknown 12 | { 13 | 14 | virtual ASIOBool init(void *sysHandle) = 0; 15 | virtual void getDriverName(char *name) = 0; 16 | virtual long getDriverVersion() = 0; 17 | virtual void getErrorMessage(char *string) = 0; 18 | virtual ASIOError start() = 0; 19 | virtual ASIOError stop() = 0; 20 | virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels) = 0; 21 | virtual ASIOError getLatencies(long *inputLatency, long *outputLatency) = 0; 22 | virtual ASIOError getBufferSize(long *minSize, long *maxSize, 23 | long *preferredSize, long *granularity) = 0; 24 | virtual ASIOError canSampleRate(ASIOSampleRate sampleRate) = 0; 25 | virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate) = 0; 26 | virtual ASIOError setSampleRate(ASIOSampleRate sampleRate) = 0; 27 | virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources) = 0; 28 | virtual ASIOError setClockSource(long reference) = 0; 29 | virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0; 30 | virtual ASIOError getChannelInfo(ASIOChannelInfo *info) = 0; 31 | virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, 32 | long bufferSize, ASIOCallbacks *callbacks) = 0; 33 | virtual ASIOError disposeBuffers() = 0; 34 | virtual ASIOError controlPanel() = 0; 35 | virtual ASIOError future(long selector,void *opt) = 0; 36 | virtual ASIOError outputReady() = 0; 37 | }; 38 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/include/iasiothiscallresolver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | IASIOThiscallResolver.cpp see the comments in iasiothiscallresolver.h for 3 | the top level description - this comment describes the technical details of 4 | the implementation. 5 | 6 | The latest version of this file is available from: 7 | http://www.audiomulch.com/~rossb/code/calliasio 8 | 9 | please email comments to Ross Bencina 10 | 11 | BACKGROUND 12 | 13 | The IASIO interface declared in the Steinberg ASIO 2 SDK declares 14 | functions with no explicit calling convention. This causes MSVC++ to default 15 | to using the thiscall convention, which is a proprietary convention not 16 | implemented by some non-microsoft compilers - notably borland BCC, 17 | C++Builder, and gcc. MSVC++ is the defacto standard compiler used by 18 | Steinberg. As a result of this situation, the ASIO sdk will compile with 19 | any compiler, however attempting to execute the compiled code will cause a 20 | crash due to different default calling conventions on non-Microsoft 21 | compilers. 22 | 23 | IASIOThiscallResolver solves the problem by providing an adapter class that 24 | delegates to the IASIO interface using the correct calling convention 25 | (thiscall). Due to the lack of support for thiscall in the Borland and GCC 26 | compilers, the calls have been implemented in assembly language. 27 | 28 | A number of macros are defined for thiscall function calls with different 29 | numbers of parameters, with and without return values - it may be possible 30 | to modify the format of these macros to make them work with other inline 31 | assemblers. 32 | 33 | 34 | THISCALL DEFINITION 35 | 36 | A number of definitions of the thiscall calling convention are floating 37 | around the internet. The following definition has been validated against 38 | output from the MSVC++ compiler: 39 | 40 | For non-vararg functions, thiscall works as follows: the object (this) 41 | pointer is passed in ECX. All arguments are passed on the stack in 42 | right to left order. The return value is placed in EAX. The callee 43 | clears the passed arguments from the stack. 44 | 45 | 46 | FINDING FUNCTION POINTERS FROM AN IASIO POINTER 47 | 48 | The first field of a COM object is a pointer to its vtble. Thus a pointer 49 | to an object implementing the IASIO interface also points to a pointer to 50 | that object's vtbl. The vtble is a table of function pointers for all of 51 | the virtual functions exposed by the implemented interfaces. 52 | 53 | If we consider a variable declared as a pointer to IASO: 54 | 55 | IASIO *theAsioDriver 56 | 57 | theAsioDriver points to: 58 | 59 | object implementing IASIO 60 | { 61 | IASIOvtbl *vtbl 62 | other data 63 | } 64 | 65 | in other words, theAsioDriver points to a pointer to an IASIOvtbl 66 | 67 | vtbl points to a table of function pointers: 68 | 69 | IASIOvtbl ( interface IASIO : public IUnknown ) 70 | { 71 | (IUnknown functions) 72 | 0 virtual HRESULT STDMETHODCALLTYPE (*QueryInterface)(REFIID riid, void **ppv) = 0; 73 | 4 virtual ULONG STDMETHODCALLTYPE (*AddRef)() = 0; 74 | 8 virtual ULONG STDMETHODCALLTYPE (*Release)() = 0; 75 | 76 | (IASIO functions) 77 | 12 virtual ASIOBool (*init)(void *sysHandle) = 0; 78 | 16 virtual void (*getDriverName)(char *name) = 0; 79 | 20 virtual long (*getDriverVersion)() = 0; 80 | 24 virtual void (*getErrorMessage)(char *string) = 0; 81 | 28 virtual ASIOError (*start)() = 0; 82 | 32 virtual ASIOError (*stop)() = 0; 83 | 36 virtual ASIOError (*getChannels)(long *numInputChannels, long *numOutputChannels) = 0; 84 | 40 virtual ASIOError (*getLatencies)(long *inputLatency, long *outputLatency) = 0; 85 | 44 virtual ASIOError (*getBufferSize)(long *minSize, long *maxSize, 86 | long *preferredSize, long *granularity) = 0; 87 | 48 virtual ASIOError (*canSampleRate)(ASIOSampleRate sampleRate) = 0; 88 | 52 virtual ASIOError (*getSampleRate)(ASIOSampleRate *sampleRate) = 0; 89 | 56 virtual ASIOError (*setSampleRate)(ASIOSampleRate sampleRate) = 0; 90 | 60 virtual ASIOError (*getClockSources)(ASIOClockSource *clocks, long *numSources) = 0; 91 | 64 virtual ASIOError (*setClockSource)(long reference) = 0; 92 | 68 virtual ASIOError (*getSamplePosition)(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0; 93 | 72 virtual ASIOError (*getChannelInfo)(ASIOChannelInfo *info) = 0; 94 | 76 virtual ASIOError (*createBuffers)(ASIOBufferInfo *bufferInfos, long numChannels, 95 | long bufferSize, ASIOCallbacks *callbacks) = 0; 96 | 80 virtual ASIOError (*disposeBuffers)() = 0; 97 | 84 virtual ASIOError (*controlPanel)() = 0; 98 | 88 virtual ASIOError (*future)(long selector,void *opt) = 0; 99 | 92 virtual ASIOError (*outputReady)() = 0; 100 | }; 101 | 102 | The numbers in the left column show the byte offset of each function ptr 103 | from the beginning of the vtbl. These numbers are used in the code below 104 | to select different functions. 105 | 106 | In order to find the address of a particular function, theAsioDriver 107 | must first be dereferenced to find the value of the vtbl pointer: 108 | 109 | mov eax, theAsioDriver 110 | mov edx, [theAsioDriver] // edx now points to vtbl[0] 111 | 112 | Then an offset must be added to the vtbl pointer to select a 113 | particular function, for example vtbl+44 points to the slot containing 114 | a pointer to the getBufferSize function. 115 | 116 | Finally vtbl+x must be dereferenced to obtain the value of the function 117 | pointer stored in that address: 118 | 119 | call [edx+44] // call the function pointed to by 120 | // the value in the getBufferSize field of the vtbl 121 | 122 | 123 | SEE ALSO 124 | 125 | Martin Fay's OpenASIO DLL at http://www.martinfay.com solves the same 126 | problem by providing a new COM interface which wraps IASIO with an 127 | interface that uses portable calling conventions. OpenASIO must be compiled 128 | with MSVC, and requires that you ship the OpenASIO DLL with your 129 | application. 130 | 131 | 132 | ACKNOWLEDGEMENTS 133 | 134 | Ross Bencina: worked out the thiscall details above, wrote the original 135 | Borland asm macros, and a patch for asio.cpp (which is no longer needed). 136 | Thanks to Martin Fay for introducing me to the issues discussed here, 137 | and to Rene G. Ceballos for assisting with asm dumps from MSVC++. 138 | 139 | Antti Silvast: converted the original calliasio to work with gcc and NASM 140 | by implementing the asm code in a separate file. 141 | 142 | Fraser Adams: modified the original calliasio containing the Borland inline 143 | asm to add inline asm for gcc i.e. Intel syntax for Borland and AT&T syntax 144 | for gcc. This seems a neater approach for gcc than to have a separate .asm 145 | file and it means that we only need one version of the thiscall patch. 146 | 147 | Fraser Adams: rewrote the original calliasio patch in the form of the 148 | IASIOThiscallResolver class in order to avoid modifications to files from 149 | the Steinberg SDK, which may have had potential licence issues. 150 | 151 | Andrew Baldwin: contributed fixes for compatibility problems with more 152 | recent versions of the gcc assembler. 153 | */ 154 | 155 | 156 | // We only need IASIOThiscallResolver at all if we are on Win32. For other 157 | // platforms we simply bypass the IASIOThiscallResolver definition to allow us 158 | // to be safely #include'd whatever the platform to keep client code portable 159 | #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64) 160 | 161 | 162 | // If microsoft compiler we can call IASIO directly so IASIOThiscallResolver 163 | // is not used. 164 | #if !defined(_MSC_VER) 165 | 166 | 167 | #include 168 | #include 169 | 170 | // We have a mechanism in iasiothiscallresolver.h to ensure that asio.h is 171 | // #include'd before it in client code, we do NOT want to do this test here. 172 | #define iasiothiscallresolver_sourcefile 1 173 | #include "iasiothiscallresolver.h" 174 | #undef iasiothiscallresolver_sourcefile 175 | 176 | // iasiothiscallresolver.h redefines ASIOInit for clients, but we don't want 177 | // this macro defined in this translation unit. 178 | #undef ASIOInit 179 | 180 | 181 | // theAsioDriver is a global pointer to the current IASIO instance which the 182 | // ASIO SDK uses to perform all actions on the IASIO interface. We substitute 183 | // our own forwarding interface into this pointer. 184 | extern IASIO* theAsioDriver; 185 | 186 | 187 | // The following macros define the inline assembler for BORLAND first then gcc 188 | 189 | #if defined(__BCPLUSPLUS__) || defined(__BORLANDC__) 190 | 191 | 192 | #define CALL_THISCALL_0( resultName, thisPtr, funcOffset )\ 193 | void *this_ = (thisPtr); \ 194 | __asm { \ 195 | mov ecx, this_ ; \ 196 | mov eax, [ecx] ; \ 197 | call [eax+funcOffset] ; \ 198 | mov resultName, eax ; \ 199 | } 200 | 201 | 202 | #define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 )\ 203 | void *this_ = (thisPtr); \ 204 | __asm { \ 205 | mov eax, param1 ; \ 206 | push eax ; \ 207 | mov ecx, this_ ; \ 208 | mov eax, [ecx] ; \ 209 | call [eax+funcOffset] ; \ 210 | } 211 | 212 | 213 | #define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 )\ 214 | void *this_ = (thisPtr); \ 215 | __asm { \ 216 | mov eax, param1 ; \ 217 | push eax ; \ 218 | mov ecx, this_ ; \ 219 | mov eax, [ecx] ; \ 220 | call [eax+funcOffset] ; \ 221 | mov resultName, eax ; \ 222 | } 223 | 224 | 225 | #define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 )\ 226 | void *this_ = (thisPtr); \ 227 | void *doubleParamPtr_ (¶m1); \ 228 | __asm { \ 229 | mov eax, doubleParamPtr_ ; \ 230 | push [eax+4] ; \ 231 | push [eax] ; \ 232 | mov ecx, this_ ; \ 233 | mov eax, [ecx] ; \ 234 | call [eax+funcOffset] ; \ 235 | mov resultName, eax ; \ 236 | } 237 | 238 | 239 | #define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 )\ 240 | void *this_ = (thisPtr); \ 241 | __asm { \ 242 | mov eax, param2 ; \ 243 | push eax ; \ 244 | mov eax, param1 ; \ 245 | push eax ; \ 246 | mov ecx, this_ ; \ 247 | mov eax, [ecx] ; \ 248 | call [eax+funcOffset] ; \ 249 | mov resultName, eax ; \ 250 | } 251 | 252 | 253 | #define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\ 254 | void *this_ = (thisPtr); \ 255 | __asm { \ 256 | mov eax, param4 ; \ 257 | push eax ; \ 258 | mov eax, param3 ; \ 259 | push eax ; \ 260 | mov eax, param2 ; \ 261 | push eax ; \ 262 | mov eax, param1 ; \ 263 | push eax ; \ 264 | mov ecx, this_ ; \ 265 | mov eax, [ecx] ; \ 266 | call [eax+funcOffset] ; \ 267 | mov resultName, eax ; \ 268 | } 269 | 270 | 271 | #elif defined(__GNUC__) 272 | 273 | 274 | #define CALL_THISCALL_0( resultName, thisPtr, funcOffset ) \ 275 | __asm__ __volatile__ ("movl (%1), %%edx\n\t" \ 276 | "call *"#funcOffset"(%%edx)\n\t" \ 277 | :"=a"(resultName) /* Output Operands */ \ 278 | :"c"(thisPtr) /* Input Operands */ \ 279 | : "%edx" /* Clobbered Registers */ \ 280 | ); \ 281 | 282 | 283 | #define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 ) \ 284 | __asm__ __volatile__ ("pushl %0\n\t" \ 285 | "movl (%1), %%edx\n\t" \ 286 | "call *"#funcOffset"(%%edx)\n\t" \ 287 | : /* Output Operands */ \ 288 | :"r"(param1), /* Input Operands */ \ 289 | "c"(thisPtr) \ 290 | : "%edx" /* Clobbered Registers */ \ 291 | ); \ 292 | 293 | 294 | #define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 ) \ 295 | __asm__ __volatile__ ("pushl %1\n\t" \ 296 | "movl (%2), %%edx\n\t" \ 297 | "call *"#funcOffset"(%%edx)\n\t" \ 298 | :"=a"(resultName) /* Output Operands */ \ 299 | :"r"(param1), /* Input Operands */ \ 300 | "c"(thisPtr) \ 301 | : "%edx" /* Clobbered Registers */ \ 302 | ); \ 303 | 304 | 305 | #define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 ) \ 306 | do { \ 307 | double param1f64 = param1; /* Cast explicitly to double */ \ 308 | double *param1f64Ptr = ¶m1f64; /* Make pointer to address */ \ 309 | __asm__ __volatile__ ("pushl 4(%1)\n\t" \ 310 | "pushl (%1)\n\t" \ 311 | "movl (%2), %%edx\n\t" \ 312 | "call *"#funcOffset"(%%edx);\n\t" \ 313 | : "=a"(resultName) /* Output Operands */ \ 314 | : "r"(param1f64Ptr), /* Input Operands */ \ 315 | "c"(thisPtr), \ 316 | "m"(*param1f64Ptr) /* Using address */ \ 317 | : "%edx" /* Clobbered Registers */ \ 318 | ); \ 319 | } while (0); \ 320 | 321 | 322 | #define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 ) \ 323 | __asm__ __volatile__ ("pushl %1\n\t" \ 324 | "pushl %2\n\t" \ 325 | "movl (%3), %%edx\n\t" \ 326 | "call *"#funcOffset"(%%edx)\n\t" \ 327 | :"=a"(resultName) /* Output Operands */ \ 328 | :"r"(param2), /* Input Operands */ \ 329 | "r"(param1), \ 330 | "c"(thisPtr) \ 331 | : "%edx" /* Clobbered Registers */ \ 332 | ); \ 333 | 334 | 335 | #define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\ 336 | __asm__ __volatile__ ("pushl %1\n\t" \ 337 | "pushl %2\n\t" \ 338 | "pushl %3\n\t" \ 339 | "pushl %4\n\t" \ 340 | "movl (%5), %%edx\n\t" \ 341 | "call *"#funcOffset"(%%edx)\n\t" \ 342 | :"=a"(resultName) /* Output Operands */ \ 343 | :"r"(param4), /* Input Operands */ \ 344 | "r"(param3), \ 345 | "r"(param2), \ 346 | "r"(param1), \ 347 | "c"(thisPtr) \ 348 | : "%edx" /* Clobbered Registers */ \ 349 | ); \ 350 | 351 | #endif 352 | 353 | 354 | 355 | // Our static singleton instance. 356 | IASIOThiscallResolver IASIOThiscallResolver::instance; 357 | 358 | // Constructor called to initialize static Singleton instance above. Note that 359 | // it is important not to clear that_ incase it has already been set by the call 360 | // to placement new in ASIOInit(). 361 | IASIOThiscallResolver::IASIOThiscallResolver() 362 | { 363 | } 364 | 365 | // Constructor called from ASIOInit() below 366 | IASIOThiscallResolver::IASIOThiscallResolver(IASIO* that) 367 | : that_( that ) 368 | { 369 | } 370 | 371 | // Implement IUnknown methods as assert(false). IASIOThiscallResolver is not 372 | // really a COM object, just a wrapper which will work with the ASIO SDK. 373 | // If you wanted to use ASIO without the SDK you might want to implement COM 374 | // aggregation in these methods. 375 | HRESULT STDMETHODCALLTYPE IASIOThiscallResolver::QueryInterface(REFIID riid, void **ppv) 376 | { 377 | (void)riid; // suppress unused variable warning 378 | 379 | assert( false ); // this function should never be called by the ASIO SDK. 380 | 381 | *ppv = NULL; 382 | return E_NOINTERFACE; 383 | } 384 | 385 | ULONG STDMETHODCALLTYPE IASIOThiscallResolver::AddRef() 386 | { 387 | assert( false ); // this function should never be called by the ASIO SDK. 388 | 389 | return 1; 390 | } 391 | 392 | ULONG STDMETHODCALLTYPE IASIOThiscallResolver::Release() 393 | { 394 | assert( false ); // this function should never be called by the ASIO SDK. 395 | 396 | return 1; 397 | } 398 | 399 | 400 | // Implement the IASIO interface methods by performing the vptr manipulation 401 | // described above then delegating to the real implementation. 402 | ASIOBool IASIOThiscallResolver::init(void *sysHandle) 403 | { 404 | ASIOBool result; 405 | CALL_THISCALL_1( result, that_, 12, sysHandle ); 406 | return result; 407 | } 408 | 409 | void IASIOThiscallResolver::getDriverName(char *name) 410 | { 411 | CALL_VOID_THISCALL_1( that_, 16, name ); 412 | } 413 | 414 | long IASIOThiscallResolver::getDriverVersion() 415 | { 416 | ASIOBool result; 417 | CALL_THISCALL_0( result, that_, 20 ); 418 | return result; 419 | } 420 | 421 | void IASIOThiscallResolver::getErrorMessage(char *string) 422 | { 423 | CALL_VOID_THISCALL_1( that_, 24, string ); 424 | } 425 | 426 | ASIOError IASIOThiscallResolver::start() 427 | { 428 | ASIOBool result; 429 | CALL_THISCALL_0( result, that_, 28 ); 430 | return result; 431 | } 432 | 433 | ASIOError IASIOThiscallResolver::stop() 434 | { 435 | ASIOBool result; 436 | CALL_THISCALL_0( result, that_, 32 ); 437 | return result; 438 | } 439 | 440 | ASIOError IASIOThiscallResolver::getChannels(long *numInputChannels, long *numOutputChannels) 441 | { 442 | ASIOBool result; 443 | CALL_THISCALL_2( result, that_, 36, numInputChannels, numOutputChannels ); 444 | return result; 445 | } 446 | 447 | ASIOError IASIOThiscallResolver::getLatencies(long *inputLatency, long *outputLatency) 448 | { 449 | ASIOBool result; 450 | CALL_THISCALL_2( result, that_, 40, inputLatency, outputLatency ); 451 | return result; 452 | } 453 | 454 | ASIOError IASIOThiscallResolver::getBufferSize(long *minSize, long *maxSize, 455 | long *preferredSize, long *granularity) 456 | { 457 | ASIOBool result; 458 | CALL_THISCALL_4( result, that_, 44, minSize, maxSize, preferredSize, granularity ); 459 | return result; 460 | } 461 | 462 | ASIOError IASIOThiscallResolver::canSampleRate(ASIOSampleRate sampleRate) 463 | { 464 | ASIOBool result; 465 | CALL_THISCALL_1_DOUBLE( result, that_, 48, sampleRate ); 466 | return result; 467 | } 468 | 469 | ASIOError IASIOThiscallResolver::getSampleRate(ASIOSampleRate *sampleRate) 470 | { 471 | ASIOBool result; 472 | CALL_THISCALL_1( result, that_, 52, sampleRate ); 473 | return result; 474 | } 475 | 476 | ASIOError IASIOThiscallResolver::setSampleRate(ASIOSampleRate sampleRate) 477 | { 478 | ASIOBool result; 479 | CALL_THISCALL_1_DOUBLE( result, that_, 56, sampleRate ); 480 | return result; 481 | } 482 | 483 | ASIOError IASIOThiscallResolver::getClockSources(ASIOClockSource *clocks, long *numSources) 484 | { 485 | ASIOBool result; 486 | CALL_THISCALL_2( result, that_, 60, clocks, numSources ); 487 | return result; 488 | } 489 | 490 | ASIOError IASIOThiscallResolver::setClockSource(long reference) 491 | { 492 | ASIOBool result; 493 | CALL_THISCALL_1( result, that_, 64, reference ); 494 | return result; 495 | } 496 | 497 | ASIOError IASIOThiscallResolver::getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) 498 | { 499 | ASIOBool result; 500 | CALL_THISCALL_2( result, that_, 68, sPos, tStamp ); 501 | return result; 502 | } 503 | 504 | ASIOError IASIOThiscallResolver::getChannelInfo(ASIOChannelInfo *info) 505 | { 506 | ASIOBool result; 507 | CALL_THISCALL_1( result, that_, 72, info ); 508 | return result; 509 | } 510 | 511 | ASIOError IASIOThiscallResolver::createBuffers(ASIOBufferInfo *bufferInfos, 512 | long numChannels, long bufferSize, ASIOCallbacks *callbacks) 513 | { 514 | ASIOBool result; 515 | CALL_THISCALL_4( result, that_, 76, bufferInfos, numChannels, bufferSize, callbacks ); 516 | return result; 517 | } 518 | 519 | ASIOError IASIOThiscallResolver::disposeBuffers() 520 | { 521 | ASIOBool result; 522 | CALL_THISCALL_0( result, that_, 80 ); 523 | return result; 524 | } 525 | 526 | ASIOError IASIOThiscallResolver::controlPanel() 527 | { 528 | ASIOBool result; 529 | CALL_THISCALL_0( result, that_, 84 ); 530 | return result; 531 | } 532 | 533 | ASIOError IASIOThiscallResolver::future(long selector,void *opt) 534 | { 535 | ASIOBool result; 536 | CALL_THISCALL_2( result, that_, 88, selector, opt ); 537 | return result; 538 | } 539 | 540 | ASIOError IASIOThiscallResolver::outputReady() 541 | { 542 | ASIOBool result; 543 | CALL_THISCALL_0( result, that_, 92 ); 544 | return result; 545 | } 546 | 547 | 548 | // Implement our substitute ASIOInit() method 549 | ASIOError IASIOThiscallResolver::ASIOInit(ASIODriverInfo *info) 550 | { 551 | // To ensure that our instance's vptr is correctly constructed, even if 552 | // ASIOInit is called prior to main(), we explicitly call its constructor 553 | // (potentially over the top of an existing instance). Note that this is 554 | // pretty ugly, and is only safe because IASIOThiscallResolver has no 555 | // destructor and contains no objects with destructors. 556 | new((void*)&instance) IASIOThiscallResolver( theAsioDriver ); 557 | 558 | // Interpose between ASIO client code and the real driver. 559 | theAsioDriver = &instance; 560 | 561 | // Note that we never need to switch theAsioDriver back to point to the 562 | // real driver because theAsioDriver is reset to zero in ASIOExit(). 563 | 564 | // Delegate to the real ASIOInit 565 | return ::ASIOInit(info); 566 | } 567 | 568 | 569 | #endif /* !defined(_MSC_VER) */ 570 | 571 | #endif /* Win32 */ 572 | 573 | -------------------------------------------------------------------------------- /trunk/external/libRtAudio/include/iasiothiscallresolver.h: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | // 3 | // Changed: I have modified this file slightly (includes) to work with 4 | // RtAudio. RtAudio.cpp must include this file after asio.h. 5 | // 6 | // File: IASIOThiscallResolver.h 7 | // Description: The IASIOThiscallResolver class implements the IASIO 8 | // interface and acts as a proxy to the real IASIO interface by 9 | // calling through its vptr table using the thiscall calling 10 | // convention. To put it another way, we interpose 11 | // IASIOThiscallResolver between ASIO SDK code and the driver. 12 | // This is necessary because most non-Microsoft compilers don't 13 | // implement the thiscall calling convention used by IASIO. 14 | // 15 | // iasiothiscallresolver.cpp contains the background of this 16 | // problem plus a technical description of the vptr 17 | // manipulations. 18 | // 19 | // In order to use this mechanism one simply has to add 20 | // iasiothiscallresolver.cpp to the list of files to compile 21 | // and #include 22 | // 23 | // Note that this #include must come after the other ASIO SDK 24 | // #includes, for example: 25 | // 26 | // #include 27 | // #include 28 | // #include 29 | // #include 30 | // #include 31 | // 32 | // Actually the important thing is to #include 33 | // after . We have 34 | // incorporated a test to enforce this ordering. 35 | // 36 | // The code transparently takes care of the interposition by 37 | // using macro substitution to intercept calls to ASIOInit() 38 | // and ASIOExit(). We save the original ASIO global 39 | // "theAsioDriver" in our "that" variable, and then set 40 | // "theAsioDriver" to equal our IASIOThiscallResolver instance. 41 | // 42 | // Whilst this method of resolving the thiscall problem requires 43 | // the addition of #include to client 44 | // code it has the advantage that it does not break the terms 45 | // of the ASIO licence by publishing it. We are NOT modifying 46 | // any Steinberg code here, we are merely implementing the IASIO 47 | // interface in the same way that we would need to do if we 48 | // wished to provide an open source ASIO driver. 49 | // 50 | // For compilation with MinGW -lole32 needs to be added to the 51 | // linker options. For BORLAND, linking with Import32.lib is 52 | // sufficient. 53 | // 54 | // The dependencies are with: CoInitialize, CoUninitialize, 55 | // CoCreateInstance, CLSIDFromString - used by asiolist.cpp 56 | // and are required on Windows whether ThiscallResolver is used 57 | // or not. 58 | // 59 | // Searching for the above strings in the root library path 60 | // of your compiler should enable the correct libraries to be 61 | // identified if they aren't immediately obvious. 62 | // 63 | // Note that the current implementation of IASIOThiscallResolver 64 | // is not COM compliant - it does not correctly implement the 65 | // IUnknown interface. Implementing it is not necessary because 66 | // it is not called by parts of the ASIO SDK which call through 67 | // theAsioDriver ptr. The IUnknown methods are implemented as 68 | // assert(false) to ensure that the code fails if they are 69 | // ever called. 70 | // Restrictions: None. Public Domain & Open Source distribute freely 71 | // You may use IASIOThiscallResolver commercially as well as 72 | // privately. 73 | // You the user assume the responsibility for the use of the 74 | // files, binary or text, and there is no guarantee or warranty, 75 | // expressed or implied, including but not limited to the 76 | // implied warranties of merchantability and fitness for a 77 | // particular purpose. You assume all responsibility and agree 78 | // to hold no entity, copyright holder or distributors liable 79 | // for any loss of data or inaccurate representations of data 80 | // as a result of using IASIOThiscallResolver. 81 | // Version: 1.4 Added separate macro CALL_THISCALL_1_DOUBLE from 82 | // Andrew Baldwin, and volatile for whole gcc asm blocks, 83 | // both for compatibility with newer gcc versions. Cleaned up 84 | // Borland asm to use one less register. 85 | // 1.3 Switched to including assert.h for better compatibility. 86 | // Wrapped entire .h and .cpp contents with a check for 87 | // _MSC_VER to provide better compatibility with MS compilers. 88 | // Changed Singleton implementation to use static instance 89 | // instead of freestore allocated instance. Removed ASIOExit 90 | // macro as it is no longer needed. 91 | // 1.2 Removed semicolons from ASIOInit and ASIOExit macros to 92 | // allow them to be embedded in expressions (if statements). 93 | // Cleaned up some comments. Removed combase.c dependency (it 94 | // doesn't compile with BCB anyway) by stubbing IUnknown. 95 | // 1.1 Incorporated comments from Ross Bencina including things 96 | // such as changing name from ThiscallResolver to 97 | // IASIOThiscallResolver, tidying up the constructor, fixing 98 | // a bug in IASIOThiscallResolver::ASIOExit() and improving 99 | // portability through the use of conditional compilation 100 | // 1.0 Initial working version. 101 | // Created: 6/09/2003 102 | // Authors: Fraser Adams 103 | // Ross Bencina 104 | // Rene G. Ceballos 105 | // Martin Fay 106 | // Antti Silvast 107 | // Andrew Baldwin 108 | // 109 | // **************************************************************************** 110 | 111 | 112 | #ifndef included_iasiothiscallresolver_h 113 | #define included_iasiothiscallresolver_h 114 | 115 | // We only need IASIOThiscallResolver at all if we are on Win32. For other 116 | // platforms we simply bypass the IASIOThiscallResolver definition to allow us 117 | // to be safely #include'd whatever the platform to keep client code portable 118 | //#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) 119 | #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64) 120 | 121 | 122 | // If microsoft compiler we can call IASIO directly so IASIOThiscallResolver 123 | // is not used. 124 | #if !defined(_MSC_VER) 125 | 126 | 127 | // The following is in order to ensure that this header is only included after 128 | // the other ASIO headers (except for the case of iasiothiscallresolver.cpp). 129 | // We need to do this because IASIOThiscallResolver works by eclipsing the 130 | // original definition of ASIOInit() with a macro (see below). 131 | #if !defined(iasiothiscallresolver_sourcefile) 132 | #if !defined(__ASIO_H) 133 | #error iasiothiscallresolver.h must be included AFTER asio.h 134 | #endif 135 | #endif 136 | 137 | #include 138 | #include "iasiodrv.h" /* From ASIO SDK */ 139 | 140 | 141 | class IASIOThiscallResolver : public IASIO { 142 | private: 143 | IASIO* that_; // Points to the real IASIO 144 | 145 | static IASIOThiscallResolver instance; // Singleton instance 146 | 147 | // Constructors - declared private so construction is limited to 148 | // our Singleton instance 149 | IASIOThiscallResolver(); 150 | IASIOThiscallResolver(IASIO* that); 151 | public: 152 | 153 | // Methods from the IUnknown interface. We don't fully implement IUnknown 154 | // because the ASIO SDK never calls these methods through theAsioDriver ptr. 155 | // These methods are implemented as assert(false). 156 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv); 157 | virtual ULONG STDMETHODCALLTYPE AddRef(); 158 | virtual ULONG STDMETHODCALLTYPE Release(); 159 | 160 | // Methods from the IASIO interface, implemented as forwarning calls to that. 161 | virtual ASIOBool init(void *sysHandle); 162 | virtual void getDriverName(char *name); 163 | virtual long getDriverVersion(); 164 | virtual void getErrorMessage(char *string); 165 | virtual ASIOError start(); 166 | virtual ASIOError stop(); 167 | virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels); 168 | virtual ASIOError getLatencies(long *inputLatency, long *outputLatency); 169 | virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); 170 | virtual ASIOError canSampleRate(ASIOSampleRate sampleRate); 171 | virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate); 172 | virtual ASIOError setSampleRate(ASIOSampleRate sampleRate); 173 | virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); 174 | virtual ASIOError setClockSource(long reference); 175 | virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); 176 | virtual ASIOError getChannelInfo(ASIOChannelInfo *info); 177 | virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks); 178 | virtual ASIOError disposeBuffers(); 179 | virtual ASIOError controlPanel(); 180 | virtual ASIOError future(long selector,void *opt); 181 | virtual ASIOError outputReady(); 182 | 183 | // Class method, see ASIOInit() macro below. 184 | static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit 185 | }; 186 | 187 | 188 | // Replace calls to ASIOInit with our interposing version. 189 | // This macro enables us to perform thiscall resolution simply by #including 190 | // after the asio #includes (this file _must_ be 191 | // included _after_ the asio #includes) 192 | 193 | #define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name)) 194 | 195 | 196 | #endif /* !defined(_MSC_VER) */ 197 | 198 | #endif /* Win32 */ 199 | 200 | #endif /* included_iasiothiscallresolver_h */ 201 | 202 | 203 | -------------------------------------------------------------------------------- /trunk/external/libmux/SDL2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/SDL2.dll -------------------------------------------------------------------------------- /trunk/external/libmux/avcodec-57.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/avcodec-57.dll -------------------------------------------------------------------------------- /trunk/external/libmux/avdevice-57.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/avdevice-57.dll -------------------------------------------------------------------------------- /trunk/external/libmux/avfilter-6.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/avfilter-6.dll -------------------------------------------------------------------------------- /trunk/external/libmux/avformat-57.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/avformat-57.dll -------------------------------------------------------------------------------- /trunk/external/libmux/avutil-55.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/avutil-55.dll -------------------------------------------------------------------------------- /trunk/external/libmux/libgcc_s_dw2-1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/libgcc_s_dw2-1.dll -------------------------------------------------------------------------------- /trunk/external/libmux/libmux.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/libmux.dll -------------------------------------------------------------------------------- /trunk/external/libmux/libwinpthread-1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/libwinpthread-1.dll -------------------------------------------------------------------------------- /trunk/external/libmux/libx264-148.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/libx264-148.dll -------------------------------------------------------------------------------- /trunk/external/libmux/postproc-54.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/postproc-54.dll -------------------------------------------------------------------------------- /trunk/external/libmux/swresample-2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/swresample-2.dll -------------------------------------------------------------------------------- /trunk/external/libmux/swscale-4.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjiegit/Bull-Record-Everything/f685494bc015064717a967f563b7c266346fe5f7/trunk/external/libmux/swscale-4.dll -------------------------------------------------------------------------------- /trunk/src/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | #include "ui_MainWindow.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "AudioSource.h" 13 | #include "MuxApi.h" 14 | #include "MuxThread.h" 15 | #include "VideoSurface.h" 16 | #include "Scene_GrabScreen.h" 17 | #include "Scene_RecordAudio.h" 18 | #include "Scene_RecordVideo.h" 19 | 20 | Q_DECLARE_METATYPE(AudioDeviceInfo) 21 | Q_DECLARE_METATYPE(QCameraInfo) 22 | 23 | #define VIDEO_WIDTH ( 640 ) 24 | #define VIDEO_HEIGHT ( 480 ) 25 | 26 | static int check_video(int bytes, void *user_data) 27 | { 28 | Q_UNUSED(bytes); 29 | Q_UNUSED(user_data); 30 | 31 | return 0; 32 | } 33 | 34 | static int check_audio(int bytes, void *user_data) 35 | { 36 | MainWindow *user = (MainWindow*)(user_data); 37 | return user->check_pcm_size(bytes); 38 | } 39 | 40 | static int get_video(char* rgb24, void *user_data) 41 | { 42 | MainWindow *user = (MainWindow*)(user_data); 43 | QImage img = user->getImage(); 44 | 45 | memcpy(rgb24, img.bits(), img.byteCount()); 46 | 47 | return 0; 48 | } 49 | 50 | static int get_audio(char* s16, int frame_size, int chs, void *user_data) 51 | { 52 | int size = frame_size * chs * 2; 53 | MainWindow *user = (MainWindow*)(user_data); 54 | user->getPcmData(s16, size); 55 | 56 | return 0; 57 | } 58 | 59 | MainWindow *g_mainWindow; 60 | MuxHandle *g_handle = NULL; 61 | 62 | MainWindow::MainWindow(QWidget *parent) 63 | : QMainWindow(parent) 64 | , ui(new Ui::MainWindow) 65 | , m_muxThread(NULL) 66 | , m_camera(NULL) 67 | { 68 | ui->setupUi(this); 69 | 70 | g_mainWindow = this; 71 | 72 | // reset window title 73 | setWindowTitle(tr("Bull-Record-Everything")); 74 | 75 | // add micro-phone devices 76 | if (true) { 77 | QList infos = AudioCapture::getAudioDevice(); 78 | for (int i = 0; i < infos.size(); ++i) { 79 | const AudioDeviceInfo &info = infos.at(i); 80 | ui->audio->addItem(info.deviceName, QVariant::fromValue(info)); 81 | } 82 | 83 | bool res = MuxApi::instance()->init("libmux.dll"); 84 | // TODO add error code 85 | qDebug() << res; 86 | } 87 | 88 | // add camera devices 89 | if (true) { 90 | QList infos = QCameraInfo::availableCameras(); 91 | for (int i = 0; i < infos.size(); ++i) { 92 | const QCameraInfo &info = infos.at(i); 93 | ui->video->addItem(info.description(), QVariant::fromValue(info)); 94 | } 95 | 96 | connect(ui->video, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentCameraChanged(int))); 97 | 98 | QTimer::singleShot(1000, this, SLOT(delayGetCameraRes())); 99 | } 100 | 101 | // init scene 102 | if (true) { 103 | m_recVideo = new Scene_RecordVideo(this); 104 | m_grabScreen = new Scene_GrabScreen(this); 105 | m_recAudio = new Scene_RecordAudio(this); 106 | 107 | ui->stackedWidget->addWidget(m_recVideo); 108 | ui->stackedWidget->addWidget(m_grabScreen); 109 | ui->stackedWidget->addWidget(m_recAudio); 110 | 111 | ui->navWidget->addTab(tr("rec-video"), m_recVideo); 112 | ui->navWidget->addTab(tr("grab-screen"), m_grabScreen); 113 | ui->navWidget->addTab(tr("rec-audio"), m_recAudio); 114 | 115 | connect(ui->navWidget, SIGNAL(tabChanged(QWidget*)), this, SLOT(onTabChanged(QWidget*))); 116 | } 117 | 118 | // add dumy image 119 | if (true) { 120 | QImage img(VIDEO_WIDTH, VIDEO_HEIGHT, QImage::Format_RGB888); 121 | img.fill(Qt::black); 122 | m_imgs << img; 123 | } 124 | } 125 | 126 | MainWindow::~MainWindow() 127 | { 128 | delete ui; 129 | } 130 | 131 | void MainWindow::onAudioFrameAvailable(const QByteArray &data) 132 | { 133 | mutex.lock(); 134 | m_pcm.append(data); 135 | 136 | if (m_pcm.size() > 20480) { 137 | m_pcm.remove(0, 12288); 138 | } 139 | 140 | mutex.unlock(); 141 | } 142 | 143 | int MainWindow::check_pcm_size(int size) 144 | { 145 | mutex.lock(); 146 | int ret = m_pcm.size() >= size ? 0 : 1; 147 | mutex.unlock(); 148 | 149 | qDebug() << size << m_pcm.size() << ret; 150 | 151 | return ret; 152 | } 153 | 154 | void MainWindow::getPcmData(char *buf, int size) 155 | { 156 | mutex.lock(); 157 | 158 | memcpy(buf, m_pcm.data(), size); 159 | m_pcm.remove(0, size); 160 | 161 | mutex.unlock(); 162 | } 163 | 164 | QImage MainWindow::getImage() 165 | { 166 | QMutexLocker lk(&mutex_video); 167 | 168 | if (m_imgs.size() >= 2) { 169 | return m_imgs.takeFirst(); 170 | } else { 171 | return m_imgs.first(); 172 | } 173 | } 174 | 175 | void MainWindow::on_start_clicked() 176 | { 177 | QCameraViewfinderSettings ds = ui->res->currentData().value(); 178 | 179 | std::string timeStr = QString("%1.mp4").arg(QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss")).toStdString(); 180 | 181 | MuxApi *muxApi = MuxApi::instance(); 182 | MuxHandle *h = muxApi->ptr_create_mux(); 183 | h->ouput_filename = qstrdup(timeStr.c_str());//const_cast("out1.mp4"); 184 | h->user_data = this; 185 | h->video_width = ds.resolution().width(); 186 | h->video_height = ds.resolution().height(); 187 | 188 | h->video_bit_rate = 800000; 189 | h->audio_bit_rate = 96000; 190 | 191 | h->check_video = check_video; 192 | h->check_audio = check_audio; 193 | h->get_video = get_video; 194 | h->get_audio = get_audio; 195 | 196 | g_handle = h; 197 | 198 | m_muxThread = new MuxThread(this); 199 | m_muxThread->setMuxHandle(h); 200 | m_muxThread->start(); 201 | } 202 | 203 | void MainWindow::on_open_audio_clicked() 204 | { 205 | AudioCapture *cap = new AudioCapture; 206 | 207 | AudioDeviceInfo info = ui->audio->currentData().value(); 208 | cap->setAudioDevice(info); 209 | cap->start(); 210 | } 211 | 212 | void MainWindow::on_stop_clicked() 213 | { 214 | MuxApi *muxApi = MuxApi::instance(); 215 | 216 | // request 217 | muxApi->ptr_stop_mux(g_handle); 218 | 219 | // wait 220 | m_muxThread->wait(); 221 | 222 | // clean 223 | muxApi->ptr_destroy_mux(g_handle); 224 | } 225 | 226 | void MainWindow::onCurrentCameraChanged(int index) 227 | { 228 | QVariant _d = ui->video->itemData(index); 229 | QCameraInfo info = _d.value(); 230 | 231 | QCamera* camera = new QCamera(info); 232 | camera->load(); 233 | 234 | qDebug() << camera->supportedViewfinderPixelFormats(); 235 | 236 | ui->res->clear(); 237 | QList ss = camera->supportedViewfinderSettings(); 238 | for (int i = 0; i < ss.size(); ++i) { 239 | const QCameraViewfinderSettings &s = ss.at(i); 240 | 241 | QString text = QString("%1x%2 %3-%4 fps").arg(s.resolution().width()).arg(s.resolution().height()) 242 | .arg(s.minimumFrameRate()).arg(s.maximumFrameRate()); 243 | 244 | ui->res->addItem(text, QVariant::fromValue(s)); 245 | } 246 | 247 | camera->deleteLater(); 248 | 249 | qDebug() << index << ss.size(); 250 | } 251 | 252 | void MainWindow::on_open_video_clicked() 253 | { 254 | if (m_camera) { 255 | m_camera->stop(); 256 | m_camera->deleteLater(); 257 | } 258 | 259 | QVariant _d = ui->video->currentData(); 260 | QCameraInfo info = _d.value(); 261 | 262 | QCameraViewfinderSettings viewfinderSettings; 263 | viewfinderSettings.setResolution(80, 60); 264 | 265 | m_camera = new QCamera(info); 266 | 267 | m_camera->load(); 268 | 269 | QCameraViewfinderSettings ds = ui->res->currentData().value(); 270 | //ds.setPixelFormat(QVideoFrame::Format_RGB24); 271 | 272 | VideoSurface *vs = new VideoSurface; 273 | m_camera->setViewfinder(vs); 274 | m_camera->setViewfinderSettings(ds); 275 | 276 | m_camera->start(); 277 | 278 | connect(vs, SIGNAL(image(QImage)), this, SLOT(onImage(QImage))); 279 | } 280 | 281 | void MainWindow::onImage(const QImage &img) 282 | { 283 | mutex_video.lock(); 284 | 285 | if (img.format() != QImage::Format_RGB888) { 286 | m_imgs << img.convertToFormat(QImage::Format_RGB888); 287 | } else { 288 | m_imgs << img; 289 | } 290 | 291 | if (m_imgs.size() >= 3) { 292 | m_imgs.removeFirst(); 293 | } 294 | 295 | mutex_video.unlock(); 296 | } 297 | 298 | void MainWindow::delayGetCameraRes() 299 | { 300 | if (ui->video->count() > 0) { 301 | onCurrentCameraChanged(ui->video->currentIndex()); 302 | } 303 | } 304 | 305 | void MainWindow::onTabChanged(QWidget *w) 306 | { 307 | qDebug() << "-------->>" <stackedWidget->setCurrentWidget(w); 309 | } 310 | -------------------------------------------------------------------------------- /trunk/src/MainWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Ui { 9 | class MainWindow; 10 | } 11 | 12 | class MuxThread; 13 | class QCamera; 14 | 15 | class Scene_RecordVideo; 16 | class Scene_GrabScreen; 17 | class Scene_RecordAudio; 18 | 19 | class MainWindow : public QMainWindow 20 | { 21 | Q_OBJECT 22 | 23 | public: 24 | explicit MainWindow(QWidget *parent = 0); 25 | ~MainWindow(); 26 | 27 | void onAudioFrameAvailable(const QByteArray &data); 28 | 29 | int check_pcm_size(int size); 30 | void getPcmData(char *buf, int size); 31 | QImage getImage(); 32 | 33 | private slots: 34 | void on_start_clicked(); 35 | 36 | void on_open_audio_clicked(); 37 | 38 | void on_stop_clicked(); 39 | 40 | void onCurrentCameraChanged(int index); 41 | 42 | void on_open_video_clicked(); 43 | 44 | void onImage(const QImage &img); 45 | 46 | void delayGetCameraRes(); 47 | 48 | void onTabChanged(QWidget *w); 49 | 50 | private: 51 | Ui::MainWindow *ui; 52 | 53 | QByteArray m_pcm; 54 | QMutex mutex; 55 | QMutex mutex_video; 56 | QList m_imgs; 57 | 58 | MuxThread* m_muxThread; 59 | QCamera* m_camera; 60 | 61 | // 62 | Scene_RecordVideo* m_recVideo; 63 | Scene_GrabScreen* m_grabScreen; 64 | Scene_RecordAudio* m_recAudio; 65 | }; 66 | 67 | #endif // MAINWINDOW_H 68 | -------------------------------------------------------------------------------- /trunk/src/MainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1113 10 | 733 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 40 28 | 10 29 | 661 30 | 41 31 | 32 | 33 | 34 | 35 | 36 | 37 | Camera: 38 | 39 | 40 | 41 | 42 | 43 | 44 | open camera 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 200 53 | 0 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Micro-Phone: 62 | 63 | 64 | 65 | 66 | 67 | 68 | open micro phone 69 | 70 | 71 | 72 | 73 | 74 | 75 | Qt::Horizontal 76 | 77 | 78 | 79 | 40 80 | 20 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 200 93 | 0 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 360 104 | 230 105 | 75 106 | 23 107 | 108 | 109 | 110 | stop 111 | 112 | 113 | 114 | 115 | 116 | 260 117 | 230 118 | 75 119 | 23 120 | 121 | 122 | 123 | start 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 0 135 | 0 136 | 1113 137 | 23 138 | 139 | 140 | 141 | 142 | &File 143 | 144 | 145 | 146 | 147 | 148 | &Help 149 | 150 | 151 | 152 | 153 | 154 | &Tools 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | TopToolBarArea 165 | 166 | 167 | false 168 | 169 | 170 | 171 | 172 | 173 | &Quit 174 | 175 | 176 | 177 | 178 | &About 179 | 180 | 181 | 182 | 183 | &Settings 184 | 185 | 186 | 187 | 188 | 189 | 190 | NavWidget 191 | QWidget 192 |
NavWidget.h
193 | 1 194 |
195 |
196 | 197 | 198 |
199 | -------------------------------------------------------------------------------- /trunk/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /trunk/src/mux/MuxApi.cpp: -------------------------------------------------------------------------------- 1 | #include "MuxApi.h" 2 | 3 | #include 4 | 5 | MuxApi *MuxApi::instance() 6 | { 7 | static MuxApi* ret = NULL; 8 | if (!ret) { 9 | ret = new MuxApi; 10 | } 11 | 12 | return ret; 13 | } 14 | 15 | bool MuxApi::init(const QString &dllPath) 16 | { 17 | QLibrary lib(dllPath); 18 | ptr_create_mux = (create_mux)lib.resolve("create_mux"); 19 | ptr_start_mux = (start_mux)lib.resolve("start_mux"); 20 | ptr_stop_mux = (stop_mux)lib.resolve("stop_mux"); 21 | ptr_destroy_mux = (destroy_mux)lib.resolve("destroy_mux"); 22 | 23 | return ptr_create_mux 24 | && ptr_start_mux 25 | && ptr_stop_mux 26 | && ptr_destroy_mux; 27 | } 28 | -------------------------------------------------------------------------------- /trunk/src/mux/MuxApi.h: -------------------------------------------------------------------------------- 1 | #ifndef MUXAPI_H 2 | #define MUXAPI_H 3 | 4 | #include "libmux.h" 5 | 6 | #include 7 | 8 | class MuxApi 9 | { 10 | public: 11 | typedef MuxHandle* (*create_mux)(); 12 | typedef int (*start_mux)(MuxHandle*); 13 | typedef int (*stop_mux)(MuxHandle*); 14 | typedef void (*destroy_mux)(MuxHandle *); 15 | 16 | public: 17 | static MuxApi *instance(); 18 | bool init(const QString &dllPath); 19 | 20 | public: 21 | create_mux ptr_create_mux; 22 | start_mux ptr_start_mux; 23 | stop_mux ptr_stop_mux; 24 | destroy_mux ptr_destroy_mux; 25 | }; 26 | 27 | #endif // MUXAPI_H 28 | -------------------------------------------------------------------------------- /trunk/src/mux/MuxThread.cpp: -------------------------------------------------------------------------------- 1 | #include "MuxThread.h" 2 | 3 | MuxThread::MuxThread(QObject *parent) 4 | : QThread(parent) 5 | , m_handle(NULL) 6 | { 7 | 8 | } 9 | 10 | void MuxThread::run() 11 | { 12 | MuxApi *muxApi = MuxApi::instance(); 13 | muxApi->ptr_start_mux(m_handle); 14 | } 15 | 16 | void MuxThread::stop() 17 | { 18 | 19 | } 20 | 21 | void MuxThread::setMuxHandle(MuxHandle *h) 22 | { 23 | m_handle = h; 24 | } 25 | -------------------------------------------------------------------------------- /trunk/src/mux/MuxThread.h: -------------------------------------------------------------------------------- 1 | #ifndef MUXTHREAD_H 2 | #define MUXTHREAD_H 3 | 4 | #include 5 | 6 | #include "MuxApi.h" 7 | 8 | class MuxThread : public QThread 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit MuxThread(QObject *parent = 0); 13 | 14 | void run(); 15 | void stop(); 16 | 17 | void setMuxHandle(MuxHandle *h); 18 | 19 | signals: 20 | 21 | public slots: 22 | 23 | private: 24 | bool _stop; 25 | MuxHandle *m_handle; 26 | }; 27 | 28 | #endif // MUXTHREAD_H 29 | -------------------------------------------------------------------------------- /trunk/src/mux/libmux.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBMUX_H 2 | #define LIBMUX_H 3 | 4 | #if defined (_WIN32) && defined (DLL_EXPORT) 5 | # define LIBMUX_API __declspec(dllexport) 6 | #elif defined (__GNUC__) && (__GNUC__ >= 4) 7 | # define LIBMUX_API __attribute__((visibility("default"))) 8 | #else 9 | # define LIBMUX_API 10 | #endif 11 | 12 | typedef int (*CheckData)(int bytes, void *user_data); 13 | typedef int (*GetVideo)(char* rgb24, void *user_data); 14 | typedef int (*GetAudio)(char* s16, int frame_size, int chs, void *user_data); 15 | 16 | struct MuxHandle 17 | { 18 | // default: NULL 19 | char *ouput_filename; 20 | 21 | // default: 320 22 | int video_width; 23 | // default: 240 24 | int video_height; 25 | // default: 400,000 26 | int video_bit_rate; 27 | // default: 96000 28 | int audio_bit_rate; 29 | 30 | // callbacks api 31 | CheckData check_video; 32 | CheckData check_audio; 33 | GetVideo get_video; 34 | GetAudio get_audio; 35 | 36 | void *private_data_video; 37 | void *private_data_audio; 38 | 39 | void *user_data; 40 | }; 41 | 42 | typedef struct MuxHandle MuxHandle; 43 | 44 | #endif // LIBMUX_H 45 | -------------------------------------------------------------------------------- /trunk/src/pages/Page_GrabCamera.cpp: -------------------------------------------------------------------------------- 1 | #include "Page_GrabCamera.h" 2 | #include "ui_Page_GrabCamera.h" 3 | 4 | Page_GrabCamera::Page_GrabCamera(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::Page_GrabCamera) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | Page_GrabCamera::~Page_GrabCamera() 12 | { 13 | delete ui; 14 | } 15 | -------------------------------------------------------------------------------- /trunk/src/pages/Page_GrabCamera.h: -------------------------------------------------------------------------------- 1 | #ifndef PAGE_GRABCAMERA_H 2 | #define PAGE_GRABCAMERA_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class Page_GrabCamera; 8 | } 9 | 10 | class Page_GrabCamera : public QWidget 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit Page_GrabCamera(QWidget *parent = 0); 16 | ~Page_GrabCamera(); 17 | 18 | private: 19 | Ui::Page_GrabCamera *ui; 20 | }; 21 | 22 | #endif // PAGE_GRABCAMERA_H 23 | -------------------------------------------------------------------------------- /trunk/src/pages/Page_GrabCamera.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page_GrabCamera 6 | 7 | 8 | 9 | 0 10 | 0 11 | 400 12 | 300 13 | 14 | 15 | 16 | Form 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /trunk/src/pages/Page_GrabDesktopArea.cpp: -------------------------------------------------------------------------------- 1 | #include "Page_GrabDesktopArea.h" 2 | #include "ui_Page_GrabDesktopArea.h" 3 | 4 | Page_GrabDesktopArea::Page_GrabDesktopArea(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::Page_GrabDesktopArea) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | Page_GrabDesktopArea::~Page_GrabDesktopArea() 12 | { 13 | delete ui; 14 | } 15 | -------------------------------------------------------------------------------- /trunk/src/pages/Page_GrabDesktopArea.h: -------------------------------------------------------------------------------- 1 | #ifndef PAGE_GRABDESKTOPAREA_H 2 | #define PAGE_GRABDESKTOPAREA_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class Page_GrabDesktopArea; 8 | } 9 | 10 | class Page_GrabDesktopArea : public QWidget 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit Page_GrabDesktopArea(QWidget *parent = 0); 16 | ~Page_GrabDesktopArea(); 17 | 18 | private: 19 | Ui::Page_GrabDesktopArea *ui; 20 | }; 21 | 22 | #endif // PAGE_GRABDESKTOPAREA_H 23 | -------------------------------------------------------------------------------- /trunk/src/pages/Page_GrabDesktopArea.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page_GrabDesktopArea 6 | 7 | 8 | 9 | 0 10 | 0 11 | 400 12 | 300 13 | 14 | 15 | 16 | Form 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /trunk/src/pages/Page_GrabScrollArea.cpp: -------------------------------------------------------------------------------- 1 | #include "Page_GrabScrollArea.h" 2 | #include "ui_Page_GrabScrollArea.h" 3 | 4 | Page_GrabScrollArea::Page_GrabScrollArea(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::Page_GrabScrollArea) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | Page_GrabScrollArea::~Page_GrabScrollArea() 12 | { 13 | delete ui; 14 | } 15 | -------------------------------------------------------------------------------- /trunk/src/pages/Page_GrabScrollArea.h: -------------------------------------------------------------------------------- 1 | #ifndef PAGE_GRABSCROLLAREA_H 2 | #define PAGE_GRABSCROLLAREA_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class Page_GrabScrollArea; 8 | } 9 | 10 | class Page_GrabScrollArea : public QWidget 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit Page_GrabScrollArea(QWidget *parent = 0); 16 | ~Page_GrabScrollArea(); 17 | 18 | private: 19 | Ui::Page_GrabScrollArea *ui; 20 | }; 21 | 22 | #endif // PAGE_GRABSCROLLAREA_H 23 | -------------------------------------------------------------------------------- /trunk/src/pages/Page_GrabScrollArea.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page_GrabScrollArea 6 | 7 | 8 | 9 | 0 10 | 0 11 | 400 12 | 300 13 | 14 | 15 | 16 | Form 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /trunk/src/pages/Page_GrabWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "Page_GrabWindow.h" 2 | #include "ui_Page_GrabWindow.h" 3 | 4 | Page_GrabWindow::Page_GrabWindow(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::Page_GrabWindow) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | Page_GrabWindow::~Page_GrabWindow() 12 | { 13 | delete ui; 14 | } 15 | -------------------------------------------------------------------------------- /trunk/src/pages/Page_GrabWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef PAGE_GRABWINDOW_H 2 | #define PAGE_GRABWINDOW_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class Page_GrabWindow; 8 | } 9 | 10 | class Page_GrabWindow : public QWidget 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit Page_GrabWindow(QWidget *parent = 0); 16 | ~Page_GrabWindow(); 17 | 18 | private: 19 | Ui::Page_GrabWindow *ui; 20 | }; 21 | 22 | #endif // PAGE_GRABWINDOW_H 23 | -------------------------------------------------------------------------------- /trunk/src/pages/Page_GrabWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page_GrabWindow 6 | 7 | 8 | 9 | 0 10 | 0 11 | 400 12 | 300 13 | 14 | 15 | 16 | Form 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /trunk/src/scene/Scene_GrabScreen.cpp: -------------------------------------------------------------------------------- 1 | #include "Scene_GrabScreen.h" 2 | #include "ui_Scene_GrabScreen.h" 3 | 4 | Scene_GrabScreen::Scene_GrabScreen(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::Scene_GrabScreen) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | Scene_GrabScreen::~Scene_GrabScreen() 12 | { 13 | delete ui; 14 | } 15 | -------------------------------------------------------------------------------- /trunk/src/scene/Scene_GrabScreen.h: -------------------------------------------------------------------------------- 1 | #ifndef SCENE_GRABSCREEN_H 2 | #define SCENE_GRABSCREEN_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class Scene_GrabScreen; 8 | } 9 | 10 | class Scene_GrabScreen : public QWidget 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit Scene_GrabScreen(QWidget *parent = 0); 16 | ~Scene_GrabScreen(); 17 | 18 | private: 19 | Ui::Scene_GrabScreen *ui; 20 | }; 21 | 22 | #endif // SCENE_GRABSCREEN_H 23 | -------------------------------------------------------------------------------- /trunk/src/scene/Scene_GrabScreen.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Scene_GrabScreen 6 | 7 | 8 | 9 | 0 10 | 0 11 | 400 12 | 300 13 | 14 | 15 | 16 | Form 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /trunk/src/scene/Scene_RecordAudio.cpp: -------------------------------------------------------------------------------- 1 | #include "Scene_RecordAudio.h" 2 | #include "ui_Scene_RecordAudio.h" 3 | 4 | Scene_RecordAudio::Scene_RecordAudio(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::Scene_RecordAudio) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | Scene_RecordAudio::~Scene_RecordAudio() 12 | { 13 | delete ui; 14 | } 15 | -------------------------------------------------------------------------------- /trunk/src/scene/Scene_RecordAudio.h: -------------------------------------------------------------------------------- 1 | #ifndef SCENE_RECORDAUDIO_H 2 | #define SCENE_RECORDAUDIO_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class Scene_RecordAudio; 8 | } 9 | 10 | class Scene_RecordAudio : public QWidget 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit Scene_RecordAudio(QWidget *parent = 0); 16 | ~Scene_RecordAudio(); 17 | 18 | private: 19 | Ui::Scene_RecordAudio *ui; 20 | }; 21 | 22 | #endif // SCENE_RECORDAUDIO_H 23 | -------------------------------------------------------------------------------- /trunk/src/scene/Scene_RecordAudio.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Scene_RecordAudio 6 | 7 | 8 | 9 | 0 10 | 0 11 | 400 12 | 300 13 | 14 | 15 | 16 | Form 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /trunk/src/scene/Scene_RecordVideo.cpp: -------------------------------------------------------------------------------- 1 | #include "Scene_RecordVideo.h" 2 | #include "ui_Scene_RecordVideo.h" 3 | 4 | Scene_RecordVideo::Scene_RecordVideo(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::Scene_RecordVideo) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | Scene_RecordVideo::~Scene_RecordVideo() 12 | { 13 | delete ui; 14 | } 15 | -------------------------------------------------------------------------------- /trunk/src/scene/Scene_RecordVideo.h: -------------------------------------------------------------------------------- 1 | #ifndef SCENE_RECORDVIDEO_H 2 | #define SCENE_RECORDVIDEO_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class Scene_RecordVideo; 8 | } 9 | 10 | class Scene_RecordVideo : public QWidget 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit Scene_RecordVideo(QWidget *parent = 0); 16 | ~Scene_RecordVideo(); 17 | 18 | private: 19 | Ui::Scene_RecordVideo *ui; 20 | }; 21 | 22 | #endif // SCENE_RECORDVIDEO_H 23 | -------------------------------------------------------------------------------- /trunk/src/scene/Scene_RecordVideo.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Scene_RecordVideo 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1020 10 | 449 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 50 20 | 10 21 | 661 22 | 54 23 | 24 | 25 | 26 | 27 | 28 | 29 | Camera: 30 | 31 | 32 | 33 | 34 | 35 | 36 | open camera 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 200 45 | 0 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Micro-Phone: 54 | 55 | 56 | 57 | 58 | 59 | 60 | open micro phone 61 | 62 | 63 | 64 | 65 | 66 | 67 | Qt::Horizontal 68 | 69 | 70 | 71 | 40 72 | 20 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 200 85 | 0 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /trunk/src/source/AudioSource.cpp: -------------------------------------------------------------------------------- 1 | #include "AudioSource.h" 2 | 3 | #include "MainWindow.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern MainWindow *g_mainWindow; 11 | 12 | #define AUDIO_OUPUT_SAMPLERATE ( 44100 ) 13 | #define AUDIO_OUTPUT_SAMPLETYPE ( 16 ) 14 | #define AUDIO_OUTPUT_CHANNELS ( 2 ) 15 | 16 | static void AudioDevideErrorCallback(RtError::Type type, const std::string &errorText, void *userData) 17 | { 18 | Q_UNUSED(type); 19 | Q_UNUSED(errorText); 20 | AudioCapture *cap = (AudioCapture *)userData; 21 | cap->stateChanged(AUDIO_DEVICE_STATE_ERROR); 22 | cap->stop(); 23 | } 24 | 25 | static int record(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, 26 | double streamTime, RtAudioStreamStatus status, void *userData) 27 | { 28 | Q_UNUSED(outputBuffer); 29 | Q_UNUSED(streamTime); 30 | 31 | if (status) { 32 | //xs_log_error("The output buffer ran low, likely causing a gap in the output sound."); 33 | } 34 | 35 | // qDebug() << nBufferFrames; 36 | AudioCapture *cap = (AudioCapture *)userData; 37 | cap->audioFrameAvailable(inputBuffer, nBufferFrames); 38 | 39 | return 0; 40 | } 41 | 42 | AudioCapture::AudioCapture(QObject *parent) 43 | : QThread(parent) 44 | , m_stopThread(false) 45 | { 46 | m_format.setSampleRate(AUDIO_OUPUT_SAMPLERATE); 47 | m_format.setChannelCount(AUDIO_OUTPUT_CHANNELS); 48 | m_format.setSampleSize(AUDIO_OUTPUT_SAMPLETYPE); 49 | m_format.setCodec("audio/pcm"); 50 | m_format.setByteOrder(QAudioFormat::LittleEndian); 51 | m_format.setSampleType(QAudioFormat::SignedInt); 52 | 53 | m_audioInfo = new AudioInfo(m_format, this); 54 | } 55 | 56 | AudioCapture::~AudioCapture() 57 | { 58 | 59 | } 60 | 61 | void AudioCapture::setAudioDevice(const AudioDeviceInfo &info) 62 | { 63 | m_audioDeviceInfo = info; 64 | } 65 | 66 | void AudioCapture::run() 67 | { 68 | RtAudio adc; 69 | 70 | int devId = getDeviceIdByInfo(m_audioDeviceInfo); 71 | if (devId < 0) { 72 | stateChanged(AUDIO_DEVICE_STATE_ERROR); 73 | return; 74 | } 75 | 76 | RtAudio::StreamParameters parameters; 77 | parameters.deviceId = devId; 78 | parameters.nChannels = m_format.channelCount(); 79 | parameters.firstChannel = 0; 80 | unsigned int sampleRate = m_format.sampleRate(); 81 | unsigned int bufferFrames = 1764; // 40ms per call 82 | 83 | try { 84 | adc.openStream(NULL, ¶meters, RTAUDIO_SINT16, sampleRate, &bufferFrames, &record, this, NULL, AudioDevideErrorCallback); 85 | adc.startStream(); 86 | 87 | stateChanged(AUDIO_DEVICE_STATE_OK); 88 | } catch (RtError& e) { 89 | e.printMessage(); 90 | stateChanged(AUDIO_DEVICE_STATE_ERROR); 91 | return; 92 | } 93 | 94 | while (!m_stopThread) { 95 | msleep(50); 96 | } 97 | 98 | 99 | // clean 100 | try { 101 | adc.stopStream(); 102 | } catch (RtError& e) { 103 | e.printMessage(); 104 | } 105 | 106 | if ( adc.isStreamOpen() ) { 107 | adc.closeStream(); 108 | } 109 | } 110 | 111 | void AudioCapture::stop() 112 | { 113 | m_stopThread = true; 114 | } 115 | 116 | QList AudioCapture::getAudioDevice() 117 | { 118 | QList devs; 119 | RtAudio adc; 120 | int count = adc.getDeviceCount(); 121 | for (int i = 0; i < count; ++i) { 122 | RtAudio::DeviceInfo dev = adc.getDeviceInfo(i); 123 | if (dev.inputChannels >= 2) { 124 | AudioDeviceInfo info; 125 | info.deviceId = i; 126 | 127 | #ifdef Q_OS_WIN 128 | info.deviceName = QString::fromStdString(dev.name); 129 | #else 130 | QByteArray ba(dev.name.data(), dev.name.size()); 131 | info.deviceName = Utils::gb2312ToUtf8(ba); 132 | #endif 133 | devs << info; 134 | } 135 | } 136 | 137 | return devs; 138 | } 139 | 140 | void AudioCapture::stateChanged(int state) 141 | { 142 | if (state == AUDIO_DEVICE_STATE_ERROR) { 143 | quint32 volume = 0; 144 | quint32 amp = m_audioInfo->getAmplitude(); 145 | 146 | emit audioVolumeChanged(volume, amp); 147 | } 148 | 149 | emit audioStateChanged(state); 150 | } 151 | 152 | void AudioCapture::audioFrameAvailable(void *inputBuffer, unsigned int nBufferFrames) 153 | { 154 | QByteArray data((char*)inputBuffer, nBufferFrames * 4); 155 | 156 | #if 0 157 | m_cachedData.append(data); 158 | if (m_cachedData.size() >= CACHE_SIZE) { 159 | (void)m_audioInfo->writeData(m_cachedData.constData(), m_cachedData.length()); 160 | quint32 volume = m_audioInfo->getValue(); 161 | quint32 amp = m_audioInfo->getAmplitude(); 162 | 163 | emit audioVolumeChanged(volume, amp); 164 | m_cachedData.clear(); 165 | } 166 | #endif 167 | 168 | (void)m_audioInfo->writeData(data.constData(), data.length()); 169 | quint32 volume = m_audioInfo->getValue(); 170 | quint32 amp = m_audioInfo->getAmplitude(); 171 | 172 | emit audioVolumeChanged(volume, amp); 173 | if (!m_stopThread) { 174 | g_mainWindow->onAudioFrameAvailable(data); 175 | } 176 | } 177 | 178 | int AudioCapture::getDeviceIdByInfo(const AudioDeviceInfo &info) 179 | { 180 | int deviceId = -1; 181 | QList devs = getAudioDevice(); 182 | for (int i = 0; i < devs.size(); ++i) { 183 | const AudioDeviceInfo &adi = devs.at(i); 184 | if (adi.deviceName == info.deviceName) { 185 | deviceId = adi.deviceId; 186 | break; 187 | } 188 | } 189 | 190 | return deviceId; 191 | } 192 | 193 | AudioInfo::AudioInfo(const QAudioFormat &format, QObject *parent) 194 | : QObject(parent) 195 | , m_format(format) 196 | , m_maxAmplitude(0) 197 | 198 | { 199 | switch (m_format.sampleSize()) { 200 | case 8: 201 | switch (m_format.sampleType()) { 202 | case QAudioFormat::UnSignedInt: 203 | m_maxAmplitude = 255; 204 | break; 205 | case QAudioFormat::SignedInt: 206 | m_maxAmplitude = 127; 207 | break; 208 | default: 209 | break; 210 | } 211 | break; 212 | case 16: 213 | switch (m_format.sampleType()) { 214 | case QAudioFormat::UnSignedInt: 215 | m_maxAmplitude = 65535; 216 | break; 217 | case QAudioFormat::SignedInt: 218 | m_maxAmplitude = 32767; 219 | break; 220 | default: 221 | break; 222 | } 223 | break; 224 | 225 | case 32: 226 | switch (m_format.sampleType()) { 227 | case QAudioFormat::UnSignedInt: 228 | m_maxAmplitude = 0xffffffff; 229 | break; 230 | case QAudioFormat::SignedInt: 231 | m_maxAmplitude = 0x7fffffff; 232 | break; 233 | case QAudioFormat::Float: 234 | m_maxAmplitude = 0x7fffffff; // Kind of 235 | default: 236 | break; 237 | } 238 | break; 239 | 240 | default: 241 | break; 242 | } 243 | } 244 | 245 | AudioInfo::~AudioInfo() 246 | { 247 | 248 | } 249 | 250 | qint64 AudioInfo::writeData(const char *data, qint64 len) 251 | { 252 | if (m_maxAmplitude) { 253 | Q_ASSERT(m_format.sampleSize() % 8 == 0); 254 | const int channelBytes = m_format.sampleSize() / 8; 255 | const int sampleBytes = m_format.channelCount() * channelBytes; 256 | Q_ASSERT(len % sampleBytes == 0); 257 | const int numSamples = len / sampleBytes; 258 | 259 | quint32 maxValue = 0; 260 | const unsigned char *ptr = reinterpret_cast(data); 261 | 262 | for (int i = 0; i < numSamples; ++i) { 263 | for (int j = 0; j < m_format.channelCount(); ++j) { 264 | quint32 value = 0; 265 | 266 | if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::UnSignedInt) { 267 | value = *reinterpret_cast(ptr); 268 | } else if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::SignedInt) { 269 | value = qAbs(*reinterpret_cast(ptr)); 270 | } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::UnSignedInt) { 271 | if (m_format.byteOrder() == QAudioFormat::LittleEndian) 272 | value = qFromLittleEndian(ptr); 273 | else 274 | value = qFromBigEndian(ptr); 275 | } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::SignedInt) { 276 | if (m_format.byteOrder() == QAudioFormat::LittleEndian) 277 | value = qAbs(qFromLittleEndian(ptr)); 278 | else 279 | value = qAbs(qFromBigEndian(ptr)); 280 | } else if (m_format.sampleSize() == 32 && m_format.sampleType() == QAudioFormat::UnSignedInt) { 281 | if (m_format.byteOrder() == QAudioFormat::LittleEndian) 282 | value = qFromLittleEndian(ptr); 283 | else 284 | value = qFromBigEndian(ptr); 285 | } else if (m_format.sampleSize() == 32 && m_format.sampleType() == QAudioFormat::SignedInt) { 286 | if (m_format.byteOrder() == QAudioFormat::LittleEndian) 287 | value = qAbs(qFromLittleEndian(ptr)); 288 | else 289 | value = qAbs(qFromBigEndian(ptr)); 290 | } else if (m_format.sampleSize() == 32 && m_format.sampleType() == QAudioFormat::Float) { 291 | value = qAbs(*reinterpret_cast(ptr) * 0x7fffffff); // assumes 0-1.0 292 | } 293 | 294 | maxValue = qMax(value, maxValue); 295 | ptr += channelBytes; 296 | } 297 | } 298 | 299 | maxValue = qMin(maxValue, m_maxAmplitude); 300 | m_maxValue = maxValue; 301 | } 302 | 303 | return len; 304 | } 305 | -------------------------------------------------------------------------------- /trunk/src/source/AudioSource.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIOSOURCE_HPP 2 | #define AUDIOSOURCE_HPP 3 | 4 | #include "RtAudio.h" 5 | 6 | #include 7 | #include 8 | 9 | #define AUDIO_DEVICE_STATE_ERROR ( -1 ) 10 | #define AUDIO_DEVICE_STATE_OK ( 0 ) 11 | 12 | class QTimer; 13 | class AudioInfo; 14 | 15 | struct AudioDeviceInfo { 16 | 17 | AudioDeviceInfo() 18 | { 19 | deviceId = -1; 20 | } 21 | 22 | bool operator==(const AudioDeviceInfo & other) const 23 | { 24 | return other.deviceId == deviceId 25 | && other.deviceName == deviceName; 26 | } 27 | 28 | QString deviceName; 29 | int deviceId; 30 | }; 31 | 32 | class AudioCapture : public QThread 33 | { 34 | Q_OBJECT 35 | public: 36 | AudioCapture(QObject *parent = 0); 37 | ~AudioCapture(); 38 | 39 | void setAudioDevice(const AudioDeviceInfo &info); 40 | void run(); 41 | void stop(); 42 | 43 | static QList getAudioDevice(); 44 | 45 | public: 46 | void stateChanged(int state); 47 | void audioFrameAvailable(void *inputBuffer, unsigned int nBufferFrames); 48 | 49 | private: 50 | int getDeviceIdByInfo(const AudioDeviceInfo &info); 51 | 52 | signals: 53 | void audioStateChanged(int state); 54 | void audioFrameAvailable(const QByteArray &data); 55 | void audioVolumeChanged(quint32 value, quint32 max); 56 | 57 | private: 58 | AudioInfo *m_audioInfo; 59 | QAudioFormat m_format; 60 | bool m_stopThread; 61 | AudioDeviceInfo m_audioDeviceInfo; 62 | QByteArray m_cachedData; 63 | }; 64 | 65 | class AudioInfo : public QObject 66 | { 67 | Q_OBJECT 68 | 69 | public: 70 | AudioInfo(const QAudioFormat &format, QObject *parent); 71 | ~AudioInfo(); 72 | 73 | inline quint32 getAmplitude() const { return m_maxAmplitude; } 74 | inline quint32 getValue() const { return m_maxValue; } 75 | 76 | qint64 writeData(const char *data, qint64 len); 77 | 78 | private: 79 | const QAudioFormat m_format; 80 | quint32 m_maxAmplitude; 81 | quint32 m_maxValue; 82 | }; 83 | 84 | #endif // AUDIOSOURCE_HPP 85 | -------------------------------------------------------------------------------- /trunk/src/source/VideoSurface.cpp: -------------------------------------------------------------------------------- 1 | #include "VideoSurface.h" 2 | 3 | #include 4 | 5 | VideoSurface::VideoSurface(QObject *parent) : QAbstractVideoSurface(parent) 6 | { 7 | 8 | } 9 | 10 | bool VideoSurface::present(const QVideoFrame &frame) 11 | { 12 | QImage::Format fmt = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()); 13 | if (fmt == QImage::Format_Invalid) { 14 | return true; 15 | } 16 | 17 | QVideoFrame &_frame = const_cast (frame); 18 | if (_frame.map(QAbstractVideoBuffer::ReadOnly)) { 19 | 20 | qDebug() << _frame.pixelFormat() << _frame.size() << fmt; 21 | 22 | if (m_cachedImage.size() != frame.size()) { 23 | m_cachedImage = QImage(_frame.size(), fmt); 24 | } 25 | 26 | memcpy(m_cachedImage.bits(), _frame.bits(), m_cachedImage.byteCount()); 27 | 28 | 29 | _frame.unmap(); 30 | 31 | QImage img = m_cachedImage.mirrored(false, true); 32 | emit image(img); 33 | //emit image(m_cachedImage); 34 | } 35 | 36 | return true; 37 | } 38 | 39 | QList VideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const 40 | { 41 | Q_UNUSED(type); 42 | 43 | QList px; 44 | 45 | px << QVideoFrame::Format_Invalid; 46 | px << QVideoFrame::Format_ARGB32; 47 | px << QVideoFrame::Format_ARGB32_Premultiplied; 48 | px << QVideoFrame::Format_RGB24; 49 | px << QVideoFrame::Format_RGB32; 50 | px << QVideoFrame::Format_RGB565; 51 | px << QVideoFrame::Format_RGB555; 52 | px << QVideoFrame::Format_ARGB8565_Premultiplied; 53 | px << QVideoFrame::Format_BGRA32; 54 | px << QVideoFrame::Format_BGRA32_Premultiplied; 55 | px << QVideoFrame::Format_BGR32; 56 | px << QVideoFrame::Format_BGR24; 57 | px << QVideoFrame::Format_BGR565; 58 | px << QVideoFrame::Format_BGR555; 59 | px << QVideoFrame::Format_BGRA5658_Premultiplied; 60 | px << QVideoFrame::Format_AYUV444; 61 | px << QVideoFrame::Format_AYUV444_Premultiplied; 62 | px << QVideoFrame::Format_YUV444; 63 | px << QVideoFrame::Format_YUV420P; 64 | px << QVideoFrame::Format_YV12; 65 | px << QVideoFrame::Format_UYVY; 66 | px << QVideoFrame::Format_YUYV; 67 | px << QVideoFrame::Format_NV12; 68 | px << QVideoFrame::Format_NV21; 69 | px << QVideoFrame::Format_IMC1; 70 | px << QVideoFrame::Format_IMC2; 71 | px << QVideoFrame::Format_IMC3; 72 | px << QVideoFrame::Format_IMC4; 73 | px << QVideoFrame::Format_Y8; 74 | px << QVideoFrame::Format_Y16; 75 | px << QVideoFrame::Format_Jpeg; 76 | px << QVideoFrame::Format_CameraRaw; 77 | px << QVideoFrame::Format_AdobeDng; 78 | 79 | return px; 80 | } 81 | -------------------------------------------------------------------------------- /trunk/src/source/VideoSurface.h: -------------------------------------------------------------------------------- 1 | #ifndef VIDEOSURFACE_H 2 | #define VIDEOSURFACE_H 3 | 4 | #include 5 | 6 | class VideoSurface : public QAbstractVideoSurface 7 | { 8 | Q_OBJECT 9 | public: 10 | explicit VideoSurface(QObject *parent = 0); 11 | 12 | bool present(const QVideoFrame &frame); 13 | QList supportedPixelFormats(QAbstractVideoBuffer::HandleType type = QAbstractVideoBuffer::NoHandle) const; 14 | 15 | signals: 16 | void image(const QImage &img); 17 | 18 | public slots: 19 | 20 | private: 21 | QImage m_cachedImage; 22 | }; 23 | 24 | #endif // VIDEOSURFACE_H 25 | -------------------------------------------------------------------------------- /trunk/src/widgets/MenuButton.cpp: -------------------------------------------------------------------------------- 1 | #include "MenuButton.h" 2 | 3 | #include 4 | 5 | class MenuButtonPrivate 6 | { 7 | public: 8 | MenuButtonPrivate() 9 | : normal(true) 10 | , hover(false) 11 | , pressed(false) 12 | { 13 | 14 | } 15 | 16 | void paint(QPainter *painter, const QPixmap &pix, const QString &text, const QColor &textColor, const QRect &r) 17 | { 18 | painter->save(); 19 | if (true) { 20 | painter->translate(QPoint(18, 0)); 21 | QRect r(0, 0, pix.width(), r.height()); 22 | QRect pr(0, 0, pix.width(), pix.height()); 23 | pr.moveCenter(r.center()); 24 | 25 | painter->drawPixmap(pr, pix); 26 | } 27 | painter->restore(); 28 | 29 | painter->save(); 30 | if (true) { 31 | painter->translate(QPoint(51, 0)); 32 | 33 | QFontMetrics fmt(painter->font()); 34 | int textWidth = fmt.width(text); 35 | QRectF textRect(0, 0, textWidth, r.height()); 36 | 37 | painter->setPen(textColor); 38 | painter->drawText(textRect, text, QTextOption(Qt::AlignVCenter)); 39 | } 40 | painter->restore(); 41 | } 42 | 43 | MenuButton::MenuButtonData data; 44 | 45 | bool normal; 46 | bool hover; 47 | bool pressed; 48 | }; 49 | 50 | MenuButton::MenuButton(QWidget *parent) 51 | : QPushButton(parent) 52 | , impl(new MenuButtonPrivate) 53 | { 54 | 55 | } 56 | 57 | MenuButton::~MenuButton() 58 | { 59 | delete impl; 60 | } 61 | 62 | void MenuButton::setInfo(const MenuButtonData &data) 63 | { 64 | impl->data = data; 65 | 66 | update(); 67 | } 68 | 69 | void MenuButton::setCheck(bool checked) 70 | { 71 | impl->pressed = checked; 72 | 73 | if (!checked) { 74 | impl->normal = true; 75 | impl->hover = false; 76 | } 77 | 78 | update(); 79 | } 80 | 81 | void MenuButton::enterEvent(QEvent *e) 82 | { 83 | if (!impl->pressed) { 84 | impl->hover = true; 85 | impl->normal = false; 86 | } 87 | 88 | update(); 89 | 90 | QPushButton::enterEvent(e); 91 | } 92 | 93 | void MenuButton::leaveEvent(QEvent *e) 94 | { 95 | if (!impl->pressed) { 96 | impl->hover = false; 97 | impl->normal = true; 98 | } 99 | 100 | update(); 101 | 102 | QPushButton::leaveEvent(e); 103 | } 104 | 105 | void MenuButton::paintEvent(QPaintEvent *) 106 | { 107 | QPainter p(this); 108 | 109 | if (impl->pressed) { 110 | p.fillRect(rect(), impl->data.pressedBackgroundColor); 111 | impl->paint(&p, impl->data.pressPix, text(), impl->data.pressTextColor, rect()); 112 | } else if (impl->normal) { 113 | p.fillRect(rect(), impl->data.normalBackgroundColor); 114 | impl->paint(&p, impl->data.normalPix, text(), impl->data.normalTextColor, rect()); 115 | } else if (impl->hover) { 116 | p.fillRect(rect(), impl->data.normalBackgroundColor); 117 | impl->paint(&p, impl->data.hoverPix, text(), impl->data.hoverTextColor, rect()); 118 | } 119 | } 120 | 121 | class MenuButtonGroupPrivate 122 | { 123 | public: 124 | QList btns; 125 | }; 126 | 127 | MenuButtonGroup::MenuButtonGroup(QObject *parent) 128 | : QObject(parent) 129 | , impl(new MenuButtonGroupPrivate) 130 | { 131 | 132 | } 133 | 134 | MenuButtonGroup::~MenuButtonGroup() 135 | { 136 | delete impl; 137 | } 138 | 139 | void MenuButtonGroup::addButton(MenuButton *btn) 140 | { 141 | impl->btns << btn; 142 | 143 | connect(btn, SIGNAL(clicked(bool)), this, SLOT(onButtonClicked())); 144 | } 145 | 146 | void MenuButtonGroup::onButtonClicked() 147 | { 148 | MenuButton *btn = dynamic_cast (sender()); 149 | if (!btn) { 150 | return; 151 | } 152 | 153 | for (int i = 0; i < impl->btns.size(); ++i) { 154 | MenuButton *m = impl->btns.at(i); 155 | if (m != btn) { 156 | m->setCheck(false); 157 | } 158 | } 159 | 160 | btn->setCheck(true); 161 | } 162 | -------------------------------------------------------------------------------- /trunk/src/widgets/MenuButton.h: -------------------------------------------------------------------------------- 1 | #ifndef MENUBUTTON_H 2 | #define MENUBUTTON_H 3 | 4 | #include 5 | 6 | class MenuButtonPrivate; 7 | 8 | class MenuButton : public QPushButton 9 | { 10 | Q_OBJECT 11 | public: 12 | 13 | struct MenuButtonData { 14 | QPixmap normalPix; 15 | QPixmap hoverPix; 16 | QPixmap pressPix; 17 | 18 | QColor normalTextColor; 19 | QColor hoverTextColor; 20 | QColor pressTextColor; 21 | QColor pressedBackgroundColor; 22 | QColor normalBackgroundColor; 23 | }; 24 | 25 | explicit MenuButton(QWidget *parent = 0); 26 | ~MenuButton(); 27 | 28 | void setInfo(const MenuButtonData &data); 29 | void setCheck(bool checked); 30 | 31 | protected: 32 | void enterEvent(QEvent *e); 33 | void leaveEvent(QEvent *e); 34 | 35 | protected: 36 | void paintEvent(QPaintEvent *); 37 | 38 | private: 39 | MenuButtonPrivate* impl; 40 | }; 41 | 42 | class MenuButtonGroupPrivate; 43 | class MenuButtonGroup : public QObject 44 | { 45 | Q_OBJECT 46 | public: 47 | explicit MenuButtonGroup(QObject *parent = 0); 48 | ~MenuButtonGroup(); 49 | 50 | void addButton(MenuButton *btn); 51 | 52 | protected slots: 53 | void onButtonClicked(); 54 | 55 | private: 56 | MenuButtonGroupPrivate* impl; 57 | }; 58 | 59 | #endif // MENUBUTTON_H 60 | -------------------------------------------------------------------------------- /trunk/src/widgets/NavWidget.cpp: -------------------------------------------------------------------------------- 1 | #include "NavWidget.h" 2 | #include "ui_NavWidget.h" 3 | 4 | #include 5 | #include 6 | 7 | NavWidget::NavWidget(QWidget *parent) : 8 | QWidget(parent), 9 | ui(new Ui::NavWidget) 10 | { 11 | ui->setupUi(this); 12 | 13 | m_signalMapper = new QSignalMapper(this); 14 | connect(m_signalMapper, SIGNAL(mapped(QWidget*)), 15 | this, SIGNAL(tabChanged(QWidget*))); 16 | } 17 | 18 | NavWidget::~NavWidget() 19 | { 20 | delete ui; 21 | } 22 | 23 | void NavWidget::addTab(const QString &text, QWidget *w) 24 | { 25 | QPushButton *button = new QPushButton(text, this); 26 | connect(button, SIGNAL(clicked()), m_signalMapper, SLOT(map())); 27 | m_signalMapper->setMapping(button, w); 28 | 29 | ui->horizontalLayout->removeItem(ui->horizontalSpacer); 30 | ui->horizontalLayout->addWidget(button); 31 | ui->horizontalLayout->addItem(ui->horizontalSpacer); 32 | } 33 | -------------------------------------------------------------------------------- /trunk/src/widgets/NavWidget.h: -------------------------------------------------------------------------------- 1 | #ifndef NAVWIDGET_H 2 | #define NAVWIDGET_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class NavWidget; 8 | } 9 | 10 | class QSignalMapper; 11 | class NavWidget : public QWidget 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | explicit NavWidget(QWidget *parent = 0); 17 | ~NavWidget(); 18 | 19 | void addTab(const QString &text, QWidget *w); 20 | 21 | signals: 22 | void tabChanged(QWidget *w); 23 | 24 | private: 25 | Ui::NavWidget *ui; 26 | QSignalMapper *m_signalMapper; 27 | }; 28 | 29 | #endif // NAVWIDGET_H 30 | -------------------------------------------------------------------------------- /trunk/src/widgets/NavWidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | NavWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 568 10 | 41 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | Qt::Horizontal 21 | 22 | 23 | 24 | 547 25 | 20 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | --------------------------------------------------------------------------------