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.

771 lines
25KB

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