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.

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