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