jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

670 lines
25KB

  1. /*
  2. Copyright (C) 2004-2006 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #ifdef WIN32
  16. #pragma warning (disable : 4786)
  17. #endif
  18. #include "pa_asio.h"
  19. #include "JackDriverLoader.h"
  20. #include "driver_interface.h"
  21. #include "JackPortAudioDriver.h"
  22. #include "JackEngineControl.h"
  23. #include "JackError.h"
  24. #include "JackTime.h"
  25. #include <iostream>
  26. namespace Jack
  27. {
  28. void JackPortAudioDriver::PrintSupportedStandardSampleRates(const PaStreamParameters* inputParameters, const PaStreamParameters* outputParameters)
  29. {
  30. static double standardSampleRates[] = {
  31. 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
  32. 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 /* negative terminated list */
  33. };
  34. int i, printCount;
  35. PaError err;
  36. printCount = 0;
  37. for (i = 0; standardSampleRates[i] > 0; i++) {
  38. err = Pa_IsFormatSupported(inputParameters, outputParameters, standardSampleRates[i]);
  39. if (err == paFormatIsSupported) {
  40. if (printCount == 0) {
  41. printf("\t%8.2f", standardSampleRates[i]);
  42. printCount = 1;
  43. } else if (printCount == 4) {
  44. printf(",\n\t%8.2f", standardSampleRates[i]);
  45. printCount = 1;
  46. } else {
  47. printf(", %8.2f", standardSampleRates[i]);
  48. ++printCount;
  49. }
  50. }
  51. }
  52. if (!printCount)
  53. printf("None\n");
  54. else
  55. printf("\n");
  56. }
  57. bool JackPortAudioDriver::GetInputDeviceFromName(const char* name, PaDeviceIndex* device, int* in_max)
  58. {
  59. const PaDeviceInfo* deviceInfo;
  60. PaDeviceIndex numDevices = Pa_GetDeviceCount();
  61. for (int i = 0; i < numDevices; i++) {
  62. deviceInfo = Pa_GetDeviceInfo(i);
  63. if (strcmp(name, deviceInfo->name) == 0) {
  64. *device = i;
  65. *in_max = deviceInfo->maxInputChannels;
  66. return true;
  67. }
  68. }
  69. return false;
  70. }
  71. bool JackPortAudioDriver::GetOutputDeviceFromName(const char* name, PaDeviceIndex* device, int* out_max)
  72. {
  73. const PaDeviceInfo* deviceInfo;
  74. PaDeviceIndex numDevices = Pa_GetDeviceCount();
  75. for (int i = 0; i < numDevices; i++) {
  76. deviceInfo = Pa_GetDeviceInfo(i);
  77. if (strcmp(name, deviceInfo->name) == 0) {
  78. *device = i;
  79. *out_max = deviceInfo->maxOutputChannels;
  80. return true;
  81. }
  82. }
  83. return false;
  84. }
  85. static void DisplayDeviceNames()
  86. {
  87. PaError err;
  88. const PaDeviceInfo* deviceInfo;
  89. PaStreamParameters inputParameters, outputParameters;
  90. int defaultDisplayed;
  91. err = Pa_Initialize();
  92. if (err != paNoError)
  93. return ;
  94. PaDeviceIndex numDevices = Pa_GetDeviceCount();
  95. printf("Number of devices = %d\n", numDevices);
  96. for (int i = 0; i < numDevices; i++) {
  97. deviceInfo = Pa_GetDeviceInfo(i);
  98. printf( "--------------------------------------- device #%d\n", i );
  99. /* Mark global and API specific default devices */
  100. defaultDisplayed = 0;
  101. if (i == Pa_GetDefaultInputDevice()) {
  102. printf("[ Default Input");
  103. defaultDisplayed = 1;
  104. } else if (i == Pa_GetHostApiInfo(deviceInfo->hostApi)->defaultInputDevice) {
  105. const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
  106. printf("[ Default %s Input", hostInfo->name);
  107. defaultDisplayed = 1;
  108. }
  109. if (i == Pa_GetDefaultOutputDevice()) {
  110. printf((defaultDisplayed ? "," : "["));
  111. printf(" Default Output");
  112. defaultDisplayed = 1;
  113. } else if (i == Pa_GetHostApiInfo(deviceInfo->hostApi)->defaultOutputDevice) {
  114. const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
  115. printf((defaultDisplayed ? "," : "["));
  116. printf(" Default %s Output", hostInfo->name);
  117. defaultDisplayed = 1;
  118. }
  119. if (defaultDisplayed)
  120. printf(" ]\n");
  121. /* print device info fields */
  122. printf("Name = %s\n", deviceInfo->name);
  123. printf("Host API = %s\n", Pa_GetHostApiInfo(deviceInfo->hostApi)->name);
  124. printf("Max inputs = %d", deviceInfo->maxInputChannels);
  125. printf(", Max outputs = %d\n", deviceInfo->maxOutputChannels);
  126. /*
  127. printf("Default low input latency = %8.3f\n", deviceInfo->defaultLowInputLatency);
  128. printf("Default low output latency = %8.3f\n", deviceInfo->defaultLowOutputLatency);
  129. printf("Default high input latency = %8.3f\n", deviceInfo->defaultHighInputLatency);
  130. printf("Default high output latency = %8.3f\n", deviceInfo->defaultHighOutputLatency);
  131. */
  132. #ifdef WIN32
  133. #ifndef PA_NO_ASIO
  134. /* ASIO specific latency information */
  135. if (Pa_GetHostApiInfo(deviceInfo->hostApi)->type == paASIO) {
  136. long minLatency, maxLatency, preferredLatency, granularity;
  137. err = PaAsio_GetAvailableLatencyValues(i, &minLatency, &maxLatency, &preferredLatency, &granularity);
  138. printf("ASIO minimum buffer size = %ld\n", minLatency);
  139. printf("ASIO maximum buffer size = %ld\n", maxLatency);
  140. printf("ASIO preferred buffer size = %ld\n", preferredLatency);
  141. if (granularity == -1)
  142. printf("ASIO buffer granularity = power of 2\n");
  143. else
  144. printf("ASIO buffer granularity = %ld\n", granularity);
  145. }
  146. #endif /* !PA_NO_ASIO */
  147. #endif /* WIN32 */
  148. printf("Default sample rate = %8.2f\n", deviceInfo->defaultSampleRate);
  149. /* poll for standard sample rates */
  150. inputParameters.device = i;
  151. inputParameters.channelCount = deviceInfo->maxInputChannels;
  152. inputParameters.sampleFormat = paInt16;
  153. inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
  154. inputParameters.hostApiSpecificStreamInfo = NULL;
  155. outputParameters.device = i;
  156. outputParameters.channelCount = deviceInfo->maxOutputChannels;
  157. outputParameters.sampleFormat = paInt16;
  158. outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
  159. outputParameters.hostApiSpecificStreamInfo = NULL;
  160. /*
  161. if (inputParameters.channelCount > 0) {
  162. printf("Supported standard sample rates\n for half-duplex 16 bit %d channel input = \n", inputParameters.channelCount);
  163. PrintSupportedStandardSampleRates(&inputParameters, NULL);
  164. }
  165. if (outputParameters.channelCount > 0) {
  166. printf("Supported standard sample rates\n for half-duplex 16 bit %d channel output = \n", outputParameters.channelCount);
  167. PrintSupportedStandardSampleRates(NULL, &outputParameters);
  168. }
  169. if (inputParameters.channelCount > 0 && outputParameters.channelCount > 0) {
  170. printf("Supported standard sample rates\n for full-duplex 16 bit %d channel input, %d channel output = \n",
  171. inputParameters.channelCount, outputParameters.channelCount );
  172. PrintSupportedStandardSampleRates(&inputParameters, &outputParameters);
  173. }
  174. */
  175. }
  176. Pa_Terminate();
  177. }
  178. int JackPortAudioDriver::Render(const void* inputBuffer, void* outputBuffer,
  179. unsigned long framesPerBuffer,
  180. const PaStreamCallbackTimeInfo* timeInfo,
  181. PaStreamCallbackFlags statusFlags,
  182. void* userData)
  183. {
  184. JackPortAudioDriver* driver = (JackPortAudioDriver*)userData;
  185. driver->fLastWaitUst = GetMicroSeconds(); // Take callback date here
  186. driver->fInputBuffer = (float**)inputBuffer;
  187. driver->fOutputBuffer = (float**)outputBuffer;
  188. return (driver->Process() == 0) ? paContinue : paAbort;
  189. }
  190. int JackPortAudioDriver::Read()
  191. {
  192. for (int i = 0; i < fCaptureChannels; i++) {
  193. memcpy(GetInputBuffer(i), fInputBuffer[i], sizeof(float) * fEngineControl->fBufferSize);
  194. }
  195. return 0;
  196. }
  197. int JackPortAudioDriver::Write()
  198. {
  199. for (int i = 0; i < fPlaybackChannels; i++) {
  200. memcpy(fOutputBuffer[i], GetOutputBuffer(i), sizeof(float) * fEngineControl->fBufferSize);
  201. }
  202. return 0;
  203. }
  204. int JackPortAudioDriver::Open(jack_nframes_t nframes,
  205. jack_nframes_t samplerate,
  206. bool capturing,
  207. bool playing,
  208. int inchannels,
  209. int outchannels,
  210. bool monitor,
  211. const char* capture_driver_uid,
  212. const char* playback_driver_uid,
  213. jack_nframes_t capture_latency,
  214. jack_nframes_t playback_latency)
  215. {
  216. PaError err;
  217. PaStreamParameters inputParameters;
  218. PaStreamParameters outputParameters;
  219. const PaDeviceInfo* deviceInfo;
  220. int in_max = 0;
  221. int out_max = 0;
  222. JackLog("JackPortAudioDriver::Open nframes = %ld in = %ld out = %ld capture name = %s playback name = %s samplerate = %ld\n",
  223. nframes, inchannels, outchannels, capture_driver_uid, playback_driver_uid, samplerate);
  224. // Generic JackAudioDriver Open
  225. if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) {
  226. return -1;
  227. }
  228. err = Pa_Initialize();
  229. if (err != paNoError) {
  230. jack_error("JackPortAudioDriver::Pa_Initialize error = %s\n", Pa_GetErrorText(err));
  231. goto error;
  232. }
  233. JackLog("JackPortAudioDriver::Pa_GetDefaultInputDevice %ld\n", Pa_GetDefaultInputDevice());
  234. JackLog("JackPortAudioDriver::Pa_GetDefaultOutputDevice %ld\n", Pa_GetDefaultOutputDevice());
  235. if (capturing) {
  236. if (!GetInputDeviceFromName(capture_driver_uid, &fInputDevice, &in_max)) {
  237. JackLog("JackPortAudioDriver::GetInputDeviceFromName cannot open %s\n", capture_driver_uid);
  238. fInputDevice = Pa_GetDefaultInputDevice();
  239. if (fInputDevice == paNoDevice)
  240. goto error;
  241. deviceInfo = Pa_GetDeviceInfo(fInputDevice);
  242. in_max = deviceInfo->maxInputChannels;
  243. capture_driver_uid = strdup(deviceInfo->name);
  244. }
  245. }
  246. if (inchannels > in_max) {
  247. jack_error("This device hasn't required input channels inchannels = %ld in_max = %ld", inchannels, in_max);
  248. goto error;
  249. }
  250. if (playing) {
  251. if (!GetOutputDeviceFromName(playback_driver_uid, &fOutputDevice, &out_max)) {
  252. JackLog("JackPortAudioDriver::GetOutputDeviceFromName cannot open %s\n", playback_driver_uid);
  253. fOutputDevice = Pa_GetDefaultOutputDevice();
  254. if (fOutputDevice == paNoDevice)
  255. goto error;
  256. deviceInfo = Pa_GetDeviceInfo(fOutputDevice);
  257. out_max = deviceInfo->maxOutputChannels;
  258. playback_driver_uid = strdup(deviceInfo->name);
  259. }
  260. }
  261. if (outchannels > out_max) {
  262. jack_error("This device hasn't required output channels outchannels = %ld out_max = %ld", outchannels, out_max);
  263. goto error;
  264. }
  265. if (inchannels == 0) {
  266. JackLog("JackPortAudioDriver::Open setup max in channels = %ld\n", in_max);
  267. inchannels = in_max;
  268. }
  269. if (outchannels == 0) {
  270. JackLog("JackPortAudioDriver::Open setup max out channels = %ld\n", out_max);
  271. outchannels = out_max;
  272. }
  273. inputParameters.device = fInputDevice;
  274. inputParameters.channelCount = inchannels;
  275. inputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output
  276. inputParameters.suggestedLatency = (fInputDevice != paNoDevice) // TODO: check how to setup this on ASIO
  277. ? Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency
  278. : 0;
  279. inputParameters.hostApiSpecificStreamInfo = NULL;
  280. outputParameters.device = fOutputDevice;
  281. outputParameters.channelCount = outchannels;
  282. outputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output
  283. outputParameters.suggestedLatency = (fOutputDevice != paNoDevice) // TODO: check how to setup this on ASIO
  284. ? Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency
  285. : 0;
  286. outputParameters.hostApiSpecificStreamInfo = NULL;
  287. err = Pa_OpenStream(&fStream,
  288. (fInputDevice == paNoDevice) ? 0 : &inputParameters,
  289. (fOutputDevice == paNoDevice) ? 0 : &outputParameters,
  290. samplerate,
  291. nframes,
  292. paNoFlag, // Clipping is on...
  293. Render,
  294. this);
  295. if (err != paNoError) {
  296. jack_error("Pa_OpenStream error = %s\n", Pa_GetErrorText(err));
  297. goto error;
  298. }
  299. #ifdef __APPLE__
  300. fEngineControl->fPeriod = fEngineControl->fPeriodUsecs * 1000;
  301. fEngineControl->fComputation = 500 * 1000;
  302. fEngineControl->fConstraint = fEngineControl->fPeriodUsecs * 1000;
  303. #endif
  304. // Core driver may have changed the in/out values
  305. fCaptureChannels = inchannels;
  306. fPlaybackChannels = outchannels;
  307. assert(strlen(capture_driver_uid) < JACK_CLIENT_NAME_SIZE);
  308. assert(strlen(playback_driver_uid) < JACK_CLIENT_NAME_SIZE);
  309. strcpy(fCaptureDriverName, capture_driver_uid);
  310. strcpy(fPlaybackDriverName, playback_driver_uid);
  311. return 0;
  312. error:
  313. Pa_Terminate();
  314. return -1;
  315. }
  316. int JackPortAudioDriver::Close()
  317. {
  318. JackAudioDriver::Close();
  319. JackLog("JackPortAudioDriver::Close\n");
  320. Pa_CloseStream(fStream);
  321. Pa_Terminate();
  322. return 0;
  323. }
  324. int JackPortAudioDriver::Start()
  325. {
  326. JackLog("JackPortAudioDriver::Start\n");
  327. JackAudioDriver::Start();
  328. PaError err = Pa_StartStream(fStream);
  329. return (err == paNoError) ? 0 : -1;
  330. }
  331. int JackPortAudioDriver::Stop()
  332. {
  333. JackLog("JackPortAudioDriver::Stop\n");
  334. PaError err = Pa_StopStream(fStream);
  335. return (err == paNoError) ? 0 : -1;
  336. }
  337. int JackPortAudioDriver::SetBufferSize(jack_nframes_t buffer_size)
  338. {
  339. PaError err;
  340. PaStreamParameters inputParameters;
  341. PaStreamParameters outputParameters;
  342. if ((err = Pa_CloseStream(fStream)) != paNoError) {
  343. jack_error("Pa_CloseStream error = %s\n", Pa_GetErrorText(err));
  344. return -1;
  345. }
  346. inputParameters.device = fInputDevice;
  347. inputParameters.channelCount = fCaptureChannels;
  348. inputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output
  349. inputParameters.suggestedLatency = (fInputDevice != paNoDevice) // TODO: check how to setup this on ASIO
  350. ? Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency
  351. : 0;
  352. inputParameters.hostApiSpecificStreamInfo = NULL;
  353. outputParameters.device = fOutputDevice;
  354. outputParameters.channelCount = fPlaybackChannels;
  355. outputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output
  356. outputParameters.suggestedLatency = (fOutputDevice != paNoDevice) // TODO: check how to setup this on ASIO
  357. ? Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency
  358. : 0;
  359. outputParameters.hostApiSpecificStreamInfo = NULL;
  360. err = Pa_OpenStream(&fStream,
  361. (fInputDevice == paNoDevice) ? 0 : &inputParameters,
  362. (fOutputDevice == paNoDevice) ? 0 : &outputParameters,
  363. fEngineControl->fSampleRate,
  364. buffer_size,
  365. paNoFlag, // Clipping is on...
  366. Render,
  367. this);
  368. if (err != paNoError) {
  369. jack_error("Pa_OpenStream error = %s\n", Pa_GetErrorText(err));
  370. return -1;
  371. } else {
  372. // Only done when success
  373. return JackAudioDriver::SetBufferSize(buffer_size); // never fails
  374. }
  375. }
  376. } // end of namespace
  377. #ifdef __cplusplus
  378. extern "C"
  379. {
  380. #endif
  381. #include "JackExports.h"
  382. EXPORT jack_driver_desc_t* driver_get_descriptor() {
  383. jack_driver_desc_t *desc;
  384. unsigned int i;
  385. desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
  386. strcpy(desc->name, "portaudio");
  387. desc->nparams = 13;
  388. desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
  389. i = 0;
  390. strcpy(desc->params[i].name, "channels");
  391. desc->params[i].character = 'c';
  392. desc->params[i].type = JackDriverParamInt;
  393. desc->params[i].value.ui = 0;
  394. strcpy(desc->params[i].short_desc, "Maximum number of channels");
  395. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  396. i++;
  397. strcpy(desc->params[i].name, "inchannels");
  398. desc->params[i].character = 'i';
  399. desc->params[i].type = JackDriverParamInt;
  400. desc->params[i].value.ui = 0;
  401. strcpy(desc->params[i].short_desc, "Maximum number of input channels");
  402. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  403. i++;
  404. strcpy(desc->params[i].name, "outchannels");
  405. desc->params[i].character = 'o';
  406. desc->params[i].type = JackDriverParamInt;
  407. desc->params[i].value.ui = 0;
  408. strcpy(desc->params[i].short_desc, "Maximum number of output channels");
  409. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  410. i++;
  411. strcpy(desc->params[i].name, "capture");
  412. desc->params[i].character = 'C';
  413. desc->params[i].type = JackDriverParamString;
  414. strcpy(desc->params[i].value.str, "will take default PortAudio input device");
  415. strcpy(desc->params[i].short_desc, "Provide capture ports. Optionally set PortAudio device name");
  416. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  417. i++;
  418. strcpy(desc->params[i].name, "playback");
  419. desc->params[i].character = 'P';
  420. desc->params[i].type = JackDriverParamString;
  421. strcpy(desc->params[i].value.str, "will take default PortAudio output device");
  422. strcpy(desc->params[i].short_desc, "Provide playback ports. Optionally set PortAudio device name");
  423. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  424. i++;
  425. strcpy (desc->params[i].name, "monitor");
  426. desc->params[i].character = 'm';
  427. desc->params[i].type = JackDriverParamBool;
  428. desc->params[i].value.i = 0;
  429. strcpy(desc->params[i].short_desc, "Provide monitor ports for the output");
  430. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  431. i++;
  432. strcpy(desc->params[i].name, "duplex");
  433. desc->params[i].character = 'D';
  434. desc->params[i].type = JackDriverParamBool;
  435. desc->params[i].value.i = TRUE;
  436. strcpy(desc->params[i].short_desc, "Provide both capture and playback ports");
  437. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  438. i++;
  439. strcpy(desc->params[i].name, "rate");
  440. desc->params[i].character = 'r';
  441. desc->params[i].type = JackDriverParamUInt;
  442. desc->params[i].value.ui = 44100U;
  443. strcpy(desc->params[i].short_desc, "Sample rate");
  444. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  445. i++;
  446. strcpy(desc->params[i].name, "period");
  447. desc->params[i].character = 'p';
  448. desc->params[i].type = JackDriverParamUInt;
  449. desc->params[i].value.ui = 128U;
  450. strcpy(desc->params[i].short_desc, "Frames per period");
  451. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  452. i++;
  453. strcpy(desc->params[i].name, "device");
  454. desc->params[i].character = 'd';
  455. desc->params[i].type = JackDriverParamString;
  456. desc->params[i].value.ui = 128U;
  457. strcpy(desc->params[i].value.str, "will take default PortAudio device name");
  458. strcpy(desc->params[i].short_desc, "PortAudio device name");
  459. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  460. i++;
  461. strcpy(desc->params[i].name, "input-latency");
  462. desc->params[i].character = 'I';
  463. desc->params[i].type = JackDriverParamUInt;
  464. desc->params[i].value.i = 0;
  465. strcpy(desc->params[i].short_desc, "Extra input latency");
  466. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  467. i++;
  468. strcpy(desc->params[i].name, "output-latency");
  469. desc->params[i].character = 'O';
  470. desc->params[i].type = JackDriverParamUInt;
  471. desc->params[i].value.i = 0;
  472. strcpy(desc->params[i].short_desc, "Extra output latency");
  473. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  474. i++;
  475. strcpy(desc->params[i].name, "list-devices");
  476. desc->params[i].character = 'l';
  477. desc->params[i].type = JackDriverParamBool;
  478. desc->params[i].value.i = TRUE;
  479. strcpy(desc->params[i].short_desc, "Display available PortAudio devices");
  480. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  481. return desc;
  482. }
  483. EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackEngine* engine, Jack::JackSynchro** table, const JSList* params) {
  484. jack_nframes_t srate = 44100;
  485. jack_nframes_t frames_per_interrupt = 512;
  486. int capture = FALSE;
  487. int playback = FALSE;
  488. int chan_in = 0;
  489. int chan_out = 0;
  490. bool monitor = false;
  491. char* capture_pcm_name = "winmme";
  492. char* playback_pcm_name = "winmme";
  493. const JSList *node;
  494. const jack_driver_param_t *param;
  495. jack_nframes_t systemic_input_latency = 0;
  496. jack_nframes_t systemic_output_latency = 0;
  497. for (node = params; node; node = jack_slist_next(node)) {
  498. param = (const jack_driver_param_t *) node->data;
  499. switch (param->character) {
  500. case 'd':
  501. capture_pcm_name = strdup(param->value.str);
  502. playback_pcm_name = strdup(param->value.str);
  503. break;
  504. case 'D':
  505. capture = TRUE;
  506. playback = TRUE;
  507. break;
  508. case 'c':
  509. chan_in = chan_out = (int) param->value.ui;
  510. break;
  511. case 'i':
  512. chan_in = (int) param->value.ui;
  513. break;
  514. case 'o':
  515. chan_out = (int) param->value.ui;
  516. break;
  517. case 'C':
  518. capture = TRUE;
  519. if (strcmp(param->value.str, "none") != 0) {
  520. capture_pcm_name = strdup(param->value.str);
  521. }
  522. break;
  523. case 'P':
  524. playback = TRUE;
  525. if (strcmp(param->value.str, "none") != 0) {
  526. playback_pcm_name = strdup(param->value.str);
  527. }
  528. break;
  529. case 'm':
  530. monitor = param->value.i;
  531. break;
  532. case 'r':
  533. srate = param->value.ui;
  534. break;
  535. case 'p':
  536. frames_per_interrupt = (unsigned int) param->value.ui;
  537. break;
  538. case 'I':
  539. systemic_input_latency = param->value.ui;
  540. break;
  541. case 'O':
  542. systemic_output_latency = param->value.ui;
  543. break;
  544. case 'l':
  545. Jack::DisplayDeviceNames();
  546. break;
  547. }
  548. }
  549. // duplex is the default
  550. if (!capture && !playback) {
  551. capture = TRUE;
  552. playback = TRUE;
  553. }
  554. Jack::JackDriverClientInterface* driver = new Jack::JackPortAudioDriver("portaudio", engine, table);
  555. 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) {
  556. return driver;
  557. } else {
  558. delete driver;
  559. return NULL;
  560. }
  561. }
  562. #ifdef __cplusplus
  563. }
  564. #endif