Add initial bits for Qt6 support
[carla.git] / source / modules / rtaudio.diff
blobb44015e21a4a07219a567138a400b3932e9d3433
1 diff --git a/RtAudio.cpp b/RtAudio.cpp
2 index 2ac2179..5fce9b2 100644
3 --- a/RtAudio.cpp
4 +++ b/RtAudio.cpp
5 @@ -76,7 +76,7 @@ const unsigned int RtApi::SAMPLE_RATES[] = {
6 return s;
9 -#elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
10 +#elif defined(__LINUX_ALSA__) || defined(__UNIX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) || defined(__HAIKU__)
11 // pthread API
12 #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
13 #define MUTEX_DESTROY(A) pthread_mutex_destroy(A)
14 @@ -110,8 +110,8 @@ void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis )
15 #if defined(__LINUX_ALSA__)
16 apis.push_back( LINUX_ALSA );
17 #endif
18 -#if defined(__LINUX_PULSE__)
19 - apis.push_back( LINUX_PULSE );
20 +#if defined(__UNIX_PULSE__)
21 + apis.push_back( UNIX_PULSE );
22 #endif
23 #if defined(__LINUX_OSS__)
24 apis.push_back( LINUX_OSS );
25 @@ -147,8 +147,8 @@ void RtAudio :: openRtApi( RtAudio::Api api )
26 if ( api == LINUX_ALSA )
27 rtapi_ = new RtApiAlsa();
28 #endif
29 -#if defined(__LINUX_PULSE__)
30 - if ( api == LINUX_PULSE )
31 +#if defined(__UNIX_PULSE__)
32 + if ( api == UNIX_PULSE )
33 rtapi_ = new RtApiPulse();
34 #endif
35 #if defined(__LINUX_OSS__)
36 @@ -222,11 +222,12 @@ void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
37 unsigned int *bufferFrames,
38 RtAudioCallback callback, void *userData,
39 RtAudio::StreamOptions *options,
40 + RtAudioBufferSizeCallback bufSizeCallback,
41 RtAudioErrorCallback errorCallback )
43 return rtapi_->openStream( outputParameters, inputParameters, format,
44 sampleRate, bufferFrames, callback,
45 - userData, options, errorCallback );
46 + userData, options, bufSizeCallback, errorCallback );
49 // *************************************************** //
50 @@ -259,6 +260,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
51 unsigned int *bufferFrames,
52 RtAudioCallback callback, void *userData,
53 RtAudio::StreamOptions *options,
54 + RtAudioBufferSizeCallback bufSizeCallback,
55 RtAudioErrorCallback errorCallback )
57 if ( stream_.state != STREAM_CLOSED ) {
58 @@ -282,7 +284,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
59 return;
62 - if ( oParams == NULL && iParams == NULL ) {
63 + if ( oParams == NULL && iParams == NULL && getCurrentApi() != RtAudio::RTAUDIO_DUMMY ) {
64 errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";
65 error( RtAudioError::INVALID_USE );
66 return;
67 @@ -340,6 +342,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
69 stream_.callbackInfo.callback = (void *) callback;
70 stream_.callbackInfo.userData = userData;
71 + stream_.callbackInfo.bufSizeCallback = (void *) bufSizeCallback;
72 stream_.callbackInfo.errorCallback = (void *) errorCallback;
74 if ( options ) options->numberOfBuffers = stream_.nBuffers;
75 @@ -1587,6 +1590,8 @@ static void *coreStopStream( void *ptr )
77 object->stopStream();
78 pthread_exit( NULL );
80 + return NULL;
83 bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
84 @@ -1925,7 +1930,7 @@ const char* RtApiCore :: getErrorCode( OSStatus code )
85 // devices are available (i.e., the JACK server is not running), a
86 // stream cannot be opened.
88 -#include <jack/jack.h>
89 +#include "jackbridge/JackBridge.hpp"
90 #include <unistd.h>
91 #include <cstdio>
93 @@ -1934,7 +1939,6 @@ const char* RtApiCore :: getErrorCode( OSStatus code )
94 struct JackHandle {
95 jack_client_t *client;
96 jack_port_t **ports[2];
97 - std::string deviceName[2];
98 bool xrun[2];
99 pthread_cond_t condition;
100 int drainCounter; // Tracks callback counts when draining
101 @@ -1944,17 +1948,9 @@ struct JackHandle {
102 :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; }
105 -#if !defined(__RTAUDIO_DEBUG__)
106 -static void jackSilentError( const char * ) {};
107 -#endif
109 RtApiJack :: RtApiJack()
110 :shouldAutoconnect_(true) {
111 // Nothing to do here.
112 -#if !defined(__RTAUDIO_DEBUG__)
113 - // Turn off Jack's internal error reporting.
114 - jack_set_error_function( &jackSilentError );
115 -#endif
118 RtApiJack :: ~RtApiJack()
119 @@ -1964,128 +1960,40 @@ RtApiJack :: ~RtApiJack()
121 unsigned int RtApiJack :: getDeviceCount( void )
123 - // See if we can become a jack client.
124 - jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption;
125 - jack_status_t *status = NULL;
126 - jack_client_t *client = jack_client_open( "RtApiJackCount", options, status );
127 - if ( client == 0 ) return 0;
129 - const char **ports;
130 - std::string port, previousPort;
131 - unsigned int nChannels = 0, nDevices = 0;
132 - ports = jack_get_ports( client, NULL, NULL, 0 );
133 - if ( ports ) {
134 - // Parse the port names up to the first colon (:).
135 - size_t iColon = 0;
136 - do {
137 - port = (char *) ports[ nChannels ];
138 - iColon = port.find(":");
139 - if ( iColon != std::string::npos ) {
140 - port = port.substr( 0, iColon + 1 );
141 - if ( port != previousPort ) {
142 - nDevices++;
143 - previousPort = port;
146 - } while ( ports[++nChannels] );
147 - free( ports );
150 - jack_client_close( client );
151 - return nDevices;
152 + return 2;
155 RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
157 - RtAudio::DeviceInfo info;
158 - info.probed = false;
159 + static RtAudio::DeviceInfo devInfo[3];
161 - jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption
162 - jack_status_t *status = NULL;
163 - jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status );
164 - if ( client == 0 ) {
165 - errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!";
166 - error( RtAudioError::WARNING );
167 - return info;
170 - const char **ports;
171 - std::string port, previousPort;
172 - unsigned int nPorts = 0, nDevices = 0;
173 - ports = jack_get_ports( client, NULL, NULL, 0 );
174 - if ( ports ) {
175 - // Parse the port names up to the first colon (:).
176 - size_t iColon = 0;
177 - do {
178 - port = (char *) ports[ nPorts ];
179 - iColon = port.find(":");
180 - if ( iColon != std::string::npos ) {
181 - port = port.substr( 0, iColon );
182 - if ( port != previousPort ) {
183 - if ( nDevices == device ) info.name = port;
184 - nDevices++;
185 - previousPort = port;
188 - } while ( ports[++nPorts] );
189 - free( ports );
192 - if ( device >= nDevices ) {
193 - jack_client_close( client );
194 - errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";
195 - error( RtAudioError::INVALID_USE );
196 - return info;
199 - // Get the current jack server sample rate.
200 - info.sampleRates.clear();
202 - info.preferredSampleRate = jack_get_sample_rate( client );
203 - info.sampleRates.push_back( info.preferredSampleRate );
205 - // Count the available ports containing the client name as device
206 - // channels. Jack "input ports" equal RtAudio output channels.
207 - unsigned int nChannels = 0;
208 - ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsInput );
209 - if ( ports ) {
210 - while ( ports[ nChannels ] ) nChannels++;
211 - free( ports );
212 - info.outputChannels = nChannels;
215 - // Jack "output ports" equal RtAudio input channels.
216 - nChannels = 0;
217 - ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsOutput );
218 - if ( ports ) {
219 - while ( ports[ nChannels ] ) nChannels++;
220 - free( ports );
221 - info.inputChannels = nChannels;
222 + if (! devInfo[0].probed)
224 + devInfo[0].probed = devInfo[1].probed = true;
225 + devInfo[0].outputChannels = devInfo[1].outputChannels = 2;
226 + devInfo[0].inputChannels = devInfo[1].inputChannels = 2;
227 + devInfo[0].duplexChannels = devInfo[1].duplexChannels = 2;
228 + devInfo[0].isDefaultOutput = devInfo[1].isDefaultOutput = true;
229 + devInfo[0].isDefaultInput = devInfo[1].isDefaultInput = true;
230 + devInfo[0].nativeFormats = devInfo[1].nativeFormats = RTAUDIO_FLOAT32;
231 + devInfo[0].name = "Auto-connect ON";
232 + devInfo[1].name = "Auto-connect OFF";
235 - if ( info.outputChannels == 0 && info.inputChannels == 0 ) {
236 - jack_client_close(client);
237 - errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!";
238 - error( RtAudioError::WARNING );
239 - return info;
241 + if (device > 2)
242 + device = 2;
244 - // If device opens for both playback and capture, we determine the channels.
245 - if ( info.outputChannels > 0 && info.inputChannels > 0 )
246 - info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
247 + return devInfo[device];
250 - // Jack always uses 32-bit floats.
251 - info.nativeFormats = RTAUDIO_FLOAT32;
252 +static int jackBufferSizeHandler( jack_nframes_t nframes, void *infoPointer )
254 + CallbackInfo *info = (CallbackInfo *) infoPointer;
256 - // Jack doesn't provide default devices so we'll use the first available one.
257 - if ( device == 0 && info.outputChannels > 0 )
258 - info.isDefaultOutput = true;
259 - if ( device == 0 && info.inputChannels > 0 )
260 - info.isDefaultInput = true;
261 + RtApiJack *object = (RtApiJack *) info->object;
262 + if ( object->bufferSizeEvent( (unsigned long) nframes ) == false ) return 1;
264 - jack_client_close(client);
265 - info.probed = true;
266 - return info;
267 + return 0;
270 static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
271 @@ -2101,7 +2009,7 @@ static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
272 // This function will be called by a spawned thread when the Jack
273 // server signals that it is shutting down. It is necessary to handle
274 // it this way because the jackShutdown() function must return before
275 -// the jack_deactivate() function (in closeStream()) will return.
276 +// the jackbridge_deactivate() function (in closeStream()) will return.
277 static void *jackCloseStream( void *ptr )
279 CallbackInfo *info = (CallbackInfo *) ptr;
280 @@ -2110,6 +2018,8 @@ static void *jackCloseStream( void *ptr )
281 object->closeStream();
283 pthread_exit( NULL );
285 + return NULL;
287 static void jackShutdown( void *infoPointer )
289 @@ -2139,7 +2049,7 @@ static int jackXrun( void *infoPointer )
292 bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
293 - unsigned int firstChannel, unsigned int sampleRate,
294 + unsigned int firstChannel, unsigned int,
295 RtAudioFormat format, unsigned int *bufferSize,
296 RtAudio::StreamOptions *options )
298 @@ -2151,9 +2061,9 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
299 jack_options_t jackoptions = (jack_options_t) ( JackNoStartServer ); //JackNullOption;
300 jack_status_t *status = NULL;
301 if ( options && !options->streamName.empty() )
302 - client = jack_client_open( options->streamName.c_str(), jackoptions, status );
303 + client = jackbridge_client_open( options->streamName.c_str(), jackoptions, status );
304 else
305 - client = jack_client_open( "RtApiJack", jackoptions, status );
306 + client = jackbridge_client_open( "Carla", jackoptions, status );
307 if ( client == 0 ) {
308 errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!";
309 error( RtAudioError::WARNING );
310 @@ -2165,75 +2075,24 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
311 client = handle->client;
314 - const char **ports;
315 - std::string port, previousPort, deviceName;
316 - unsigned int nPorts = 0, nDevices = 0;
317 - ports = jack_get_ports( client, NULL, NULL, 0 );
318 - if ( ports ) {
319 - // Parse the port names up to the first colon (:).
320 - size_t iColon = 0;
321 - do {
322 - port = (char *) ports[ nPorts ];
323 - iColon = port.find(":");
324 - if ( iColon != std::string::npos ) {
325 - port = port.substr( 0, iColon );
326 - if ( port != previousPort ) {
327 - if ( nDevices == device ) deviceName = port;
328 - nDevices++;
329 - previousPort = port;
332 - } while ( ports[++nPorts] );
333 - free( ports );
336 - if ( device >= nDevices ) {
337 - errorText_ = "RtApiJack::probeDeviceOpen: device ID is invalid!";
338 - return FAILURE;
341 - // Count the available ports containing the client name as device
342 - // channels. Jack "input ports" equal RtAudio output channels.
343 - unsigned int nChannels = 0;
344 - unsigned long flag = JackPortIsInput;
345 - if ( mode == INPUT ) flag = JackPortIsOutput;
346 - ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
347 - if ( ports ) {
348 - while ( ports[ nChannels ] ) nChannels++;
349 - free( ports );
352 - // Compare the jack ports for specified client to the requested number of channels.
353 - if ( nChannels < (channels + firstChannel) ) {
354 - errorStream_ << "RtApiJack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ").";
355 - errorText_ = errorStream_.str();
356 - return FAILURE;
359 // Check the jack server sample rate.
360 - unsigned int jackRate = jack_get_sample_rate( client );
361 - if ( sampleRate != jackRate ) {
362 - jack_client_close( client );
363 - errorStream_ << "RtApiJack::probeDeviceOpen: the requested sample rate (" << sampleRate << ") is different than the JACK server rate (" << jackRate << ").";
364 - errorText_ = errorStream_.str();
365 - return FAILURE;
367 - stream_.sampleRate = jackRate;
368 + stream_.sampleRate = jackbridge_get_sample_rate( client );
370 // Get the latency of the JACK port.
371 - ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
372 + const char **ports;
373 + ports = jackbridge_get_ports( client, "system:", NULL, JackPortIsInput );
374 if ( ports[ firstChannel ] ) {
375 // Added by Ge Wang
376 jack_latency_callback_mode_t cbmode = (mode == INPUT ? JackCaptureLatency : JackPlaybackLatency);
377 // the range (usually the min and max are equal)
378 jack_latency_range_t latrange; latrange.min = latrange.max = 0;
379 // get the latency range
380 - jack_port_get_latency_range( jack_port_by_name( client, ports[firstChannel] ), cbmode, &latrange );
381 + jackbridge_port_get_latency_range( jackbridge_port_by_name( client, ports[firstChannel] ), cbmode, &latrange );
382 // be optimistic, use the min!
383 stream_.latency[mode] = latrange.min;
384 - //stream_.latency[mode] = jack_port_get_latency( jack_port_by_name( client, ports[ firstChannel ] ) );
385 + //stream_.latency[mode] = jack_port_get_latency( jackbridge_port_by_name( client, ports[ firstChannel ] ) );
387 - free( ports );
388 + jackbridge_free( ports );
390 // The jack server always uses 32-bit floating-point data.
391 stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
392 @@ -2250,7 +2109,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
394 // Get the buffer size. The buffer size and number of buffers
395 // (periods) is set when the jack server is started.
396 - stream_.bufferSize = (int) jack_get_buffer_size( client );
397 + stream_.bufferSize = (int) jackbridge_get_buffer_size( client );
398 *bufferSize = stream_.bufferSize;
400 stream_.nDeviceChannels[mode] = channels;
401 @@ -2281,11 +2140,10 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
402 stream_.apiHandle = (void *) handle;
403 handle->client = client;
405 - handle->deviceName[mode] = deviceName;
407 // Allocate necessary internal buffers.
408 unsigned long bufferBytes;
409 - bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
410 + bufferBytes = stream_.nUserChannels[mode] * 8192 * formatBytes( stream_.userFormat );
411 stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
412 if ( stream_.userBuffer[mode] == NULL ) {
413 errorText_ = "RtApiJack::probeDeviceOpen: error allocating user buffer memory.";
414 @@ -2306,7 +2164,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
417 if ( makeBuffer ) {
418 - bufferBytes *= *bufferSize;
419 + bufferBytes *= 8192;
420 if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
421 stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
422 if ( stream_.deviceBuffer == NULL ) {
423 @@ -2333,28 +2191,34 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
424 stream_.mode = DUPLEX;
425 else {
426 stream_.mode = mode;
427 - jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo );
428 - jack_set_xrun_callback( handle->client, jackXrun, (void *) &stream_.apiHandle );
429 - jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo );
430 + jackbridge_set_buffer_size_callback( handle->client, jackBufferSizeHandler, (void *) &stream_.callbackInfo );
431 + jackbridge_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo );
432 + jackbridge_set_xrun_callback( handle->client, jackXrun, (void *) &stream_.apiHandle );
433 + jackbridge_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo );
436 // Register our ports.
437 char label[64];
438 if ( mode == OUTPUT ) {
439 for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
440 - snprintf( label, 64, "outport %d", i );
441 - handle->ports[0][i] = jack_port_register( handle->client, (const char *)label,
442 + snprintf( label, 64, "audio-out%d", i+1 );
443 + handle->ports[0][i] = jackbridge_port_register( handle->client, (const char *)label,
444 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
447 else {
448 for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
449 - snprintf( label, 64, "inport %d", i );
450 - handle->ports[1][i] = jack_port_register( handle->client, (const char *)label,
451 + snprintf( label, 64, "audio-in%d", i+1 );
452 + handle->ports[1][i] = jackbridge_port_register( handle->client, (const char *)label,
453 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
457 + // auto-connect-off "device" is at index 1
458 + shouldAutoconnect_ = (device != 1 &&
459 + std::getenv("LADISH_APP_NAME") == nullptr &&
460 + std::getenv("NSM_URL") == nullptr);
462 // Setup the buffer conversion information structure. We don't use
463 // buffers to do channel offsets, so we override that parameter
464 // here.
465 @@ -2367,7 +2231,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
466 error:
467 if ( handle ) {
468 pthread_cond_destroy( &handle->condition );
469 - jack_client_close( handle->client );
470 + jackbridge_client_close( handle->client );
472 if ( handle->ports[0] ) free( handle->ports[0] );
473 if ( handle->ports[1] ) free( handle->ports[1] );
474 @@ -2403,9 +2267,9 @@ void RtApiJack :: closeStream( void )
475 if ( handle ) {
477 if ( stream_.state == STREAM_RUNNING )
478 - jack_deactivate( handle->client );
479 + jackbridge_deactivate( handle->client );
481 - jack_client_close( handle->client );
482 + jackbridge_client_close( handle->client );
485 if ( handle ) {
486 @@ -2442,8 +2306,8 @@ void RtApiJack :: startStream( void )
489 JackHandle *handle = (JackHandle *) stream_.apiHandle;
490 - int result = jack_activate( handle->client );
491 - if ( result ) {
492 + bool result = jackbridge_activate( handle->client );
493 + if ( ! result ) {
494 errorText_ = "RtApiJack::startStream(): unable to activate JACK client!";
495 goto unlock;
497 @@ -2452,8 +2316,8 @@ void RtApiJack :: startStream( void )
499 // Get the list of available ports.
500 if ( shouldAutoconnect_ && (stream_.mode == OUTPUT || stream_.mode == DUPLEX) ) {
501 - result = 1;
502 - ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);
503 + result = false;
504 + ports = jackbridge_get_ports( handle->client, "system:", NULL, JackPortIsInput);
505 if ( ports == NULL) {
506 errorText_ = "RtApiJack::startStream(): error determining available JACK input ports!";
507 goto unlock;
508 @@ -2463,21 +2327,21 @@ void RtApiJack :: startStream( void )
509 // allow the user to select particular channels of a device, we'll
510 // just open the first "nChannels" ports with offset.
511 for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
512 - result = 1;
513 + result = false;
514 if ( ports[ stream_.channelOffset[0] + i ] )
515 - result = jack_connect( handle->client, jack_port_name( handle->ports[0][i] ), ports[ stream_.channelOffset[0] + i ] );
516 - if ( result ) {
517 - free( ports );
518 + result = jackbridge_connect( handle->client, jackbridge_port_name( handle->ports[0][i] ), ports[ stream_.channelOffset[0] + i ] );
519 + if ( ! result ) {
520 + jackbridge_free( ports );
521 errorText_ = "RtApiJack::startStream(): error connecting output ports!";
522 goto unlock;
525 - free(ports);
526 + jackbridge_free(ports);
529 if ( shouldAutoconnect_ && (stream_.mode == INPUT || stream_.mode == DUPLEX) ) {
530 - result = 1;
531 - ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput );
532 + result = false;
533 + ports = jackbridge_get_ports( handle->client, "system:", NULL, JackPortIsOutput );
534 if ( ports == NULL) {
535 errorText_ = "RtApiJack::startStream(): error determining available JACK output ports!";
536 goto unlock;
537 @@ -2485,16 +2349,16 @@ void RtApiJack :: startStream( void )
539 // Now make the port connections. See note above.
540 for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
541 - result = 1;
542 + result = false;
543 if ( ports[ stream_.channelOffset[1] + i ] )
544 - result = jack_connect( handle->client, ports[ stream_.channelOffset[1] + i ], jack_port_name( handle->ports[1][i] ) );
545 - if ( result ) {
546 - free( ports );
547 + result = jackbridge_connect( handle->client, ports[ stream_.channelOffset[1] + i ], jackbridge_port_name( handle->ports[1][i] ) );
548 + if ( ! result ) {
549 + jackbridge_free( ports );
550 errorText_ = "RtApiJack::startStream(): error connecting input ports!";
551 goto unlock;
554 - free(ports);
555 + jackbridge_free(ports);
558 handle->drainCounter = 0;
559 @@ -2502,7 +2366,7 @@ void RtApiJack :: startStream( void )
560 stream_.state = STREAM_RUNNING;
562 unlock:
563 - if ( result == 0 ) return;
564 + if ( result ) return;
565 error( RtAudioError::SYSTEM_ERROR );
568 @@ -2524,7 +2388,7 @@ void RtApiJack :: stopStream( void )
572 - jack_deactivate( handle->client );
573 + jackbridge_deactivate( handle->client );
574 stream_.state = STREAM_STOPPED;
577 @@ -2546,7 +2410,7 @@ void RtApiJack :: abortStream( void )
578 // This function will be called by a spawned thread when the user
579 // callback function signals that the stream should be stopped or
580 // aborted. It is necessary to handle it this way because the
581 -// callbackEvent() function must return before the jack_deactivate()
582 +// callbackEvent() function must return before the jackbridge_deactivate()
583 // function will return.
584 static void *jackStopStream( void *ptr )
586 @@ -2555,6 +2419,8 @@ static void *jackStopStream( void *ptr )
588 object->stopStream();
589 pthread_exit( NULL );
591 + return NULL;
594 bool RtApiJack :: callbackEvent( unsigned long nframes )
595 @@ -2565,8 +2431,8 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
596 error( RtAudioError::WARNING );
597 return FAILURE;
599 - if ( stream_.bufferSize != nframes ) {
600 - errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!";
601 + if ( nframes > 8192 ) {
602 + errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size is too big ... cannot process!";
603 error( RtAudioError::WARNING );
604 return FAILURE;
606 @@ -2600,7 +2466,7 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
607 handle->xrun[1] = false;
609 int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
610 - stream_.bufferSize, streamTime, status, info->userData );
611 + nframes, streamTime, status, info->userData );
612 if ( cbReturnValue == 2 ) {
613 stream_.state = STREAM_STOPPING;
614 handle->drainCounter = 2;
615 @@ -2621,7 +2487,7 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
616 if ( handle->drainCounter > 1 ) { // write zeros to the output stream
618 for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
619 - jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
620 + jackbuffer = (jack_default_audio_sample_t *) jackbridge_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
621 memset( jackbuffer, 0, bufferBytes );
624 @@ -2631,13 +2497,13 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
625 convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );
627 for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
628 - jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
629 + jackbuffer = (jack_default_audio_sample_t *) jackbridge_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
630 memcpy( jackbuffer, &stream_.deviceBuffer[i*bufferBytes], bufferBytes );
633 else { // no buffer conversion
634 for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
635 - jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
636 + jackbuffer = (jack_default_audio_sample_t *) jackbridge_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
637 memcpy( jackbuffer, &stream_.userBuffer[0][i*bufferBytes], bufferBytes );
640 @@ -2653,14 +2519,14 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
642 if ( stream_.doConvertBuffer[1] ) {
643 for ( unsigned int i=0; i<stream_.nDeviceChannels[1]; i++ ) {
644 - jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );
645 + jackbuffer = (jack_default_audio_sample_t *) jackbridge_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );
646 memcpy( &stream_.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes );
648 convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
650 else { // no buffer conversion
651 for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
652 - jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );
653 + jackbuffer = (jack_default_audio_sample_t *) jackbridge_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );
654 memcpy( &stream_.userBuffer[1][i*bufferBytes], jackbuffer, bufferBytes );
657 @@ -2670,6 +2536,26 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
658 RtApi::tickStreamTime();
659 return SUCCESS;
662 +bool RtApiJack :: bufferSizeEvent( unsigned long nframes )
664 + if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;
665 + if ( stream_.state == STREAM_CLOSED ) {
666 + errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
667 + error( RtAudioError::WARNING );
668 + return FAILURE;
670 + if ( nframes > 8192 ) {
671 + errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size is too big ... cannot process!";
672 + error( RtAudioError::WARNING );
673 + return FAILURE;
676 + CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
678 + RtAudioBufferSizeCallback callback = (RtAudioBufferSizeCallback) info->bufSizeCallback;
679 + return callback( nframes, info->userData );
681 //******************** End of __UNIX_JACK__ *********************//
682 #endif
684 @@ -2691,10 +2577,10 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
685 // on information found in
686 // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html.
688 -#include "asiosys.h"
689 -#include "asio.h"
690 -#include "iasiothiscallresolver.h"
691 -#include "asiodrivers.h"
692 +#include "asio.cpp"
693 +#include "asiodrivers.cpp"
694 +#include "asiolist.cpp"
695 +#include "iasiothiscallresolver.cpp"
696 #include <cmath>
698 static AsioDrivers drivers;
699 @@ -5487,8 +5373,8 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
700 // two. This is a judgement call and a value of two is probably too
701 // low for capture, but it should work for playback.
702 int nBuffers = 0;
703 - if ( options ) nBuffers = options->numberOfBuffers;
704 if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) nBuffers = 2;
705 + if ( options && options->numberOfBuffers > 0 ) nBuffers = options->numberOfBuffers;
706 if ( nBuffers < 2 ) nBuffers = 3;
708 // Check the lower range of the user-specified buffer size and set
709 @@ -6795,7 +6681,9 @@ unsigned int RtApiAlsa :: getDeviceCount( void )
710 nDevices++;
712 nextcard:
713 - snd_ctl_close( handle );
714 + if (result == 0) {
715 + snd_ctl_close( handle );
717 snd_card_next( &card );
720 @@ -8012,12 +7900,14 @@ static void *alsaCallbackHandler( void *ptr )
723 pthread_exit( NULL );
725 + return NULL;
728 //******************** End of __LINUX_ALSA__ *********************//
729 #endif
731 -#if defined(__LINUX_PULSE__)
732 +#if defined(__UNIX_PULSE__)
734 // Code written by Peter Meerwald, pmeerw@pmeerw.net
735 // and Tristan Matthews.
736 @@ -8092,6 +7982,8 @@ static void *pulseaudio_callback( void * user )
739 pthread_exit( NULL );
741 + return NULL;
744 void RtApiPulse::closeStream( void )
745 @@ -8502,7 +8394,7 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
746 return FAILURE;
749 -//******************** End of __LINUX_PULSE__ *********************//
750 +//******************** End of __UNIX_PULSE__ *********************//
751 #endif
753 #if defined(__LINUX_OSS__)
754 @@ -9446,6 +9338,8 @@ static void *ossCallbackHandler( void *ptr )
757 pthread_exit( NULL );
759 + return NULL;
762 //******************** End of __LINUX_OSS__ *********************//
763 diff --git a/RtAudio.h b/RtAudio.h
764 index 34a2534..289e254 100644
765 --- a/RtAudio.h
766 +++ b/RtAudio.h
767 @@ -46,16 +46,7 @@
768 #define __RTAUDIO_H
770 #define RTAUDIO_VERSION "5.0.0"
772 -#if defined _WIN32 || defined __CYGWIN__
773 - #define RTAUDIO_DLL_PUBLIC
774 -#else
775 - #if __GNUC__ >= 4
776 - #define RTAUDIO_DLL_PUBLIC __attribute__( (visibility( "default" )) )
777 - #else
778 - #define RTAUDIO_DLL_PUBLIC
779 - #endif
780 -#endif
781 +#define RTAUDIO_DLL_PUBLIC
783 #include <string>
784 #include <vector>
785 @@ -255,6 +246,9 @@ class RTAUDIO_DLL_PUBLIC RtAudioError : public std::runtime_error
787 typedef void (*RtAudioErrorCallback)( RtAudioError::Type type, const std::string &errorText );
789 +//! RtAudio buffer size change callback.
790 +typedef bool (*RtAudioBufferSizeCallback)( unsigned int bufferSize, void* userData );
792 // **************************************************************** //
794 // RtAudio class declaration.
795 @@ -278,8 +272,8 @@ class RTAUDIO_DLL_PUBLIC RtAudio
796 enum Api {
797 UNSPECIFIED, /*!< Search for a working compiled API. */
798 LINUX_ALSA, /*!< The Advanced Linux Sound Architecture API. */
799 - LINUX_PULSE, /*!< The Linux PulseAudio API. */
800 LINUX_OSS, /*!< The Linux Open Sound System API. */
801 + UNIX_PULSE, /*!< The PulseAudio API. */
802 UNIX_JACK, /*!< The Jack Low-Latency Audio Server API. */
803 MACOSX_CORE, /*!< Macintosh OS-X Core Audio API. */
804 WINDOWS_WASAPI, /*!< The Microsoft WASAPI API. */
805 @@ -416,7 +410,7 @@ class RTAUDIO_DLL_PUBLIC RtAudio
806 ~RtAudio();
808 //! Returns the audio API specifier for the current instance of RtAudio.
809 - RtAudio::Api getCurrentApi( void );
810 + RtAudio::Api getCurrentApi( void ) const;
812 //! A public function that queries for the number of audio devices available.
814 @@ -503,7 +497,9 @@ class RTAUDIO_DLL_PUBLIC RtAudio
815 RtAudio::StreamParameters *inputParameters,
816 RtAudioFormat format, unsigned int sampleRate,
817 unsigned int *bufferFrames, RtAudioCallback callback,
818 - void *userData = NULL, RtAudio::StreamOptions *options = NULL, RtAudioErrorCallback errorCallback = NULL );
819 + void *userData = NULL, RtAudio::StreamOptions *options = NULL,
820 + RtAudioBufferSizeCallback bufSizeCallback = NULL,
821 + RtAudioErrorCallback errorCallback = NULL );
823 //! A function that closes a stream and frees any associated stream memory.
825 @@ -597,7 +593,7 @@ class RTAUDIO_DLL_PUBLIC RtAudio
826 typedef uintptr_t ThreadHandle;
827 typedef CRITICAL_SECTION StreamMutex;
829 -#elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
830 +#elif defined(__LINUX_ALSA__) || defined(__UNIX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) || defined(__HAIKU__)
831 // Using pthread library for various flavors of unix.
832 #include <pthread.h>
834 @@ -620,6 +616,7 @@ struct CallbackInfo {
835 ThreadHandle thread;
836 void *callback;
837 void *userData;
838 + void *bufSizeCallback;
839 void *errorCallback;
840 void *apiInfo; // void pointer for API specific callback information
841 bool isRunning;
842 @@ -628,7 +625,7 @@ struct CallbackInfo {
844 // Default constructor.
845 CallbackInfo()
846 - :object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false), priority(0) {}
847 + :object(0), callback(0), userData(0), bufSizeCallback(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false), priority(0) {}
850 // **************************************************************** //
851 @@ -687,7 +684,7 @@ public:
853 RtApi();
854 virtual ~RtApi();
855 - virtual RtAudio::Api getCurrentApi( void ) = 0;
856 + virtual RtAudio::Api getCurrentApi( void ) const = 0;
857 virtual unsigned int getDeviceCount( void ) = 0;
858 virtual RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) = 0;
859 virtual unsigned int getDefaultInputDevice( void );
860 @@ -697,6 +694,7 @@ public:
861 RtAudioFormat format, unsigned int sampleRate,
862 unsigned int *bufferFrames, RtAudioCallback callback,
863 void *userData, RtAudio::StreamOptions *options,
864 + RtAudioBufferSizeCallback bufSizeCallback,
865 RtAudioErrorCallback errorCallback );
866 virtual void closeStream( void );
867 virtual void startStream( void ) = 0;
868 @@ -836,7 +834,7 @@ protected:
870 // **************************************************************** //
872 -inline RtAudio::Api RtAudio :: getCurrentApi( void ) { return rtapi_->getCurrentApi(); }
873 +inline RtAudio::Api RtAudio :: getCurrentApi( void ) const { return rtapi_->getCurrentApi(); }
874 inline unsigned int RtAudio :: getDeviceCount( void ) { return rtapi_->getDeviceCount(); }
875 inline RtAudio::DeviceInfo RtAudio :: getDeviceInfo( unsigned int device ) { return rtapi_->getDeviceInfo( device ); }
876 inline unsigned int RtAudio :: getDefaultInputDevice( void ) { return rtapi_->getDefaultInputDevice(); }
877 @@ -865,7 +863,7 @@ public:
879 RtApiCore();
880 ~RtApiCore();
881 - RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; }
882 + RtAudio::Api getCurrentApi( void ) const { return RtAudio::MACOSX_CORE; }
883 unsigned int getDeviceCount( void );
884 RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
885 unsigned int getDefaultOutputDevice( void );
886 @@ -903,7 +901,7 @@ public:
888 RtApiJack();
889 ~RtApiJack();
890 - RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; }
891 + RtAudio::Api getCurrentApi( void ) const { return RtAudio::UNIX_JACK; }
892 unsigned int getDeviceCount( void );
893 RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
894 void closeStream( void );
895 @@ -918,6 +916,9 @@ public:
896 // will most likely produce highly undesireable results!
897 bool callbackEvent( unsigned long nframes );
899 + // Buffer size change callback
900 + bool bufferSizeEvent( unsigned long nframes );
902 private:
904 bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
905 @@ -938,7 +939,7 @@ public:
907 RtApiAsio();
908 ~RtApiAsio();
909 - RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; }
910 + RtAudio::Api getCurrentApi( void ) const { return RtAudio::WINDOWS_ASIO; }
911 unsigned int getDeviceCount( void );
912 RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
913 void closeStream( void );
914 @@ -974,7 +975,7 @@ public:
916 RtApiDs();
917 ~RtApiDs();
918 - RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; }
919 + RtAudio::Api getCurrentApi( void ) const { return RtAudio::WINDOWS_DS; }
920 unsigned int getDeviceCount( void );
921 unsigned int getDefaultOutputDevice( void );
922 unsigned int getDefaultInputDevice( void );
923 @@ -1015,7 +1016,7 @@ public:
924 RtApiWasapi();
925 ~RtApiWasapi();
927 - RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_WASAPI; }
928 + RtAudio::Api getCurrentApi( void ) const { return RtAudio::WINDOWS_WASAPI; }
929 unsigned int getDeviceCount( void );
930 RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
931 unsigned int getDefaultOutputDevice( void );
932 @@ -1050,7 +1051,7 @@ public:
934 RtApiAlsa();
935 ~RtApiAlsa();
936 - RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; }
937 + RtAudio::Api getCurrentApi() const { return RtAudio::LINUX_ALSA; }
938 unsigned int getDeviceCount( void );
939 RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
940 void closeStream( void );
941 @@ -1076,13 +1077,13 @@ public:
943 #endif
945 -#if defined(__LINUX_PULSE__)
946 +#if defined(__UNIX_PULSE__)
948 class RtApiPulse: public RtApi
950 public:
951 ~RtApiPulse();
952 - RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; }
953 + RtAudio::Api getCurrentApi() const { return RtAudio::UNIX_PULSE; }
954 unsigned int getDeviceCount( void );
955 RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
956 void closeStream( void );
957 @@ -1116,7 +1117,7 @@ public:
959 RtApiOss();
960 ~RtApiOss();
961 - RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; }
962 + RtAudio::Api getCurrentApi() const { return RtAudio::LINUX_OSS; }
963 unsigned int getDeviceCount( void );
964 RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
965 void closeStream( void );
966 @@ -1147,7 +1148,7 @@ class RtApiDummy: public RtApi
967 public:
969 RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtAudioError::WARNING ); }
970 - RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; }
971 + RtAudio::Api getCurrentApi( void ) const { return RtAudio::RTAUDIO_DUMMY; }
972 unsigned int getDeviceCount( void ) { return 0; }
973 RtAudio::DeviceInfo getDeviceInfo( unsigned int /*device*/ ) { RtAudio::DeviceInfo info; return info; }
974 void closeStream( void ) {}
975 diff --git a/include/asio.h b/include/asio.h
976 index 8ec811f..656f681 100644
977 --- a/include/asio.h
978 +++ b/include/asio.h
979 @@ -3,11 +3,12 @@
982 Steinberg Audio Stream I/O API
983 - (c) 1997 - 2005, Steinberg Media Technologies GmbH
984 + (c) 1997 - 2013, Steinberg Media Technologies GmbH
986 - ASIO Interface Specification v 2.1
987 + ASIO Interface Specification v 2.3
989 2005 - Added support for DSD sample data (in cooperation with Sony)
990 + 2012 - Added support for drop out detection
993 basic concept is an i/o synchronous double-buffer scheme:
994 @@ -916,6 +917,7 @@ enum
995 kAsioCanInputMeter,
996 kAsioCanOutputGain,
997 kAsioCanOutputMeter,
998 + kAsioOptionalOne,
1000 // DSD support
1001 // The following extensions are required to allow switching
1002 @@ -923,6 +925,9 @@ enum
1003 kAsioSetIoFormat = 0x23111961, /* ASIOIoFormat * in params. */
1004 kAsioGetIoFormat = 0x23111983, /* ASIOIoFormat * in params. */
1005 kAsioCanDoIoFormat = 0x23112004, /* ASIOIoFormat * in params. */
1006 + // Extension for drop out detection
1007 + kAsioCanReportOverload = 0x24042012, /* return ASE_SUCCESS if driver can detect and report overloads */
1008 + kAsioGetInternalBufferSamples = 0x25042012 /* ASIOInternalBufferInfo * in params. Deliver size of driver internal buffering, return ASE_SUCCESS if supported */
1011 typedef struct ASIOInputMonitor
1012 @@ -1003,6 +1008,14 @@ typedef struct ASIOIoFormat_s
1013 char future[512-sizeof(ASIOIoFormatType)];
1014 } ASIOIoFormat;
1016 +// Extension for drop detection
1017 +// Note: Refers to buffering that goes beyond the double buffer e.g. used by USB driver designs
1018 +typedef struct ASIOInternalBufferInfo
1020 + long inputSamples; // size of driver's internal input buffering which is included in getLatencies
1021 + long outputSamples; // size of driver's internal output buffering which is included in getLatencies
1022 +} ASIOInternalBufferInfo;
1025 ASIOError ASIOOutputReady(void);
1026 /* Purpose:
1027 diff --git a/include/asiosys.h b/include/asiosys.h
1028 index 37f7a48..c974fc3 100644
1029 --- a/include/asiosys.h
1030 +++ b/include/asiosys.h
1031 @@ -1,7 +1,7 @@
1032 #ifndef __asiosys__
1033 #define __asiosys__
1035 - #ifdef WIN32
1036 + #if defined(WIN32) || defined(_WIN64)
1037 #undef MAC
1038 #define PPC 0
1039 #define WINDOWS 1
1040 diff --git a/include/ginclude.h b/include/ginclude.h
1041 index b627dc2..8c609c7 100644
1042 --- a/include/ginclude.h
1043 +++ b/include/ginclude.h
1044 @@ -8,7 +8,7 @@
1046 #define ASIO_BIG_ENDIAN 1
1047 #define ASIO_CPU_MIPS 1
1048 -#elif defined WIN32
1049 +#elif defined(WIN32) || defined(_WIN64)
1050 #undef BEOS
1051 #undef MAC
1052 #undef SGI
1053 diff --git a/include/iasiodrv.h b/include/iasiodrv.h
1054 index 64d2dbb..860675c 100644
1055 --- a/include/iasiodrv.h
1056 +++ b/include/iasiodrv.h
1057 @@ -1,3 +1,4 @@
1058 +#pragma once
1059 #include "asiosys.h"
1060 #include "asio.h"