Version 0.62
[jack2.git] / windows / JackASIODriver.cpp
blobb31d27e69f95fefec545d7a2ccd73a87dda06c83
1 /*
2 Copyright (C) 2006 Grame
4 Portable Audio I/O Library for ASIO Drivers
5 Author: Stephane Letz
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.
25 #include "pa_asio.h"
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"
35 #include <iostream>
38 #include <windows.h>
39 #include <mmsystem.h>
41 #include "asiosys.h"
42 #include "asio.h"
43 #include "asiodrivers.h"
44 #include "iasiothiscallresolver.h"
47 /* external references */
48 extern AsioDrivers* asioDrivers ;
49 bool loadAsioDriver(char *name);
52 namespace Jack
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;
66 ASIOError asioError;
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" );
73 goto error;
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 );
83 goto error;
85 else
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 );
95 goto error;
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 );
104 goto error;
107 if( ASIOOutputReady() == ASE_OK )
108 driverInfo->postOutput = true;
109 else
110 driverInfo->postOutput = false;
112 return result;
114 error:
115 if( asioIsInitialized )
116 ASIOExit();
118 return result;
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
129 // simplicity.
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
135 ASIOTime timeInfo;
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()
156 return 0;
159 int JackASIODriver::Write()
161 return 0;
165 int JackASIODriver::Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
167 PaError result = paNoError;
168 int i, driverCount;
169 PaAsioHostApiRepresentation *asioHostApi;
170 PaAsioDeviceInfo *deviceInfoArray;
171 char **names;
172 PaAsioDriverInfo paAsioDriverInfo;
174 asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) );
175 if( !asioHostApi )
177 result = paInsufficientMemory;
178 goto error;
181 asioHostApi->allocations = PaUtil_CreateAllocationGroup();
182 if( !asioHostApi->allocations )
184 result = paInsufficientMemory;
185 goto error;
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;
198 #ifdef WINDOWS
199 /* use desktop window as system specific ptr */
200 asioHostApi->systemSpecific = GetDesktopWindow();
201 CoInitialize(NULL);
202 #endif
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. */
209 #if MAC
210 driverCount = asioDrivers->getNumFragments();
211 #elif WINDOWS
212 driverCount = asioDrivers->asioGetNumDev();
213 #endif
215 if( driverCount > 0 )
217 names = GetAsioDriverNames( asioHostApi->allocations, driverCount );
218 if( !names )
220 result = paInsufficientMemory;
221 goto error;
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;
232 goto error;
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;
241 goto error;
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"));
262 continue;
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;
296 break;
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;
333 }else{
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;
359 goto error;
362 int a;
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 );
372 goto error;
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 );
385 goto error;
390 /* unload the driver */
391 ASIOExit();
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;
404 else
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 );
426 return result;
428 error:
429 if( asioHostApi )
431 if( asioHostApi->allocations )
433 PaUtil_FreeAllAllocations( asioHostApi->allocations );
434 PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
437 PaUtil_FreeMemory( asioHostApi );
439 return result;
444 void JackASIODriverTerminate( struct PaUtilHostApiRepresentation *hostApi )
446 PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
449 IMPLEMENT ME:
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,
465 int capturing,
466 int playing,
467 int inchannels,
468 int outchannels,
469 bool monitor,
470 const char* capture_driver_uid,
471 const char* playback_driver_uid,
472 jack_nframes_t capture_latency,
473 jack_nframes_t playback_latency)
475 return 0;
477 error:
478 return -1;
481 int JackASIODriver::Close()
483 return 0;
486 int JackASIODriver::Start()
488 JackLog("JackASIODriver::Start\n");
489 return 0;
492 int JackASIODriver::Stop()
494 JackLog("JackASIODriver::Stop\n");
495 return 0;
498 int JackASIODriver::SetBufferSize(jack_nframes_t nframes)
500 return 0;
503 void JackASIODriver::PrintState()
505 int i;
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
533 #ifdef __cplusplus
534 extern "C"
536 #endif
538 #include "JackExports.h"
540 EXPORT jack_driver_desc_t* driver_get_descriptor() {
541 jack_driver_desc_t *desc;
542 unsigned int i;
543 desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
545 strcpy(desc->name, "ASIO");
547 desc->nparams = 13;
548 desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
550 i = 0;
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);
558 i++;
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);
566 i++;
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);
574 i++;
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);
582 i++;
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);
590 i++;
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);
598 i++;
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);
606 i++;
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);
614 i++;
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);
622 i++;
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);
631 i++;
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);
639 i++;
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);
647 i++;
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);
655 return 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;
662 int capture = FALSE;
663 int playback = FALSE;
664 int chan_in = 0;
665 int chan_out = 0;
666 bool monitor = false;
667 char* capture_pcm_name = "";
668 char* playback_pcm_name = "";
669 const JSList *node;
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) {
679 case 'd':
680 capture_pcm_name = strdup(param->value.str);
681 playback_pcm_name = strdup(param->value.str);
682 break;
684 case 'D':
685 capture = TRUE;
686 playback = TRUE;
687 break;
689 case 'c':
690 chan_in = chan_out = (int) param->value.ui;
691 break;
693 case 'i':
694 chan_in = (int) param->value.ui;
695 break;
697 case 'o':
698 chan_out = (int) param->value.ui;
699 break;
701 case 'C':
702 capture = TRUE;
703 if (strcmp(param->value.str, "none") != 0) {
704 capture_pcm_name = strdup(param->value.str);
706 break;
708 case 'P':
709 playback = TRUE;
710 if (strcmp(param->value.str, "none") != 0) {
711 playback_pcm_name = strdup(param->value.str);
713 break;
715 case 'm':
716 monitor = param->value.i;
717 break;
719 case 'r':
720 srate = param->value.ui;
721 break;
723 case 'p':
724 frames_per_interrupt = (unsigned int) param->value.ui;
725 break;
727 case 'I':
728 systemic_input_latency = param->value.ui;
729 break;
731 case 'O':
732 systemic_output_latency = param->value.ui;
733 break;
735 case 'l':
736 Jack::DisplayDeviceNames();
737 break;
741 // duplex is the default
742 if (!capture && !playback) {
743 capture = TRUE;
744 playback = TRUE;
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) {
749 return driver;
750 } else {
751 delete driver;
752 return NULL;
756 #ifdef __cplusplus
758 #endif