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.

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