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.

703 lines
24KB

  1. /*
  2. Copyright (C) 2009 Grame
  3. Copyright (C) 2011 Devin Anderson
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include <stdexcept>
  17. #include <mach/mach_time.h>
  18. #include "JackCoreMidiDriver.h"
  19. #include "JackCoreMidiUtil.h"
  20. #include "JackEngineControl.h"
  21. using Jack::JackCoreMidiDriver;
  22. ///////////////////////////////////////////////////////////////////////////////
  23. // Static callbacks
  24. ///////////////////////////////////////////////////////////////////////////////
  25. void
  26. JackCoreMidiDriver::HandleInputEvent(const MIDIPacketList *packet_list,
  27. void *driver, void *port)
  28. {
  29. ((JackCoreMidiPhysicalInputPort *) port)->ProcessCoreMidi(packet_list);
  30. }
  31. void
  32. JackCoreMidiDriver::HandleNotificationEvent(const MIDINotification *message,
  33. void *driver)
  34. {
  35. ((JackCoreMidiDriver *) driver)->HandleNotification(message);
  36. }
  37. ///////////////////////////////////////////////////////////////////////////////
  38. // Class
  39. ///////////////////////////////////////////////////////////////////////////////
  40. JackCoreMidiDriver::JackCoreMidiDriver(const char *name, const char *alias,
  41. JackLockedEngine *engine,
  42. JackSynchro *table):
  43. JackMidiDriver(name, alias, engine, table)
  44. {
  45. mach_timebase_info_data_t info;
  46. kern_return_t result = mach_timebase_info(&info);
  47. if (result != KERN_SUCCESS) {
  48. throw std::runtime_error(mach_error_string(result));
  49. }
  50. client = 0;
  51. fCaptureChannels = 0;
  52. fPlaybackChannels = 0;
  53. num_physical_inputs = 0;
  54. num_physical_outputs = 0;
  55. num_virtual_inputs = 0;
  56. num_virtual_outputs = 0;
  57. physical_input_ports = 0;
  58. physical_output_ports = 0;
  59. time_ratio = (((double) info.numer) / info.denom) / 1000.0;
  60. virtual_input_ports = 0;
  61. virtual_output_ports = 0;
  62. }
  63. JackCoreMidiDriver::~JackCoreMidiDriver()
  64. {
  65. Stop();
  66. Close();
  67. }
  68. int
  69. JackCoreMidiDriver::Attach()
  70. {
  71. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  72. jack_port_id_t index;
  73. jack_nframes_t latency = buffer_size;
  74. jack_latency_range_t latency_range;
  75. const char *name;
  76. JackPort *port;
  77. JackCoreMidiPort *port_obj;
  78. latency_range.max = latency;
  79. latency_range.min = latency;
  80. // Physical inputs
  81. for (int i = 0; i < num_physical_inputs; i++) {
  82. port_obj = physical_input_ports[i];
  83. name = port_obj->GetName();
  84. index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
  85. JACK_DEFAULT_MIDI_TYPE,
  86. CaptureDriverFlags, buffer_size);
  87. if (index == NO_PORT) {
  88. jack_error("JackCoreMidiDriver::Attach - cannot register physical "
  89. "input port with name '%s'.", name);
  90. // X: Do we need to deallocate ports?
  91. return -1;
  92. }
  93. port = fGraphManager->GetPort(index);
  94. port->SetAlias(port_obj->GetAlias());
  95. port->SetLatencyRange(JackCaptureLatency, &latency_range);
  96. fCapturePortList[i] = index;
  97. }
  98. // Virtual inputs
  99. for (int i = 0; i < num_virtual_inputs; i++) {
  100. port_obj = virtual_input_ports[i];
  101. name = port_obj->GetName();
  102. index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
  103. JACK_DEFAULT_MIDI_TYPE,
  104. CaptureDriverFlags, buffer_size);
  105. if (index == NO_PORT) {
  106. jack_error("JackCoreMidiDriver::Attach - cannot register virtual "
  107. "input port with name '%s'.", name);
  108. // X: Do we need to deallocate ports?
  109. return -1;
  110. }
  111. port = fGraphManager->GetPort(index);
  112. port->SetAlias(port_obj->GetAlias());
  113. port->SetLatencyRange(JackCaptureLatency, &latency_range);
  114. fCapturePortList[num_physical_inputs + i] = index;
  115. }
  116. if (! fEngineControl->fSyncMode) {
  117. latency += buffer_size;
  118. latency_range.max = latency;
  119. latency_range.min = latency;
  120. }
  121. // Physical outputs
  122. for (int i = 0; i < num_physical_outputs; i++) {
  123. port_obj = physical_output_ports[i];
  124. name = port_obj->GetName();
  125. index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
  126. JACK_DEFAULT_MIDI_TYPE,
  127. PlaybackDriverFlags, buffer_size);
  128. if (index == NO_PORT) {
  129. jack_error("JackCoreMidiDriver::Attach - cannot register physical "
  130. "output port with name '%s'.", name);
  131. // X: Do we need to deallocate ports?
  132. return -1;
  133. }
  134. port = fGraphManager->GetPort(index);
  135. port->SetAlias(port_obj->GetAlias());
  136. port->SetLatencyRange(JackPlaybackLatency, &latency_range);
  137. fPlaybackPortList[i] = index;
  138. }
  139. // Virtual outputs
  140. for (int i = 0; i < num_virtual_outputs; i++) {
  141. port_obj = virtual_output_ports[i];
  142. name = port_obj->GetName();
  143. index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
  144. JACK_DEFAULT_MIDI_TYPE,
  145. PlaybackDriverFlags, buffer_size);
  146. if (index == NO_PORT) {
  147. jack_error("JackCoreMidiDriver::Attach - cannot register virtual "
  148. "output port with name '%s'.", name);
  149. // X: Do we need to deallocate ports?
  150. return -1;
  151. }
  152. port = fGraphManager->GetPort(index);
  153. port->SetAlias(port_obj->GetAlias());
  154. port->SetLatencyRange(JackPlaybackLatency, &latency_range);
  155. fPlaybackPortList[num_physical_outputs + i] = index;
  156. }
  157. return 0;
  158. }
  159. int
  160. JackCoreMidiDriver::Close()
  161. {
  162. int result = 0;
  163. OSStatus status;
  164. if (physical_input_ports) {
  165. for (int i = 0; i < num_physical_inputs; i++) {
  166. delete physical_input_ports[i];
  167. }
  168. delete[] physical_input_ports;
  169. num_physical_inputs = 0;
  170. physical_input_ports = 0;
  171. status = MIDIPortDispose(internal_input);
  172. if (status != noErr) {
  173. WriteMacOSError("JackCoreMidiDriver::Close", "MIDIPortDispose",
  174. status);
  175. result = -1;
  176. }
  177. }
  178. if (physical_output_ports) {
  179. for (int i = 0; i < num_physical_outputs; i++) {
  180. delete physical_output_ports[i];
  181. }
  182. delete[] physical_output_ports;
  183. num_physical_outputs = 0;
  184. physical_output_ports = 0;
  185. status = MIDIPortDispose(internal_output);
  186. if (status != noErr) {
  187. WriteMacOSError("JackCoreMidiDriver::Close", "MIDIPortDispose",
  188. status);
  189. result = -1;
  190. }
  191. }
  192. if (virtual_input_ports) {
  193. for (int i = 0; i < num_virtual_inputs; i++) {
  194. delete virtual_input_ports[i];
  195. }
  196. delete[] virtual_input_ports;
  197. num_virtual_inputs = 0;
  198. virtual_input_ports = 0;
  199. }
  200. if (virtual_output_ports) {
  201. for (int i = 0; i < num_virtual_outputs; i++) {
  202. delete virtual_output_ports[i];
  203. }
  204. delete[] virtual_output_ports;
  205. num_virtual_outputs = 0;
  206. virtual_output_ports = 0;
  207. }
  208. if (client) {
  209. status = MIDIClientDispose(client);
  210. if (status != noErr) {
  211. WriteMacOSError("JackCoreMidiDriver::Close", "MIDIClientDispose",
  212. status);
  213. result = -1;
  214. }
  215. client = 0;
  216. }
  217. return result;
  218. }
  219. void
  220. JackCoreMidiDriver::HandleNotification(const MIDINotification *message)
  221. {
  222. // Empty
  223. }
  224. int
  225. JackCoreMidiDriver::Open(bool capturing, bool playing, int in_channels,
  226. int out_channels, bool monitor,
  227. const char* capture_driver_name,
  228. const char* playback_driver_name,
  229. jack_nframes_t capture_latency,
  230. jack_nframes_t playback_latency)
  231. {
  232. int pi_count = 0;
  233. int po_count = 0;
  234. int vi_count = 0;
  235. int vo_count = 0;
  236. ItemCount potential_po_count;
  237. ItemCount potential_pi_count;
  238. CFStringRef name = CFStringCreateWithCString(0, "JackMidi",
  239. CFStringGetSystemEncoding());
  240. if (! name) {
  241. jack_error("JackCoreMidiDriver::Open - failed to allocate memory for "
  242. "client name string");
  243. return -1;
  244. }
  245. OSStatus status = MIDIClientCreate(name, HandleNotificationEvent, this,
  246. &client);
  247. CFRelease(name);
  248. if (status != noErr) {
  249. WriteMacOSError("JackCoreMidiDriver::Close", "MIDIClientCreate",
  250. status);
  251. return -1;
  252. }
  253. char *client_name = fClientControl.fName;
  254. int port_rt_priority = fEngineControl->fServerPriority + 1;
  255. // Allocate and connect virtual inputs
  256. if (in_channels) {
  257. try {
  258. virtual_input_ports =
  259. new JackCoreMidiVirtualInputPort*[in_channels];
  260. } catch (std::exception e) {
  261. jack_error("JackCoreMidiDriver::Open - while creating virtual "
  262. "input port array: %s", e.what());
  263. goto destroy_client;
  264. }
  265. for (vi_count = 0; vi_count < in_channels; vi_count++) {
  266. try {
  267. virtual_input_ports[vi_count] =
  268. new JackCoreMidiVirtualInputPort(fAliasName, client_name,
  269. capture_driver_name,
  270. vi_count, client,
  271. time_ratio);
  272. } catch (std::exception e) {
  273. jack_error("JackCoreMidiDriver::Open - while creating virtual "
  274. "input port: %s", e.what());
  275. goto destroy_virtual_input_ports;
  276. }
  277. }
  278. }
  279. // Allocate and connect virtual outputs
  280. if (out_channels) {
  281. try {
  282. virtual_output_ports =
  283. new JackCoreMidiVirtualOutputPort*[out_channels];
  284. } catch (std::exception e) {
  285. jack_error("JackCoreMidiDriver::Open - while creating virtual "
  286. "output port array: %s", e.what());
  287. goto destroy_virtual_input_ports;
  288. }
  289. for (vo_count = 0; vo_count < out_channels; vo_count++) {
  290. try {
  291. virtual_output_ports[vo_count] =
  292. new JackCoreMidiVirtualOutputPort(fAliasName, client_name,
  293. playback_driver_name,
  294. vo_count, client,
  295. time_ratio,
  296. port_rt_priority);
  297. } catch (std::exception e) {
  298. jack_error("JackCoreMidiDriver::Open - while creating virtual "
  299. "output port: %s", e.what());
  300. goto destroy_virtual_output_ports;
  301. }
  302. }
  303. }
  304. // Allocate and connect physical inputs
  305. potential_pi_count = MIDIGetNumberOfSources();
  306. if (potential_pi_count) {
  307. status = MIDIInputPortCreate(client, CFSTR("Physical Input Port"),
  308. HandleInputEvent, this, &internal_input);
  309. if (status != noErr) {
  310. WriteMacOSError("JackCoreMidiDriver::Open", "MIDIInputPortCreate",
  311. status);
  312. goto destroy_virtual_output_ports;
  313. }
  314. try {
  315. physical_input_ports =
  316. new JackCoreMidiPhysicalInputPort*[potential_pi_count];
  317. } catch (std::exception e) {
  318. jack_error("JackCoreMidiDriver::Open - while creating physical "
  319. "input port array: %s", e.what());
  320. goto destroy_internal_input_port;
  321. }
  322. for (ItemCount i = 0; i < potential_pi_count; i++) {
  323. try {
  324. physical_input_ports[pi_count] =
  325. new JackCoreMidiPhysicalInputPort(fAliasName, client_name,
  326. capture_driver_name, i,
  327. client, internal_input,
  328. time_ratio);
  329. } catch (std::exception e) {
  330. jack_error("JackCoreMidiDriver::Open - while creating "
  331. "physical input port: %s", e.what());
  332. continue;
  333. }
  334. pi_count++;
  335. }
  336. }
  337. // Allocate and connect physical outputs
  338. potential_po_count = MIDIGetNumberOfDestinations();
  339. if (potential_po_count) {
  340. status = MIDIOutputPortCreate(client, CFSTR("Physical Output Port"),
  341. &internal_output);
  342. if (status != noErr) {
  343. WriteMacOSError("JackCoreMidiDriver::Open", "MIDIOutputPortCreate",
  344. status);
  345. goto destroy_physical_input_ports;
  346. }
  347. try {
  348. physical_output_ports =
  349. new JackCoreMidiPhysicalOutputPort*[potential_po_count];
  350. } catch (std::exception e) {
  351. jack_error("JackCoreMidiDriver::Open - while creating physical "
  352. "output port array: %s", e.what());
  353. goto destroy_internal_output_port;
  354. }
  355. for (ItemCount i = 0; i < potential_po_count; i++) {
  356. try {
  357. physical_output_ports[po_count] =
  358. new JackCoreMidiPhysicalOutputPort(fAliasName, client_name,
  359. playback_driver_name, i,
  360. client, internal_output,
  361. time_ratio,
  362. port_rt_priority);
  363. } catch (std::exception e) {
  364. jack_error("JackCoreMidiDriver::Open - while creating "
  365. "physical output port: %s", e.what());
  366. continue;
  367. }
  368. po_count++;
  369. }
  370. }
  371. if (! (pi_count || po_count || in_channels || out_channels)) {
  372. jack_error("JackCoreMidiDriver::Open - no CoreMIDI inputs or outputs "
  373. "found, and no virtual ports allocated.");
  374. } else if (! JackMidiDriver::Open(capturing, playing,
  375. in_channels + pi_count,
  376. out_channels + po_count, monitor,
  377. capture_driver_name,
  378. playback_driver_name, capture_latency,
  379. playback_latency)) {
  380. num_physical_inputs = pi_count;
  381. num_physical_outputs = po_count;
  382. num_virtual_inputs = in_channels;
  383. num_virtual_outputs = out_channels;
  384. return 0;
  385. }
  386. // Cleanup
  387. if (physical_output_ports) {
  388. for (int i = 0; i < po_count; i++) {
  389. delete physical_output_ports[i];
  390. }
  391. delete[] physical_output_ports;
  392. physical_output_ports = 0;
  393. }
  394. destroy_internal_output_port:
  395. status = MIDIPortDispose(internal_output);
  396. if (status != noErr) {
  397. WriteMacOSError("JackCoreMidiDriver::Open", "MIDIPortDispose", status);
  398. }
  399. destroy_physical_input_ports:
  400. if (physical_input_ports) {
  401. for (int i = 0; i < pi_count; i++) {
  402. delete physical_input_ports[i];
  403. }
  404. delete[] physical_input_ports;
  405. physical_input_ports = 0;
  406. }
  407. destroy_internal_input_port:
  408. status = MIDIPortDispose(internal_input);
  409. if (status != noErr) {
  410. WriteMacOSError("JackCoreMidiDriver::Open", "MIDIPortDispose", status);
  411. }
  412. destroy_virtual_output_ports:
  413. if (virtual_output_ports) {
  414. for (int i = 0; i < vo_count; i++) {
  415. delete virtual_output_ports[i];
  416. }
  417. delete[] virtual_output_ports;
  418. virtual_output_ports = 0;
  419. }
  420. destroy_virtual_input_ports:
  421. if (virtual_input_ports) {
  422. for (int i = 0; i < vi_count; i++) {
  423. delete virtual_input_ports[i];
  424. }
  425. delete[] virtual_input_ports;
  426. virtual_input_ports = 0;
  427. }
  428. destroy_client:
  429. status = MIDIClientDispose(client);
  430. if (status != noErr) {
  431. WriteMacOSError("JackCoreMidiDriver::Open", "MIDIClientDispose",
  432. status);
  433. }
  434. client = 0;
  435. return -1;
  436. }
  437. int
  438. JackCoreMidiDriver::Read()
  439. {
  440. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  441. for (int i = 0; i < num_physical_inputs; i++) {
  442. physical_input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
  443. }
  444. for (int i = 0; i < num_virtual_inputs; i++) {
  445. virtual_input_ports[i]->
  446. ProcessJack(GetInputBuffer(num_physical_inputs + i), buffer_size);
  447. }
  448. return 0;
  449. }
  450. int
  451. JackCoreMidiDriver::Start()
  452. {
  453. jack_info("JackCoreMidiDriver::Start - Starting driver.");
  454. JackMidiDriver::Start();
  455. int pi_count = 0;
  456. int po_count = 0;
  457. int vi_count = 0;
  458. int vo_count = 0;
  459. jack_info("JackCoreMidiDriver::Start - Enabling physical input ports.");
  460. for (; pi_count < num_physical_inputs; pi_count++) {
  461. if (physical_input_ports[pi_count]->Start() < 0) {
  462. jack_error("JackCoreMidiDriver::Start - Failed to enable physical "
  463. "input port.");
  464. goto stop_physical_input_ports;
  465. }
  466. }
  467. jack_info("JackCoreMidiDriver::Start - Enabling physical output ports.");
  468. for (; po_count < num_physical_outputs; po_count++) {
  469. if (physical_output_ports[po_count]->Start() < 0) {
  470. jack_error("JackCoreMidiDriver::Start - Failed to enable physical "
  471. "output port.");
  472. goto stop_physical_output_ports;
  473. }
  474. }
  475. jack_info("JackCoreMidiDriver::Start - Enabling virtual input ports.");
  476. for (; vi_count < num_virtual_inputs; vi_count++) {
  477. if (virtual_input_ports[vi_count]->Start() < 0) {
  478. jack_error("JackCoreMidiDriver::Start - Failed to enable virtual "
  479. "input port.");
  480. goto stop_virtual_input_ports;
  481. }
  482. }
  483. jack_info("JackCoreMidiDriver::Start - Enabling virtual output ports.");
  484. for (; vo_count < num_virtual_outputs; vo_count++) {
  485. if (virtual_output_ports[vo_count]->Start() < 0) {
  486. jack_error("JackCoreMidiDriver::Start - Failed to enable virtual "
  487. "output port.");
  488. goto stop_virtual_output_ports;
  489. }
  490. }
  491. jack_info("JackCoreMidiDriver::Start - Driver started.");
  492. return 0;
  493. stop_virtual_output_ports:
  494. for (int i = 0; i < vo_count; i++) {
  495. if (virtual_output_ports[i]->Stop() < 0) {
  496. jack_error("JackCoreMidiDriver::Start - Failed to disable virtual "
  497. "output port.");
  498. }
  499. }
  500. stop_virtual_input_ports:
  501. for (int i = 0; i < vi_count; i++) {
  502. if (virtual_input_ports[i]->Stop() < 0) {
  503. jack_error("JackCoreMidiDriver::Start - Failed to disable virtual "
  504. "input port.");
  505. }
  506. }
  507. stop_physical_output_ports:
  508. for (int i = 0; i < po_count; i++) {
  509. if (physical_output_ports[i]->Stop() < 0) {
  510. jack_error("JackCoreMidiDriver::Start - Failed to disable "
  511. "physical output port.");
  512. }
  513. }
  514. stop_physical_input_ports:
  515. for (int i = 0; i < pi_count; i++) {
  516. if (physical_input_ports[i]->Stop() < 0) {
  517. jack_error("JackCoreMidiDriver::Start - Failed to disable "
  518. "physical input port.");
  519. }
  520. }
  521. return -1;
  522. }
  523. int
  524. JackCoreMidiDriver::Stop()
  525. {
  526. int result = 0;
  527. jack_info("JackCoreMidiDriver::Stop - disabling physical input ports.");
  528. for (int i = 0; i < num_physical_inputs; i++) {
  529. if (physical_input_ports[i]->Stop() < 0) {
  530. jack_error("JackCoreMidiDriver::Stop - Failed to disable physical "
  531. "input port.");
  532. result = -1;
  533. }
  534. }
  535. jack_info("JackCoreMidiDriver::Stop - disabling physical output ports.");
  536. for (int i = 0; i < num_physical_outputs; i++) {
  537. if (physical_output_ports[i]->Stop() < 0) {
  538. jack_error("JackCoreMidiDriver::Stop - Failed to disable physical "
  539. "output port.");
  540. result = -1;
  541. }
  542. }
  543. jack_info("JackCoreMidiDriver::Stop - disabling virtual input ports.");
  544. for (int i = 0; i < num_virtual_inputs; i++) {
  545. if (virtual_input_ports[i]->Stop() < 0) {
  546. jack_error("JackCoreMidiDriver::Stop - Failed to disable virtual "
  547. "input port.");
  548. result = -1;
  549. }
  550. }
  551. jack_info("JackCoreMidiDriver::Stop - disabling virtual output ports.");
  552. for (int i = 0; i < num_virtual_outputs; i++) {
  553. if (virtual_output_ports[i]->Stop() < 0) {
  554. jack_error("JackCoreMidiDriver::Stop - Failed to disable virtual "
  555. "output port.");
  556. result = -1;
  557. }
  558. }
  559. return result;
  560. }
  561. int
  562. JackCoreMidiDriver::Write()
  563. {
  564. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  565. for (int i = 0; i < num_physical_outputs; i++) {
  566. physical_output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
  567. }
  568. for (int i = 0; i < num_virtual_outputs; i++) {
  569. virtual_output_ports[i]->
  570. ProcessJack(GetOutputBuffer(num_physical_outputs + i),
  571. buffer_size);
  572. }
  573. return 0;
  574. }
  575. #ifdef __cplusplus
  576. extern "C" {
  577. #endif
  578. SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
  579. {
  580. jack_driver_desc_t * desc;
  581. unsigned int i;
  582. desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
  583. strcpy(desc->name, "coremidi"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
  584. strcpy(desc->desc, "Apple CoreMIDI API based MIDI backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
  585. desc->nparams = 2;
  586. desc->params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
  587. i = 0;
  588. strcpy(desc->params[i].name, "inchannels");
  589. desc->params[i].character = 'i';
  590. desc->params[i].type = JackDriverParamInt;
  591. desc->params[i].value.ui = 0;
  592. strcpy(desc->params[i].short_desc, "CoreMIDI virtual bus");
  593. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  594. i++;
  595. strcpy(desc->params[i].name, "outchannels");
  596. desc->params[i].character = 'o';
  597. desc->params[i].type = JackDriverParamInt;
  598. desc->params[i].value.ui = 0;
  599. strcpy(desc->params[i].short_desc, "CoreMIDI virtual bus");
  600. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  601. return desc;
  602. }
  603. SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
  604. {
  605. const JSList * node;
  606. const jack_driver_param_t * param;
  607. int virtual_in = 0;
  608. int virtual_out = 0;
  609. for (node = params; node; node = jack_slist_next (node)) {
  610. param = (const jack_driver_param_t *) node->data;
  611. switch (param->character) {
  612. case 'i':
  613. virtual_in = param->value.ui;
  614. break;
  615. case 'o':
  616. virtual_out = param->value.ui;
  617. break;
  618. }
  619. }
  620. Jack::JackDriverClientInterface* driver = new Jack::JackCoreMidiDriver("system_midi", "coremidi", engine, table);
  621. if (driver->Open(1, 1, virtual_in, virtual_out, false, "in", "out", 0, 0) == 0) {
  622. return driver;
  623. } else {
  624. delete driver;
  625. return NULL;
  626. }
  627. }
  628. #ifdef __cplusplus
  629. }
  630. #endif