Jack2  1.9.10
JackWinMMEDriver.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 <cmath>
00022 
00023 #include "JackEngineControl.h"
00024 #include "JackWinMMEDriver.h"
00025 #include "driver_interface.h"
00026 
00027 using Jack::JackWinMMEDriver;
00028 
00029 JackWinMMEDriver::JackWinMMEDriver(const char *name, const char *alias,
00030                                    JackLockedEngine *engine,
00031                                    JackSynchro *table):
00032     JackMidiDriver(name, alias, engine, table)
00033 {
00034     input_ports = 0;
00035     output_ports = 0;
00036     period = 0;
00037 }
00038 
00039 JackWinMMEDriver::~JackWinMMEDriver()
00040 {}
00041 
00042 int
00043 JackWinMMEDriver::Attach()
00044 {
00045     jack_nframes_t buffer_size = fEngineControl->fBufferSize;
00046     jack_port_id_t index;
00047     jack_nframes_t latency = buffer_size;
00048     jack_latency_range_t latency_range;
00049     const char *name;
00050     JackPort *port;
00051     latency_range.max = latency +
00052         ((jack_nframes_t) std::ceil((period / 1000.0) *
00053                                     fEngineControl->fSampleRate));
00054     latency_range.min = latency;
00055 
00056     jack_info("JackWinMMEDriver::Attach - fCaptureChannels  %d", fCaptureChannels);
00057     jack_info("JackWinMMEDriver::Attach - fPlaybackChannels  %d", fPlaybackChannels);
00058 
00059     // Inputs
00060     for (int i = 0; i < fCaptureChannels; i++) {
00061         JackWinMMEInputPort *input_port = input_ports[i];
00062         name = input_port->GetName();
00063         if (fEngine->PortRegister(fClientControl.fRefNum, name,
00064                                 JACK_DEFAULT_MIDI_TYPE,
00065                                 CaptureDriverFlags, buffer_size, &index) < 0) {
00066             jack_error("JackWinMMEDriver::Attach - cannot register input port "
00067                        "with name '%s'.", name);
00068             // X: Do we need to deallocate ports?
00069             return -1;
00070         }
00071         port = fGraphManager->GetPort(index);
00072         port->SetAlias(input_port->GetAlias());
00073         port->SetLatencyRange(JackCaptureLatency, &latency_range);
00074         fCapturePortList[i] = index;
00075     }
00076 
00077     if (! fEngineControl->fSyncMode) {
00078         latency += buffer_size;
00079         latency_range.max = latency;
00080         latency_range.min = latency;
00081     }
00082 
00083     // Outputs
00084     for (int i = 0; i < fPlaybackChannels; i++) {
00085         JackWinMMEOutputPort *output_port = output_ports[i];
00086         name = output_port->GetName();
00087         if (fEngine->PortRegister(fClientControl.fRefNum, name,
00088                                 JACK_DEFAULT_MIDI_TYPE,
00089                                 PlaybackDriverFlags, buffer_size, &index) < 0) {
00090             jack_error("JackWinMMEDriver::Attach - cannot register output "
00091                        "port with name '%s'.", name);
00092             // X: Do we need to deallocate ports?
00093             return -1;
00094         }
00095         port = fGraphManager->GetPort(index);
00096         port->SetAlias(output_port->GetAlias());
00097         port->SetLatencyRange(JackPlaybackLatency, &latency_range);
00098         fPlaybackPortList[i] = index;
00099     }
00100 
00101     return 0;
00102 }
00103 
00104 int
00105 JackWinMMEDriver::Close()
00106 {
00107     // Generic MIDI driver close
00108     int result = JackMidiDriver::Close();
00109 
00110     if (input_ports) {
00111         for (int i = 0; i < fCaptureChannels; i++) {
00112             delete input_ports[i];
00113         }
00114         delete[] input_ports;
00115         input_ports = 0;
00116     }
00117     if (output_ports) {
00118         for (int i = 0; i < fPlaybackChannels; i++) {
00119             delete output_ports[i];
00120         }
00121         delete[] output_ports;
00122         output_ports = 0;
00123     }
00124     if (period) {
00125         if (timeEndPeriod(period) != TIMERR_NOERROR) {
00126             jack_error("JackWinMMEDriver::Close - failed to unset timer "
00127                        "resolution.");
00128             result = -1;
00129         }
00130     }
00131     return result;
00132 }
00133 
00134 int
00135 JackWinMMEDriver::Open(bool capturing, bool playing, int in_channels,
00136                        int out_channels, bool monitor,
00137                        const char* capture_driver_name,
00138                        const char* playback_driver_name,
00139                        jack_nframes_t capture_latency,
00140                        jack_nframes_t playback_latency)
00141 {
00142     const char *client_name = fClientControl.fName;
00143     int input_count = 0;
00144     int output_count = 0;
00145     int num_potential_inputs = midiInGetNumDevs();
00146     int num_potential_outputs = midiOutGetNumDevs();
00147 
00148     jack_info("JackWinMMEDriver::Open - num_potential_inputs  %d", num_potential_inputs);
00149     jack_info("JackWinMMEDriver::Open - num_potential_outputs  %d", num_potential_outputs);
00150 
00151     period = 0;
00152     TIMECAPS caps;
00153     if (timeGetDevCaps(&caps, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
00154         jack_error("JackWinMMEDriver::Open - could not get timer device "
00155                    "capabilities.  Continuing anyway ...");
00156     } else {
00157         period = caps.wPeriodMin;
00158         if (timeBeginPeriod(period) != TIMERR_NOERROR) {
00159             jack_error("JackWinMMEDriver::Open - could not set minimum timer "
00160                        "resolution.  Continuing anyway ...");
00161             period = 0;
00162         } else {
00163 
00164             jack_info("JackWinMMEDriver::Open - multimedia timer resolution "
00165                       "set to %d milliseconds.", period);
00166 
00167         }
00168     }
00169 
00170     if (num_potential_inputs) {
00171         try {
00172             input_ports = new JackWinMMEInputPort *[num_potential_inputs];
00173         } catch (std::exception& e) {
00174             jack_error("JackWinMMEDriver::Open - while creating input port "
00175                        "array: %s", e.what());
00176             goto unset_timer_resolution;
00177         }
00178         for (int i = 0; i < num_potential_inputs; i++) {
00179             try {
00180                 input_ports[input_count] =
00181                     new JackWinMMEInputPort(fAliasName, client_name,
00182                                             capture_driver_name, i);
00183             } catch (std::exception& e) {
00184                 jack_error("JackWinMMEDriver::Open - while creating input "
00185                            "port: %s", e.what());
00186                 continue;
00187             }
00188             input_count++;
00189         }
00190     }
00191     if (num_potential_outputs) {
00192         try {
00193             output_ports = new JackWinMMEOutputPort *[num_potential_outputs];
00194         } catch (std::exception& e) {
00195             jack_error("JackWinMMEDriver::Open - while creating output port "
00196                        "array: %s", e.what());
00197             goto destroy_input_ports;
00198         }
00199         for (int i = 0; i < num_potential_outputs; i++) {
00200             try {
00201                 output_ports[output_count] =
00202                     new JackWinMMEOutputPort(fAliasName, client_name,
00203                                              playback_driver_name, i);
00204             } catch (std::exception& e) {
00205                 jack_error("JackWinMMEDriver::Open - while creating output "
00206                            "port: %s", e.what());
00207                 continue;
00208             }
00209             output_count++;
00210         }
00211     }
00212 
00213     jack_info("JackWinMMEDriver::Open - input_count  %d", input_count);
00214     jack_info("JackWinMMEDriver::Open - output_count  %d", output_count);
00215 
00216     if (! (input_count || output_count)) {
00217         jack_error("JackWinMMEDriver::Open - no WinMME inputs or outputs "
00218                    "allocated.");
00219     } else if (! JackMidiDriver::Open(capturing, playing, input_count,
00220                                       output_count, monitor,
00221                                       capture_driver_name,
00222                                       playback_driver_name, capture_latency,
00223                                       playback_latency)) {
00224         return 0;
00225     }
00226 
00227     if (output_ports) {
00228         for (int i = 0; i < output_count; i++) {
00229             delete output_ports[i];
00230         }
00231         delete[] output_ports;
00232         output_ports = 0;
00233     }
00234  destroy_input_ports:
00235     if (input_ports) {
00236         for (int i = 0; i < input_count; i++) {
00237             delete input_ports[i];
00238         }
00239         delete[] input_ports;
00240         input_ports = 0;
00241     }
00242  unset_timer_resolution:
00243     if (period) {
00244         if (timeEndPeriod(period) != TIMERR_NOERROR) {
00245             jack_error("JackWinMMEDriver::Open - failed to unset timer "
00246                        "resolution.");
00247         }
00248     }
00249     return -1;
00250 }
00251 
00252 int
00253 JackWinMMEDriver::Read()
00254 {
00255     jack_nframes_t buffer_size = fEngineControl->fBufferSize;
00256     for (int i = 0; i < fCaptureChannels; i++) {
00257         input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
00258     }
00259 
00260     return 0;
00261 }
00262 
00263 int
00264 JackWinMMEDriver::Write()
00265 {
00266     jack_nframes_t buffer_size = fEngineControl->fBufferSize;
00267     for (int i = 0; i < fPlaybackChannels; i++) {
00268         output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
00269     }
00270 
00271     return 0;
00272 }
00273 
00274 int
00275 JackWinMMEDriver::Start()
00276 {
00277     jack_info("JackWinMMEDriver::Start - Starting driver.");
00278 
00279     JackMidiDriver::Start();
00280 
00281     int input_count = 0;
00282     int output_count = 0;
00283 
00284     jack_info("JackWinMMEDriver::Start - Enabling input ports.");
00285 
00286     for (; input_count < fCaptureChannels; input_count++) {
00287         if (input_ports[input_count]->Start() < 0) {
00288             jack_error("JackWinMMEDriver::Start - Failed to enable input "
00289                        "port.");
00290             goto stop_input_ports;
00291         }
00292     }
00293 
00294     jack_info("JackWinMMEDriver::Start - Enabling output ports.");
00295 
00296     for (; output_count < fPlaybackChannels; output_count++) {
00297         if (output_ports[output_count]->Start() < 0) {
00298             jack_error("JackWinMMEDriver::Start - Failed to enable output "
00299                        "port.");
00300             goto stop_output_ports;
00301         }
00302     }
00303 
00304     jack_info("JackWinMMEDriver::Start - Driver started.");
00305 
00306     return 0;
00307 
00308  stop_output_ports:
00309     for (int i = 0; i < output_count; i++) {
00310         if (output_ports[i]->Stop() < 0) {
00311             jack_error("JackWinMMEDriver::Start - Failed to disable output "
00312                        "port.");
00313         }
00314     }
00315  stop_input_ports:
00316     for (int i = 0; i < input_count; i++) {
00317         if (input_ports[i]->Stop() < 0) {
00318             jack_error("JackWinMMEDriver::Start - Failed to disable input "
00319                        "port.");
00320         }
00321     }
00322 
00323     return -1;
00324 }
00325 
00326 int
00327 JackWinMMEDriver::Stop()
00328 {
00329     int result = 0;
00330 
00331     JackMidiDriver::Stop();
00332 
00333     jack_info("JackWinMMEDriver::Stop - disabling input ports.");
00334 
00335     for (int i = 0; i < fCaptureChannels; i++) {
00336         if (input_ports[i]->Stop() < 0) {
00337             jack_error("JackWinMMEDriver::Stop - Failed to disable input "
00338                        "port.");
00339             result = -1;
00340         }
00341     }
00342 
00343     jack_info("JackWinMMEDriver::Stop - disabling output ports.");
00344 
00345     for (int i = 0; i < fPlaybackChannels; i++) {
00346         if (output_ports[i]->Stop() < 0) {
00347             jack_error("JackWinMMEDriver::Stop - Failed to disable output "
00348                        "port.");
00349             result = -1;
00350         }
00351     }
00352 
00353     return result;
00354 }
00355 
00356 #ifdef __cplusplus
00357 extern "C"
00358 {
00359 #endif
00360 
00361     // singleton kind of driver
00362     static Jack::JackWinMMEDriver* driver = NULL;
00363 
00364     SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
00365     {
00366         return jack_driver_descriptor_construct("winmme", JackDriverSlave, "WinMME API based MIDI backend", NULL);
00367     }
00368 
00369     SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
00370     {
00371         /*
00372         unsigned int capture_ports = 2;
00373         unsigned int playback_ports = 2;
00374         unsigned long wait_time = 0;
00375         const JSList * node;
00376         const jack_driver_param_t * param;
00377         bool monitor = false;
00378 
00379         for (node = params; node; node = jack_slist_next (node)) {
00380             param = (const jack_driver_param_t *) node->data;
00381 
00382             switch (param->character) {
00383 
00384                 case 'C':
00385                     capture_ports = param->value.ui;
00386                     break;
00387 
00388                 case 'P':
00389                     playback_ports = param->value.ui;
00390                     break;
00391 
00392                 case 'r':
00393                     sample_rate = param->value.ui;
00394                     break;
00395 
00396                 case 'p':
00397                     period_size = param->value.ui;
00398                     break;
00399 
00400                 case 'w':
00401                     wait_time = param->value.ui;
00402                     break;
00403 
00404                 case 'm':
00405                     monitor = param->value.i;
00406                     break;
00407             }
00408         }
00409         */
00410 
00411         // singleton kind of driver
00412         if (!driver) {
00413             driver = new Jack::JackWinMMEDriver("system_midi", "winmme", engine, table);
00414             if (driver->Open(1, 1, 0, 0, false, "in", "out", 0, 0) == 0) {
00415                 return driver;
00416             } else {
00417                 delete driver;
00418                 return NULL;
00419             }
00420         } else {
00421             jack_info("JackWinMMEDriver already allocated, cannot be loaded twice");
00422             return NULL;
00423         }
00424 
00425     }
00426 
00427 #ifdef __cplusplus
00428 }
00429 #endif
00430 
00431 
00432 /*
00433 jack_connect system:midi_capture_1 system_midi:playback_1
00434 jack_connect system:midi_capture_1 system_midi:playback_2
00435 
00436 jack_connect system:midi_capture_1 system_midi:playback_1
00437 
00438 jack_connect system:midi_capture_1 system_midi:playback_1
00439 
00440 jack_connect system:midi_capture_1 system_midi:playback_1
00441 
00442 jack_connect system_midi:capture_1 system:midi_playback_1
00443 jack_connect system_midi:capture_2 system:midi_playback_1
00444 
00445 jack_connect system_midi:capture_1  system_midi:playback_1
00446 
00447 */
00448