2 Copyright (C) 2009 Grame
3 Copyright (C) 2011 Devin Anderson
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.
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.
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.
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>
30 using Jack::JackCoreMidiDriver
;
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
;
40 ///////////////////////////////////////////////////////////////////////////////
42 ///////////////////////////////////////////////////////////////////////////////
45 JackCoreMidiDriver::HandleInputEvent(const MIDIPacketList
*packet_list
,
46 void *driver
, void *port
)
48 ((JackCoreMidiPhysicalInputPort
*) port
)->ProcessCoreMidi(packet_list
);
52 JackCoreMidiDriver::HandleNotificationEvent(const MIDINotification
*message
,
55 ((JackCoreMidiDriver
*) driver
)->HandleNotification(message
);
58 ///////////////////////////////////////////////////////////////////////////////
60 ///////////////////////////////////////////////////////////////////////////////
62 JackCoreMidiDriver::JackCoreMidiDriver(const char *name
, const char *alias
,
63 JackLockedEngine
*engine
,
65 JackMidiDriver(name
, alias
, engine
, table
),fThread(this)
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()
91 bool JackCoreMidiDriver::Init()
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
;
126 // Allocate and connect physical inputs
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());
162 // Allocate and connect physical outputs
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());
198 // Allocate and connect virtual inputs
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());
224 // Allocate and connect virtual outputs
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
;
354 jack_latency_range_t latency_range
;
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
);
370 // X: Do we need to deallocate ports?
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
);
388 // X: Do we need to deallocate ports?
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
);
413 // X: Do we need to deallocate ports?
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
);
432 // X: Do we need to deallocate ports?
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()
454 // Generic MIDI driver close
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
);
790 // singleton kind of driver
791 static Jack::JackDriverClientInterface
* driver
= NULL
;
793 SERVER_EXPORT jack_driver_desc_t
* driver_get_descriptor()
795 jack_driver_desc_t
* desc
;
796 jack_driver_desc_filler_t filler
;
797 jack_driver_param_value_t value
;
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
);
808 SERVER_EXPORT
Jack::JackDriverClientInterface
* driver_initialize(Jack::JackLockedEngine
* engine
, Jack::JackSynchro
* table
, const JSList
* params
)
811 const jack_driver_param_t
* param
;
815 for (node
= params
; node
; node
= jack_slist_next (node
)) {
816 param
= (const jack_driver_param_t
*) node
->data
;
818 switch (param
->character
) {
821 virtual_in
= param
->value
.ui
;
825 virtual_out
= param
->value
.ui
;
830 // singleton kind of driver
832 driver
= new Jack::JackCoreMidiDriver("system_midi", "coremidi", engine
, table
);
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");