21 #include "JackCompilerDeps.h"
22 #include "JackCoreMidiDriver.h"
23 #include "JackCoreMidiUtil.h"
24 #include "JackEngineControl.h"
25 #include "driver_interface.h"
28 #include <mach/mach_time.h>
32 static char capture_driver_name[256];
33 static char playback_driver_name[256];
35 static int in_channels, out_channels;
36 static bool capturing, playing, monitor;
38 static jack_nframes_t capture_latency, playback_latency;
45 JackCoreMidiDriver::HandleInputEvent(
const MIDIPacketList *packet_list,
46 void *driver,
void *port)
48 ((JackCoreMidiPhysicalInputPort *) port)->ProcessCoreMidi(packet_list);
52 JackCoreMidiDriver::HandleNotificationEvent(
const MIDINotification *message,
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));
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;
88 JackCoreMidiDriver::~JackCoreMidiDriver()
96 bool JackCoreMidiDriver::OpenAux()
102 ItemCount potential_po_count;
103 ItemCount potential_pi_count;
105 CFStringRef name = CFStringCreateWithCString(0,
"JackMidi",
106 CFStringGetSystemEncoding());
108 jack_error(
"JackCoreMidiDriver::Open - failed to allocate memory for "
109 "client name string");
113 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, 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, vo_count + po_count, client,
240 }
catch (std::exception& e) {
241 jack_error(
"JackCoreMidiDriver::Open - while creating virtual "
242 "output port: %s", e.what());
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.");
253 if (! JackMidiDriver::Open(capturing, playing,
254 in_channels + pi_count,
255 out_channels + po_count, monitor,
257 playback_driver_name, capture_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;
268 if (physical_input_ports) {
269 for (
int i = 0; i < pi_count; i++) {
270 delete physical_input_ports[i];
272 delete[] physical_input_ports;
273 physical_input_ports = 0;
276 if (physical_output_ports) {
277 for (
int i = 0; i < po_count; i++) {
278 delete physical_output_ports[i];
280 delete[] physical_output_ports;
281 physical_output_ports = 0;
284 if (virtual_input_ports) {
285 for (
int i = 0; i < vi_count; i++) {
286 delete virtual_input_ports[i];
288 delete[] virtual_input_ports;
289 virtual_input_ports = 0;
292 if (virtual_output_ports) {
293 for (
int i = 0; i < vo_count; i++) {
294 delete virtual_output_ports[i];
296 delete[] virtual_output_ports;
297 virtual_output_ports = 0;
300 if (internal_output) {
301 status = MIDIPortDispose(internal_output);
302 if (status != noErr) {
303 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIPortDispose", status);
307 if (internal_input) {
308 status = MIDIPortDispose(internal_input);
309 if (status != noErr) {
310 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIPortDispose", status);
315 status = MIDIClientDispose(client);
316 if (status != noErr) {
317 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIClientDispose",
323 if (! JackMidiDriver::Open(capturing, playing,
324 in_channels + pi_count,
325 out_channels + po_count, monitor,
327 playback_driver_name, capture_latency,
330 num_physical_inputs = 0;
331 num_physical_outputs = 0;
332 num_virtual_inputs = 0;
333 num_virtual_outputs = 0;
340 bool JackCoreMidiDriver::Execute()
347 JackCoreMidiDriver::Attach()
349 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
350 jack_port_id_t index;
351 jack_nframes_t latency = buffer_size;
355 JackCoreMidiPort *port_obj;
356 latency_range.
max = latency;
357 latency_range.
min = latency;
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);
371 port = fGraphManager->GetPort(index);
372 port->SetAlias(port_obj->GetAlias());
373 port->SetLatencyRange(JackCaptureLatency, &latency_range);
374 fCapturePortList[i] = index;
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);
389 port = fGraphManager->GetPort(index);
390 port->SetAlias(port_obj->GetAlias());
391 port->SetLatencyRange(JackCaptureLatency, &latency_range);
392 fCapturePortList[num_physical_inputs + i] = index;
395 if (! fEngineControl->fSyncMode) {
396 latency += buffer_size;
397 latency_range.
max = latency;
398 latency_range.
min = latency;
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);
414 port = fGraphManager->GetPort(index);
415 port->SetAlias(port_obj->GetAlias());
416 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
417 fPlaybackPortList[i] = index;
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);
433 port = fGraphManager->GetPort(index);
434 port->SetAlias(port_obj->GetAlias());
435 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
436 fPlaybackPortList[num_physical_outputs + i] = index;
443 JackCoreMidiDriver::Close()
450 JackCoreMidiDriver::CloseAux()
453 int result = JackMidiDriver::Close();
456 if (physical_input_ports) {
457 for (
int i = 0; i < num_physical_inputs; i++) {
458 delete physical_input_ports[i];
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",
473 if (physical_output_ports) {
474 for (
int i = 0; i < num_physical_outputs; i++) {
475 delete physical_output_ports[i];
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",
490 if (virtual_input_ports) {
491 for (
int i = 0; i < num_virtual_inputs; i++) {
492 delete virtual_input_ports[i];
494 delete[] virtual_input_ports;
495 num_virtual_inputs = 0;
496 virtual_input_ports = 0;
498 if (virtual_output_ports) {
499 for (
int i = 0; i < num_virtual_outputs; i++) {
500 delete virtual_output_ports[i];
502 delete[] virtual_output_ports;
503 num_virtual_outputs = 0;
504 virtual_output_ports = 0;
508 status = MIDIClientDispose(client);
509 if (status != noErr) {
510 WriteMacOSError(
"JackCoreMidiDriver::Close",
"MIDIClientDispose",
520 JackCoreMidiDriver::Restart()
526 if (fEngine->Lock()) {
536 LoadConnections(1,
false);
544 JackCoreMidiDriver::HandleNotification(
const MIDINotification *message)
546 switch (message->messageID) {
548 case kMIDIMsgObjectAdded: {
552 const MIDIObjectAddRemoveNotification* add_message =
reinterpret_cast<const MIDIObjectAddRemoveNotification*
>(message);
553 if (!JackCoreMidiPort::IsInternalPort(add_message->child)) {
559 case kMIDIMsgObjectRemoved: {
563 const MIDIObjectAddRemoveNotification* remove_message =
reinterpret_cast<const MIDIObjectAddRemoveNotification*
>(message);
564 if (!JackCoreMidiPort::IsInternalPort(remove_message->child)) {
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)
581 strcpy(capture_driver_name, capture_driver_name_aux);
582 strcpy(playback_driver_name, playback_driver_name_aux);
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;
595 while (fThread.GetStatus() != JackThread::kRunning && ++count < WAIT_COUNTER) {
597 jack_log(
"JackCoreMidiDriver::Open wait count = %d", count);
600 if (count == WAIT_COUNTER) {
601 jack_info(
"Cannot open CoreMIDI driver");
606 jack_info(
"CoreMIDI driver is opened...");
613 JackCoreMidiDriver::Start()
615 jack_info(
"JackCoreMidiDriver::Start - Starting driver.");
617 JackMidiDriver::Start();
624 jack_info(
"JackCoreMidiDriver::Start - Enabling physical input ports.");
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 "
630 goto stop_physical_input_ports;
634 jack_info(
"JackCoreMidiDriver::Start - Enabling physical output ports.");
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 "
640 goto stop_physical_output_ports;
644 jack_info(
"JackCoreMidiDriver::Start - Enabling virtual input ports.");
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 "
650 goto stop_virtual_input_ports;
654 jack_info(
"JackCoreMidiDriver::Start - Enabling virtual output ports.");
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 "
660 goto stop_virtual_output_ports;
664 jack_info(
"JackCoreMidiDriver::Start - Driver started.");
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 "
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 "
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.");
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.");
701 JackCoreMidiDriver::Stop()
705 JackMidiDriver::Stop();
707 jack_info(
"JackCoreMidiDriver::Stop - disabling physical input ports.");
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 "
717 jack_info(
"JackCoreMidiDriver::Stop - disabling physical output ports.");
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 "
727 jack_info(
"JackCoreMidiDriver::Stop - disabling virtual input ports.");
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 "
737 jack_info(
"JackCoreMidiDriver::Stop - disabling virtual output ports.");
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 "
751 JackCoreMidiDriver::ProcessRead()
755 res = (fEngineControl->fSyncMode) ? ProcessReadSync() : ProcessReadAsync();
764 JackCoreMidiDriver::ProcessWrite()
768 res = (fEngineControl->fSyncMode) ? ProcessWriteSync() : ProcessWriteAsync();
777 JackCoreMidiDriver::Read()
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);
783 for (
int i = 0; i < num_virtual_inputs; i++) {
784 virtual_input_ports[i]->
785 ProcessJack(GetInputBuffer(num_physical_inputs + i), buffer_size);
791 JackCoreMidiDriver::Write()
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);
797 for (
int i = 0; i < num_virtual_outputs; i++) {
798 virtual_output_ports[i]->
799 ProcessJack(GetOutputBuffer(num_physical_outputs + i), buffer_size);
817 desc = jack_driver_descriptor_construct(
"coremidi", JackDriverSlave,
"Apple CoreMIDI API based MIDI backend", &filler);
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);
833 for (node = params; node; node = jack_slist_next (node)) {
836 switch (param->character) {
839 virtual_in = param->value.ui;
843 virtual_out = param->value.ui;
851 if (driver->Open(1, 1, virtual_in, virtual_out,
false,
"in",
"out", 0, 0) == 0) {
858 jack_info(
"JackCoreMidiDriver already allocated, cannot be loaded twice");