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