Jack2 1.9.10

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 "JackCompilerDeps.h"
00022 #include "JackCoreMidiDriver.h"
00023 #include "JackCoreMidiUtil.h"
00024 #include "JackEngineControl.h"
00025 #include "driver_interface.h"
00026 
00027 #include <stdexcept>
00028 #include <mach/mach_time.h>
00029 
00030 using Jack::JackCoreMidiDriver;
00031 
00032 static char capture_driver_name[256];
00033 static char playback_driver_name[256];
00034 
00035 static int in_channels, out_channels;
00036 static bool capturing, playing, monitor;
00037 
00038 static jack_nframes_t capture_latency, playback_latency;
00039 
00041 // Static callbacks
00043 
00044 void
00045 JackCoreMidiDriver::HandleInputEvent(const MIDIPacketList *packet_list,
00046                                      void *driver, void *port)
00047 {
00048     ((JackCoreMidiPhysicalInputPort *) port)->ProcessCoreMidi(packet_list);
00049 }
00050 
00051 void
00052 JackCoreMidiDriver::HandleNotificationEvent(const MIDINotification *message,
00053                                             void *driver)
00054 {
00055     ((JackCoreMidiDriver *) driver)->HandleNotification(message);
00056 }
00057 
00059 // Class
00061 
00062 JackCoreMidiDriver::JackCoreMidiDriver(const char *name, const char *alias,
00063                                        JackLockedEngine *engine,
00064                                        JackSynchro *table):
00065     JackMidiDriver(name, alias, engine, table),fThread(this)
00066 {
00067     mach_timebase_info_data_t info;
00068     kern_return_t result = mach_timebase_info(&info);
00069     if (result != KERN_SUCCESS) {
00070         throw std::runtime_error(mach_error_string(result));
00071     }
00072     client = 0;
00073     fCaptureChannels = 0;
00074     fPlaybackChannels = 0;
00075     num_physical_inputs = 0;
00076     num_physical_outputs = 0;
00077     num_virtual_inputs = 0;
00078     num_virtual_outputs = 0;
00079     physical_input_ports = 0;
00080     physical_output_ports = 0;
00081     time_ratio = (((double) info.numer) / info.denom) / 1000.0;
00082     virtual_input_ports = 0;
00083     virtual_output_ports = 0;
00084     internal_input = 0;
00085     internal_output = 0;
00086 }
00087 
00088 JackCoreMidiDriver::~JackCoreMidiDriver()
00089 {}
00090 
00091 bool JackCoreMidiDriver::Init()
00092 {
00093     return OpenAux();
00094 }
00095 
00096 bool JackCoreMidiDriver::OpenAux()
00097 {
00098     int pi_count = 0;
00099     int po_count = 0;
00100     int vi_count = 0;
00101     int vo_count = 0;
00102     ItemCount potential_po_count;
00103     ItemCount potential_pi_count;
00104 
00105     CFStringRef name = CFStringCreateWithCString(0, "JackMidi",
00106                                                  CFStringGetSystemEncoding());
00107     if (! name) {
00108         jack_error("JackCoreMidiDriver::Open - failed to allocate memory for "
00109                    "client name string");
00110         return false;
00111     }
00112 
00113     OSStatus status = MIDIClientCreate(name, HandleNotificationEvent, this,
00114                                        &client);
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, 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, 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     if (! (pi_count || po_count || in_channels || out_channels)) {
00249         jack_error("JackCoreMidiDriver::Open - no CoreMIDI inputs or outputs "
00250                    "found, and no virtual ports allocated.");
00251     }
00252 
00253     if (! JackMidiDriver::Open(capturing, playing,
00254                               in_channels + pi_count,
00255                               out_channels + po_count, monitor,
00256                               capture_driver_name,
00257                               playback_driver_name, capture_latency,
00258                               playback_latency)) {
00259         num_physical_inputs = pi_count;
00260         num_physical_outputs = po_count;
00261         num_virtual_inputs = in_channels;
00262         num_virtual_outputs = out_channels;
00263         return true;
00264     }
00265 
00266  destroy:
00267 
00268     if (physical_input_ports) {
00269         for (int i = 0; i < pi_count; i++) {
00270             delete physical_input_ports[i];
00271         }
00272         delete[] physical_input_ports;
00273         physical_input_ports = 0;
00274     }
00275 
00276     if (physical_output_ports) {
00277         for (int i = 0; i < po_count; i++) {
00278             delete physical_output_ports[i];
00279         }
00280         delete[] physical_output_ports;
00281         physical_output_ports = 0;
00282     }
00283 
00284     if (virtual_input_ports) {
00285         for (int i = 0; i < vi_count; i++) {
00286             delete virtual_input_ports[i];
00287         }
00288         delete[] virtual_input_ports;
00289         virtual_input_ports = 0;
00290     }
00291 
00292     if (virtual_output_ports) {
00293         for (int i = 0; i < vo_count; i++) {
00294             delete virtual_output_ports[i];
00295         }
00296         delete[] virtual_output_ports;
00297         virtual_output_ports = 0;
00298     }
00299 
00300     if (internal_output) {
00301         status = MIDIPortDispose(internal_output);
00302         if (status != noErr) {
00303             WriteMacOSError("JackCoreMidiDriver::Open", "MIDIPortDispose", status);
00304         }
00305     }
00306 
00307     if (internal_input) {
00308         status = MIDIPortDispose(internal_input);
00309         if (status != noErr) {
00310             WriteMacOSError("JackCoreMidiDriver::Open", "MIDIPortDispose", status);
00311         }
00312     }
00313 
00314     if (client) {
00315         status = MIDIClientDispose(client);
00316         if (status != noErr) {
00317             WriteMacOSError("JackCoreMidiDriver::Open", "MIDIClientDispose",
00318                             status);
00319         }
00320     }
00321 
00322     // Default open
00323     if (! JackMidiDriver::Open(capturing, playing,
00324                               in_channels + pi_count,
00325                               out_channels + po_count, monitor,
00326                               capture_driver_name,
00327                               playback_driver_name, capture_latency,
00328                               playback_latency)) {
00329         client = 0;
00330         num_physical_inputs = 0;
00331         num_physical_outputs = 0;
00332         num_virtual_inputs = 0;
00333         num_virtual_outputs = 0;
00334        return true;
00335     } else {
00336         return false;
00337     }
00338 }
00339 
00340 bool JackCoreMidiDriver::Execute()
00341 {
00342     CFRunLoopRun();
00343     return false;
00344 }
00345 
00346 int
00347 JackCoreMidiDriver::Attach()
00348 {
00349     jack_nframes_t buffer_size = fEngineControl->fBufferSize;
00350     jack_port_id_t index;
00351     jack_nframes_t latency = buffer_size;
00352     jack_latency_range_t latency_range;
00353     const char *name;
00354     JackPort *port;
00355     JackCoreMidiPort *port_obj;
00356     latency_range.max = latency;
00357     latency_range.min = latency;
00358     
00359     // Physical inputs
00360     for (int i = 0; i < num_physical_inputs; i++) {
00361         port_obj = physical_input_ports[i];
00362         name = port_obj->GetName();
00363         if (fEngine->PortRegister(fClientControl.fRefNum, name,
00364                                 JACK_DEFAULT_MIDI_TYPE,
00365                                 CaptureDriverFlags, buffer_size, &index) < 0) {
00366             jack_error("JackCoreMidiDriver::Attach - cannot register physical "
00367                        "input port with name '%s'.", name);
00368             // X: Do we need to deallocate ports?
00369             return -1;
00370         }
00371         port = fGraphManager->GetPort(index);
00372         port->SetAlias(port_obj->GetAlias());
00373         port->SetLatencyRange(JackCaptureLatency, &latency_range);
00374         fCapturePortList[i] = index;
00375     }
00376 
00377     // Virtual inputs
00378     for (int i = 0; i < num_virtual_inputs; i++) {
00379         port_obj = virtual_input_ports[i];
00380         name = port_obj->GetName();
00381         if (fEngine->PortRegister(fClientControl.fRefNum, name,
00382                                 JACK_DEFAULT_MIDI_TYPE,
00383                                 CaptureDriverFlags, buffer_size, &index) < 0) {
00384             jack_error("JackCoreMidiDriver::Attach - cannot register virtual "
00385                        "input port with name '%s'.", name);
00386             // X: Do we need to deallocate ports?
00387             return -1;
00388         }
00389         port = fGraphManager->GetPort(index);
00390         port->SetAlias(port_obj->GetAlias());
00391         port->SetLatencyRange(JackCaptureLatency, &latency_range);
00392         fCapturePortList[num_physical_inputs + i] = index;
00393     }
00394 
00395     if (! fEngineControl->fSyncMode) {
00396         latency += buffer_size;
00397         latency_range.max = latency;
00398         latency_range.min = latency;
00399     }
00400 
00401     // Physical outputs
00402     for (int i = 0; i < num_physical_outputs; i++) {
00403         port_obj = physical_output_ports[i];
00404         name = port_obj->GetName();
00405         fEngine->PortRegister(fClientControl.fRefNum, name,
00406                             JACK_DEFAULT_MIDI_TYPE,
00407                             PlaybackDriverFlags, buffer_size, &index);
00408         if (index == NO_PORT) {
00409             jack_error("JackCoreMidiDriver::Attach - cannot register physical "
00410                        "output port with name '%s'.", name);
00411             // X: Do we need to deallocate ports?
00412             return -1;
00413         }
00414         port = fGraphManager->GetPort(index);
00415         port->SetAlias(port_obj->GetAlias());
00416         port->SetLatencyRange(JackPlaybackLatency, &latency_range);
00417         fPlaybackPortList[i] = index;
00418     }
00419 
00420     // Virtual outputs
00421     for (int i = 0; i < num_virtual_outputs; i++) {
00422         port_obj = virtual_output_ports[i];
00423         name = port_obj->GetName();
00424         fEngine->PortRegister(fClientControl.fRefNum, name,
00425                             JACK_DEFAULT_MIDI_TYPE,
00426                             PlaybackDriverFlags, buffer_size, &index);
00427         if (index == NO_PORT) {
00428             jack_error("JackCoreMidiDriver::Attach - cannot register virtual "
00429                        "output port with name '%s'.", name);
00430             // X: Do we need to deallocate ports?
00431             return -1;
00432         }
00433         port = fGraphManager->GetPort(index);
00434         port->SetAlias(port_obj->GetAlias());
00435         port->SetLatencyRange(JackPlaybackLatency, &latency_range);
00436         fPlaybackPortList[num_physical_outputs + i] = index;
00437     }
00438 
00439     return 0;
00440 }
00441 
00442 int
00443 JackCoreMidiDriver::Close()
00444 {
00445     fThread.Kill();
00446     return CloseAux();
00447 }
00448 
00449 int
00450 JackCoreMidiDriver::CloseAux()
00451 {
00452     // Generic MIDI driver close
00453     int result = JackMidiDriver::Close();
00454 
00455     OSStatus status;
00456     if (physical_input_ports) {
00457         for (int i = 0; i < num_physical_inputs; i++) {
00458             delete physical_input_ports[i];
00459         }
00460         delete[] physical_input_ports;
00461         num_physical_inputs = 0;
00462         physical_input_ports = 0;
00463         if (internal_input) {
00464             status = MIDIPortDispose(internal_input);
00465             if (status != noErr) {
00466                 WriteMacOSError("JackCoreMidiDriver::Close", "MIDIPortDispose",
00467                                 status);
00468                 result = -1;
00469             }
00470             internal_input = 0;
00471         }
00472     }
00473     if (physical_output_ports) {
00474         for (int i = 0; i < num_physical_outputs; i++) {
00475             delete physical_output_ports[i];
00476         }
00477         delete[] physical_output_ports;
00478         num_physical_outputs = 0;
00479         physical_output_ports = 0;
00480         if (internal_output) {
00481             status = MIDIPortDispose(internal_output);
00482             if (status != noErr) {
00483                 WriteMacOSError("JackCoreMidiDriver::Close", "MIDIPortDispose",
00484                                 status);
00485                 result = -1;
00486             }
00487             internal_output = 0;
00488         }
00489     }
00490     if (virtual_input_ports) {
00491         for (int i = 0; i < num_virtual_inputs; i++) {
00492             delete virtual_input_ports[i];
00493         }
00494         delete[] virtual_input_ports;
00495         num_virtual_inputs = 0;
00496         virtual_input_ports = 0;
00497     }
00498     if (virtual_output_ports) {
00499         for (int i = 0; i < num_virtual_outputs; i++) {
00500             delete virtual_output_ports[i];
00501         }
00502         delete[] virtual_output_ports;
00503         num_virtual_outputs = 0;
00504         virtual_output_ports = 0;
00505     }
00506 
00507     if (client) {
00508         status = MIDIClientDispose(client);
00509         if (status != noErr) {
00510             WriteMacOSError("JackCoreMidiDriver::Close", "MIDIClientDispose",
00511                             status);
00512             result = -1;
00513         }
00514         client = 0;
00515     }
00516     return result;
00517 }
00518 
00519 void
00520 JackCoreMidiDriver::Restart()
00521 {
00522     // Lock between this thread and RT thread
00523     JackLock lock(this);
00524     
00525     // Lock between this thread and request thread
00526     if (fEngine->Lock()) {
00527         // Use first alias
00528         SaveConnections(1);
00529         Stop();
00530         Detach();
00531         CloseAux();
00532         OpenAux();
00533         Attach();
00534         Start();
00535         // Use first alias and partial port naming
00536         LoadConnections(1, false);
00537         fEngine->Unlock();
00538     } else {
00539         jack_error("Cannot acquire engine lock...");
00540     }
00541 }
00542 
00543 void
00544 JackCoreMidiDriver::HandleNotification(const MIDINotification *message)
00545 {
00546     switch (message->messageID) {
00547 
00548         case kMIDIMsgObjectAdded: {
00549             /*
00550                 We don't want to restart when our internal virtual in/out are created.
00551             */
00552             const MIDIObjectAddRemoveNotification* add_message = reinterpret_cast<const MIDIObjectAddRemoveNotification*>(message);
00553             if (!JackCoreMidiPort::IsInternalPort(add_message->child)) {
00554                 Restart();
00555             }
00556             break;
00557         }
00558         
00559         case kMIDIMsgObjectRemoved: {
00560             /*
00561                 We don't want to restart when our internal virtual in/out are created.
00562             */
00563             const MIDIObjectAddRemoveNotification* remove_message = reinterpret_cast<const MIDIObjectAddRemoveNotification*>(message);
00564             if (!JackCoreMidiPort::IsInternalPort(remove_message->child)) {
00565                 Restart();
00566             }
00567             break;
00568         }
00569     }
00570 }
00571 
00572 int
00573 JackCoreMidiDriver::Open(bool capturing_aux, bool playing_aux, int in_channels_aux,
00574                          int out_channels_aux, bool monitor_aux,
00575                          const char* capture_driver_name_aux,
00576                          const char* playback_driver_name_aux,
00577                          jack_nframes_t capture_latency_aux,
00578                          jack_nframes_t playback_latency_aux)
00579 {
00580 
00581     strcpy(capture_driver_name, capture_driver_name_aux);
00582     strcpy(playback_driver_name, playback_driver_name_aux);
00583 
00584     capturing = capturing_aux;
00585     playing = playing_aux;
00586     in_channels = in_channels_aux;
00587     out_channels = out_channels_aux;
00588     monitor = monitor_aux;
00589     capture_latency = capture_latency_aux;
00590     playback_latency = playback_latency_aux;
00591 
00592     fThread.StartSync();
00593 
00594     int count = 0;
00595     while (fThread.GetStatus() != JackThread::kRunning && ++count < WAIT_COUNTER) {
00596         JackSleep(100000);
00597         jack_log("JackCoreMidiDriver::Open wait count = %d", count);
00598 
00599     }
00600     if (count == WAIT_COUNTER) {
00601         jack_info("Cannot open CoreMIDI driver");
00602         fThread.Kill();
00603         return -1;
00604     } else {
00605         JackSleep(10000);
00606         jack_info("CoreMIDI driver is opened...");
00607     }
00608 
00609     return 0;
00610 }
00611 
00612 int
00613 JackCoreMidiDriver::Start()
00614 {
00615     jack_info("JackCoreMidiDriver::Start - Starting driver.");
00616 
00617     JackMidiDriver::Start();
00618 
00619     int pi_count = 0;
00620     int po_count = 0;
00621     int vi_count = 0;
00622     int vo_count = 0;
00623 
00624     jack_info("JackCoreMidiDriver::Start - Enabling physical input ports.");
00625 
00626     for (; pi_count < num_physical_inputs; pi_count++) {
00627         if (physical_input_ports[pi_count]->Start() < 0) {
00628             jack_error("JackCoreMidiDriver::Start - Failed to enable physical "
00629                        "input port.");
00630             goto stop_physical_input_ports;
00631         }
00632     }
00633 
00634     jack_info("JackCoreMidiDriver::Start - Enabling physical output ports.");
00635 
00636     for (; po_count < num_physical_outputs; po_count++) {
00637         if (physical_output_ports[po_count]->Start() < 0) {
00638             jack_error("JackCoreMidiDriver::Start - Failed to enable physical "
00639                        "output port.");
00640             goto stop_physical_output_ports;
00641         }
00642     }
00643 
00644     jack_info("JackCoreMidiDriver::Start - Enabling virtual input ports.");
00645 
00646     for (; vi_count < num_virtual_inputs; vi_count++) {
00647         if (virtual_input_ports[vi_count]->Start() < 0) {
00648             jack_error("JackCoreMidiDriver::Start - Failed to enable virtual "
00649                        "input port.");
00650             goto stop_virtual_input_ports;
00651         }
00652     }
00653 
00654     jack_info("JackCoreMidiDriver::Start - Enabling virtual output ports.");
00655 
00656     for (; vo_count < num_virtual_outputs; vo_count++) {
00657         if (virtual_output_ports[vo_count]->Start() < 0) {
00658             jack_error("JackCoreMidiDriver::Start - Failed to enable virtual "
00659                        "output port.");
00660             goto stop_virtual_output_ports;
00661         }
00662     }
00663 
00664     jack_info("JackCoreMidiDriver::Start - Driver started.");
00665 
00666     return 0;
00667 
00668  stop_virtual_output_ports:
00669     for (int i = 0; i < vo_count; i++) {
00670         if (virtual_output_ports[i]->Stop() < 0) {
00671             jack_error("JackCoreMidiDriver::Start - Failed to disable virtual "
00672                        "output port.");
00673         }
00674     }
00675  stop_virtual_input_ports:
00676     for (int i = 0; i < vi_count; i++) {
00677         if (virtual_input_ports[i]->Stop() < 0) {
00678             jack_error("JackCoreMidiDriver::Start - Failed to disable virtual "
00679                        "input port.");
00680         }
00681     }
00682  stop_physical_output_ports:
00683     for (int i = 0; i < po_count; i++) {
00684         if (physical_output_ports[i]->Stop() < 0) {
00685             jack_error("JackCoreMidiDriver::Start - Failed to disable "
00686                        "physical output port.");
00687         }
00688     }
00689  stop_physical_input_ports:
00690     for (int i = 0; i < pi_count; i++) {
00691         if (physical_input_ports[i]->Stop() < 0) {
00692             jack_error("JackCoreMidiDriver::Start - Failed to disable "
00693                        "physical input port.");
00694         }
00695     }
00696 
00697     return -1;
00698 }
00699 
00700 int
00701 JackCoreMidiDriver::Stop()
00702 {
00703     int result = 0;
00704 
00705     JackMidiDriver::Stop();
00706 
00707     jack_info("JackCoreMidiDriver::Stop - disabling physical input ports.");
00708 
00709     for (int i = 0; i < num_physical_inputs; i++) {
00710         if (physical_input_ports[i]->Stop() < 0) {
00711             jack_error("JackCoreMidiDriver::Stop - Failed to disable physical "
00712                        "input port.");
00713             result = -1;
00714         }
00715     }
00716 
00717     jack_info("JackCoreMidiDriver::Stop - disabling physical output ports.");
00718 
00719     for (int i = 0; i < num_physical_outputs; i++) {
00720         if (physical_output_ports[i]->Stop() < 0) {
00721             jack_error("JackCoreMidiDriver::Stop - Failed to disable physical "
00722                        "output port.");
00723             result = -1;
00724         }
00725     }
00726 
00727     jack_info("JackCoreMidiDriver::Stop - disabling virtual input ports.");
00728 
00729     for (int i = 0; i < num_virtual_inputs; i++) {
00730         if (virtual_input_ports[i]->Stop() < 0) {
00731             jack_error("JackCoreMidiDriver::Stop - Failed to disable virtual "
00732                        "input port.");
00733             result = -1;
00734         }
00735     }
00736 
00737     jack_info("JackCoreMidiDriver::Stop - disabling virtual output ports.");
00738 
00739     for (int i = 0; i < num_virtual_outputs; i++) {
00740         if (virtual_output_ports[i]->Stop() < 0) {
00741             jack_error("JackCoreMidiDriver::Stop - Failed to disable virtual "
00742                        "output port.");
00743             result = -1;
00744         }
00745     }
00746 
00747     return result;
00748 }
00749 
00750 int
00751 JackCoreMidiDriver::ProcessRead()
00752 {
00753     int res;
00754     if (Trylock()) {
00755         res = (fEngineControl->fSyncMode) ? ProcessReadSync() : ProcessReadAsync();
00756         Unlock();
00757     } else {
00758         res = -1;
00759     }
00760     return res;
00761 }
00762 
00763 int
00764 JackCoreMidiDriver::ProcessWrite()
00765 {
00766     int res;
00767     if (Trylock()) {
00768         res = (fEngineControl->fSyncMode) ? ProcessWriteSync() : ProcessWriteAsync();
00769         Unlock();
00770     } else {
00771         res = -1;
00772     }
00773     return res;
00774 }
00775 
00776 int
00777 JackCoreMidiDriver::Read()
00778 {
00779     jack_nframes_t buffer_size = fEngineControl->fBufferSize;
00780     for (int i = 0; i < num_physical_inputs; i++) {
00781         physical_input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
00782     }
00783     for (int i = 0; i < num_virtual_inputs; i++) {
00784         virtual_input_ports[i]->
00785             ProcessJack(GetInputBuffer(num_physical_inputs + i), buffer_size);
00786     }
00787     return 0;
00788 }
00789 
00790 int
00791 JackCoreMidiDriver::Write()
00792 {
00793     jack_nframes_t buffer_size = fEngineControl->fBufferSize;
00794     for (int i = 0; i < num_physical_outputs; i++) {
00795         physical_output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
00796     }
00797     for (int i = 0; i < num_virtual_outputs; i++) {
00798         virtual_output_ports[i]->
00799             ProcessJack(GetOutputBuffer(num_physical_outputs + i), buffer_size);
00800     }
00801     return 0;
00802 }
00803 
00804 #ifdef __cplusplus
00805 extern "C" {
00806 #endif
00807 
00808     // singleton kind of driver
00809     static Jack::JackCoreMidiDriver* driver = NULL;
00810 
00811     SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
00812     {
00813         jack_driver_desc_t * desc;
00814         jack_driver_desc_filler_t filler;
00815         jack_driver_param_value_t value;
00816 
00817         desc = jack_driver_descriptor_construct("coremidi", JackDriverSlave, "Apple CoreMIDI API based MIDI backend", &filler);
00818 
00819         value.ui  = 0;
00820         jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "CoreMIDI virtual bus", NULL);
00821         jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "CoreMIDI virtual bus", NULL);
00822 
00823         return desc;
00824     }
00825 
00826     SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
00827     {
00828         const JSList * node;
00829         const jack_driver_param_t * param;
00830         int virtual_in = 2;
00831         int virtual_out = 2;
00832 
00833         for (node = params; node; node = jack_slist_next (node)) {
00834             param = (const jack_driver_param_t *) node->data;
00835 
00836             switch (param->character) {
00837 
00838                 case 'i':
00839                     virtual_in = param->value.ui;
00840                     break;
00841 
00842                 case 'o':
00843                     virtual_out = param->value.ui;
00844                     break;
00845                 }
00846         }
00847 
00848         // singleton kind of driver
00849         if (!driver) {
00850             driver = new Jack::JackCoreMidiDriver("system_midi", "coremidi", engine, table);
00851             if (driver->Open(1, 1, virtual_in, virtual_out, false, "in", "out", 0, 0) == 0) {
00852                 return driver;
00853             } else {
00854                 delete driver;
00855                 return NULL;
00856             }
00857         } else {
00858             jack_info("JackCoreMidiDriver already allocated, cannot be loaded twice");
00859             return NULL;
00860         }
00861     }
00862 
00863 #ifdef __cplusplus
00864 }
00865 #endif