Jack2: JackWinMMEDriver.cpp Source File

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
27 using Jack::JackWinMMEDriver;
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
Jack::JackLockedEngine
Locked Engine, access to methods is serialized using a mutex.
Definition: JackLockedEngine.h:78
Jack::JackPosixSemaphore
Inter process synchronization using POSIX semaphore.
Definition: JackPosixSemaphore.h:36
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
_jack_latency_range::min
jack_nframes_t min
Definition: types.h:270
jack_info
SERVER_EXPORT void jack_info(const char *fmt,...)
Definition: JackError.cpp:100
_jack_latency_range
Definition: types.h:265
_jack_latency_range::max
jack_nframes_t max
Definition: types.h:274
Jack::JackWinMMEDriver
Definition: JackWinMMEDriver.h:30
Jack::JackDriverClientInterface
The base interface for drivers clients.
Definition: JackDriver.h:114
_JSList
Definition: linux/alsa/jslist.h:35
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
jack_driver_desc_t
Definition: driver_interface.h:132