Jack2  1.9.13
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  fEngine->PortSetDeviceMetadata(fClientControl.fRefNum, index,
75  input_port->GetDeviceName());
76  fCapturePortList[i] = index;
77  }
78 
79  if (! fEngineControl->fSyncMode) {
80  latency += buffer_size;
81  latency_range.max = latency;
82  latency_range.min = latency;
83  }
84 
85  // Outputs
86  for (int i = 0; i < fPlaybackChannels; i++) {
87  JackWinMMEOutputPort *output_port = output_ports[i];
88  name = output_port->GetName();
89  if (fEngine->PortRegister(fClientControl.fRefNum, name,
90  JACK_DEFAULT_MIDI_TYPE,
91  PlaybackDriverFlags, buffer_size, &index) < 0) {
92  jack_error("JackWinMMEDriver::Attach - cannot register output "
93  "port with name '%s'.", name);
94  // X: Do we need to deallocate ports?
95  return -1;
96  }
97  port = fGraphManager->GetPort(index);
98  port->SetAlias(output_port->GetAlias());
99  port->SetLatencyRange(JackPlaybackLatency, &latency_range);
100  fEngine->PortSetDeviceMetadata(fClientControl.fRefNum, index,
101  output_port->GetDeviceName());
102  fPlaybackPortList[i] = index;
103  }
104 
105  return 0;
106 }
107 
108 int
109 JackWinMMEDriver::Close()
110 {
111  // Generic MIDI driver close
112  int result = JackMidiDriver::Close();
113 
114  if (input_ports) {
115  for (int i = 0; i < fCaptureChannels; i++) {
116  delete input_ports[i];
117  }
118  delete[] input_ports;
119  input_ports = 0;
120  }
121  if (output_ports) {
122  for (int i = 0; i < fPlaybackChannels; i++) {
123  delete output_ports[i];
124  }
125  delete[] output_ports;
126  output_ports = 0;
127  }
128  if (period) {
129  if (timeEndPeriod(period) != TIMERR_NOERROR) {
130  jack_error("JackWinMMEDriver::Close - failed to unset timer "
131  "resolution.");
132  result = -1;
133  }
134  }
135  return result;
136 }
137 
138 int
139 JackWinMMEDriver::Open(bool capturing, bool playing, int in_channels,
140  int out_channels, bool monitor,
141  const char* capture_driver_name,
142  const char* playback_driver_name,
143  jack_nframes_t capture_latency,
144  jack_nframes_t playback_latency)
145 {
146  const char *client_name = fClientControl.fName;
147  int input_count = 0;
148  int output_count = 0;
149  int num_potential_inputs = midiInGetNumDevs();
150  int num_potential_outputs = midiOutGetNumDevs();
151 
152  jack_log("JackWinMMEDriver::Open - num_potential_inputs %d", num_potential_inputs);
153  jack_log("JackWinMMEDriver::Open - num_potential_outputs %d", num_potential_outputs);
154 
155  period = 0;
156  TIMECAPS caps;
157  if (timeGetDevCaps(&caps, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
158  jack_error("JackWinMMEDriver::Open - could not get timer device "
159  "capabilities. Continuing anyway ...");
160  } else {
161  period = caps.wPeriodMin;
162  if (timeBeginPeriod(period) != TIMERR_NOERROR) {
163  jack_error("JackWinMMEDriver::Open - could not set minimum timer "
164  "resolution. Continuing anyway ...");
165  period = 0;
166  } else {
167  jack_log("JackWinMMEDriver::Open - multimedia timer resolution "
168  "set to %d milliseconds.", period);
169  }
170  }
171 
172  if (num_potential_inputs) {
173  try {
174  input_ports = new JackWinMMEInputPort *[num_potential_inputs];
175  } catch (std::exception& e) {
176  jack_error("JackWinMMEDriver::Open - while creating input port "
177  "array: %s", e.what());
178  goto unset_timer_resolution;
179  }
180  for (int i = 0; i < num_potential_inputs; i++) {
181  try {
182  input_ports[input_count] =
183  new JackWinMMEInputPort(fAliasName, client_name,
184  capture_driver_name, i);
185  } catch (std::exception& e) {
186  jack_error("JackWinMMEDriver::Open - while creating input "
187  "port: %s", e.what());
188  continue;
189  }
190  input_count++;
191  }
192  }
193  if (num_potential_outputs) {
194  try {
195  output_ports = new JackWinMMEOutputPort *[num_potential_outputs];
196  } catch (std::exception& e) {
197  jack_error("JackWinMMEDriver::Open - while creating output port "
198  "array: %s", e.what());
199  goto destroy_input_ports;
200  }
201  for (int i = 0; i < num_potential_outputs; i++) {
202  try {
203  output_ports[output_count] =
204  new JackWinMMEOutputPort(fAliasName, client_name,
205  playback_driver_name, i);
206  } catch (std::exception& e) {
207  jack_error("JackWinMMEDriver::Open - while creating output "
208  "port: %s", e.what());
209  continue;
210  }
211  output_count++;
212  }
213  }
214 
215  jack_log("JackWinMMEDriver::Open - input_count %d", input_count);
216  jack_log("JackWinMMEDriver::Open - output_count %d", output_count);
217 
218  if (! (input_count || output_count)) {
219  jack_error("JackWinMMEDriver::Open - no WinMME inputs or outputs "
220  "allocated.");
221  } else if (! JackMidiDriver::Open(capturing, playing, input_count,
222  output_count, monitor,
223  capture_driver_name,
224  playback_driver_name, capture_latency,
225  playback_latency)) {
226  return 0;
227  }
228 
229  if (output_ports) {
230  for (int i = 0; i < output_count; i++) {
231  delete output_ports[i];
232  }
233  delete[] output_ports;
234  output_ports = 0;
235  }
236  destroy_input_ports:
237  if (input_ports) {
238  for (int i = 0; i < input_count; i++) {
239  delete input_ports[i];
240  }
241  delete[] input_ports;
242  input_ports = 0;
243  }
244  unset_timer_resolution:
245  if (period) {
246  if (timeEndPeriod(period) != TIMERR_NOERROR) {
247  jack_error("JackWinMMEDriver::Open - failed to unset timer "
248  "resolution.");
249  }
250  }
251  return -1;
252 }
253 
254 int
255 JackWinMMEDriver::Read()
256 {
257  jack_nframes_t buffer_size = fEngineControl->fBufferSize;
258  for (int i = 0; i < fCaptureChannels; i++) {
259  input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
260  }
261 
262  return 0;
263 }
264 
265 int
266 JackWinMMEDriver::Write()
267 {
268  jack_nframes_t buffer_size = fEngineControl->fBufferSize;
269  for (int i = 0; i < fPlaybackChannels; i++) {
270  output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
271  }
272 
273  return 0;
274 }
275 
276 int
277 JackWinMMEDriver::Start()
278 {
279  jack_log("JackWinMMEDriver::Start - Starting driver.");
280 
281  JackMidiDriver::Start();
282 
283  int input_count = 0;
284  int output_count = 0;
285 
286  jack_log("JackWinMMEDriver::Start - Enabling input ports.");
287 
288  for (; input_count < fCaptureChannels; input_count++) {
289  if (input_ports[input_count]->Start() < 0) {
290  jack_error("JackWinMMEDriver::Start - Failed to enable input "
291  "port.");
292  goto stop_input_ports;
293  }
294  }
295 
296  jack_log("JackWinMMEDriver::Start - Enabling output ports.");
297 
298  for (; output_count < fPlaybackChannels; output_count++) {
299  if (output_ports[output_count]->Start() < 0) {
300  jack_error("JackWinMMEDriver::Start - Failed to enable output "
301  "port.");
302  goto stop_output_ports;
303  }
304  }
305 
306  jack_log("JackWinMMEDriver::Start - Driver started.");
307  return 0;
308 
309  stop_output_ports:
310  for (int i = 0; i < output_count; i++) {
311  if (output_ports[i]->Stop() < 0) {
312  jack_error("JackWinMMEDriver::Start - Failed to disable output "
313  "port.");
314  }
315  }
316  stop_input_ports:
317  for (int i = 0; i < input_count; i++) {
318  if (input_ports[i]->Stop() < 0) {
319  jack_error("JackWinMMEDriver::Start - Failed to disable input "
320  "port.");
321  }
322  }
323 
324  return -1;
325 }
326 
327 int
328 JackWinMMEDriver::Stop()
329 {
330  int result = 0;
331 
332  JackMidiDriver::Stop();
333 
334  jack_log("JackWinMMEDriver::Stop - disabling input ports.");
335 
336  for (int i = 0; i < fCaptureChannels; i++) {
337  if (input_ports[i]->Stop() < 0) {
338  jack_error("JackWinMMEDriver::Stop - Failed to disable input "
339  "port.");
340  result = -1;
341  }
342  }
343 
344  jack_log("JackWinMMEDriver::Stop - disabling output ports.");
345 
346  for (int i = 0; i < fPlaybackChannels; i++) {
347  if (output_ports[i]->Stop() < 0) {
348  jack_error("JackWinMMEDriver::Stop - Failed to disable output "
349  "port.");
350  result = -1;
351  }
352  }
353 
354  return result;
355 }
356 
357 #ifdef __cplusplus
358 extern "C"
359 {
360 #endif
361 
362  // singleton kind of driver
363  static Jack::JackWinMMEDriver* driver = NULL;
364 
365  SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
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
Locked Engine, access to methods is serialized using a mutex.
Inter process synchronization using POSIX semaphore.
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
jack_nframes_t min
Definition: types.h:270
SERVER_EXPORT void jack_info(const char *fmt,...)
Definition: JackError.cpp:100
jack_nframes_t max
Definition: types.h:274
The base interface for drivers clients.
Definition: JackDriver.h:114
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108