Jack2  1.9.8
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 <stdexcept>
22 
23 #include <mach/mach_time.h>
24 
25 #include "JackCoreMidiDriver.h"
26 #include "JackCoreMidiUtil.h"
27 #include "JackEngineControl.h"
28 
30 
31 static char capture_driver_name[256];
32 static char playback_driver_name[256];
33 
34 static int in_channels, out_channels;
35 static bool capturing, playing, monitor;
36 
37 static jack_nframes_t capture_latency, playback_latency;
38 
40 // Static callbacks
42 
43 void
44 JackCoreMidiDriver::HandleInputEvent(const MIDIPacketList *packet_list,
45  void *driver, void *port)
46 {
47  ((JackCoreMidiPhysicalInputPort *) port)->ProcessCoreMidi(packet_list);
48 }
49 
50 void
51 JackCoreMidiDriver::HandleNotificationEvent(const MIDINotification *message,
52  void *driver)
53 {
54  ((JackCoreMidiDriver *) driver)->HandleNotification(message);
55 }
56 
58 // Class
60 
61 JackCoreMidiDriver::JackCoreMidiDriver(const char *name, const char *alias,
62  JackLockedEngine *engine,
63  JackSynchro *table):
64  JackMidiDriver(name, alias, engine, table),fThread(this)
65 {
66  mach_timebase_info_data_t info;
67  kern_return_t result = mach_timebase_info(&info);
68  if (result != KERN_SUCCESS) {
69  throw std::runtime_error(mach_error_string(result));
70  }
71  client = 0;
72  fCaptureChannels = 0;
73  fPlaybackChannels = 0;
74  num_physical_inputs = 0;
75  num_physical_outputs = 0;
76  num_virtual_inputs = 0;
77  num_virtual_outputs = 0;
78  physical_input_ports = 0;
79  physical_output_ports = 0;
80  time_ratio = (((double) info.numer) / info.denom) / 1000.0;
81  virtual_input_ports = 0;
82  virtual_output_ports = 0;
83  internal_input = 0;
84  internal_output = 0;
85 }
86 
87 JackCoreMidiDriver::~JackCoreMidiDriver()
88 {}
89 
91 {
92  return OpenAux();
93 }
94 
95 bool JackCoreMidiDriver::OpenAux()
96 {
97  int pi_count = 0;
98  int po_count = 0;
99  int vi_count = 0;
100  int vo_count = 0;
101  ItemCount potential_po_count;
102  ItemCount potential_pi_count;
103 
104  CFStringRef name = CFStringCreateWithCString(0, "JackMidi",
105  CFStringGetSystemEncoding());
106  if (! name) {
107  jack_error("JackCoreMidiDriver::Open - failed to allocate memory for "
108  "client name string");
109  return false;
110  }
111 
112  OSStatus status = MIDIClientCreate(name, HandleNotificationEvent, this,
113  &client);
114 
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 + 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 + 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 
249  if (! (pi_count || po_count || in_channels || out_channels)) {
250  jack_error("JackCoreMidiDriver::Open - no CoreMIDI inputs or outputs "
251  "found, and no virtual ports allocated.");
252  }
253 
254  if (! JackMidiDriver::Open(capturing, playing,
255  in_channels + pi_count,
256  out_channels + po_count, monitor,
257  capture_driver_name,
258  playback_driver_name, capture_latency,
259  playback_latency)) {
260  num_physical_inputs = pi_count;
261  num_physical_outputs = po_count;
262  num_virtual_inputs = in_channels;
263  num_virtual_outputs = out_channels;
264  return true;
265  }
266 
267  destroy:
268 
269  if (physical_input_ports) {
270  for (int i = 0; i < pi_count; i++) {
271  delete physical_input_ports[i];
272  }
273  delete[] physical_input_ports;
274  physical_input_ports = 0;
275  }
276 
277  if (physical_output_ports) {
278  for (int i = 0; i < po_count; i++) {
279  delete physical_output_ports[i];
280  }
281  delete[] physical_output_ports;
282  physical_output_ports = 0;
283  }
284 
285  if (virtual_input_ports) {
286  for (int i = 0; i < vi_count; i++) {
287  delete virtual_input_ports[i];
288  }
289  delete[] virtual_input_ports;
290  virtual_input_ports = 0;
291  }
292 
293  if (virtual_output_ports) {
294  for (int i = 0; i < vo_count; i++) {
295  delete virtual_output_ports[i];
296  }
297  delete[] virtual_output_ports;
298  virtual_output_ports = 0;
299  }
300 
301  if (internal_output) {
302  status = MIDIPortDispose(internal_output);
303  if (status != noErr) {
304  WriteMacOSError("JackCoreMidiDriver::Open", "MIDIPortDispose", status);
305  }
306  }
307 
308  if (internal_input) {
309  status = MIDIPortDispose(internal_input);
310  if (status != noErr) {
311  WriteMacOSError("JackCoreMidiDriver::Open", "MIDIPortDispose", status);
312  }
313  }
314 
315  if (client) {
316  status = MIDIClientDispose(client);
317  if (status != noErr) {
318  WriteMacOSError("JackCoreMidiDriver::Open", "MIDIClientDispose",
319  status);
320  }
321  }
322 
323  // Default open
324  if (! JackMidiDriver::Open(capturing, playing,
325  in_channels + pi_count,
326  out_channels + po_count, monitor,
327  capture_driver_name,
328  playback_driver_name, capture_latency,
329  playback_latency)) {
330  client = 0;
331  num_physical_inputs = 0;
332  num_physical_outputs = 0;
333  num_virtual_inputs = 0;
334  num_virtual_outputs = 0;
335  return true;
336  } else {
337  return false;
338  }
339 }
340 
341 bool JackCoreMidiDriver::Execute()
342 {
343  CFRunLoopRun();
344  return false;
345 }
346 
347 int
348 JackCoreMidiDriver::Attach()
349 {
350  jack_nframes_t buffer_size = fEngineControl->fBufferSize;
351  jack_port_id_t index;
352  jack_nframes_t latency = buffer_size;
353  jack_latency_range_t latency_range;
354  const char *name;
355  JackPort *port;
356  JackCoreMidiPort *port_obj;
357  latency_range.max = latency;
358  latency_range.min = latency;
359 
360  // Physical inputs
361  for (int i = 0; i < num_physical_inputs; i++) {
362  port_obj = physical_input_ports[i];
363  name = port_obj->GetName();
364  if (fEngine->PortRegister(fClientControl.fRefNum, name,
365  JACK_DEFAULT_MIDI_TYPE,
366  CaptureDriverFlags, buffer_size, &index) < 0) {
367  jack_error("JackCoreMidiDriver::Attach - cannot register physical "
368  "input port with name '%s'.", name);
369  // X: Do we need to deallocate ports?
370  return -1;
371  }
372  port = fGraphManager->GetPort(index);
373  port->SetAlias(port_obj->GetAlias());
374  port->SetLatencyRange(JackCaptureLatency, &latency_range);
375  fCapturePortList[i] = index;
376  }
377 
378  // Virtual inputs
379  for (int i = 0; i < num_virtual_inputs; i++) {
380  port_obj = virtual_input_ports[i];
381  name = port_obj->GetName();
382  if (fEngine->PortRegister(fClientControl.fRefNum, name,
383  JACK_DEFAULT_MIDI_TYPE,
384  CaptureDriverFlags, buffer_size, &index) < 0) {
385  jack_error("JackCoreMidiDriver::Attach - cannot register virtual "
386  "input port with name '%s'.", name);
387  // X: Do we need to deallocate ports?
388  return -1;
389  }
390  port = fGraphManager->GetPort(index);
391  port->SetAlias(port_obj->GetAlias());
392  port->SetLatencyRange(JackCaptureLatency, &latency_range);
393  fCapturePortList[num_physical_inputs + i] = index;
394  }
395 
396  if (! fEngineControl->fSyncMode) {
397  latency += buffer_size;
398  latency_range.max = latency;
399  latency_range.min = latency;
400  }
401 
402  // Physical outputs
403  for (int i = 0; i < num_physical_outputs; i++) {
404  port_obj = physical_output_ports[i];
405  name = port_obj->GetName();
406  fEngine->PortRegister(fClientControl.fRefNum, name,
407  JACK_DEFAULT_MIDI_TYPE,
408  PlaybackDriverFlags, buffer_size, &index);
409  if (index == NO_PORT) {
410  jack_error("JackCoreMidiDriver::Attach - cannot register physical "
411  "output port with name '%s'.", name);
412  // X: Do we need to deallocate ports?
413  return -1;
414  }
415  port = fGraphManager->GetPort(index);
416  port->SetAlias(port_obj->GetAlias());
417  port->SetLatencyRange(JackPlaybackLatency, &latency_range);
418  fPlaybackPortList[i] = index;
419  }
420 
421  // Virtual outputs
422  for (int i = 0; i < num_virtual_outputs; i++) {
423  port_obj = virtual_output_ports[i];
424  name = port_obj->GetName();
425  fEngine->PortRegister(fClientControl.fRefNum, name,
426  JACK_DEFAULT_MIDI_TYPE,
427  PlaybackDriverFlags, buffer_size, &index);
428  if (index == NO_PORT) {
429  jack_error("JackCoreMidiDriver::Attach - cannot register virtual "
430  "output port with name '%s'.", name);
431  // X: Do we need to deallocate ports?
432  return -1;
433  }
434  port = fGraphManager->GetPort(index);
435  port->SetAlias(port_obj->GetAlias());
436  port->SetLatencyRange(JackPlaybackLatency, &latency_range);
437  fPlaybackPortList[num_physical_outputs + i] = index;
438  }
439 
440  return 0;
441 }
442 
443 int
444 JackCoreMidiDriver::Close()
445 {
446  fThread.Kill();
447  return CloseAux();
448 }
449 
450 int
451 JackCoreMidiDriver::CloseAux()
452 {
453  // Generic MIDI driver close
454  int result = JackMidiDriver::Close();
455 
456  OSStatus status;
457  if (physical_input_ports) {
458  for (int i = 0; i < num_physical_inputs; i++) {
459  delete physical_input_ports[i];
460  }
461  delete[] physical_input_ports;
462  num_physical_inputs = 0;
463  physical_input_ports = 0;
464  if (internal_input) {
465  status = MIDIPortDispose(internal_input);
466  if (status != noErr) {
467  WriteMacOSError("JackCoreMidiDriver::Close", "MIDIPortDispose",
468  status);
469  result = -1;
470  }
471  internal_input = 0;
472  }
473  }
474  if (physical_output_ports) {
475  for (int i = 0; i < num_physical_outputs; i++) {
476  delete physical_output_ports[i];
477  }
478  delete[] physical_output_ports;
479  num_physical_outputs = 0;
480  physical_output_ports = 0;
481  if (internal_output) {
482  status = MIDIPortDispose(internal_output);
483  if (status != noErr) {
484  WriteMacOSError("JackCoreMidiDriver::Close", "MIDIPortDispose",
485  status);
486  result = -1;
487  }
488  internal_output = 0;
489  }
490  }
491  if (virtual_input_ports) {
492  for (int i = 0; i < num_virtual_inputs; i++) {
493  delete virtual_input_ports[i];
494  }
495  delete[] virtual_input_ports;
496  num_virtual_inputs = 0;
497  virtual_input_ports = 0;
498  }
499  if (virtual_output_ports) {
500  for (int i = 0; i < num_virtual_outputs; i++) {
501  delete virtual_output_ports[i];
502  }
503  delete[] virtual_output_ports;
504  num_virtual_outputs = 0;
505  virtual_output_ports = 0;
506  }
507 
508  if (client) {
509  status = MIDIClientDispose(client);
510  if (status != noErr) {
511  WriteMacOSError("JackCoreMidiDriver::Close", "MIDIClientDispose",
512  status);
513  result = -1;
514  }
515  client = 0;
516  }
517  return result;
518 }
519 
520 void
521 JackCoreMidiDriver::Restart()
522 {
523  JackLock lock(this);
524 
525  SaveConnections();
526  Stop();
527  Detach();
528  CloseAux();
529  OpenAux();
530  Attach();
531  Start();
532  RestoreConnections();
533 }
534 
535 void
536 JackCoreMidiDriver::HandleNotification(const MIDINotification *message)
537 {
538  switch (message->messageID) {
539 
540  case kMIDIMsgSetupChanged:
541  Restart();
542  break;
543 
544  case kMIDIMsgObjectAdded:
545  break;
546 
547  case kMIDIMsgObjectRemoved:
548  break;
549 
550  }
551 }
552 
553 int
554 JackCoreMidiDriver::Open(bool capturing_aux, bool playing_aux, int in_channels_aux,
555  int out_channels_aux, bool monitor_aux,
556  const char* capture_driver_name_aux,
557  const char* playback_driver_name_aux,
558  jack_nframes_t capture_latency_aux,
559  jack_nframes_t playback_latency_aux)
560 {
561 
562  strcpy(capture_driver_name, capture_driver_name_aux);
563  strcpy(playback_driver_name, playback_driver_name_aux);
564 
565  capturing = capturing_aux;
566  playing = playing_aux;
567  in_channels = in_channels_aux;
568  out_channels = out_channels_aux;
569  monitor = monitor_aux;
570  capture_latency = capture_latency_aux;
571  playback_latency = playback_latency_aux;
572 
573  fThread.StartSync();
574 
575  int count = 0;
576  while (fThread.GetStatus() != JackThread::kRunning && ++count < WAIT_COUNTER) {
577  JackSleep(100000);
578  jack_log("JackCoreMidiDriver::Open wait count = %d", count);
579 
580  }
581  if (count == WAIT_COUNTER) {
582  jack_info("Cannot open CoreMIDI driver");
583  fThread.Kill();
584  return -1;
585  } else {
586  JackSleep(10000);
587  jack_info("CoreMIDI driver is running...");
588  }
589 
590  return 0;
591 }
592 
593 int
594 JackCoreMidiDriver::Start()
595 {
596  jack_info("JackCoreMidiDriver::Start - Starting driver.");
597 
598  JackMidiDriver::Start();
599 
600  int pi_count = 0;
601  int po_count = 0;
602  int vi_count = 0;
603  int vo_count = 0;
604 
605  jack_info("JackCoreMidiDriver::Start - Enabling physical input ports.");
606 
607  for (; pi_count < num_physical_inputs; pi_count++) {
608  if (physical_input_ports[pi_count]->Start() < 0) {
609  jack_error("JackCoreMidiDriver::Start - Failed to enable physical "
610  "input port.");
611  goto stop_physical_input_ports;
612  }
613  }
614 
615  jack_info("JackCoreMidiDriver::Start - Enabling physical output ports.");
616 
617  for (; po_count < num_physical_outputs; po_count++) {
618  if (physical_output_ports[po_count]->Start() < 0) {
619  jack_error("JackCoreMidiDriver::Start - Failed to enable physical "
620  "output port.");
621  goto stop_physical_output_ports;
622  }
623  }
624 
625  jack_info("JackCoreMidiDriver::Start - Enabling virtual input ports.");
626 
627  for (; vi_count < num_virtual_inputs; vi_count++) {
628  if (virtual_input_ports[vi_count]->Start() < 0) {
629  jack_error("JackCoreMidiDriver::Start - Failed to enable virtual "
630  "input port.");
631  goto stop_virtual_input_ports;
632  }
633  }
634 
635  jack_info("JackCoreMidiDriver::Start - Enabling virtual output ports.");
636 
637  for (; vo_count < num_virtual_outputs; vo_count++) {
638  if (virtual_output_ports[vo_count]->Start() < 0) {
639  jack_error("JackCoreMidiDriver::Start - Failed to enable virtual "
640  "output port.");
641  goto stop_virtual_output_ports;
642  }
643  }
644 
645  jack_info("JackCoreMidiDriver::Start - Driver started.");
646 
647  return 0;
648 
649  stop_virtual_output_ports:
650  for (int i = 0; i < vo_count; i++) {
651  if (virtual_output_ports[i]->Stop() < 0) {
652  jack_error("JackCoreMidiDriver::Start - Failed to disable virtual "
653  "output port.");
654  }
655  }
656  stop_virtual_input_ports:
657  for (int i = 0; i < vi_count; i++) {
658  if (virtual_input_ports[i]->Stop() < 0) {
659  jack_error("JackCoreMidiDriver::Start - Failed to disable virtual "
660  "input port.");
661  }
662  }
663  stop_physical_output_ports:
664  for (int i = 0; i < po_count; i++) {
665  if (physical_output_ports[i]->Stop() < 0) {
666  jack_error("JackCoreMidiDriver::Start - Failed to disable "
667  "physical output port.");
668  }
669  }
670  stop_physical_input_ports:
671  for (int i = 0; i < pi_count; i++) {
672  if (physical_input_ports[i]->Stop() < 0) {
673  jack_error("JackCoreMidiDriver::Start - Failed to disable "
674  "physical input port.");
675  }
676  }
677 
678  return -1;
679 }
680 
681 int
682 JackCoreMidiDriver::Stop()
683 {
684  int result = 0;
685 
686  JackMidiDriver::Stop();
687 
688  jack_info("JackCoreMidiDriver::Stop - disabling physical input ports.");
689 
690  for (int i = 0; i < num_physical_inputs; i++) {
691  if (physical_input_ports[i]->Stop() < 0) {
692  jack_error("JackCoreMidiDriver::Stop - Failed to disable physical "
693  "input port.");
694  result = -1;
695  }
696  }
697 
698  jack_info("JackCoreMidiDriver::Stop - disabling physical output ports.");
699 
700  for (int i = 0; i < num_physical_outputs; i++) {
701  if (physical_output_ports[i]->Stop() < 0) {
702  jack_error("JackCoreMidiDriver::Stop - Failed to disable physical "
703  "output port.");
704  result = -1;
705  }
706  }
707 
708  jack_info("JackCoreMidiDriver::Stop - disabling virtual input ports.");
709 
710  for (int i = 0; i < num_virtual_inputs; i++) {
711  if (virtual_input_ports[i]->Stop() < 0) {
712  jack_error("JackCoreMidiDriver::Stop - Failed to disable virtual "
713  "input port.");
714  result = -1;
715  }
716  }
717 
718  jack_info("JackCoreMidiDriver::Stop - disabling virtual output ports.");
719 
720  for (int i = 0; i < num_virtual_outputs; i++) {
721  if (virtual_output_ports[i]->Stop() < 0) {
722  jack_error("JackCoreMidiDriver::Stop - Failed to disable virtual "
723  "output port.");
724  result = -1;
725  }
726  }
727 
728  return result;
729 }
730 
731 int
732 JackCoreMidiDriver::ProcessRead()
733 {
734  int res;
735  if (Trylock()) {
736  res = (fEngineControl->fSyncMode) ? ProcessReadSync() : ProcessReadAsync();
737  Unlock();
738  } else {
739  res = -1;
740  }
741  return res;
742 }
743 
744 int
745 JackCoreMidiDriver::ProcessWrite()
746 {
747  int res;
748  if (Trylock()) {
749  res = (fEngineControl->fSyncMode) ? ProcessWriteSync() : ProcessWriteAsync();
750  Unlock();
751  } else {
752  res = -1;
753  }
754  return res;
755 }
756 
757 int
758 JackCoreMidiDriver::Read()
759 {
760  jack_nframes_t buffer_size = fEngineControl->fBufferSize;
761  for (int i = 0; i < num_physical_inputs; i++) {
762  physical_input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
763  }
764  for (int i = 0; i < num_virtual_inputs; i++) {
765  virtual_input_ports[i]->
766  ProcessJack(GetInputBuffer(num_physical_inputs + i), buffer_size);
767  }
768  return 0;
769 }
770 
771 int
772 JackCoreMidiDriver::Write()
773 {
774  jack_nframes_t buffer_size = fEngineControl->fBufferSize;
775  for (int i = 0; i < num_physical_outputs; i++) {
776  physical_output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
777  }
778  for (int i = 0; i < num_virtual_outputs; i++) {
779  virtual_output_ports[i]->
780  ProcessJack(GetOutputBuffer(num_physical_outputs + i), buffer_size);
781  }
782  return 0;
783 }
784 
785 #ifdef __cplusplus
786 extern "C" {
787 #endif
788 
789  // singleton kind of driver
790  static Jack::JackDriverClientInterface* driver = NULL;
791 
792  SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
793  {
794  jack_driver_desc_t * desc;
797 
798  desc = jack_driver_descriptor_construct("coremidi", JackDriverSlave, "Apple CoreMIDI API based MIDI backend", &filler);
799 
800  value.ui = 0;
801  jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "CoreMIDI virtual bus", NULL);
802  jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "CoreMIDI virtual bus", NULL);
803 
804  return desc;
805  }
806 
807  SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
808  {
809  const JSList * node;
810  const jack_driver_param_t * param;
811  int virtual_in = 0;
812  int virtual_out = 0;
813 
814  for (node = params; node; node = jack_slist_next (node)) {
815  param = (const jack_driver_param_t *) node->data;
816 
817  switch (param->character) {
818 
819  case 'i':
820  virtual_in = param->value.ui;
821  break;
822 
823  case 'o':
824  virtual_out = param->value.ui;
825  break;
826  }
827  }
828 
829  // singleton kind of driver
830  if (!driver) {
831  driver = new Jack::JackCoreMidiDriver("system_midi", "coremidi", engine, table);
832  if (driver->Open(1, 1, virtual_in, virtual_out, false, "in", "out", 0, 0) == 0) {
833  return driver;
834  } else {
835  delete driver;
836  return NULL;
837  }
838  } else {
839  jack_info("JackCoreMidiDriver already allocated, cannot be loaded twice");
840  return NULL;
841  }
842  }
843 
844 #ifdef __cplusplus
845 }
846 #endif