Jack2  1.9.12
JackWinMMEDriver.cpp
1 /*
2 Copyright (C) 2009 Grame
3 Copyright (C) 2011 Devin Anderson
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 
21 #include <cmath>
22 
23 #include "JackEngineControl.h"
24 #include "JackWinMMEDriver.h"
25 #include "driver_interface.h"
26 
28 
29 JackWinMMEDriver::JackWinMMEDriver(const char *name, const char *alias,
30  JackLockedEngine *engine,
31  JackSynchro *table):
32  JackMidiDriver(name, alias, engine, table)
33 {
34  input_ports = 0;
35  output_ports = 0;
36  period = 0;
37 }
38 
39 JackWinMMEDriver::~JackWinMMEDriver()
40 {}
41 
42 int
43 JackWinMMEDriver::Attach()
44 {
45  jack_nframes_t buffer_size = fEngineControl->fBufferSize;
46  jack_port_id_t index;
47  jack_nframes_t latency = buffer_size;
48  jack_latency_range_t latency_range;
49  const char *name;
50  JackPort *port;
51  latency_range.max = latency +
52  ((jack_nframes_t) std::ceil((period / 1000.0) *
53  fEngineControl->fSampleRate));
54  latency_range.min = latency;
55 
56  jack_log("JackWinMMEDriver::Attach - fCaptureChannels %d", fCaptureChannels);
57  jack_log("JackWinMMEDriver::Attach - fPlaybackChannels %d", fPlaybackChannels);
58 
59  // Inputs
60  for (int i = 0; i < fCaptureChannels; i++) {
61  JackWinMMEInputPort *input_port = input_ports[i];
62  name = input_port->GetName();
63  if (fEngine->PortRegister(fClientControl.fRefNum, name,
64  JACK_DEFAULT_MIDI_TYPE,
65  CaptureDriverFlags, buffer_size, &index) < 0) {
66  jack_error("JackWinMMEDriver::Attach - cannot register input port "
67  "with name '%s'.", name);
68  // X: Do we need to deallocate ports?
69  return -1;
70  }
71  port = fGraphManager->GetPort(index);
72  port->SetAlias(input_port->GetAlias());
73  port->SetLatencyRange(JackCaptureLatency, &latency_range);
74  fCapturePortList[i] = index;
75  }
76 
77  if (! fEngineControl->fSyncMode) {
78  latency += buffer_size;
79  latency_range.max = latency;
80  latency_range.min = latency;
81  }
82 
83  // Outputs
84  for (int i = 0; i < fPlaybackChannels; i++) {
85  JackWinMMEOutputPort *output_port = output_ports[i];
86  name = output_port->GetName();
87  if (fEngine->PortRegister(fClientControl.fRefNum, name,
88  JACK_DEFAULT_MIDI_TYPE,
89  PlaybackDriverFlags, buffer_size, &index) < 0) {
90  jack_error("JackWinMMEDriver::Attach - cannot register output "
91  "port with name '%s'.", name);
92  // X: Do we need to deallocate ports?
93  return -1;
94  }
95  port = fGraphManager->GetPort(index);
96  port->SetAlias(output_port->GetAlias());
97  port->SetLatencyRange(JackPlaybackLatency, &latency_range);
98  fPlaybackPortList[i] = index;
99  }
100 
101  return 0;
102 }
103 
104 int
105 JackWinMMEDriver::Close()
106 {
107  // Generic MIDI driver close
108  int result = JackMidiDriver::Close();
109 
110  if (input_ports) {
111  for (int i = 0; i < fCaptureChannels; i++) {
112  delete input_ports[i];
113  }
114  delete[] input_ports;
115  input_ports = 0;
116  }
117  if (output_ports) {
118  for (int i = 0; i < fPlaybackChannels; i++) {
119  delete output_ports[i];
120  }
121  delete[] output_ports;
122  output_ports = 0;
123  }
124  if (period) {
125  if (timeEndPeriod(period) != TIMERR_NOERROR) {
126  jack_error("JackWinMMEDriver::Close - failed to unset timer "
127  "resolution.");
128  result = -1;
129  }
130  }
131  return result;
132 }
133 
134 int
135 JackWinMMEDriver::Open(bool capturing, bool playing, int in_channels,
136  int out_channels, bool monitor,
137  const char* capture_driver_name,
138  const char* playback_driver_name,
139  jack_nframes_t capture_latency,
140  jack_nframes_t playback_latency)
141 {
142  const char *client_name = fClientControl.fName;
143  int input_count = 0;
144  int output_count = 0;
145  int num_potential_inputs = midiInGetNumDevs();
146  int num_potential_outputs = midiOutGetNumDevs();
147 
148  jack_log("JackWinMMEDriver::Open - num_potential_inputs %d", num_potential_inputs);
149  jack_log("JackWinMMEDriver::Open - num_potential_outputs %d", num_potential_outputs);
150 
151  period = 0;
152  TIMECAPS caps;
153  if (timeGetDevCaps(&caps, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
154  jack_error("JackWinMMEDriver::Open - could not get timer device "
155  "capabilities. Continuing anyway ...");
156  } else {
157  period = caps.wPeriodMin;
158  if (timeBeginPeriod(period) != TIMERR_NOERROR) {
159  jack_error("JackWinMMEDriver::Open - could not set minimum timer "
160  "resolution. Continuing anyway ...");
161  period = 0;
162  } else {
163  jack_log("JackWinMMEDriver::Open - multimedia timer resolution "
164  "set to %d milliseconds.", period);
165  }
166  }
167 
168  if (num_potential_inputs) {
169  try {
170  input_ports = new JackWinMMEInputPort *[num_potential_inputs];
171  } catch (std::exception& e) {
172  jack_error("JackWinMMEDriver::Open - while creating input port "
173  "array: %s", e.what());
174  goto unset_timer_resolution;
175  }
176  for (int i = 0; i < num_potential_inputs; i++) {
177  try {
178  input_ports[input_count] =
179  new JackWinMMEInputPort(fAliasName, client_name,
180  capture_driver_name, i);
181  } catch (std::exception& e) {
182  jack_error("JackWinMMEDriver::Open - while creating input "
183  "port: %s", e.what());
184  continue;
185  }
186  input_count++;
187  }
188  }
189  if (num_potential_outputs) {
190  try {
191  output_ports = new JackWinMMEOutputPort *[num_potential_outputs];
192  } catch (std::exception& e) {
193  jack_error("JackWinMMEDriver::Open - while creating output port "
194  "array: %s", e.what());
195  goto destroy_input_ports;
196  }
197  for (int i = 0; i < num_potential_outputs; i++) {
198  try {
199  output_ports[output_count] =
200  new JackWinMMEOutputPort(fAliasName, client_name,
201  playback_driver_name, i);
202  } catch (std::exception& e) {
203  jack_error("JackWinMMEDriver::Open - while creating output "
204  "port: %s", e.what());
205  continue;
206  }
207  output_count++;
208  }
209  }
210 
211  jack_log("JackWinMMEDriver::Open - input_count %d", input_count);
212  jack_log("JackWinMMEDriver::Open - output_count %d", output_count);
213 
214  if (! (input_count || output_count)) {
215  jack_error("JackWinMMEDriver::Open - no WinMME inputs or outputs "
216  "allocated.");
217  } else if (! JackMidiDriver::Open(capturing, playing, input_count,
218  output_count, monitor,
219  capture_driver_name,
220  playback_driver_name, capture_latency,
221  playback_latency)) {
222  return 0;
223  }
224 
225  if (output_ports) {
226  for (int i = 0; i < output_count; i++) {
227  delete output_ports[i];
228  }
229  delete[] output_ports;
230  output_ports = 0;
231  }
232  destroy_input_ports:
233  if (input_ports) {
234  for (int i = 0; i < input_count; i++) {
235  delete input_ports[i];
236  }
237  delete[] input_ports;
238  input_ports = 0;
239  }
240  unset_timer_resolution:
241  if (period) {
242  if (timeEndPeriod(period) != TIMERR_NOERROR) {
243  jack_error("JackWinMMEDriver::Open - failed to unset timer "
244  "resolution.");
245  }
246  }
247  return -1;
248 }
249 
250 int
251 JackWinMMEDriver::Read()
252 {
253  jack_nframes_t buffer_size = fEngineControl->fBufferSize;
254  for (int i = 0; i < fCaptureChannels; i++) {
255  input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
256  }
257 
258  return 0;
259 }
260 
261 int
262 JackWinMMEDriver::Write()
263 {
264  jack_nframes_t buffer_size = fEngineControl->fBufferSize;
265  for (int i = 0; i < fPlaybackChannels; i++) {
266  output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
267  }
268 
269  return 0;
270 }
271 
272 int
273 JackWinMMEDriver::Start()
274 {
275  jack_log("JackWinMMEDriver::Start - Starting driver.");
276 
277  JackMidiDriver::Start();
278 
279  int input_count = 0;
280  int output_count = 0;
281 
282  jack_log("JackWinMMEDriver::Start - Enabling input ports.");
283 
284  for (; input_count < fCaptureChannels; input_count++) {
285  if (input_ports[input_count]->Start() < 0) {
286  jack_error("JackWinMMEDriver::Start - Failed to enable input "
287  "port.");
288  goto stop_input_ports;
289  }
290  }
291 
292  jack_log("JackWinMMEDriver::Start - Enabling output ports.");
293 
294  for (; output_count < fPlaybackChannels; output_count++) {
295  if (output_ports[output_count]->Start() < 0) {
296  jack_error("JackWinMMEDriver::Start - Failed to enable output "
297  "port.");
298  goto stop_output_ports;
299  }
300  }
301 
302  jack_log("JackWinMMEDriver::Start - Driver started.");
303  return 0;
304 
305  stop_output_ports:
306  for (int i = 0; i < output_count; i++) {
307  if (output_ports[i]->Stop() < 0) {
308  jack_error("JackWinMMEDriver::Start - Failed to disable output "
309  "port.");
310  }
311  }
312  stop_input_ports:
313  for (int i = 0; i < input_count; i++) {
314  if (input_ports[i]->Stop() < 0) {
315  jack_error("JackWinMMEDriver::Start - Failed to disable input "
316  "port.");
317  }
318  }
319 
320  return -1;
321 }
322 
323 int
324 JackWinMMEDriver::Stop()
325 {
326  int result = 0;
327 
328  JackMidiDriver::Stop();
329 
330  jack_log("JackWinMMEDriver::Stop - disabling input ports.");
331 
332  for (int i = 0; i < fCaptureChannels; i++) {
333  if (input_ports[i]->Stop() < 0) {
334  jack_error("JackWinMMEDriver::Stop - Failed to disable input "
335  "port.");
336  result = -1;
337  }
338  }
339 
340  jack_log("JackWinMMEDriver::Stop - disabling output ports.");
341 
342  for (int i = 0; i < fPlaybackChannels; i++) {
343  if (output_ports[i]->Stop() < 0) {
344  jack_error("JackWinMMEDriver::Stop - Failed to disable output "
345  "port.");
346  result = -1;
347  }
348  }
349 
350  return result;
351 }
352 
353 #ifdef __cplusplus
354 extern "C"
355 {
356 #endif
357 
358  // singleton kind of driver
359  static Jack::JackWinMMEDriver* driver = NULL;
360 
361  SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
362  {
363  return jack_driver_descriptor_construct("winmme", JackDriverSlave, "WinMME API based MIDI backend", NULL);
364  }
365 
366  SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
367  {
368  /*
369  unsigned int capture_ports = 2;
370  unsigned int playback_ports = 2;
371  unsigned long wait_time = 0;
372  const JSList * node;
373  const jack_driver_param_t * param;
374  bool monitor = false;
375 
376  for (node = params; node; node = jack_slist_next (node)) {
377  param = (const jack_driver_param_t *) node->data;
378 
379  switch (param->character) {
380 
381  case 'C':
382  capture_ports = param->value.ui;
383  break;
384 
385  case 'P':
386  playback_ports = param->value.ui;
387  break;
388 
389  case 'r':
390  sample_rate = param->value.ui;
391  break;
392 
393  case 'p':
394  period_size = param->value.ui;
395  break;
396 
397  case 'w':
398  wait_time = param->value.ui;
399  break;
400 
401  case 'm':
402  monitor = param->value.i;
403  break;
404  }
405  }
406  */
407 
408  // singleton kind of driver
409  if (!driver) {
410  driver = new Jack::JackWinMMEDriver("system_midi", "winmme", engine, table);
411  if (driver->Open(1, 1, 0, 0, false, "in", "out", 0, 0) == 0) {
412  return driver;
413  } else {
414  delete driver;
415  return NULL;
416  }
417  } else {
418  jack_info("JackWinMMEDriver already allocated, cannot be loaded twice");
419  return NULL;
420  }
421 
422  }
423 
424 #ifdef __cplusplus
425 }
426 #endif
427 
428 
429 /*
430 jack_connect system:midi_capture_1 system_midi:playback_1
431 jack_connect system:midi_capture_1 system_midi:playback_2
432 
433 jack_connect system:midi_capture_1 system_midi:playback_1
434 
435 jack_connect system:midi_capture_1 system_midi:playback_1
436 
437 jack_connect system:midi_capture_1 system_midi:playback_1
438 
439 jack_connect system_midi:capture_1 system:midi_playback_1
440 jack_connect system_midi:capture_2 system:midi_playback_1
441 
442 jack_connect system_midi:capture_1 system_midi:playback_1
443 
444 */
445