Jack2 1.9.8

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