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.

875 lines
28KB

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