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.

697 lines
26KB

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