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,
118 if (status != noErr) {
119 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIClientCreate",
124 char *client_name = fClientControl.fName;
127 potential_pi_count = MIDIGetNumberOfSources();
128 if (potential_pi_count) {
129 status = MIDIInputPortCreate(client, CFSTR(
"Physical Input Port"),
130 HandleInputEvent,
this, &internal_input);
131 if (status != noErr) {
132 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIInputPortCreate",
138 physical_input_ports =
139 new JackCoreMidiPhysicalInputPort*[potential_pi_count];
140 }
catch (std::exception e) {
141 jack_error(
"JackCoreMidiDriver::Open - while creating physical "
142 "input port array: %s", e.what());
146 for (ItemCount i = 0; i < potential_pi_count; i++) {
148 physical_input_ports[pi_count] =
149 new JackCoreMidiPhysicalInputPort(fAliasName, client_name,
150 capture_driver_name, i,
151 client, internal_input,
153 }
catch (std::exception e) {
154 jack_error(
"JackCoreMidiDriver::Open - while creating "
155 "physical input port: %s", e.what());
163 potential_po_count = MIDIGetNumberOfDestinations();
164 if (potential_po_count) {
165 status = MIDIOutputPortCreate(client, CFSTR(
"Physical Output Port"),
167 if (status != noErr) {
168 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIOutputPortCreate",
174 physical_output_ports =
175 new JackCoreMidiPhysicalOutputPort*[potential_po_count];
176 }
catch (std::exception e) {
177 jack_error(
"JackCoreMidiDriver::Open - while creating physical "
178 "output port array: %s", e.what());
182 for (ItemCount i = 0; i < potential_po_count; i++) {
184 physical_output_ports[po_count] =
185 new JackCoreMidiPhysicalOutputPort(fAliasName, client_name,
186 playback_driver_name, i,
187 client, internal_output,
189 }
catch (std::exception e) {
190 jack_error(
"JackCoreMidiDriver::Open - while creating "
191 "physical output port: %s", e.what());
201 virtual_input_ports =
202 new JackCoreMidiVirtualInputPort*[in_channels];
203 }
catch (std::exception e) {
204 jack_error(
"JackCoreMidiDriver::Open - while creating virtual "
205 "input port array: %s", e.what());
209 for (vi_count = 0; vi_count < in_channels; vi_count++) {
211 virtual_input_ports[vi_count] =
212 new JackCoreMidiVirtualInputPort(fAliasName, client_name,
214 vi_count + pi_count, client,
216 }
catch (std::exception e) {
217 jack_error(
"JackCoreMidiDriver::Open - while creating virtual "
218 "input port: %s", e.what());
227 virtual_output_ports =
228 new JackCoreMidiVirtualOutputPort*[out_channels];
229 }
catch (std::exception e) {
230 jack_error(
"JackCoreMidiDriver::Open - while creating virtual "
231 "output port array: %s", e.what());
234 for (vo_count = 0; vo_count < out_channels; vo_count++) {
236 virtual_output_ports[vo_count] =
237 new JackCoreMidiVirtualOutputPort(fAliasName, client_name,
238 playback_driver_name,
239 vo_count + po_count, client,
241 }
catch (std::exception e) {
242 jack_error(
"JackCoreMidiDriver::Open - while creating virtual "
243 "output port: %s", e.what());
250 if (! (pi_count || po_count || in_channels || out_channels)) {
251 jack_error(
"JackCoreMidiDriver::Open - no CoreMIDI inputs or outputs "
252 "found, and no virtual ports allocated.");
255 if (! JackMidiDriver::Open(capturing, playing,
256 in_channels + pi_count,
257 out_channels + po_count, monitor,
259 playback_driver_name, capture_latency,
261 num_physical_inputs = pi_count;
262 num_physical_outputs = po_count;
263 num_virtual_inputs = in_channels;
264 num_virtual_outputs = out_channels;
270 if (physical_input_ports) {
271 for (
int i = 0; i < pi_count; i++) {
272 delete physical_input_ports[i];
274 delete[] physical_input_ports;
275 physical_input_ports = 0;
278 if (physical_output_ports) {
279 for (
int i = 0; i < po_count; i++) {
280 delete physical_output_ports[i];
282 delete[] physical_output_ports;
283 physical_output_ports = 0;
286 if (virtual_input_ports) {
287 for (
int i = 0; i < vi_count; i++) {
288 delete virtual_input_ports[i];
290 delete[] virtual_input_ports;
291 virtual_input_ports = 0;
294 if (virtual_output_ports) {
295 for (
int i = 0; i < vo_count; i++) {
296 delete virtual_output_ports[i];
298 delete[] virtual_output_ports;
299 virtual_output_ports = 0;
302 if (internal_output) {
303 status = MIDIPortDispose(internal_output);
304 if (status != noErr) {
305 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIPortDispose", status);
309 if (internal_input) {
310 status = MIDIPortDispose(internal_input);
311 if (status != noErr) {
312 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIPortDispose", status);
317 status = MIDIClientDispose(client);
318 if (status != noErr) {
319 WriteMacOSError(
"JackCoreMidiDriver::Open",
"MIDIClientDispose",
325 if (! JackMidiDriver::Open(capturing, playing,
326 in_channels + pi_count,
327 out_channels + po_count, monitor,
329 playback_driver_name, capture_latency,
332 num_physical_inputs = 0;
333 num_physical_outputs = 0;
334 num_virtual_inputs = 0;
335 num_virtual_outputs = 0;
342 bool JackCoreMidiDriver::Execute()
349 JackCoreMidiDriver::Attach()
351 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
352 jack_port_id_t index;
353 jack_nframes_t latency = buffer_size;
357 JackCoreMidiPort *port_obj;
358 latency_range.
max = latency;
359 latency_range.
min = latency;
362 for (
int i = 0; i < num_physical_inputs; i++) {
363 port_obj = physical_input_ports[i];
364 name = port_obj->GetName();
365 if (fEngine->PortRegister(fClientControl.fRefNum, name,
366 JACK_DEFAULT_MIDI_TYPE,
367 CaptureDriverFlags, buffer_size, &index) < 0) {
368 jack_error(
"JackCoreMidiDriver::Attach - cannot register physical "
369 "input port with name '%s'.", name);
373 port = fGraphManager->GetPort(index);
374 port->SetAlias(port_obj->GetAlias());
375 port->SetLatencyRange(JackCaptureLatency, &latency_range);
376 fCapturePortList[i] = index;
380 for (
int i = 0; i < num_virtual_inputs; i++) {
381 port_obj = virtual_input_ports[i];
382 name = port_obj->GetName();
383 if (fEngine->PortRegister(fClientControl.fRefNum, name,
384 JACK_DEFAULT_MIDI_TYPE,
385 CaptureDriverFlags, buffer_size, &index) < 0) {
386 jack_error(
"JackCoreMidiDriver::Attach - cannot register virtual "
387 "input port with name '%s'.", name);
391 port = fGraphManager->GetPort(index);
392 port->SetAlias(port_obj->GetAlias());
393 port->SetLatencyRange(JackCaptureLatency, &latency_range);
394 fCapturePortList[num_physical_inputs + i] = index;
397 if (! fEngineControl->fSyncMode) {
398 latency += buffer_size;
399 latency_range.
max = latency;
400 latency_range.
min = latency;
404 for (
int i = 0; i < num_physical_outputs; i++) {
405 port_obj = physical_output_ports[i];
406 name = port_obj->GetName();
407 fEngine->PortRegister(fClientControl.fRefNum, name,
408 JACK_DEFAULT_MIDI_TYPE,
409 PlaybackDriverFlags, buffer_size, &index);
410 if (index == NO_PORT) {
411 jack_error(
"JackCoreMidiDriver::Attach - cannot register physical "
412 "output port with name '%s'.", name);
416 port = fGraphManager->GetPort(index);
417 port->SetAlias(port_obj->GetAlias());
418 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
419 fPlaybackPortList[i] = index;
423 for (
int i = 0; i < num_virtual_outputs; i++) {
424 port_obj = virtual_output_ports[i];
425 name = port_obj->GetName();
426 fEngine->PortRegister(fClientControl.fRefNum, name,
427 JACK_DEFAULT_MIDI_TYPE,
428 PlaybackDriverFlags, buffer_size, &index);
429 if (index == NO_PORT) {
430 jack_error(
"JackCoreMidiDriver::Attach - cannot register virtual "
431 "output port with name '%s'.", name);
435 port = fGraphManager->GetPort(index);
436 port->SetAlias(port_obj->GetAlias());
437 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
438 fPlaybackPortList[num_physical_outputs + i] = index;
445 JackCoreMidiDriver::Close()
452 JackCoreMidiDriver::CloseAux()
455 int result = JackMidiDriver::Close();
458 if (physical_input_ports) {
459 for (
int i = 0; i < num_physical_inputs; i++) {
460 delete physical_input_ports[i];
462 delete[] physical_input_ports;
463 num_physical_inputs = 0;
464 physical_input_ports = 0;
465 if (internal_input) {
466 status = MIDIPortDispose(internal_input);
467 if (status != noErr) {
468 WriteMacOSError(
"JackCoreMidiDriver::Close",
"MIDIPortDispose",
475 if (physical_output_ports) {
476 for (
int i = 0; i < num_physical_outputs; i++) {
477 delete physical_output_ports[i];
479 delete[] physical_output_ports;
480 num_physical_outputs = 0;
481 physical_output_ports = 0;
482 if (internal_output) {
483 status = MIDIPortDispose(internal_output);
484 if (status != noErr) {
485 WriteMacOSError(
"JackCoreMidiDriver::Close",
"MIDIPortDispose",
492 if (virtual_input_ports) {
493 for (
int i = 0; i < num_virtual_inputs; i++) {
494 delete virtual_input_ports[i];
496 delete[] virtual_input_ports;
497 num_virtual_inputs = 0;
498 virtual_input_ports = 0;
500 if (virtual_output_ports) {
501 for (
int i = 0; i < num_virtual_outputs; i++) {
502 delete virtual_output_ports[i];
504 delete[] virtual_output_ports;
505 num_virtual_outputs = 0;
506 virtual_output_ports = 0;
510 status = MIDIClientDispose(client);
511 if (status != noErr) {
512 WriteMacOSError(
"JackCoreMidiDriver::Close",
"MIDIClientDispose",
522 JackCoreMidiDriver::Restart()
533 RestoreConnections();
537 JackCoreMidiDriver::HandleNotification(
const MIDINotification *message)
539 switch (message->messageID) {
541 case kMIDIMsgSetupChanged:
545 case kMIDIMsgObjectAdded:
548 case kMIDIMsgObjectRemoved:
555 JackCoreMidiDriver::Open(
bool capturing_aux,
bool playing_aux,
int in_channels_aux,
556 int out_channels_aux,
bool monitor_aux,
557 const char* capture_driver_name_aux,
558 const char* playback_driver_name_aux,
559 jack_nframes_t capture_latency_aux,
560 jack_nframes_t playback_latency_aux)
563 strcpy(capture_driver_name, capture_driver_name_aux);
564 strcpy(playback_driver_name, playback_driver_name_aux);
566 capturing = capturing_aux;
567 playing = playing_aux;
568 in_channels = in_channels_aux;
569 out_channels = out_channels_aux;
570 monitor = monitor_aux;
571 capture_latency = capture_latency_aux;
572 playback_latency = playback_latency_aux;
577 while (fThread.GetStatus() != JackThread::kRunning && ++count < WAIT_COUNTER) {
579 jack_log(
"JackCoreMidiDriver::Open wait count = %d", count);
582 if (count == WAIT_COUNTER) {
583 jack_info(
"Cannot open CoreMIDI driver");
588 jack_info(
"CoreMIDI driver is running...");
595 JackCoreMidiDriver::Start()
597 jack_info(
"JackCoreMidiDriver::Start - Starting driver.");
599 JackMidiDriver::Start();
606 jack_info(
"JackCoreMidiDriver::Start - Enabling physical input ports.");
608 for (; pi_count < num_physical_inputs; pi_count++) {
609 if (physical_input_ports[pi_count]->Start() < 0) {
610 jack_error(
"JackCoreMidiDriver::Start - Failed to enable physical "
612 goto stop_physical_input_ports;
616 jack_info(
"JackCoreMidiDriver::Start - Enabling physical output ports.");
618 for (; po_count < num_physical_outputs; po_count++) {
619 if (physical_output_ports[po_count]->Start() < 0) {
620 jack_error(
"JackCoreMidiDriver::Start - Failed to enable physical "
622 goto stop_physical_output_ports;
626 jack_info(
"JackCoreMidiDriver::Start - Enabling virtual input ports.");
628 for (; vi_count < num_virtual_inputs; vi_count++) {
629 if (virtual_input_ports[vi_count]->Start() < 0) {
630 jack_error(
"JackCoreMidiDriver::Start - Failed to enable virtual "
632 goto stop_virtual_input_ports;
636 jack_info(
"JackCoreMidiDriver::Start - Enabling virtual output ports.");
638 for (; vo_count < num_virtual_outputs; vo_count++) {
639 if (virtual_output_ports[vo_count]->Start() < 0) {
640 jack_error(
"JackCoreMidiDriver::Start - Failed to enable virtual "
642 goto stop_virtual_output_ports;
646 jack_info(
"JackCoreMidiDriver::Start - Driver started.");
650 stop_virtual_output_ports:
651 for (
int i = 0; i < vo_count; i++) {
652 if (virtual_output_ports[i]->Stop() < 0) {
653 jack_error(
"JackCoreMidiDriver::Start - Failed to disable virtual "
657 stop_virtual_input_ports:
658 for (
int i = 0; i < vi_count; i++) {
659 if (virtual_input_ports[i]->Stop() < 0) {
660 jack_error(
"JackCoreMidiDriver::Start - Failed to disable virtual "
664 stop_physical_output_ports:
665 for (
int i = 0; i < po_count; i++) {
666 if (physical_output_ports[i]->Stop() < 0) {
667 jack_error(
"JackCoreMidiDriver::Start - Failed to disable "
668 "physical output port.");
671 stop_physical_input_ports:
672 for (
int i = 0; i < pi_count; i++) {
673 if (physical_input_ports[i]->Stop() < 0) {
674 jack_error(
"JackCoreMidiDriver::Start - Failed to disable "
675 "physical input port.");
683 JackCoreMidiDriver::Stop()
687 JackMidiDriver::Stop();
689 jack_info(
"JackCoreMidiDriver::Stop - disabling physical input ports.");
691 for (
int i = 0; i < num_physical_inputs; i++) {
692 if (physical_input_ports[i]->Stop() < 0) {
693 jack_error(
"JackCoreMidiDriver::Stop - Failed to disable physical "
699 jack_info(
"JackCoreMidiDriver::Stop - disabling physical output ports.");
701 for (
int i = 0; i < num_physical_outputs; i++) {
702 if (physical_output_ports[i]->Stop() < 0) {
703 jack_error(
"JackCoreMidiDriver::Stop - Failed to disable physical "
709 jack_info(
"JackCoreMidiDriver::Stop - disabling virtual input ports.");
711 for (
int i = 0; i < num_virtual_inputs; i++) {
712 if (virtual_input_ports[i]->Stop() < 0) {
713 jack_error(
"JackCoreMidiDriver::Stop - Failed to disable virtual "
719 jack_info(
"JackCoreMidiDriver::Stop - disabling virtual output ports.");
721 for (
int i = 0; i < num_virtual_outputs; i++) {
722 if (virtual_output_ports[i]->Stop() < 0) {
723 jack_error(
"JackCoreMidiDriver::Stop - Failed to disable virtual "
733 JackCoreMidiDriver::ProcessRead()
737 res = (fEngineControl->fSyncMode) ? ProcessReadSync() : ProcessReadAsync();
746 JackCoreMidiDriver::ProcessWrite()
750 res = (fEngineControl->fSyncMode) ? ProcessWriteSync() : ProcessWriteAsync();
759 JackCoreMidiDriver::Read()
761 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
762 for (
int i = 0; i < num_physical_inputs; i++) {
763 physical_input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
765 for (
int i = 0; i < num_virtual_inputs; i++) {
766 virtual_input_ports[i]->
767 ProcessJack(GetInputBuffer(num_physical_inputs + i), buffer_size);
773 JackCoreMidiDriver::Write()
775 jack_nframes_t buffer_size = fEngineControl->fBufferSize;
776 for (
int i = 0; i < num_physical_outputs; i++) {
777 physical_output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
779 for (
int i = 0; i < num_virtual_outputs; i++) {
780 virtual_output_ports[i]->
781 ProcessJack(GetOutputBuffer(num_physical_outputs + i), buffer_size);
799 desc = jack_driver_descriptor_construct(
"coremidi", JackDriverSlave,
"Apple CoreMIDI API based MIDI backend", &filler);
802 jack_driver_descriptor_add_parameter(desc, &filler,
"inchannels",
'i', JackDriverParamUInt, &value, NULL,
"CoreMIDI virtual bus", NULL);
803 jack_driver_descriptor_add_parameter(desc, &filler,
"outchannels",
'o', JackDriverParamUInt, &value, NULL,
"CoreMIDI virtual bus", NULL);
815 for (node = params; node; node = jack_slist_next (node)) {
818 switch (param->character) {
821 virtual_in = param->value.ui;
825 virtual_out = param->value.ui;
833 if (driver->Open(1, 1, virtual_in, virtual_out,
false,
"in",
"out", 0, 0) == 0) {
840 jack_info(
"JackCoreMidiDriver already allocated, cannot be loaded twice");
The base class for MIDI drivers: drivers with MIDI ports.
Inter process synchronization using using Mach semaphore.
Locked Engine, access to methods is serialized using a mutex.
SERVER_EXPORT void jack_error(const char *fmt,...)
SERVER_EXPORT void jack_info(const char *fmt,...)
JackCoreMidiDriver(const char *name, const char *alias, JackLockedEngine *engine, JackSynchro *table)
The base interface for drivers clients.
SERVER_EXPORT void jack_log(const char *fmt,...)