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.

668 lines
22KB

  1. /*
  2. Copyright (C) 2011 Devin Anderson
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include <memory>
  16. #include <new>
  17. #include <stdexcept>
  18. #include <alsa/asoundlib.h>
  19. #include "JackALSARawMidiDriver.h"
  20. #include "JackALSARawMidiUtil.h"
  21. #include "JackEngineControl.h"
  22. #include "JackError.h"
  23. #include "JackMidiUtil.h"
  24. #include "driver_interface.h"
  25. using Jack::JackALSARawMidiDriver;
  26. JackALSARawMidiDriver::JackALSARawMidiDriver(const char *name,
  27. const char *alias,
  28. JackLockedEngine *engine,
  29. JackSynchro *table):
  30. JackMidiDriver(name, alias, engine, table)
  31. {
  32. thread = new JackThread(this);
  33. fds[0] = -1;
  34. fds[1] = -1;
  35. input_ports = 0;
  36. output_ports = 0;
  37. output_port_timeouts = 0;
  38. poll_fds = 0;
  39. }
  40. JackALSARawMidiDriver::~JackALSARawMidiDriver()
  41. {
  42. delete thread;
  43. }
  44. int
  45. JackALSARawMidiDriver::Attach()
  46. {
  47. const char *alias;
  48. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  49. jack_port_id_t index;
  50. jack_nframes_t latency = buffer_size;
  51. jack_latency_range_t latency_range;
  52. const char *name;
  53. JackPort *port;
  54. latency_range.max = latency;
  55. latency_range.min = latency;
  56. for (int i = 0; i < fCaptureChannels; i++) {
  57. JackALSARawMidiInputPort *input_port = input_ports[i];
  58. name = input_port->GetName();
  59. fEngine->PortRegister(fClientControl.fRefNum, name,
  60. JACK_DEFAULT_MIDI_TYPE,
  61. CaptureDriverFlags, buffer_size, &index);
  62. if (index == NO_PORT) {
  63. jack_error("JackALSARawMidiDriver::Attach - cannot register input "
  64. "port with name '%s'.", name);
  65. // XX: Do we need to deallocate ports?
  66. return -1;
  67. }
  68. alias = input_port->GetAlias();
  69. port = fGraphManager->GetPort(index);
  70. port->SetAlias(alias);
  71. port->SetLatencyRange(JackCaptureLatency, &latency_range);
  72. fEngine->PortSetDefaultMetadata(fClientControl.fRefNum, index,
  73. input_port->GetDeviceName());
  74. fCapturePortList[i] = index;
  75. jack_info("JackALSARawMidiDriver::Attach - input port registered "
  76. "(name='%s', alias='%s').", name, alias);
  77. }
  78. if (! fEngineControl->fSyncMode) {
  79. latency += buffer_size;
  80. latency_range.max = latency;
  81. latency_range.min = latency;
  82. }
  83. for (int i = 0; i < fPlaybackChannels; i++) {
  84. JackALSARawMidiOutputPort *output_port = output_ports[i];
  85. name = output_port->GetName();
  86. fEngine->PortRegister(fClientControl.fRefNum, name,
  87. JACK_DEFAULT_MIDI_TYPE,
  88. PlaybackDriverFlags, buffer_size, &index);
  89. if (index == NO_PORT) {
  90. jack_error("JackALSARawMidiDriver::Attach - cannot register "
  91. "output port with name '%s'.", name);
  92. // XX: Do we need to deallocate ports?
  93. return -1;
  94. }
  95. alias = output_port->GetAlias();
  96. port = fGraphManager->GetPort(index);
  97. port->SetAlias(alias);
  98. port->SetLatencyRange(JackPlaybackLatency, &latency_range);
  99. fEngine->PortSetDefaultMetadata(fClientControl.fRefNum, index,
  100. output_port->GetDeviceName());
  101. fPlaybackPortList[i] = index;
  102. jack_info("JackALSARawMidiDriver::Attach - output port registered "
  103. "(name='%s', alias='%s').", name, alias);
  104. }
  105. return 0;
  106. }
  107. int
  108. JackALSARawMidiDriver::Close()
  109. {
  110. // Generic MIDI driver close
  111. int result = JackMidiDriver::Close();
  112. if (input_ports) {
  113. for (int i = 0; i < fCaptureChannels; i++) {
  114. delete input_ports[i];
  115. }
  116. delete[] input_ports;
  117. input_ports = 0;
  118. }
  119. if (output_ports) {
  120. for (int i = 0; i < fPlaybackChannels; i++) {
  121. delete output_ports[i];
  122. }
  123. delete[] output_ports;
  124. output_ports = 0;
  125. }
  126. return result;
  127. }
  128. bool
  129. JackALSARawMidiDriver::Execute()
  130. {
  131. jack_nframes_t timeout_frame = 0;
  132. for (;;) {
  133. struct timespec timeout;
  134. struct timespec *timeout_ptr;
  135. if (! timeout_frame) {
  136. timeout_ptr = 0;
  137. } else {
  138. // The timeout value is relative to the time that
  139. // 'GetMicroSeconds()' is called, not the time that 'poll()' is
  140. // called. This means that the amount of time that passes between
  141. // 'GetMicroSeconds()' and 'ppoll()' is time that will be lost
  142. // while waiting for 'poll() to timeout.
  143. //
  144. // I tried to replace the timeout with a 'timerfd' with absolute
  145. // times, but, strangely, it actually slowed things down, and made
  146. // the code a lot more complicated.
  147. //
  148. // I wonder about using the 'epoll' interface instead of 'ppoll()'.
  149. // The problem with the 'epoll' interface is that the timeout
  150. // resolution of 'epoll_wait()' is set in milliseconds. We need
  151. // microsecond resolution. Without microsecond resolution, we
  152. // impose the same jitter as USB MIDI.
  153. //
  154. // Another problem is that 'ppoll()' returns later than the wait
  155. // time. The problem can be minimized with high precision timers.
  156. timeout_ptr = &timeout;
  157. jack_time_t next_time = GetTimeFromFrames(timeout_frame);
  158. jack_time_t now = GetMicroSeconds();
  159. if (next_time <= now) {
  160. timeout.tv_sec = 0;
  161. timeout.tv_nsec = 0;
  162. } else {
  163. jack_time_t wait_time = next_time - now;
  164. timeout.tv_sec = wait_time / 1000000;
  165. timeout.tv_nsec = (wait_time % 1000000) * 1000;
  166. }
  167. }
  168. int poll_result = ppoll(poll_fds, poll_fd_count, timeout_ptr, 0);
  169. // Getting the current frame value here allows us to use it for
  170. // incoming MIDI bytes. This makes sense, as the data has already
  171. // arrived at this point.
  172. jack_nframes_t current_frame = GetCurrentFrame();
  173. if (poll_result == -1) {
  174. if (errno == EINTR) {
  175. continue;
  176. }
  177. jack_error("JackALSARawMidiDriver::Execute - poll error: %s",
  178. strerror(errno));
  179. break;
  180. }
  181. jack_nframes_t port_timeout;
  182. timeout_frame = 0;
  183. if (! poll_result) {
  184. // No I/O events occurred. So, only handle timeout events on
  185. // output ports.
  186. for (int i = 0; i < fPlaybackChannels; i++) {
  187. port_timeout = output_port_timeouts[i];
  188. if (port_timeout && (port_timeout <= current_frame)) {
  189. if (! output_ports[i]->ProcessPollEvents(false, true,
  190. &port_timeout)) {
  191. jack_error("JackALSARawMidiDriver::Execute - a fatal "
  192. "error occurred while processing ALSA "
  193. "output events.");
  194. goto cleanup;
  195. }
  196. output_port_timeouts[i] = port_timeout;
  197. }
  198. if (port_timeout && ((! timeout_frame) ||
  199. (port_timeout < timeout_frame))) {
  200. timeout_frame = port_timeout;
  201. }
  202. }
  203. continue;
  204. }
  205. // See if it's time to shutdown.
  206. unsigned short revents = poll_fds[0].revents;
  207. if (revents) {
  208. if (revents & (~ POLLHUP)) {
  209. jack_error("JackALSARawMidiDriver::Execute - unexpected poll "
  210. "event on pipe file descriptor.");
  211. }
  212. break;
  213. }
  214. // Handle I/O events *and* timeout events on output ports.
  215. for (int i = 0; i < fPlaybackChannels; i++) {
  216. port_timeout = output_port_timeouts[i];
  217. bool timeout = port_timeout && (port_timeout <= current_frame);
  218. if (! output_ports[i]->ProcessPollEvents(true, timeout,
  219. &port_timeout)) {
  220. jack_error("JackALSARawMidiDriver::Execute - a fatal error "
  221. "occurred while processing ALSA output events.");
  222. goto cleanup;
  223. }
  224. output_port_timeouts[i] = port_timeout;
  225. if (port_timeout && ((! timeout_frame) ||
  226. (port_timeout < timeout_frame))) {
  227. timeout_frame = port_timeout;
  228. }
  229. }
  230. // Handle I/O events on input ports. We handle these last because we
  231. // already computed the arrival time above, and will impose a delay on
  232. // the events by 'period-size' frames anyway, which gives us a bit of
  233. // borrowed time.
  234. for (int i = 0; i < fCaptureChannels; i++) {
  235. if (! input_ports[i]->ProcessPollEvents(current_frame)) {
  236. jack_error("JackALSARawMidiDriver::Execute - a fatal error "
  237. "occurred while processing ALSA input events.");
  238. goto cleanup;
  239. }
  240. }
  241. }
  242. cleanup:
  243. close(fds[0]);
  244. fds[0] = -1;
  245. jack_info("JackALSARawMidiDriver::Execute - ALSA thread exiting.");
  246. return false;
  247. }
  248. void
  249. JackALSARawMidiDriver::
  250. FreeDeviceInfo(std::vector<snd_rawmidi_info_t *> *in_info_list,
  251. std::vector<snd_rawmidi_info_t *> *out_info_list)
  252. {
  253. size_t length = in_info_list->size();
  254. for (size_t i = 0; i < length; i++) {
  255. snd_rawmidi_info_free(in_info_list->at(i));
  256. }
  257. length = out_info_list->size();
  258. for (size_t i = 0; i < length; i++) {
  259. snd_rawmidi_info_free(out_info_list->at(i));
  260. }
  261. }
  262. void
  263. JackALSARawMidiDriver::
  264. GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info,
  265. std::vector<snd_rawmidi_info_t *> *info_list)
  266. {
  267. snd_rawmidi_info_set_subdevice(info, 0);
  268. int code = snd_ctl_rawmidi_info(control, info);
  269. if (code) {
  270. if (code != -ENOENT) {
  271. HandleALSAError("GetDeviceInfo", "snd_ctl_rawmidi_info", code);
  272. }
  273. return;
  274. }
  275. unsigned int count = snd_rawmidi_info_get_subdevices_count(info);
  276. for (unsigned int i = 0; i < count; i++) {
  277. snd_rawmidi_info_set_subdevice(info, i);
  278. int code = snd_ctl_rawmidi_info(control, info);
  279. if (code) {
  280. HandleALSAError("GetDeviceInfo", "snd_ctl_rawmidi_info", code);
  281. continue;
  282. }
  283. snd_rawmidi_info_t *info_copy;
  284. code = snd_rawmidi_info_malloc(&info_copy);
  285. if (code) {
  286. HandleALSAError("GetDeviceInfo", "snd_rawmidi_info_malloc", code);
  287. continue;
  288. }
  289. snd_rawmidi_info_copy(info_copy, info);
  290. try {
  291. info_list->push_back(info_copy);
  292. } catch (std::bad_alloc &e) {
  293. snd_rawmidi_info_free(info_copy);
  294. jack_error("JackALSARawMidiDriver::GetDeviceInfo - "
  295. "std::vector::push_back: %s", e.what());
  296. }
  297. }
  298. }
  299. void
  300. JackALSARawMidiDriver::HandleALSAError(const char *driver_func,
  301. const char *alsa_func, int code)
  302. {
  303. jack_error("JackALSARawMidiDriver::%s - %s: %s", driver_func, alsa_func,
  304. snd_strerror(code));
  305. }
  306. bool
  307. JackALSARawMidiDriver::Init()
  308. {
  309. set_threaded_log_function();
  310. if (thread->AcquireSelfRealTime(fEngineControl->fServerPriority + 1)) {
  311. jack_error("JackALSARawMidiDriver::Init - could not acquire realtime "
  312. "scheduling. Continuing anyway.");
  313. }
  314. return true;
  315. }
  316. int
  317. JackALSARawMidiDriver::Open(bool capturing, bool playing, int in_channels,
  318. int out_channels, bool monitor,
  319. const char *capture_driver_name,
  320. const char *playback_driver_name,
  321. jack_nframes_t capture_latency,
  322. jack_nframes_t playback_latency)
  323. {
  324. snd_rawmidi_info_t *info;
  325. int code = snd_rawmidi_info_malloc(&info);
  326. if (code) {
  327. HandleALSAError("Open", "snd_rawmidi_info_malloc", code);
  328. return -1;
  329. }
  330. std::vector<snd_rawmidi_info_t *> in_info_list;
  331. std::vector<snd_rawmidi_info_t *> out_info_list;
  332. for (int card = -1;;) {
  333. int code = snd_card_next(&card);
  334. if (code) {
  335. HandleALSAError("Open", "snd_card_next", code);
  336. continue;
  337. }
  338. if (card == -1) {
  339. break;
  340. }
  341. char name[32];
  342. snprintf(name, sizeof(name), "hw:%d", card);
  343. snd_ctl_t *control;
  344. code = snd_ctl_open(&control, name, SND_CTL_NONBLOCK);
  345. if (code) {
  346. HandleALSAError("Open", "snd_ctl_open", code);
  347. continue;
  348. }
  349. for (int device = -1;;) {
  350. code = snd_ctl_rawmidi_next_device(control, &device);
  351. if (code) {
  352. HandleALSAError("Open", "snd_ctl_rawmidi_next_device", code);
  353. continue;
  354. }
  355. if (device == -1) {
  356. break;
  357. }
  358. snd_rawmidi_info_set_device(info, device);
  359. snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
  360. GetDeviceInfo(control, info, &in_info_list);
  361. snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT);
  362. GetDeviceInfo(control, info, &out_info_list);
  363. }
  364. snd_ctl_close(control);
  365. }
  366. snd_rawmidi_info_free(info);
  367. size_t potential_inputs = in_info_list.size();
  368. size_t potential_outputs = out_info_list.size();
  369. if (! (potential_inputs || potential_outputs)) {
  370. jack_error("JackALSARawMidiDriver::Open - no ALSA raw MIDI input or "
  371. "output ports found.");
  372. FreeDeviceInfo(&in_info_list, &out_info_list);
  373. return -1;
  374. }
  375. size_t num_inputs = 0;
  376. size_t num_outputs = 0;
  377. const char *client_name = fClientControl.fName;
  378. if (potential_inputs) {
  379. try {
  380. input_ports = new JackALSARawMidiInputPort *[potential_inputs];
  381. } catch (std::exception& e) {
  382. jack_error("JackALSARawMidiDriver::Open - while creating input "
  383. "port array: %s", e.what());
  384. FreeDeviceInfo(&in_info_list, &out_info_list);
  385. return -1;
  386. }
  387. }
  388. if (potential_outputs) {
  389. try {
  390. output_ports = new JackALSARawMidiOutputPort *[potential_outputs];
  391. } catch (std::exception& e) {
  392. jack_error("JackALSARawMidiDriver::Open - while creating output "
  393. "port array: %s", e.what());
  394. FreeDeviceInfo(&in_info_list, &out_info_list);
  395. goto delete_input_ports;
  396. }
  397. }
  398. for (size_t i = 0; i < potential_inputs; i++) {
  399. snd_rawmidi_info_t *info = in_info_list.at(i);
  400. try {
  401. input_ports[num_inputs] = new JackALSARawMidiInputPort(client_name, info, i);
  402. num_inputs++;
  403. } catch (std::exception& e) {
  404. jack_error("JackALSARawMidiDriver::Open - while creating new "
  405. "JackALSARawMidiInputPort: %s", e.what());
  406. }
  407. snd_rawmidi_info_free(info);
  408. }
  409. for (size_t i = 0; i < potential_outputs; i++) {
  410. snd_rawmidi_info_t *info = out_info_list.at(i);
  411. try {
  412. output_ports[num_outputs] = new JackALSARawMidiOutputPort(client_name, info, i);
  413. num_outputs++;
  414. } catch (std::exception& e) {
  415. jack_error("JackALSARawMidiDriver::Open - while creating new "
  416. "JackALSARawMidiOutputPort: %s", e.what());
  417. }
  418. snd_rawmidi_info_free(info);
  419. }
  420. if (! (num_inputs || num_outputs)) {
  421. jack_error("JackALSARawMidiDriver::Open - none of the potential "
  422. "inputs or outputs were successfully opened.");
  423. } else if (JackMidiDriver::Open(capturing, playing, num_inputs,
  424. num_outputs, monitor, capture_driver_name,
  425. playback_driver_name, capture_latency,
  426. playback_latency)) {
  427. jack_error("JackALSARawMidiDriver::Open - JackMidiDriver::Open error");
  428. } else {
  429. return 0;
  430. }
  431. if (output_ports) {
  432. for (size_t i = 0; i < num_outputs; i++) {
  433. delete output_ports[i];
  434. }
  435. delete[] output_ports;
  436. output_ports = 0;
  437. }
  438. delete_input_ports:
  439. if (input_ports) {
  440. for (size_t i = 0; i < num_inputs; i++) {
  441. delete input_ports[i];
  442. }
  443. delete[] input_ports;
  444. input_ports = 0;
  445. }
  446. return -1;
  447. }
  448. int
  449. JackALSARawMidiDriver::Read()
  450. {
  451. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  452. for (int i = 0; i < fCaptureChannels; i++) {
  453. if (! input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size)) {
  454. return -1;
  455. }
  456. }
  457. return 0;
  458. }
  459. int
  460. JackALSARawMidiDriver::Start()
  461. {
  462. jack_info("JackALSARawMidiDriver::Start - Starting 'alsarawmidi' driver.");
  463. JackMidiDriver::Start();
  464. poll_fd_count = 1;
  465. for (int i = 0; i < fCaptureChannels; i++) {
  466. poll_fd_count += input_ports[i]->GetPollDescriptorCount();
  467. }
  468. for (int i = 0; i < fPlaybackChannels; i++) {
  469. poll_fd_count += output_ports[i]->GetPollDescriptorCount();
  470. }
  471. try {
  472. poll_fds = new pollfd[poll_fd_count];
  473. } catch (std::exception& e) {
  474. jack_error("JackALSARawMidiDriver::Start - creating poll descriptor "
  475. "structures failed: %s", e.what());
  476. return -1;
  477. }
  478. if (fPlaybackChannels) {
  479. try {
  480. output_port_timeouts = new jack_nframes_t[fPlaybackChannels];
  481. } catch (std::exception& e) {
  482. jack_error("JackALSARawMidiDriver::Start - creating array for "
  483. "output port timeout values failed: %s", e.what());
  484. goto free_poll_descriptors;
  485. }
  486. }
  487. struct pollfd *poll_fd_iter;
  488. try {
  489. CreateNonBlockingPipe(fds);
  490. } catch (std::exception& e) {
  491. jack_error("JackALSARawMidiDriver::Start - while creating wake pipe: "
  492. "%s", e.what());
  493. goto free_output_port_timeouts;
  494. }
  495. poll_fds[0].events = POLLERR | POLLIN | POLLNVAL;
  496. poll_fds[0].fd = fds[0];
  497. poll_fd_iter = poll_fds + 1;
  498. for (int i = 0; i < fCaptureChannels; i++) {
  499. JackALSARawMidiInputPort *input_port = input_ports[i];
  500. input_port->PopulatePollDescriptors(poll_fd_iter);
  501. poll_fd_iter += input_port->GetPollDescriptorCount();
  502. }
  503. for (int i = 0; i < fPlaybackChannels; i++) {
  504. JackALSARawMidiOutputPort *output_port = output_ports[i];
  505. output_port->PopulatePollDescriptors(poll_fd_iter);
  506. poll_fd_iter += output_port->GetPollDescriptorCount();
  507. output_port_timeouts[i] = 0;
  508. }
  509. jack_info("JackALSARawMidiDriver::Start - starting ALSA thread ...");
  510. if (! thread->StartSync()) {
  511. jack_info("JackALSARawMidiDriver::Start - started ALSA thread.");
  512. return 0;
  513. }
  514. jack_error("JackALSARawMidiDriver::Start - failed to start MIDI "
  515. "processing thread.");
  516. DestroyNonBlockingPipe(fds);
  517. fds[1] = -1;
  518. fds[0] = -1;
  519. free_output_port_timeouts:
  520. delete[] output_port_timeouts;
  521. output_port_timeouts = 0;
  522. free_poll_descriptors:
  523. delete[] poll_fds;
  524. poll_fds = 0;
  525. return -1;
  526. }
  527. int
  528. JackALSARawMidiDriver::Stop()
  529. {
  530. jack_info("JackALSARawMidiDriver::Stop - stopping 'alsarawmidi' driver.");
  531. JackMidiDriver::Stop();
  532. if (fds[1] != -1) {
  533. close(fds[1]);
  534. fds[1] = -1;
  535. }
  536. int result;
  537. const char *verb;
  538. switch (thread->GetStatus()) {
  539. case JackThread::kIniting:
  540. case JackThread::kStarting:
  541. result = thread->Kill();
  542. verb = "kill";
  543. break;
  544. case JackThread::kRunning:
  545. result = thread->Stop();
  546. verb = "stop";
  547. break;
  548. default:
  549. result = 0;
  550. verb = 0;
  551. }
  552. if (fds[0] != -1) {
  553. close(fds[0]);
  554. fds[0] = -1;
  555. }
  556. if (output_port_timeouts) {
  557. delete[] output_port_timeouts;
  558. output_port_timeouts = 0;
  559. }
  560. if (poll_fds) {
  561. delete[] poll_fds;
  562. poll_fds = 0;
  563. }
  564. if (result) {
  565. jack_error("JackALSARawMidiDriver::Stop - could not %s MIDI "
  566. "processing thread.", verb);
  567. }
  568. return result;
  569. }
  570. int
  571. JackALSARawMidiDriver::Write()
  572. {
  573. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  574. for (int i = 0; i < fPlaybackChannels; i++) {
  575. if (! output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size)) {
  576. return -1;
  577. }
  578. }
  579. return 0;
  580. }
  581. #ifdef __cplusplus
  582. extern "C" {
  583. #endif
  584. // singleton kind of driver
  585. static Jack::JackALSARawMidiDriver* driver = NULL;
  586. SERVER_EXPORT jack_driver_desc_t *
  587. driver_get_descriptor()
  588. {
  589. // X: There could be parameters here regarding setting I/O buffer
  590. // sizes. I don't think MIDI drivers can accept parameters right
  591. // now without being set as the main driver.
  592. return jack_driver_descriptor_construct("alsarawmidi", JackDriverSlave, "Alternative ALSA raw MIDI backend.", NULL);
  593. }
  594. SERVER_EXPORT Jack::JackDriverClientInterface *
  595. driver_initialize(Jack::JackLockedEngine *engine, Jack::JackSynchro *table,
  596. const JSList *params)
  597. {
  598. // singleton kind of driver
  599. if (!driver) {
  600. driver = new Jack::JackALSARawMidiDriver("system_midi", "alsarawmidi", engine, table);
  601. if (driver->Open(1, 1, 0, 0, false, "midi in", "midi out", 0, 0) == 0) {
  602. return driver;
  603. } else {
  604. delete driver;
  605. return NULL;
  606. }
  607. } else {
  608. jack_info("JackALSARawMidiDriver already allocated, cannot be loaded twice");
  609. return NULL;
  610. }
  611. }
  612. #ifdef __cplusplus
  613. }
  614. #endif