Jack2  1.9.9
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_info("JackWinMMEDriver::Attach - fCaptureChannels %d", fCaptureChannels);
57  jack_info("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_info("JackWinMMEDriver::Open - num_potential_inputs %d", num_potential_inputs);
149  jack_info("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 
164  jack_info("JackWinMMEDriver::Open - multimedia timer resolution "
165  "set to %d milliseconds.", period);
166 
167  }
168  }
169 
170  if (num_potential_inputs) {
171  try {
172  input_ports = new JackWinMMEInputPort *[num_potential_inputs];
173  } catch (std::exception e) {
174  jack_error("JackWinMMEDriver::Open - while creating input port "
175  "array: %s", e.what());
176  goto unset_timer_resolution;
177  }
178  for (int i = 0; i < num_potential_inputs; i++) {
179  try {
180  input_ports[input_count] =
181  new JackWinMMEInputPort(fAliasName, client_name,
182  capture_driver_name, i);
183  } catch (std::exception e) {
184  jack_error("JackWinMMEDriver::Open - while creating input "
185  "port: %s", e.what());
186  continue;
187  }
188  input_count++;
189  }
190  }
191  if (num_potential_outputs) {
192  try {
193  output_ports = new JackWinMMEOutputPort *[num_potential_outputs];
194  } catch (std::exception e) {
195  jack_error("JackWinMMEDriver::Open - while creating output port "
196  "array: %s", e.what());
197  goto destroy_input_ports;
198  }
199  for (int i = 0; i < num_potential_outputs; i++) {
200  try {
201  output_ports[output_count] =
202  new JackWinMMEOutputPort(fAliasName, client_name,
203  playback_driver_name, i);
204  } catch (std::exception e) {
205  jack_error("JackWinMMEDriver::Open - while creating output "
206  "port: %s", e.what());
207  continue;
208  }
209  output_count++;
210  }
211  }
212 
213  jack_info("JackWinMMEDriver::Open - input_count %d", input_count);
214  jack_info("JackWinMMEDriver::Open - output_count %d", output_count);
215 
216  if (! (input_count || output_count)) {
217  jack_error("JackWinMMEDriver::Open - no WinMME inputs or outputs "
218  "allocated.");
219  } else if (! JackMidiDriver::Open(capturing, playing, input_count,
220  output_count, monitor,
221  capture_driver_name,
222  playback_driver_name, capture_latency,
223  playback_latency)) {
224  return 0;
225  }
226 
227  if (output_ports) {
228  for (int i = 0; i < output_count; i++) {
229  delete output_ports[i];
230  }
231  delete[] output_ports;
232  output_ports = 0;
233  }
234  destroy_input_ports:
235  if (input_ports) {
236  for (int i = 0; i < input_count; i++) {
237  delete input_ports[i];
238  }
239  delete[] input_ports;
240  input_ports = 0;
241  }
242  unset_timer_resolution:
243  if (period) {
244  if (timeEndPeriod(period) != TIMERR_NOERROR) {
245  jack_error("JackWinMMEDriver::Open - failed to unset timer "
246  "resolution.");
247  }
248  }
249  return -1;
250 }
251 
252 int
253 JackWinMMEDriver::Read()
254 {
255  jack_nframes_t buffer_size = fEngineControl->fBufferSize;
256  for (int i = 0; i < fCaptureChannels; i++) {
257  input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
258  }
259 
260  return 0;
261 }
262 
263 int
264 JackWinMMEDriver::Write()
265 {
266  jack_nframes_t buffer_size = fEngineControl->fBufferSize;
267  for (int i = 0; i < fPlaybackChannels; i++) {
268  output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
269  }
270 
271  return 0;
272 }
273 
274 int
275 JackWinMMEDriver::Start()
276 {
277  jack_info("JackWinMMEDriver::Start - Starting driver.");
278 
279  JackMidiDriver::Start();
280 
281  int input_count = 0;
282  int output_count = 0;
283 
284  jack_info("JackWinMMEDriver::Start - Enabling input ports.");
285 
286  for (; input_count < fCaptureChannels; input_count++) {
287  if (input_ports[input_count]->Start() < 0) {
288  jack_error("JackWinMMEDriver::Start - Failed to enable input "
289  "port.");
290  goto stop_input_ports;
291  }
292  }
293 
294  jack_info("JackWinMMEDriver::Start - Enabling output ports.");
295 
296  for (; output_count < fPlaybackChannels; output_count++) {
297  if (output_ports[output_count]->Start() < 0) {
298  jack_error("JackWinMMEDriver::Start - Failed to enable output "
299  "port.");
300  goto stop_output_ports;
301  }
302  }
303 
304  jack_info("JackWinMMEDriver::Start - Driver started.");
305 
306  return 0;
307 
308  stop_output_ports:
309  for (int i = 0; i < output_count; i++) {
310  if (output_ports[i]->Stop() < 0) {
311  jack_error("JackWinMMEDriver::Start - Failed to disable output "
312  "port.");
313  }
314  }
315  stop_input_ports:
316  for (int i = 0; i < input_count; i++) {
317  if (input_ports[i]->Stop() < 0) {
318  jack_error("JackWinMMEDriver::Start - Failed to disable input "
319  "port.");
320  }
321  }
322 
323  return -1;
324 }
325 
326 int
327 JackWinMMEDriver::Stop()
328 {
329  int result = 0;
330 
331  JackMidiDriver::Stop();
332 
333  jack_info("JackWinMMEDriver::Stop - disabling input ports.");
334 
335  for (int i = 0; i < fCaptureChannels; i++) {
336  if (input_ports[i]->Stop() < 0) {
337  jack_error("JackWinMMEDriver::Stop - Failed to disable input "
338  "port.");
339  result = -1;
340  }
341  }
342 
343  jack_info("JackWinMMEDriver::Stop - disabling output ports.");
344 
345  for (int i = 0; i < fPlaybackChannels; i++) {
346  if (output_ports[i]->Stop() < 0) {
347  jack_error("JackWinMMEDriver::Stop - Failed to disable output "
348  "port.");
349  result = -1;
350  }
351  }
352 
353  return result;
354 }
355 
356 #ifdef __cplusplus
357 extern "C"
358 {
359 #endif
360 
361  // singleton kind of driver
362  static Jack::JackDriverClientInterface* driver = NULL;
363 
364  SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
365  {
366  return jack_driver_descriptor_construct("winmme", JackDriverSlave, "WinMME API based MIDI backend", NULL);
367  }
368 
369  SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
370  {
371  /*
372  unsigned int capture_ports = 2;
373  unsigned int playback_ports = 2;
374  unsigned long wait_time = 0;
375  const JSList * node;
376  const jack_driver_param_t * param;
377  bool monitor = false;
378 
379  for (node = params; node; node = jack_slist_next (node)) {
380  param = (const jack_driver_param_t *) node->data;
381 
382  switch (param->character) {
383 
384  case 'C':
385  capture_ports = param->value.ui;
386  break;
387 
388  case 'P':
389  playback_ports = param->value.ui;
390  break;
391 
392  case 'r':
393  sample_rate = param->value.ui;
394  break;
395 
396  case 'p':
397  period_size = param->value.ui;
398  break;
399 
400  case 'w':
401  wait_time = param->value.ui;
402  break;
403 
404  case 'm':
405  monitor = param->value.i;
406  break;
407  }
408  }
409  */
410 
411  // singleton kind of driver
412  if (!driver) {
413  driver = new Jack::JackWinMMEDriver("system_midi", "winmme", engine, table);
414  if (driver->Open(1, 1, 0, 0, false, "in", "out", 0, 0) == 0) {
415  return driver;
416  } else {
417  delete driver;
418  return NULL;
419  }
420  } else {
421  jack_info("JackWinMMEDriver already allocated, cannot be loaded twice");
422  return NULL;
423  }
424 
425  }
426 
427 #ifdef __cplusplus
428 }
429 #endif
430 
431 
432 /*
433 jack_connect system:midi_capture_1 system_midi:playback_1
434 jack_connect system:midi_capture_1 system_midi:playback_2
435 
436 jack_connect system:midi_capture_1 system_midi:playback_1
437 
438 jack_connect system:midi_capture_1 system_midi:playback_1
439 
440 jack_connect system:midi_capture_1 system_midi:playback_1
441 
442 jack_connect system_midi:capture_1 system:midi_playback_1
443 jack_connect system_midi:capture_2 system:midi_playback_1
444 
445 jack_connect system_midi:capture_1 system_midi:playback_1
446 
447 */
448 
Inter process synchronization using using Mach semaphore.
Locked Engine, access to methods is serialized using a mutex.
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:91
jack_nframes_t min
Definition: types.h:268
SERVER_EXPORT void jack_info(const char *fmt,...)
Definition: JackError.cpp:99
jack_nframes_t max
Definition: types.h:272
The base interface for drivers clients.
Definition: JackDriver.h:122