2 Copyright (C) 2006 Grame
4 Portable Audio I/O Library for ASIO Drivers
6 Based on the Open Source API proposed by Ross Bencina
7 Copyright (c) 2000-2002 Stephane Letz, Phil Burk, Ross Bencina
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "JackDriverLoader.h"
27 #include "driver_interface.h"
29 #include "JackASIODriver.h"
30 #include "JackEngineControl.h"
31 #include "JackGraphManager.h"
32 #include "JackError.h"
33 #include "JackClientControl.h"
34 #include "JackGlobals.h"
43 #include "asiodrivers.h"
44 #include "iasiothiscallresolver.h"
47 /* external references */
48 extern AsioDrivers
* asioDrivers
;
49 bool loadAsioDriver(char *name
);
57 load the asio driver named by <driverName> and return statistics about
58 the driver in info. If no error occurred, the driver will remain open
59 and must be closed by the called by calling ASIOExit() - if an error
60 is returned the driver will already be closed.
62 static PaError
LoadAsioDriver( const char *driverName
,
63 PaAsioDriverInfo
*driverInfo
, void *systemSpecific
)
65 PaError result
= paNoError
;
67 int asioIsInitialized
= 0;
69 if( !loadAsioDriver(const_cast<char*>(driverName
)))
71 result
= paUnanticipatedHostError
;
72 PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" );
76 memset( &driverInfo
->asioDriverInfo
, 0, sizeof(ASIODriverInfo
) );
77 driverInfo
->asioDriverInfo
.asioVersion
= 2;
78 driverInfo
->asioDriverInfo
.sysRef
= systemSpecific
;
79 if( (asioError
= ASIOInit( &driverInfo
->asioDriverInfo
)) != ASE_OK
)
81 result
= paUnanticipatedHostError
;
82 PA_ASIO_SET_LAST_ASIO_ERROR( asioError
);
87 asioIsInitialized
= 1;
90 if( (asioError
= ASIOGetChannels(&driverInfo
->inputChannelCount
,
91 &driverInfo
->outputChannelCount
)) != ASE_OK
)
93 result
= paUnanticipatedHostError
;
94 PA_ASIO_SET_LAST_ASIO_ERROR( asioError
);
98 if( (asioError
= ASIOGetBufferSize(&driverInfo
->bufferMinSize
,
99 &driverInfo
->bufferMaxSize
, &driverInfo
->bufferPreferredSize
,
100 &driverInfo
->bufferGranularity
)) != ASE_OK
)
102 result
= paUnanticipatedHostError
;
103 PA_ASIO_SET_LAST_ASIO_ERROR( asioError
);
107 if( ASIOOutputReady() == ASE_OK
)
108 driverInfo
->postOutput
= true;
110 driverInfo
->postOutput
= false;
115 if( asioIsInitialized
)
122 int JackASIODriver::bufferSwitch(long index
, ASIOBool directProcess
)
124 JackASIODriver
* driver
= (JackASIODriver
*)userData
;
126 // the actual processing callback.
127 // Beware that this is normally in a seperate thread, hence be sure that
128 // you take care about thread synchronization. This is omitted here for
131 // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs
132 // to be created though it will only set the timeInfo.samplePosition and
133 // timeInfo.systemTime fields and the according flags
136 memset(&timeInfo
, 0, sizeof(timeInfo
));
138 // get the time stamp of the buffer, not necessary if no
139 // synchronization to other media is required
140 if( ASIOGetSamplePosition(&timeInfo
.timeInfo
.samplePosition
, &timeInfo
.timeInfo
.systemTime
) == ASE_OK
)
141 timeInfo
.timeInfo
.flags
= kSystemTimeValid
| kSamplePositionValid
;
144 driver
->fLastWaitUst
= GetMicroSeconds(); // Take callback date here
145 driver
->fInputBuffer
= (float**)inputBuffer
;
146 driver
->fOutputBuffer
= (float**)outputBuffer
;
148 // Call the real callback
149 bufferSwitchTimeInfo( &timeInfo
, index
, directProcess
);
151 return driver
->Process();
154 int JackASIODriver::Read()
159 int JackASIODriver::Write()
165 int JackASIODriver::Initialize( PaUtilHostApiRepresentation
**hostApi
, PaHostApiIndex hostApiIndex
)
167 PaError result
= paNoError
;
169 PaAsioHostApiRepresentation
*asioHostApi
;
170 PaAsioDeviceInfo
*deviceInfoArray
;
172 PaAsioDriverInfo paAsioDriverInfo
;
174 asioHostApi
= (PaAsioHostApiRepresentation
*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation
) );
177 result
= paInsufficientMemory
;
181 asioHostApi
->allocations
= PaUtil_CreateAllocationGroup();
182 if( !asioHostApi
->allocations
)
184 result
= paInsufficientMemory
;
188 asioHostApi
->systemSpecific
= 0;
189 asioHostApi
->openAsioDeviceIndex
= paNoDevice
;
191 *hostApi
= &asioHostApi
->inheritedHostApiRep
;
192 (*hostApi
)->info
.structVersion
= 1;
194 (*hostApi
)->info
.type
= paASIO
;
195 (*hostApi
)->info
.name
= "ASIO";
196 (*hostApi
)->info
.deviceCount
= 0;
199 /* use desktop window as system specific ptr */
200 asioHostApi
->systemSpecific
= GetDesktopWindow();
204 /* MUST BE CHECKED : to force fragments loading on Mac */
205 loadAsioDriver( "dummy" );
207 /* driverCount is the number of installed drivers - not necessarily
208 the number of installed physical devices. */
210 driverCount
= asioDrivers
->getNumFragments();
212 driverCount
= asioDrivers
->asioGetNumDev();
215 if( driverCount
> 0 )
217 names
= GetAsioDriverNames( asioHostApi
->allocations
, driverCount
);
220 result
= paInsufficientMemory
;
225 /* allocate enough space for all drivers, even if some aren't installed */
227 (*hostApi
)->deviceInfos
= (PaDeviceInfo
**)PaUtil_GroupAllocateMemory(
228 asioHostApi
->allocations
, sizeof(PaDeviceInfo
*) * driverCount
);
229 if( !(*hostApi
)->deviceInfos
)
231 result
= paInsufficientMemory
;
235 /* allocate all device info structs in a contiguous block */
236 deviceInfoArray
= (PaAsioDeviceInfo
*)PaUtil_GroupAllocateMemory(
237 asioHostApi
->allocations
, sizeof(PaAsioDeviceInfo
) * driverCount
);
238 if( !deviceInfoArray
)
240 result
= paInsufficientMemory
;
244 for( i
=0; i
< driverCount
; ++i
)
247 PA_DEBUG(("ASIO names[%d]:%s\n",i
,names
[i
]));
249 // Since portaudio opens ALL ASIO drivers, and no one else does that,
250 // we face fact that some drivers were not meant for it, drivers which act
251 // like shells on top of REAL drivers, for instance.
252 // so we get duplicate handles, locks and other problems.
253 // so lets NOT try to load any such wrappers.
254 // The ones i [davidv] know of so far are:
256 if ( strcmp (names
[i
],"ASIO DirectX Full Duplex Driver") == 0
257 || strcmp (names
[i
],"ASIO Multimedia Driver") == 0
258 || strncmp(names
[i
],"Premiere",8) == 0 //"Premiere Elements Windows Sound 1.0"
259 || strncmp(names
[i
],"Adobe",5) == 0 ) //"Adobe Default Windows Sound 1.5"
261 PA_DEBUG(("BLACKLISTED!!!\n"));
266 /* Attempt to load the asio driver... */
267 if( LoadAsioDriver( names
[i
], &paAsioDriverInfo
, asioHostApi
->systemSpecific
) == paNoError
)
269 PaAsioDeviceInfo
*asioDeviceInfo
= &deviceInfoArray
[ (*hostApi
)->info
.deviceCount
];
270 PaDeviceInfo
*deviceInfo
= &asioDeviceInfo
->commonDeviceInfo
;
272 deviceInfo
->structVersion
= 2;
273 deviceInfo
->hostApi
= hostApiIndex
;
275 deviceInfo
->name
= names
[i
];
276 PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n", i
,deviceInfo
->name
));
277 PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels = %d\n", i
, paAsioDriverInfo
.inputChannelCount
));
278 PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels = %d\n", i
, paAsioDriverInfo
.outputChannelCount
));
279 PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize = %d\n", i
, paAsioDriverInfo
.bufferMinSize
));
280 PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize = %d\n", i
, paAsioDriverInfo
.bufferMaxSize
));
281 PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", i
, paAsioDriverInfo
.bufferPreferredSize
));
282 PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity = %d\n", i
, paAsioDriverInfo
.bufferGranularity
));
284 deviceInfo
->maxInputChannels
= paAsioDriverInfo
.inputChannelCount
;
285 deviceInfo
->maxOutputChannels
= paAsioDriverInfo
.outputChannelCount
;
287 deviceInfo
->defaultSampleRate
= 0.;
288 bool foundDefaultSampleRate
= false;
289 for( int j
=0; j
< PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_
; ++j
)
291 ASIOError asioError
= ASIOCanSampleRate( defaultSampleRateSearchOrder_
[j
] );
292 if( asioError
!= ASE_NoClock
&& asioError
!= ASE_NotPresent
)
294 deviceInfo
->defaultSampleRate
= defaultSampleRateSearchOrder_
[j
];
295 foundDefaultSampleRate
= true;
300 PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", i
, deviceInfo
->defaultSampleRate
));
302 if( foundDefaultSampleRate
){
304 /* calculate default latency values from bufferPreferredSize
305 for default low latency, and bufferPreferredSize * 3
306 for default high latency.
307 use the default sample rate to convert from samples to
308 seconds. Without knowing what sample rate the user will
309 use this is the best we can do.
312 double defaultLowLatency
=
313 paAsioDriverInfo
.bufferPreferredSize
/ deviceInfo
->defaultSampleRate
;
315 deviceInfo
->defaultLowInputLatency
= defaultLowLatency
;
316 deviceInfo
->defaultLowOutputLatency
= defaultLowLatency
;
318 long defaultHighLatencyBufferSize
=
319 paAsioDriverInfo
.bufferPreferredSize
* 3;
321 if( defaultHighLatencyBufferSize
> paAsioDriverInfo
.bufferMaxSize
)
322 defaultHighLatencyBufferSize
= paAsioDriverInfo
.bufferMaxSize
;
324 double defaultHighLatency
=
325 defaultHighLatencyBufferSize
/ deviceInfo
->defaultSampleRate
;
327 if( defaultHighLatency
< defaultLowLatency
)
328 defaultHighLatency
= defaultLowLatency
; /* just incase the driver returns something strange */
330 deviceInfo
->defaultHighInputLatency
= defaultHighLatency
;
331 deviceInfo
->defaultHighOutputLatency
= defaultHighLatency
;
335 deviceInfo
->defaultLowInputLatency
= 0.;
336 deviceInfo
->defaultLowOutputLatency
= 0.;
337 deviceInfo
->defaultHighInputLatency
= 0.;
338 deviceInfo
->defaultHighOutputLatency
= 0.;
341 PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", i
, deviceInfo
->defaultLowInputLatency
));
342 PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", i
, deviceInfo
->defaultLowOutputLatency
));
343 PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", i
, deviceInfo
->defaultHighInputLatency
));
344 PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", i
, deviceInfo
->defaultHighOutputLatency
));
346 asioDeviceInfo
->minBufferSize
= paAsioDriverInfo
.bufferMinSize
;
347 asioDeviceInfo
->maxBufferSize
= paAsioDriverInfo
.bufferMaxSize
;
348 asioDeviceInfo
->preferredBufferSize
= paAsioDriverInfo
.bufferPreferredSize
;
349 asioDeviceInfo
->bufferGranularity
= paAsioDriverInfo
.bufferGranularity
;
352 asioDeviceInfo
->asioChannelInfos
= (ASIOChannelInfo
*)PaUtil_GroupAllocateMemory(
353 asioHostApi
->allocations
,
354 sizeof(ASIOChannelInfo
) * (deviceInfo
->maxInputChannels
355 + deviceInfo
->maxOutputChannels
) );
356 if( !asioDeviceInfo
->asioChannelInfos
)
358 result
= paInsufficientMemory
;
364 for( a
=0; a
< deviceInfo
->maxInputChannels
; ++a
){
365 asioDeviceInfo
->asioChannelInfos
[a
].channel
= a
;
366 asioDeviceInfo
->asioChannelInfos
[a
].isInput
= ASIOTrue
;
367 ASIOError asioError
= ASIOGetChannelInfo( &asioDeviceInfo
->asioChannelInfos
[a
] );
368 if( asioError
!= ASE_OK
)
370 result
= paUnanticipatedHostError
;
371 PA_ASIO_SET_LAST_ASIO_ERROR( asioError
);
376 for( a
=0; a
< deviceInfo
->maxOutputChannels
; ++a
){
377 int b
= deviceInfo
->maxInputChannels
+ a
;
378 asioDeviceInfo
->asioChannelInfos
[b
].channel
= a
;
379 asioDeviceInfo
->asioChannelInfos
[b
].isInput
= ASIOFalse
;
380 ASIOError asioError
= ASIOGetChannelInfo( &asioDeviceInfo
->asioChannelInfos
[b
] );
381 if( asioError
!= ASE_OK
)
383 result
= paUnanticipatedHostError
;
384 PA_ASIO_SET_LAST_ASIO_ERROR( asioError
);
390 /* unload the driver */
393 (*hostApi
)->deviceInfos
[ (*hostApi
)->info
.deviceCount
] = deviceInfo
;
394 ++(*hostApi
)->info
.deviceCount
;
399 if( (*hostApi
)->info
.deviceCount
> 0 )
401 (*hostApi
)->info
.defaultInputDevice
= 0;
402 (*hostApi
)->info
.defaultOutputDevice
= 0;
406 (*hostApi
)->info
.defaultInputDevice
= paNoDevice
;
407 (*hostApi
)->info
.defaultOutputDevice
= paNoDevice
;
411 (*hostApi
)->Terminate
= Terminate
;
412 (*hostApi
)->OpenStream
= OpenStream
;
413 (*hostApi
)->IsFormatSupported
= IsFormatSupported
;
415 PaUtil_InitializeStreamInterface( &asioHostApi
->callbackStreamInterface
, CloseStream
, StartStream
,
416 StopStream
, AbortStream
, IsStreamStopped
, IsStreamActive
,
417 GetStreamTime
, GetStreamCpuLoad
,
418 PaUtil_DummyRead
, PaUtil_DummyWrite
,
419 PaUtil_DummyGetReadAvailable
, PaUtil_DummyGetWriteAvailable
);
421 PaUtil_InitializeStreamInterface( &asioHostApi
->blockingStreamInterface
, CloseStream
, StartStream
,
422 StopStream
, AbortStream
, IsStreamStopped
, IsStreamActive
,
423 GetStreamTime
, PaUtil_DummyGetCpuLoad
,
424 ReadStream
, WriteStream
, GetStreamReadAvailable
, GetStreamWriteAvailable
);
431 if( asioHostApi
->allocations
)
433 PaUtil_FreeAllAllocations( asioHostApi
->allocations
);
434 PaUtil_DestroyAllocationGroup( asioHostApi
->allocations
);
437 PaUtil_FreeMemory( asioHostApi
);
444 void JackASIODriverTerminate( struct PaUtilHostApiRepresentation
*hostApi
)
446 PaAsioHostApiRepresentation
*asioHostApi
= (PaAsioHostApiRepresentation
*)hostApi
;
450 - clean up any resources not handled by the allocation group
453 if( asioHostApi
->allocations
)
455 PaUtil_FreeAllAllocations( asioHostApi
->allocations
);
456 PaUtil_DestroyAllocationGroup( asioHostApi
->allocations
);
459 PaUtil_FreeMemory( asioHostApi
);
463 int JackASIODriver::Open(jack_nframes_t nframes
,
464 jack_nframes_t samplerate
,
470 const char* capture_driver_uid
,
471 const char* playback_driver_uid
,
472 jack_nframes_t capture_latency
,
473 jack_nframes_t playback_latency
)
481 int JackASIODriver::Close()
486 int JackASIODriver::Start()
488 JackLog("JackASIODriver::Start\n");
492 int JackASIODriver::Stop()
494 JackLog("JackASIODriver::Stop\n");
498 int JackASIODriver::SetBufferSize(jack_nframes_t nframes
)
503 void JackASIODriver::PrintState()
506 std::cout
<< "JackASIODriver state" << std::endl
;
508 jack_port_id_t port_index
;
510 std::cout
<< "Input ports" << std::endl
;
513 for (i = 0; i < fPlaybackChannels; i++) {
514 port_index = fCapturePortList[i];
515 JackPort* port = fGraphManager->GetPort(port_index);
516 std::cout << port->GetName() << std::endl;
517 if (fGraphManager->GetConnectionsNum(port_index)) {}
520 std::cout << "Output ports" << std::endl;
522 for (i = 0; i < fCaptureChannels; i++) {
523 port_index = fPlaybackPortList[i];
524 JackPort* port = fGraphManager->GetPort(port_index);
525 std::cout << port->GetName() << std::endl;
526 if (fGraphManager->GetConnectionsNum(port_index)) {}
531 } // end of namespace
538 #include "JackExports.h"
540 EXPORT jack_driver_desc_t
* driver_get_descriptor() {
541 jack_driver_desc_t
*desc
;
543 desc
= (jack_driver_desc_t
*)calloc(1, sizeof(jack_driver_desc_t
));
545 strcpy(desc
->name
, "ASIO");
548 desc
->params
= (jack_driver_param_desc_t
*)calloc(desc
->nparams
, sizeof(jack_driver_param_desc_t
));
551 strcpy(desc
->params
[i
].name
, "channels");
552 desc
->params
[i
].character
= 'c';
553 desc
->params
[i
].type
= JackDriverParamInt
;
554 desc
->params
[i
].value
.ui
= 0;
555 strcpy(desc
->params
[i
].short_desc
, "Maximum number of channels");
556 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
559 strcpy(desc
->params
[i
].name
, "inchannels");
560 desc
->params
[i
].character
= 'i';
561 desc
->params
[i
].type
= JackDriverParamInt
;
562 desc
->params
[i
].value
.ui
= 0;
563 strcpy(desc
->params
[i
].short_desc
, "Maximum number of input channels");
564 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
567 strcpy(desc
->params
[i
].name
, "outchannels");
568 desc
->params
[i
].character
= 'o';
569 desc
->params
[i
].type
= JackDriverParamInt
;
570 desc
->params
[i
].value
.ui
= 0;
571 strcpy(desc
->params
[i
].short_desc
, "Maximum number of output channels");
572 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
575 strcpy(desc
->params
[i
].name
, "capture");
576 desc
->params
[i
].character
= 'C';
577 desc
->params
[i
].type
= JackDriverParamString
;
578 strcpy(desc
->params
[i
].value
.str
, "will take default PortAudio input device");
579 strcpy(desc
->params
[i
].short_desc
, "Provide capture ports. Optionally set PortAudio device name");
580 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
583 strcpy(desc
->params
[i
].name
, "playback");
584 desc
->params
[i
].character
= 'P';
585 desc
->params
[i
].type
= JackDriverParamString
;
586 strcpy(desc
->params
[i
].value
.str
, "will take default PortAudio output device");
587 strcpy(desc
->params
[i
].short_desc
, "Provide playback ports. Optionally set PortAudio device name");
588 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
591 strcpy (desc
->params
[i
].name
, "monitor");
592 desc
->params
[i
].character
= 'm';
593 desc
->params
[i
].type
= JackDriverParamBool
;
594 desc
->params
[i
].value
.i
= 0;
595 strcpy(desc
->params
[i
].short_desc
, "Provide monitor ports for the output");
596 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
599 strcpy(desc
->params
[i
].name
, "duplex");
600 desc
->params
[i
].character
= 'D';
601 desc
->params
[i
].type
= JackDriverParamBool
;
602 desc
->params
[i
].value
.i
= TRUE
;
603 strcpy(desc
->params
[i
].short_desc
, "Provide both capture and playback ports");
604 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
607 strcpy(desc
->params
[i
].name
, "rate");
608 desc
->params
[i
].character
= 'r';
609 desc
->params
[i
].type
= JackDriverParamUInt
;
610 desc
->params
[i
].value
.ui
= 44100U;
611 strcpy(desc
->params
[i
].short_desc
, "Sample rate");
612 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
615 strcpy(desc
->params
[i
].name
, "period");
616 desc
->params
[i
].character
= 'p';
617 desc
->params
[i
].type
= JackDriverParamUInt
;
618 desc
->params
[i
].value
.ui
= 128U;
619 strcpy(desc
->params
[i
].short_desc
, "Frames per period");
620 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
623 strcpy(desc
->params
[i
].name
, "device");
624 desc
->params
[i
].character
= 'd';
625 desc
->params
[i
].type
= JackDriverParamString
;
626 desc
->params
[i
].value
.ui
= 128U;
627 strcpy(desc
->params
[i
].value
.str
, "will take default CoreAudio device name");
628 strcpy(desc
->params
[i
].short_desc
, "CoreAudio device name");
629 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
632 strcpy(desc
->params
[i
].name
, "input-latency");
633 desc
->params
[i
].character
= 'I';
634 desc
->params
[i
].type
= JackDriverParamUInt
;
635 desc
->params
[i
].value
.i
= 0;
636 strcpy(desc
->params
[i
].short_desc
, "Extra input latency");
637 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
640 strcpy(desc
->params
[i
].name
, "output-latency");
641 desc
->params
[i
].character
= 'O';
642 desc
->params
[i
].type
= JackDriverParamUInt
;
643 desc
->params
[i
].value
.i
= 0;
644 strcpy(desc
->params
[i
].short_desc
, "Extra output latency");
645 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
648 strcpy(desc
->params
[i
].name
, "list-devices");
649 desc
->params
[i
].character
= 'l';
650 desc
->params
[i
].type
= JackDriverParamBool
;
651 desc
->params
[i
].value
.i
= TRUE
;
652 strcpy(desc
->params
[i
].short_desc
, "Display available CoreAudio devices");
653 strcpy(desc
->params
[i
].long_desc
, desc
->params
[i
].short_desc
);
658 EXPORT
Jack::JackDriverClientInterface
* driver_initialize(Jack::JackEngine
* engine
, Jack::JackSynchro
** table
, const JSList
* params
)
660 jack_nframes_t srate
= 44100;
661 jack_nframes_t frames_per_interrupt
= 512;
663 int playback
= FALSE
;
666 bool monitor
= false;
667 char* capture_pcm_name
= "";
668 char* playback_pcm_name
= "";
670 const jack_driver_param_t
*param
;
671 jack_nframes_t systemic_input_latency
= 0;
672 jack_nframes_t systemic_output_latency
= 0;
674 for (node
= params
; node
; node
= jack_slist_next(node
)) {
675 param
= (const jack_driver_param_t
*) node
->data
;
677 switch (param
->character
) {
680 capture_pcm_name
= strdup(param
->value
.str
);
681 playback_pcm_name
= strdup(param
->value
.str
);
690 chan_in
= chan_out
= (int) param
->value
.ui
;
694 chan_in
= (int) param
->value
.ui
;
698 chan_out
= (int) param
->value
.ui
;
703 if (strcmp(param
->value
.str
, "none") != 0) {
704 capture_pcm_name
= strdup(param
->value
.str
);
710 if (strcmp(param
->value
.str
, "none") != 0) {
711 playback_pcm_name
= strdup(param
->value
.str
);
716 monitor
= param
->value
.i
;
720 srate
= param
->value
.ui
;
724 frames_per_interrupt
= (unsigned int) param
->value
.ui
;
728 systemic_input_latency
= param
->value
.ui
;
732 systemic_output_latency
= param
->value
.ui
;
736 Jack::DisplayDeviceNames();
741 // duplex is the default
742 if (!capture
&& !playback
) {
747 Jack::JackDriverClientInterface
* driver
= new Jack::JackASIODriver("ASIO", engine
, table
);
748 if (driver
->Open(frames_per_interrupt
, srate
, capture
, playback
, chan_in
, chan_out
, monitor
, capture_pcm_name
, playback_pcm_name
, systemic_input_latency
, systemic_output_latency
) == 0) {