23 #include <mach/mach_time.h>
25 #include "JackCoreMidiDriver.h"
26 #include "JackCoreMidiUtil.h"
27 #include "JackEngineControl.h"
31 static char capture_driver_name[256];
32 static char playback_driver_name[256];
34 static int in_channels, out_channels;
35 static bool capturing, playing, monitor;
37 static jack_nframes_t capture_latency, playback_latency;
44 JackCoreMidiDriver::HandleInputEvent(
const MIDIPacketList *packet_list,
45 void *driver,
void *port)
47 ((JackCoreMidiPhysicalInputPort *) port)->ProcessCoreMidi(packet_list);
51 JackCoreMidiDriver::HandleNotificationEvent(
const MIDINotification *message,
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));
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;
87 JackCoreMidiDriver::~JackCoreMidiDriver()
95 bool JackCoreMidiDriver::OpenAux()
101 ItemCount potential_po_count;
102 ItemCount potential_pi_count;
104 CFStringRef name = CFStringCreateWithCString(0,
"JackMidi",
105 CFStringGetSystemEncoding());
107 jack_error(
"JackCoreMidiDriver::Open - failed to allocate memory for "
108 "client name string");
112 OSStatus status = MIDIClientCreate(name, HandleNotificationEvent,
this,
117 if (status != noErr) {
118 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIClientCreate",
123 char *client_name = fClientControl.fName;
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",
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());
145 for (ItemCount i = 0; i < potential_pi_count; i++) {
147 physical_input_ports[pi_count] =
148 new JackCoreMidiPhysicalInputPort(fAliasName, client_name,
149 capture_driver_name, i,
150 client, internal_input,
152 }
catch (std::exception e) {
153 jack_error(
"JackCoreMidiDriver::Open - while creating "
154 "physical input port: %s", e.what());
162 potential_po_count = MIDIGetNumberOfDestinations();
163 if (potential_po_count) {
164 status = MIDIOutputPortCreate(client, CFSTR(
"Physical Output Port"),
166 if (status != noErr) {
167 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIOutputPortCreate",
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());
181 for (ItemCount i = 0; i < potential_po_count; i++) {
183 physical_output_ports[po_count] =
184 new JackCoreMidiPhysicalOutputPort(fAliasName, client_name,
185 playback_driver_name, i,
186 client, internal_output,
188 }
catch (std::exception e) {
189 jack_error(
"JackCoreMidiDriver::Open - while creating "
190 "physical output port: %s", e.what());
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());
208 for (vi_count = 0; vi_count < in_channels; vi_count++) {
210 virtual_input_ports[vi_count] =
211 new JackCoreMidiVirtualInputPort(fAliasName, client_name,
213 vi_count + pi_count, client,
215 }
catch (std::exception e) {
216 jack_error(
"JackCoreMidiDriver::Open - while creating virtual "
217 "input port: %s", e.what());
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());
233 for (vo_count = 0; vo_count < out_channels; vo_count++) {
235 virtual_output_ports[vo_count] =
236 new JackCoreMidiVirtualOutputPort(fAliasName, client_name,
237 playback_driver_name,
238 vo_count + po_count, client,
240 }
catch (std::exception e) {
241 jack_error(
"JackCoreMidiDriver::Open - while creating virtual "
242 "output port: %s", e.what());
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.");
254 if (! JackMidiDriver::Open(capturing, playing,
255 in_channels + pi_count,
256 out_channels + po_count, monitor,
258 playback_driver_name, capture_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;
269 if (physical_input_ports) {
270 for (
int i = 0; i < pi_count; i++) {
271 delete physical_input_ports[i];
273 delete[] physical_input_ports;
274 physical_input_ports = 0;
277 if (physical_output_ports) {
278 for (
int i = 0; i < po_count; i++) {
279 delete physical_output_ports[i];
281 delete[] physical_output_ports;
282 physical_output_ports = 0;
285 if (virtual_input_ports) {
286 for (
int i = 0; i < vi_count; i++) {
287 delete virtual_input_ports[i];
289 delete[] virtual_input_ports;
290 virtual_input_ports = 0;
293 if (virtual_output_ports) {
294 for (
int i = 0; i < vo_count; i++) {
295 delete virtual_output_ports[i];
297 delete[] virtual_output_ports;
298 virtual_output_ports = 0;
301 if (internal_output) {
302 status = MIDIPortDispose(internal_output);
303 if (status != noErr) {
304 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIPortDispose", status);
308 if (internal_input) {
309 status = MIDIPortDispose(internal_input);
310 if (status != noErr) {
311 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIPortDispose", status);
316 status = MIDIClientDispose(client);
317 if (status != noErr) {
318 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIClientDispose",
324 if (! JackMidiDriver::Open(capturing, playing,
325 in_channels + pi_count,
326 out_channels + po_count, monitor,
328 playback_driver_name, capture_latency,
331 num_physical_inputs = 0;
332 num_physical_outputs = 0;
333 num_virtual_inputs = 0;
334 num_virtual_outputs = 0;
341 bool JackCoreMidiDriver::Execute()
348 JackCoreMidiDriver::Attach()
350 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
351 jack_port_id_t index;
352 jack_nframes_t latency = buffer_size;
356 JackCoreMidiPort *port_obj;
357 latency_range.
max = latency;
358 latency_range.
min = latency;
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);
372 port = fGraphManager->GetPort(index);
373 port->SetAlias(port_obj->GetAlias());
374 port->SetLatencyRange(JackCaptureLatency, &latency_range);
375 fCapturePortList[i] = index;
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);
390 port = fGraphManager->GetPort(index);
391 port->SetAlias(port_obj->GetAlias());
392 port->SetLatencyRange(JackCaptureLatency, &latency_range);
393 fCapturePortList[num_physical_inputs + i] = index;
396 if (! fEngineControl->fSyncMode) {
397 latency += buffer_size;
398 latency_range.
max = latency;
399 latency_range.
min = latency;
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);
415 port = fGraphManager->GetPort(index);
416 port->SetAlias(port_obj->GetAlias());
417 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
418 fPlaybackPortList[i] = index;
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);
434 port = fGraphManager->GetPort(index);
435 port->SetAlias(port_obj->GetAlias());
436 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
437 fPlaybackPortList[num_physical_outputs + i] = index;
444 JackCoreMidiDriver::Close()
451 JackCoreMidiDriver::CloseAux()
454 int result = JackMidiDriver::Close();
457 if (physical_input_ports) {
458 for (
int i = 0; i < num_physical_inputs; i++) {
459 delete physical_input_ports[i];
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",
474 if (physical_output_ports) {
475 for (
int i = 0; i < num_physical_outputs; i++) {
476 delete physical_output_ports[i];
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",
491 if (virtual_input_ports) {
492 for (
int i = 0; i < num_virtual_inputs; i++) {
493 delete virtual_input_ports[i];
495 delete[] virtual_input_ports;
496 num_virtual_inputs = 0;
497 virtual_input_ports = 0;
499 if (virtual_output_ports) {
500 for (
int i = 0; i < num_virtual_outputs; i++) {
501 delete virtual_output_ports[i];
503 delete[] virtual_output_ports;
504 num_virtual_outputs = 0;
505 virtual_output_ports = 0;
509 status = MIDIClientDispose(client);
510 if (status != noErr) {
511 WriteMacOSError(
"JackCoreMidiDriver::Close",
"MIDIClientDispose",
521 JackCoreMidiDriver::Restart()
532 RestoreConnections();
536 JackCoreMidiDriver::HandleNotification(
const MIDINotification *message)
538 switch (message->messageID) {
540 case kMIDIMsgSetupChanged:
544 case kMIDIMsgObjectAdded:
547 case kMIDIMsgObjectRemoved:
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)
562 strcpy(capture_driver_name, capture_driver_name_aux);
563 strcpy(playback_driver_name, playback_driver_name_aux);
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;
576 while (fThread.GetStatus() != JackThread::kRunning && ++count < WAIT_COUNTER) {
578 jack_log(
"JackCoreMidiDriver::Open wait count = %d", count);
581 if (count == WAIT_COUNTER) {
582 jack_info(
"Cannot open CoreMIDI driver");
587 jack_info(
"CoreMIDI driver is running...");
594 JackCoreMidiDriver::Start()
596 jack_info(
"JackCoreMidiDriver::Start - Starting driver.");
598 JackMidiDriver::Start();
605 jack_info(
"JackCoreMidiDriver::Start - Enabling physical input ports.");
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 "
611 goto stop_physical_input_ports;
615 jack_info(
"JackCoreMidiDriver::Start - Enabling physical output ports.");
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 "
621 goto stop_physical_output_ports;
625 jack_info(
"JackCoreMidiDriver::Start - Enabling virtual input ports.");
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 "
631 goto stop_virtual_input_ports;
635 jack_info(
"JackCoreMidiDriver::Start - Enabling virtual output ports.");
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 "
641 goto stop_virtual_output_ports;
645 jack_info(
"JackCoreMidiDriver::Start - Driver started.");
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 "
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 "
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.");
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.");
682 JackCoreMidiDriver::Stop()
686 JackMidiDriver::Stop();
688 jack_info(
"JackCoreMidiDriver::Stop - disabling physical input ports.");
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 "
698 jack_info(
"JackCoreMidiDriver::Stop - disabling physical output ports.");
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 "
708 jack_info(
"JackCoreMidiDriver::Stop - disabling virtual input ports.");
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 "
718 jack_info(
"JackCoreMidiDriver::Stop - disabling virtual output ports.");
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 "
732 JackCoreMidiDriver::ProcessRead()
736 res = (fEngineControl->fSyncMode) ? ProcessReadSync() : ProcessReadAsync();
745 JackCoreMidiDriver::ProcessWrite()
749 res = (fEngineControl->fSyncMode) ? ProcessWriteSync() : ProcessWriteAsync();
758 JackCoreMidiDriver::Read()
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);
764 for (
int i = 0; i < num_virtual_inputs; i++) {
765 virtual_input_ports[i]->
766 ProcessJack(GetInputBuffer(num_physical_inputs + i), buffer_size);
772 JackCoreMidiDriver::Write()
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);
778 for (
int i = 0; i < num_virtual_outputs; i++) {
779 virtual_output_ports[i]->
780 ProcessJack(GetOutputBuffer(num_physical_outputs + i), buffer_size);
798 desc = jack_driver_descriptor_construct(
"coremidi", JackDriverSlave,
"Apple CoreMIDI API based MIDI backend", &filler);
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);
814 for (node = params; node; node = jack_slist_next (node)) {
817 switch (param->character) {
820 virtual_in = param->value.ui;
824 virtual_out = param->value.ui;
832 if (driver->Open(1, 1, virtual_in, virtual_out,
false,
"in",
"out", 0, 0) == 0) {
839 jack_info(
"JackCoreMidiDriver already allocated, cannot be loaded twice");