Jack2 1.9.8

JackCoreMidiDriver.cpp

00001 /*
00002 Copyright (C) 2009 Grame
00003 Copyright (C) 2011 Devin Anderson
00004 
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU General Public License as published by
00007 the Free Software Foundation; either version 2 of the License, or
00008 (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 
00019 */
00020 
00021 #include <stdexcept>
00022 
00023 #include <mach/mach_time.h>
00024 
00025 #include "JackCoreMidiDriver.h"
00026 #include "JackCoreMidiUtil.h"
00027 #include "JackEngineControl.h"
00028 
00029 using Jack::JackCoreMidiDriver;
00030 
00031 static char capture_driver_name[256];
00032 static char playback_driver_name[256];
00033 
00034 static int in_channels, out_channels;
00035 static bool capturing, playing, monitor;
00036 
00037 static jack_nframes_t capture_latency, playback_latency;
00038 
00040 // Static callbacks
00042 
00043 void
00044 JackCoreMidiDriver::HandleInputEvent(const MIDIPacketList *packet_list,
00045                                      void *driver, void *port)
00046 {
00047     ((JackCoreMidiPhysicalInputPort *) port)->ProcessCoreMidi(packet_list);
00048 }
00049 
00050 void
00051 JackCoreMidiDriver::HandleNotificationEvent(const MIDINotification *message,
00052                                             void *driver)
00053 {
00054     ((JackCoreMidiDriver *) driver)->HandleNotification(message);
00055 }
00056 
00058 // Class
00060 
00061 JackCoreMidiDriver::JackCoreMidiDriver(const char *name, const char *alias,
00062                                        JackLockedEngine *engine,
00063                                        JackSynchro *table):
00064     JackMidiDriver(name, alias, engine, table),fThread(this)
00065 {
00066     mach_timebase_info_data_t info;
00067     kern_return_t result = mach_timebase_info(&info);
00068     if (result != KERN_SUCCESS) {
00069         throw std::runtime_error(mach_error_string(result));
00070     }
00071     client = 0;
00072     fCaptureChannels = 0;
00073     fPlaybackChannels = 0;
00074     num_physical_inputs = 0;
00075     num_physical_outputs = 0;
00076     num_virtual_inputs = 0;
00077     num_virtual_outputs = 0;
00078     physical_input_ports = 0;
00079     physical_output_ports = 0;
00080     time_ratio = (((double) info.numer) / info.denom) / 1000.0;
00081     virtual_input_ports = 0;
00082     virtual_output_ports = 0;
00083     internal_input = 0;
00084     internal_output = 0;
00085 }
00086 
00087 JackCoreMidiDriver::~JackCoreMidiDriver()
00088 {}
00089 
00090 bool JackCoreMidiDriver::Init()
00091 {
00092     return OpenAux();
00093 }
00094 
00095 bool JackCoreMidiDriver::OpenAux()
00096 {
00097     int pi_count = 0;
00098     int po_count = 0;
00099     int vi_count = 0;
00100     int vo_count = 0;
00101     ItemCount potential_po_count;
00102     ItemCount potential_pi_count;
00103 
00104     CFStringRef name = CFStringCreateWithCString(0, "JackMidi",
00105                                                  CFStringGetSystemEncoding());
00106     if (! name) {
00107         jack_error("JackCoreMidiDriver::Open - failed to allocate memory for "
00108                    "client name string");
00109         return false;
00110     }
00111 
00112     OSStatus status = MIDIClientCreate(name, HandleNotificationEvent, this,
00113                                        &client);
00114 
00115     CFRelease(name);
00116 
00117     if (status != noErr) {
00118         WriteMacOSError("JackCoreMidiDriver::Open", "MIDIClientCreate",
00119                         status);
00120         return false;
00121     }
00122 
00123     char *client_name = fClientControl.fName;
00124 
00125     // Allocate and connect physical inputs
00126     potential_pi_count = MIDIGetNumberOfSources();
00127     if (potential_pi_count) {
00128         status = MIDIInputPortCreate(client, CFSTR("Physical Input Port"),
00129                                      HandleInputEvent, this, &internal_input);
00130         if (status != noErr) {
00131             WriteMacOSError("JackCoreMidiDriver::Open", "MIDIInputPortCreate",
00132                             status);
00133             goto destroy;
00134         }
00135 
00136         try {
00137             physical_input_ports =
00138                 new JackCoreMidiPhysicalInputPort*[potential_pi_count];
00139         } catch (std::exception e) {
00140             jack_error("JackCoreMidiDriver::Open - while creating physical "
00141                        "input port array: %s", e.what());
00142             goto destroy;
00143         }
00144 
00145         for (ItemCount i = 0; i < potential_pi_count; i++) {
00146             try {
00147                 physical_input_ports[pi_count] =
00148                     new JackCoreMidiPhysicalInputPort(fAliasName, client_name,
00149                                                       capture_driver_name, i,
00150                                                       client, internal_input,
00151                                                       time_ratio);
00152             } catch (std::exception e) {
00153                 jack_error("JackCoreMidiDriver::Open - while creating "
00154                            "physical input port: %s", e.what());
00155                 goto destroy;
00156             }
00157             pi_count++;
00158         }
00159     }
00160 
00161     // Allocate and connect physical outputs
00162     potential_po_count = MIDIGetNumberOfDestinations();
00163     if (potential_po_count) {
00164         status = MIDIOutputPortCreate(client, CFSTR("Physical Output Port"),
00165                                       &internal_output);
00166         if (status != noErr) {
00167             WriteMacOSError("JackCoreMidiDriver::Open", "MIDIOutputPortCreate",
00168                             status);
00169             goto destroy;
00170         }
00171 
00172         try {
00173             physical_output_ports =
00174                 new JackCoreMidiPhysicalOutputPort*[potential_po_count];
00175         } catch (std::exception e) {
00176             jack_error("JackCoreMidiDriver::Open - while creating physical "
00177                        "output port array: %s", e.what());
00178             goto destroy;
00179         }
00180 
00181         for (ItemCount i = 0; i < potential_po_count; i++) {
00182             try {
00183                 physical_output_ports[po_count] =
00184                     new JackCoreMidiPhysicalOutputPort(fAliasName, client_name,
00185                                                        playback_driver_name, i,
00186                                                        client, internal_output,
00187                                                        time_ratio);
00188             } catch (std::exception e) {
00189                 jack_error("JackCoreMidiDriver::Open - while creating "
00190                            "physical output port: %s", e.what());
00191                 goto destroy;
00192             }
00193             po_count++;
00194         }
00195     }
00196 
00197     // Allocate and connect virtual inputs
00198     if (in_channels) {
00199         try {
00200             virtual_input_ports =
00201                 new JackCoreMidiVirtualInputPort*[in_channels];
00202         } catch (std::exception e) {
00203             jack_error("JackCoreMidiDriver::Open - while creating virtual "
00204                        "input port array: %s", e.what());
00205             goto destroy;
00206 
00207         }
00208         for (vi_count = 0; vi_count < in_channels; vi_count++) {
00209             try {
00210                 virtual_input_ports[vi_count] =
00211                     new JackCoreMidiVirtualInputPort(fAliasName, client_name,
00212                                                      capture_driver_name,
00213                                                      vi_count + pi_count, client,
00214                                                      time_ratio);
00215             } catch (std::exception e) {
00216                 jack_error("JackCoreMidiDriver::Open - while creating virtual "
00217                            "input port: %s", e.what());
00218                 goto destroy;
00219             }
00220         }
00221     }
00222 
00223     // Allocate and connect virtual outputs
00224     if (out_channels) {
00225         try {
00226             virtual_output_ports =
00227                 new JackCoreMidiVirtualOutputPort*[out_channels];
00228         } catch (std::exception e) {
00229             jack_error("JackCoreMidiDriver::Open - while creating virtual "
00230                        "output port array: %s", e.what());
00231             goto destroy;
00232         }
00233         for (vo_count = 0; vo_count < out_channels; vo_count++) {
00234             try {
00235                 virtual_output_ports[vo_count] =
00236                     new JackCoreMidiVirtualOutputPort(fAliasName, client_name,
00237                                                       playback_driver_name,
00238                                                       vo_count + po_count, client,
00239                                                       time_ratio);
00240             } catch (std::exception e) {
00241                 jack_error("JackCoreMidiDriver::Open - while creating virtual "
00242                            "output port: %s", e.what());
00243                 goto destroy;
00244             }
00245         }
00246     }
00247 
00248 
00249     if (! (pi_count || po_count || in_channels || out_channels)) {
00250         jack_error("JackCoreMidiDriver::Open - no CoreMIDI inputs or outputs "
00251                    "found, and no virtual ports allocated.");
00252     }
00253 
00254     if (! JackMidiDriver::Open(capturing, playing,
00255                               in_channels + pi_count,
00256                               out_channels + po_count, monitor,
00257                               capture_driver_name,
00258                               playback_driver_name, capture_latency,
00259                               playback_latency)) {
00260         num_physical_inputs = pi_count;
00261         num_physical_outputs = po_count;
00262         num_virtual_inputs = in_channels;
00263         num_virtual_outputs = out_channels;
00264         return true;
00265     }
00266 
00267  destroy:
00268 
00269     if (physical_input_ports) {
00270         for (int i = 0; i < pi_count; i++) {
00271             delete physical_input_ports[i];
00272         }
00273         delete[] physical_input_ports;
00274         physical_input_ports = 0;
00275     }
00276 
00277     if (physical_output_ports) {
00278         for (int i = 0; i < po_count; i++) {
00279             delete physical_output_ports[i];
00280         }
00281         delete[] physical_output_ports;
00282         physical_output_ports = 0;
00283     }
00284 
00285     if (virtual_input_ports) {
00286         for (int i = 0; i < vi_count; i++) {
00287             delete virtual_input_ports[i];
00288         }
00289         delete[] virtual_input_ports;
00290         virtual_input_ports = 0;
00291     }
00292 
00293     if (virtual_output_ports) {
00294         for (int i = 0; i < vo_count; i++) {
00295             delete virtual_output_ports[i];
00296         }
00297         delete[] virtual_output_ports;
00298         virtual_output_ports = 0;
00299     }
00300 
00301     if (internal_output) {
00302         status = MIDIPortDispose(internal_output);
00303         if (status != noErr) {
00304             WriteMacOSError("JackCoreMidiDriver::Open", "MIDIPortDispose", status);
00305         }
00306     }
00307 
00308     if (internal_input) {
00309         status = MIDIPortDispose(internal_input);
00310         if (status != noErr) {
00311             WriteMacOSError("JackCoreMidiDriver::Open", "MIDIPortDispose", status);
00312         }
00313     }
00314 
00315     if (client) {
00316         status = MIDIClientDispose(client);
00317         if (status != noErr) {
00318             WriteMacOSError("JackCoreMidiDriver::Open", "MIDIClientDispose",
00319                             status);
00320         }
00321     }
00322 
00323     // Default open
00324     if (! JackMidiDriver::Open(capturing, playing,
00325                               in_channels + pi_count,
00326                               out_channels + po_count, monitor,
00327                               capture_driver_name,
00328                               playback_driver_name, capture_latency,
00329                               playback_latency)) {
00330         client = 0;
00331         num_physical_inputs = 0;
00332         num_physical_outputs = 0;
00333         num_virtual_inputs = 0;
00334         num_virtual_outputs = 0;
00335        return true;
00336     } else {
00337         return false;
00338     }
00339 }
00340 
00341 bool JackCoreMidiDriver::Execute()
00342 {
00343     CFRunLoopRun();
00344     return false;
00345 }
00346 
00347 int
00348 JackCoreMidiDriver::Attach()
00349 {
00350     jack_nframes_t buffer_size = fEngineControl->fBufferSize;
00351     jack_port_id_t index;
00352     jack_nframes_t latency = buffer_size;
00353     jack_latency_range_t latency_range;
00354     const char *name;
00355     JackPort *port;
00356     JackCoreMidiPort *port_obj;
00357     latency_range.max = latency;
00358     latency_range.min = latency;
00359 
00360     // Physical inputs
00361     for (int i = 0; i < num_physical_inputs; i++) {
00362         port_obj = physical_input_ports[i];
00363         name = port_obj->GetName();
00364         if (fEngine->PortRegister(fClientControl.fRefNum, name,
00365                                 JACK_DEFAULT_MIDI_TYPE,
00366                                 CaptureDriverFlags, buffer_size, &index) < 0) {
00367             jack_error("JackCoreMidiDriver::Attach - cannot register physical "
00368                        "input port with name '%s'.", name);
00369             // X: Do we need to deallocate ports?
00370             return -1;
00371         }
00372         port = fGraphManager->GetPort(index);
00373         port->SetAlias(port_obj->GetAlias());
00374         port->SetLatencyRange(JackCaptureLatency, &latency_range);
00375         fCapturePortList[i] = index;
00376     }
00377 
00378     // Virtual inputs
00379     for (int i = 0; i < num_virtual_inputs; i++) {
00380         port_obj = virtual_input_ports[i];
00381         name = port_obj->GetName();
00382         if (fEngine->PortRegister(fClientControl.fRefNum, name,
00383                                 JACK_DEFAULT_MIDI_TYPE,
00384                                 CaptureDriverFlags, buffer_size, &index) < 0) {
00385             jack_error("JackCoreMidiDriver::Attach - cannot register virtual "
00386                        "input port with name '%s'.", name);
00387             // X: Do we need to deallocate ports?
00388             return -1;
00389         }
00390         port = fGraphManager->GetPort(index);
00391         port->SetAlias(port_obj->GetAlias());
00392         port->SetLatencyRange(JackCaptureLatency, &latency_range);
00393         fCapturePortList[num_physical_inputs + i] = index;
00394     }
00395 
00396     if (! fEngineControl->fSyncMode) {
00397         latency += buffer_size;
00398         latency_range.max = latency;
00399         latency_range.min = latency;
00400     }
00401 
00402     // Physical outputs
00403     for (int i = 0; i < num_physical_outputs; i++) {
00404         port_obj = physical_output_ports[i];
00405         name = port_obj->GetName();
00406         fEngine->PortRegister(fClientControl.fRefNum, name,
00407                             JACK_DEFAULT_MIDI_TYPE,
00408                             PlaybackDriverFlags, buffer_size, &index);
00409         if (index == NO_PORT) {
00410             jack_error("JackCoreMidiDriver::Attach - cannot register physical "
00411                        "output port with name '%s'.", name);
00412             // X: Do we need to deallocate ports?
00413             return -1;
00414         }
00415         port = fGraphManager->GetPort(index);
00416         port->SetAlias(port_obj->GetAlias());
00417         port->SetLatencyRange(JackPlaybackLatency, &latency_range);
00418         fPlaybackPortList[i] = index;
00419     }
00420 
00421     // Virtual outputs
00422     for (int i = 0; i < num_virtual_outputs; i++) {
00423         port_obj = virtual_output_ports[i];
00424         name = port_obj->GetName();
00425         fEngine->PortRegister(fClientControl.fRefNum, name,
00426                             JACK_DEFAULT_MIDI_TYPE,
00427                             PlaybackDriverFlags, buffer_size, &index);
00428         if (index == NO_PORT) {
00429             jack_error("JackCoreMidiDriver::Attach - cannot register virtual "
00430                        "output port with name '%s'.", name);
00431             // X: Do we need to deallocate ports?
00432             return -1;
00433         }
00434         port = fGraphManager->GetPort(index);
00435         port->SetAlias(port_obj->GetAlias());
00436         port->SetLatencyRange(JackPlaybackLatency, &latency_range);
00437         fPlaybackPortList[num_physical_outputs + i] = index;
00438     }
00439 
00440     return 0;
00441 }
00442 
00443 int
00444 JackCoreMidiDriver::Close()
00445 {
00446     fThread.Kill();
00447     return CloseAux();
00448 }
00449 
00450 int
00451 JackCoreMidiDriver::CloseAux()
00452 {
00453     // Generic MIDI driver close
00454     int result = JackMidiDriver::Close();
00455 
00456     OSStatus status;
00457     if (physical_input_ports) {
00458         for (int i = 0; i < num_physical_inputs; i++) {
00459             delete physical_input_ports[i];
00460         }
00461         delete[] physical_input_ports;
00462         num_physical_inputs = 0;
00463         physical_input_ports = 0;
00464         if (internal_input) {
00465             status = MIDIPortDispose(internal_input);
00466             if (status != noErr) {
00467                 WriteMacOSError("JackCoreMidiDriver::Close", "MIDIPortDispose",
00468                                 status);
00469                 result = -1;
00470             }
00471             internal_input = 0;
00472         }
00473     }
00474     if (physical_output_ports) {
00475         for (int i = 0; i < num_physical_outputs; i++) {
00476             delete physical_output_ports[i];
00477         }
00478         delete[] physical_output_ports;
00479         num_physical_outputs = 0;
00480         physical_output_ports = 0;
00481         if (internal_output) {
00482             status = MIDIPortDispose(internal_output);
00483             if (status != noErr) {
00484                 WriteMacOSError("JackCoreMidiDriver::Close", "MIDIPortDispose",
00485                                 status);
00486                 result = -1;
00487             }
00488             internal_output = 0;
00489         }
00490     }
00491     if (virtual_input_ports) {
00492         for (int i = 0; i < num_virtual_inputs; i++) {
00493             delete virtual_input_ports[i];
00494         }
00495         delete[] virtual_input_ports;
00496         num_virtual_inputs = 0;
00497         virtual_input_ports = 0;
00498     }
00499     if (virtual_output_ports) {
00500         for (int i = 0; i < num_virtual_outputs; i++) {
00501             delete virtual_output_ports[i];
00502         }
00503         delete[] virtual_output_ports;
00504         num_virtual_outputs = 0;
00505         virtual_output_ports = 0;
00506     }
00507 
00508     if (client) {
00509         status = MIDIClientDispose(client);
00510         if (status != noErr) {
00511             WriteMacOSError("JackCoreMidiDriver::Close", "MIDIClientDispose",
00512                             status);
00513             result = -1;
00514         }
00515         client = 0;
00516     }
00517     return result;
00518 }
00519 
00520 void
00521 JackCoreMidiDriver::Restart()
00522 {
00523     JackLock lock(this);
00524 
00525     SaveConnections();
00526     Stop();
00527     Detach();
00528     CloseAux();
00529     OpenAux();
00530     Attach();
00531     Start();
00532     RestoreConnections();
00533 }
00534 
00535 void
00536 JackCoreMidiDriver::HandleNotification(const MIDINotification *message)
00537 {
00538     switch (message->messageID) {
00539 
00540         case kMIDIMsgSetupChanged:
00541             Restart();
00542             break;
00543 
00544         case kMIDIMsgObjectAdded:
00545             break;
00546 
00547         case kMIDIMsgObjectRemoved:
00548             break;
00549 
00550     }
00551 }
00552 
00553 int
00554 JackCoreMidiDriver::Open(bool capturing_aux, bool playing_aux, int in_channels_aux,
00555                          int out_channels_aux, bool monitor_aux,
00556                          const char* capture_driver_name_aux,
00557                          const char* playback_driver_name_aux,
00558                          jack_nframes_t capture_latency_aux,
00559                          jack_nframes_t playback_latency_aux)
00560 {
00561 
00562     strcpy(capture_driver_name, capture_driver_name_aux);
00563     strcpy(playback_driver_name, playback_driver_name_aux);
00564 
00565     capturing = capturing_aux;
00566     playing = playing_aux;
00567     in_channels = in_channels_aux;
00568     out_channels = out_channels_aux;
00569     monitor = monitor_aux;
00570     capture_latency = capture_latency_aux;
00571     playback_latency = playback_latency_aux;
00572 
00573     fThread.StartSync();
00574 
00575     int count = 0;
00576     while (fThread.GetStatus() != JackThread::kRunning && ++count < WAIT_COUNTER) {
00577         JackSleep(100000);
00578         jack_log("JackCoreMidiDriver::Open wait count = %d", count);
00579 
00580     }
00581     if (count == WAIT_COUNTER) {
00582         jack_info("Cannot open CoreMIDI driver");
00583         fThread.Kill();
00584         return -1;
00585     } else {
00586         JackSleep(10000);
00587         jack_info("CoreMIDI driver is running...");
00588     }
00589 
00590     return 0;
00591 }
00592 
00593 int
00594 JackCoreMidiDriver::Start()
00595 {
00596     jack_info("JackCoreMidiDriver::Start - Starting driver.");
00597 
00598     JackMidiDriver::Start();
00599 
00600     int pi_count = 0;
00601     int po_count = 0;
00602     int vi_count = 0;
00603     int vo_count = 0;
00604 
00605     jack_info("JackCoreMidiDriver::Start - Enabling physical input ports.");
00606 
00607     for (; pi_count < num_physical_inputs; pi_count++) {
00608         if (physical_input_ports[pi_count]->Start() < 0) {
00609             jack_error("JackCoreMidiDriver::Start - Failed to enable physical "
00610                        "input port.");
00611             goto stop_physical_input_ports;
00612         }
00613     }
00614 
00615     jack_info("JackCoreMidiDriver::Start - Enabling physical output ports.");
00616 
00617     for (; po_count < num_physical_outputs; po_count++) {
00618         if (physical_output_ports[po_count]->Start() < 0) {
00619             jack_error("JackCoreMidiDriver::Start - Failed to enable physical "
00620                        "output port.");
00621             goto stop_physical_output_ports;
00622         }
00623     }
00624 
00625     jack_info("JackCoreMidiDriver::Start - Enabling virtual input ports.");
00626 
00627     for (; vi_count < num_virtual_inputs; vi_count++) {
00628         if (virtual_input_ports[vi_count]->Start() < 0) {
00629             jack_error("JackCoreMidiDriver::Start - Failed to enable virtual "
00630                        "input port.");
00631             goto stop_virtual_input_ports;
00632         }
00633     }
00634 
00635     jack_info("JackCoreMidiDriver::Start - Enabling virtual output ports.");
00636 
00637     for (; vo_count < num_virtual_outputs; vo_count++) {
00638         if (virtual_output_ports[vo_count]->Start() < 0) {
00639             jack_error("JackCoreMidiDriver::Start - Failed to enable virtual "
00640                        "output port.");
00641             goto stop_virtual_output_ports;
00642         }
00643     }
00644 
00645     jack_info("JackCoreMidiDriver::Start - Driver started.");
00646 
00647     return 0;
00648 
00649  stop_virtual_output_ports:
00650     for (int i = 0; i < vo_count; i++) {
00651         if (virtual_output_ports[i]->Stop() < 0) {
00652             jack_error("JackCoreMidiDriver::Start - Failed to disable virtual "
00653                        "output port.");
00654         }
00655     }
00656  stop_virtual_input_ports:
00657     for (int i = 0; i < vi_count; i++) {
00658         if (virtual_input_ports[i]->Stop() < 0) {
00659             jack_error("JackCoreMidiDriver::Start - Failed to disable virtual "
00660                        "input port.");
00661         }
00662     }
00663  stop_physical_output_ports:
00664     for (int i = 0; i < po_count; i++) {
00665         if (physical_output_ports[i]->Stop() < 0) {
00666             jack_error("JackCoreMidiDriver::Start - Failed to disable "
00667                        "physical output port.");
00668         }
00669     }
00670  stop_physical_input_ports:
00671     for (int i = 0; i < pi_count; i++) {
00672         if (physical_input_ports[i]->Stop() < 0) {
00673             jack_error("JackCoreMidiDriver::Start - Failed to disable "
00674                        "physical input port.");
00675         }
00676     }
00677 
00678     return -1;
00679 }
00680 
00681 int
00682 JackCoreMidiDriver::Stop()
00683 {
00684     int result = 0;
00685 
00686     JackMidiDriver::Stop();
00687 
00688     jack_info("JackCoreMidiDriver::Stop - disabling physical input ports.");
00689 
00690     for (int i = 0; i < num_physical_inputs; i++) {
00691         if (physical_input_ports[i]->Stop() < 0) {
00692             jack_error("JackCoreMidiDriver::Stop - Failed to disable physical "
00693                        "input port.");
00694             result = -1;
00695         }
00696     }
00697 
00698     jack_info("JackCoreMidiDriver::Stop - disabling physical output ports.");
00699 
00700     for (int i = 0; i < num_physical_outputs; i++) {
00701         if (physical_output_ports[i]->Stop() < 0) {
00702             jack_error("JackCoreMidiDriver::Stop - Failed to disable physical "
00703                        "output port.");
00704             result = -1;
00705         }
00706     }
00707 
00708     jack_info("JackCoreMidiDriver::Stop - disabling virtual input ports.");
00709 
00710     for (int i = 0; i < num_virtual_inputs; i++) {
00711         if (virtual_input_ports[i]->Stop() < 0) {
00712             jack_error("JackCoreMidiDriver::Stop - Failed to disable virtual "
00713                        "input port.");
00714             result = -1;
00715         }
00716     }
00717 
00718     jack_info("JackCoreMidiDriver::Stop - disabling virtual output ports.");
00719 
00720     for (int i = 0; i < num_virtual_outputs; i++) {
00721         if (virtual_output_ports[i]->Stop() < 0) {
00722             jack_error("JackCoreMidiDriver::Stop - Failed to disable virtual "
00723                        "output port.");
00724             result = -1;
00725         }
00726     }
00727 
00728     return result;
00729 }
00730 
00731 int
00732 JackCoreMidiDriver::ProcessRead()
00733 {
00734     int res;
00735     if (Trylock()) {
00736         res = (fEngineControl->fSyncMode) ? ProcessReadSync() : ProcessReadAsync();
00737         Unlock();
00738     } else {
00739         res = -1;
00740     }
00741     return res;
00742 }
00743 
00744 int
00745 JackCoreMidiDriver::ProcessWrite()
00746 {
00747     int res;
00748     if (Trylock()) {
00749         res = (fEngineControl->fSyncMode) ? ProcessWriteSync() : ProcessWriteAsync();
00750         Unlock();
00751     } else {
00752         res = -1;
00753     }
00754     return res;
00755 }
00756 
00757 int
00758 JackCoreMidiDriver::Read()
00759 {
00760     jack_nframes_t buffer_size = fEngineControl->fBufferSize;
00761     for (int i = 0; i < num_physical_inputs; i++) {
00762         physical_input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
00763     }
00764     for (int i = 0; i < num_virtual_inputs; i++) {
00765         virtual_input_ports[i]->
00766             ProcessJack(GetInputBuffer(num_physical_inputs + i), buffer_size);
00767     }
00768     return 0;
00769 }
00770 
00771 int
00772 JackCoreMidiDriver::Write()
00773 {
00774     jack_nframes_t buffer_size = fEngineControl->fBufferSize;
00775     for (int i = 0; i < num_physical_outputs; i++) {
00776         physical_output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
00777     }
00778     for (int i = 0; i < num_virtual_outputs; i++) {
00779         virtual_output_ports[i]->
00780             ProcessJack(GetOutputBuffer(num_physical_outputs + i), buffer_size);
00781     }
00782     return 0;
00783 }
00784 
00785 #ifdef __cplusplus
00786 extern "C" {
00787 #endif
00788 
00789     // singleton kind of driver
00790     static Jack::JackDriverClientInterface* driver = NULL;
00791 
00792     SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
00793     {
00794         jack_driver_desc_t * desc;
00795         jack_driver_desc_filler_t filler;
00796         jack_driver_param_value_t value;
00797 
00798         desc = jack_driver_descriptor_construct("coremidi", JackDriverSlave, "Apple CoreMIDI API based MIDI backend", &filler);
00799 
00800         value.ui  = 0;
00801         jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "CoreMIDI virtual bus", NULL);
00802         jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "CoreMIDI virtual bus", NULL);
00803 
00804         return desc;
00805     }
00806 
00807     SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
00808     {
00809         const JSList * node;
00810         const jack_driver_param_t * param;
00811         int virtual_in = 0;
00812         int virtual_out = 0;
00813 
00814         for (node = params; node; node = jack_slist_next (node)) {
00815             param = (const jack_driver_param_t *) node->data;
00816 
00817             switch (param->character) {
00818 
00819                 case 'i':
00820                     virtual_in = param->value.ui;
00821                     break;
00822 
00823                 case 'o':
00824                     virtual_out = param->value.ui;
00825                     break;
00826                 }
00827         }
00828 
00829         // singleton kind of driver
00830         if (!driver) {
00831             driver = new Jack::JackCoreMidiDriver("system_midi", "coremidi", engine, table);
00832             if (driver->Open(1, 1, virtual_in, virtual_out, false, "in", "out", 0, 0) == 0) {
00833                 return driver;
00834             } else {
00835                 delete driver;
00836                 return NULL;
00837             }
00838         } else {
00839             jack_info("JackCoreMidiDriver already allocated, cannot be loaded twice");
00840             return NULL;
00841         }
00842     }
00843 
00844 #ifdef __cplusplus
00845 }
00846 #endif