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.

866 lines
27KB

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