Replace Util.pprint by Logs.pprint
[jack2.git] / windows / winmme / JackWinMMEDriver.cpp
blobeaa70859473f7423509d01fed2bad2f8af725eb8
1 /*
2 Copyright (C) 2009 Grame
3 Copyright (C) 2011 Devin Anderson
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.
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.
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.
21 #include <cmath>
23 #include "JackEngineControl.h"
24 #include "JackWinMMEDriver.h"
25 #include "driver_interface.h"
27 using Jack::JackWinMMEDriver;
29 JackWinMMEDriver::JackWinMMEDriver(const char *name, const char *alias,
30 JackLockedEngine *engine,
31 JackSynchro *table):
32 JackMidiDriver(name, alias, engine, table)
34 input_ports = 0;
35 output_ports = 0;
36 period = 0;
39 JackWinMMEDriver::~JackWinMMEDriver()
42 int
43 JackWinMMEDriver::Attach()
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;
56 jack_info("JackWinMMEDriver::Attach - fCaptureChannels %d", fCaptureChannels);
57 jack_info("JackWinMMEDriver::Attach - fPlaybackChannels %d", fPlaybackChannels);
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;
71 port = fGraphManager->GetPort(index);
72 port->SetAlias(input_port->GetAlias());
73 port->SetLatencyRange(JackCaptureLatency, &latency_range);
74 fCapturePortList[i] = index;
77 if (! fEngineControl->fSyncMode) {
78 latency += buffer_size;
79 latency_range.max = latency;
80 latency_range.min = latency;
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;
95 port = fGraphManager->GetPort(index);
96 port->SetAlias(output_port->GetAlias());
97 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
98 fPlaybackPortList[i] = index;
101 return 0;
105 JackWinMMEDriver::Close()
107 // Generic MIDI driver close
108 int result = JackMidiDriver::Close();
110 if (input_ports) {
111 for (int i = 0; i < fCaptureChannels; i++) {
112 delete input_ports[i];
114 delete[] input_ports;
115 input_ports = 0;
117 if (output_ports) {
118 for (int i = 0; i < fPlaybackChannels; i++) {
119 delete output_ports[i];
121 delete[] output_ports;
122 output_ports = 0;
124 if (period) {
125 if (timeEndPeriod(period) != TIMERR_NOERROR) {
126 jack_error("JackWinMMEDriver::Close - failed to unset timer "
127 "resolution.");
128 result = -1;
131 return result;
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)
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();
148 jack_info("JackWinMMEDriver::Open - num_potential_inputs %d", num_potential_inputs);
149 jack_info("JackWinMMEDriver::Open - num_potential_outputs %d", num_potential_outputs);
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 {
164 jack_info("JackWinMMEDriver::Open - multimedia timer resolution "
165 "set to %d milliseconds.", period);
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;
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;
188 input_count++;
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;
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;
209 output_count++;
213 jack_info("JackWinMMEDriver::Open - input_count %d", input_count);
214 jack_info("JackWinMMEDriver::Open - output_count %d", output_count);
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;
227 if (output_ports) {
228 for (int i = 0; i < output_count; i++) {
229 delete output_ports[i];
231 delete[] output_ports;
232 output_ports = 0;
234 destroy_input_ports:
235 if (input_ports) {
236 for (int i = 0; i < input_count; i++) {
237 delete input_ports[i];
239 delete[] input_ports;
240 input_ports = 0;
242 unset_timer_resolution:
243 if (period) {
244 if (timeEndPeriod(period) != TIMERR_NOERROR) {
245 jack_error("JackWinMMEDriver::Open - failed to unset timer "
246 "resolution.");
249 return -1;
253 JackWinMMEDriver::Read()
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);
260 return 0;
264 JackWinMMEDriver::Write()
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);
271 return 0;
275 JackWinMMEDriver::Start()
277 jack_info("JackWinMMEDriver::Start - Starting driver.");
279 JackMidiDriver::Start();
281 int input_count = 0;
282 int output_count = 0;
284 jack_info("JackWinMMEDriver::Start - Enabling input ports.");
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;
294 jack_info("JackWinMMEDriver::Start - Enabling output ports.");
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;
304 jack_info("JackWinMMEDriver::Start - Driver started.");
306 return 0;
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.");
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.");
323 return -1;
327 JackWinMMEDriver::Stop()
329 int result = 0;
331 JackMidiDriver::Stop();
333 jack_info("JackWinMMEDriver::Stop - disabling input ports.");
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;
343 jack_info("JackWinMMEDriver::Stop - disabling output ports.");
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;
353 return result;
356 #ifdef __cplusplus
357 extern "C"
359 #endif
361 // singleton kind of driver
362 static Jack::JackDriverClientInterface* driver = NULL;
364 SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
366 return jack_driver_descriptor_construct("winmme", JackDriverSlave, "WinMME API based MIDI backend", NULL);
369 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
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;
379 for (node = params; node; node = jack_slist_next (node)) {
380 param = (const jack_driver_param_t *) node->data;
382 switch (param->character) {
384 case 'C':
385 capture_ports = param->value.ui;
386 break;
388 case 'P':
389 playback_ports = param->value.ui;
390 break;
392 case 'r':
393 sample_rate = param->value.ui;
394 break;
396 case 'p':
397 period_size = param->value.ui;
398 break;
400 case 'w':
401 wait_time = param->value.ui;
402 break;
404 case 'm':
405 monitor = param->value.i;
406 break;
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;
420 } else {
421 jack_info("JackWinMMEDriver already allocated, cannot be loaded twice");
422 return NULL;
427 #ifdef __cplusplus
429 #endif
433 jack_connect system:midi_capture_1 system_midi:playback_1
434 jack_connect system:midi_capture_1 system_midi:playback_2
436 jack_connect system:midi_capture_1 system_midi:playback_1
438 jack_connect system:midi_capture_1 system_midi:playback_1
440 jack_connect system:midi_capture_1 system_midi:playback_1
442 jack_connect system_midi:capture_1 system:midi_playback_1
443 jack_connect system_midi:capture_2 system:midi_playback_1
445 jack_connect system_midi:capture_1 system_midi:playback_1