Correct JackEngine::NotifyGraphReorder : graph-order callback now notified after...
[jack2.git] / macosx / coremidi / JackCoreMidiDriver.cpp
blobdf8bd0659ae399106dba5197a5d1bbca0096dddc
1 /*
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"
27 #include <stdexcept>
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 ///////////////////////////////////////////////////////////////////////////////
41 // Static callbacks
42 ///////////////////////////////////////////////////////////////////////////////
44 void
45 JackCoreMidiDriver::HandleInputEvent(const MIDIPacketList *packet_list,
46 void *driver, void *port)
48 ((JackCoreMidiPhysicalInputPort *) port)->ProcessCoreMidi(packet_list);
51 void
52 JackCoreMidiDriver::HandleNotificationEvent(const MIDINotification *message,
53 void *driver)
55 ((JackCoreMidiDriver *) driver)->HandleNotification(message);
58 ///////////////////////////////////////////////////////////////////////////////
59 // Class
60 ///////////////////////////////////////////////////////////////////////////////
62 JackCoreMidiDriver::JackCoreMidiDriver(const char *name, const char *alias,
63 JackLockedEngine *engine,
64 JackSynchro *table):
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));
72 client = 0;
73 fCaptureChannels = 0;
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;
84 internal_input = 0;
85 internal_output = 0;
88 JackCoreMidiDriver::~JackCoreMidiDriver()
91 bool JackCoreMidiDriver::Init()
93 return OpenAux();
96 bool JackCoreMidiDriver::OpenAux()
98 int pi_count = 0;
99 int po_count = 0;
100 int vi_count = 0;
101 int vo_count = 0;
102 ItemCount potential_po_count;
103 ItemCount potential_pi_count;
105 CFStringRef name = CFStringCreateWithCString(0, "JackMidi",
106 CFStringGetSystemEncoding());
107 if (! name) {
108 jack_error("JackCoreMidiDriver::Open - failed to allocate memory for "
109 "client name string");
110 return false;
113 OSStatus status = MIDIClientCreate(name, HandleNotificationEvent, this,
114 &client);
116 CFRelease(name);
118 if (status != noErr) {
119 WriteMacOSError("JackCoreMidiDriver::Open", "MIDIClientCreate",
120 status);
121 return false;
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",
133 status);
134 goto destroy;
137 try {
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());
143 goto destroy;
146 for (ItemCount i = 0; i < potential_pi_count; i++) {
147 try {
148 physical_input_ports[pi_count] =
149 new JackCoreMidiPhysicalInputPort(fAliasName, client_name,
150 capture_driver_name, i,
151 client, internal_input,
152 time_ratio);
153 } catch (std::exception e) {
154 jack_error("JackCoreMidiDriver::Open - while creating "
155 "physical input port: %s", e.what());
156 goto destroy;
158 pi_count++;
162 // Allocate and connect physical outputs
163 potential_po_count = MIDIGetNumberOfDestinations();
164 if (potential_po_count) {
165 status = MIDIOutputPortCreate(client, CFSTR("Physical Output Port"),
166 &internal_output);
167 if (status != noErr) {
168 WriteMacOSError("JackCoreMidiDriver::Open", "MIDIOutputPortCreate",
169 status);
170 goto destroy;
173 try {
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());
179 goto destroy;
182 for (ItemCount i = 0; i < potential_po_count; i++) {
183 try {
184 physical_output_ports[po_count] =
185 new JackCoreMidiPhysicalOutputPort(fAliasName, client_name,
186 playback_driver_name, i,
187 client, internal_output,
188 time_ratio);
189 } catch (std::exception e) {
190 jack_error("JackCoreMidiDriver::Open - while creating "
191 "physical output port: %s", e.what());
192 goto destroy;
194 po_count++;
198 // Allocate and connect virtual inputs
199 if (in_channels) {
200 try {
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());
206 goto destroy;
209 for (vi_count = 0; vi_count < in_channels; vi_count++) {
210 try {
211 virtual_input_ports[vi_count] =
212 new JackCoreMidiVirtualInputPort(fAliasName, client_name,
213 capture_driver_name,
214 vi_count + pi_count, client,
215 time_ratio);
216 } catch (std::exception e) {
217 jack_error("JackCoreMidiDriver::Open - while creating virtual "
218 "input port: %s", e.what());
219 goto destroy;
224 // Allocate and connect virtual outputs
225 if (out_channels) {
226 try {
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());
232 goto destroy;
234 for (vo_count = 0; vo_count < out_channels; vo_count++) {
235 try {
236 virtual_output_ports[vo_count] =
237 new JackCoreMidiVirtualOutputPort(fAliasName, client_name,
238 playback_driver_name,
239 vo_count + po_count, client,
240 time_ratio);
241 } catch (std::exception e) {
242 jack_error("JackCoreMidiDriver::Open - while creating virtual "
243 "output port: %s", e.what());
244 goto destroy;
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,
258 capture_driver_name,
259 playback_driver_name, capture_latency,
260 playback_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;
265 return true;
268 destroy:
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);
316 if (client) {
317 status = MIDIClientDispose(client);
318 if (status != noErr) {
319 WriteMacOSError("JackCoreMidiDriver::Open", "MIDIClientDispose",
320 status);
324 // Default open
325 if (! JackMidiDriver::Open(capturing, playing,
326 in_channels + pi_count,
327 out_channels + po_count, monitor,
328 capture_driver_name,
329 playback_driver_name, capture_latency,
330 playback_latency)) {
331 client = 0;
332 num_physical_inputs = 0;
333 num_physical_outputs = 0;
334 num_virtual_inputs = 0;
335 num_virtual_outputs = 0;
336 return true;
337 } else {
338 return false;
342 bool JackCoreMidiDriver::Execute()
344 CFRunLoopRun();
345 return false;
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;
355 const char *name;
356 JackPort *port;
357 JackCoreMidiPort *port_obj;
358 latency_range.max = latency;
359 latency_range.min = latency;
361 // Physical inputs
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?
371 return -1;
373 port = fGraphManager->GetPort(index);
374 port->SetAlias(port_obj->GetAlias());
375 port->SetLatencyRange(JackCaptureLatency, &latency_range);
376 fCapturePortList[i] = index;
379 // Virtual inputs
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?
389 return -1;
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;
403 // Physical outputs
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?
414 return -1;
416 port = fGraphManager->GetPort(index);
417 port->SetAlias(port_obj->GetAlias());
418 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
419 fPlaybackPortList[i] = index;
422 // Virtual outputs
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?
433 return -1;
435 port = fGraphManager->GetPort(index);
436 port->SetAlias(port_obj->GetAlias());
437 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
438 fPlaybackPortList[num_physical_outputs + i] = index;
441 return 0;
445 JackCoreMidiDriver::Close()
447 fThread.Kill();
448 return CloseAux();
452 JackCoreMidiDriver::CloseAux()
454 // Generic MIDI driver close
455 int result = JackMidiDriver::Close();
457 OSStatus status;
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",
469 status);
470 result = -1;
472 internal_input = 0;
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",
486 status);
487 result = -1;
489 internal_output = 0;
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;
509 if (client) {
510 status = MIDIClientDispose(client);
511 if (status != noErr) {
512 WriteMacOSError("JackCoreMidiDriver::Close", "MIDIClientDispose",
513 status);
514 result = -1;
516 client = 0;
518 return result;
521 void
522 JackCoreMidiDriver::Restart()
524 JackLock lock(this);
526 SaveConnections();
527 Stop();
528 Detach();
529 CloseAux();
530 OpenAux();
531 Attach();
532 Start();
533 RestoreConnections();
536 void
537 JackCoreMidiDriver::HandleNotification(const MIDINotification *message)
539 switch (message->messageID) {
541 case kMIDIMsgSetupChanged:
542 Restart();
543 break;
545 case kMIDIMsgObjectAdded:
546 break;
548 case kMIDIMsgObjectRemoved:
549 break;
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;
574 fThread.StartSync();
576 int count = 0;
577 while (fThread.GetStatus() != JackThread::kRunning && ++count < WAIT_COUNTER) {
578 JackSleep(100000);
579 jack_log("JackCoreMidiDriver::Open wait count = %d", count);
582 if (count == WAIT_COUNTER) {
583 jack_info("Cannot open CoreMIDI driver");
584 fThread.Kill();
585 return -1;
586 } else {
587 JackSleep(10000);
588 jack_info("CoreMIDI driver is running...");
591 return 0;
595 JackCoreMidiDriver::Start()
597 jack_info("JackCoreMidiDriver::Start - Starting driver.");
599 JackMidiDriver::Start();
601 int pi_count = 0;
602 int po_count = 0;
603 int vi_count = 0;
604 int vo_count = 0;
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 "
611 "input port.");
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 "
621 "output port.");
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 "
631 "input port.");
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 "
641 "output port.");
642 goto stop_virtual_output_ports;
646 jack_info("JackCoreMidiDriver::Start - Driver started.");
648 return 0;
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 "
654 "output port.");
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 "
661 "input port.");
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.");
679 return -1;
683 JackCoreMidiDriver::Stop()
685 int result = 0;
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 "
694 "input port.");
695 result = -1;
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 "
704 "output port.");
705 result = -1;
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 "
714 "input port.");
715 result = -1;
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 "
724 "output port.");
725 result = -1;
729 return result;
733 JackCoreMidiDriver::ProcessRead()
735 int res;
736 if (Trylock()) {
737 res = (fEngineControl->fSyncMode) ? ProcessReadSync() : ProcessReadAsync();
738 Unlock();
739 } else {
740 res = -1;
742 return res;
746 JackCoreMidiDriver::ProcessWrite()
748 int res;
749 if (Trylock()) {
750 res = (fEngineControl->fSyncMode) ? ProcessWriteSync() : ProcessWriteAsync();
751 Unlock();
752 } else {
753 res = -1;
755 return res;
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);
769 return 0;
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);
783 return 0;
786 #ifdef __cplusplus
787 extern "C" {
788 #endif
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);
801 value.ui = 0;
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);
805 return desc;
808 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
810 const JSList * node;
811 const jack_driver_param_t * param;
812 int virtual_in = 0;
813 int virtual_out = 0;
815 for (node = params; node; node = jack_slist_next (node)) {
816 param = (const jack_driver_param_t *) node->data;
818 switch (param->character) {
820 case 'i':
821 virtual_in = param->value.ui;
822 break;
824 case 'o':
825 virtual_out = param->value.ui;
826 break;
830 // singleton kind of driver
831 if (!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) {
834 return driver;
835 } else {
836 delete driver;
837 return NULL;
839 } else {
840 jack_info("JackCoreMidiDriver already allocated, cannot be loaded twice");
841 return NULL;
845 #ifdef __cplusplus
847 #endif