Update changelog
[jack2.git] / windows / winmme / JackWinMMEDriver.cpp
blobab1bc9090f60fd5601ef10fdfe5f8f0daa172360
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_log("JackWinMMEDriver::Attach - fCaptureChannels %d", fCaptureChannels);
57 jack_log("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 fEngine->PortSetDefaultMetadata(fClientControl.fRefNum, index,
75 input_port->GetDeviceName());
76 fCapturePortList[i] = index;
79 if (! fEngineControl->fSyncMode) {
80 latency += buffer_size;
81 latency_range.max = latency;
82 latency_range.min = latency;
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;
97 port = fGraphManager->GetPort(index);
98 port->SetAlias(output_port->GetAlias());
99 port->SetLatencyRange(JackPlaybackLatency, &latency_range);
100 fEngine->PortSetDefaultMetadata(fClientControl.fRefNum, index,
101 output_port->GetDeviceName());
102 fPlaybackPortList[i] = index;
105 return 0;
109 JackWinMMEDriver::Close()
111 // Generic MIDI driver close
112 int result = JackMidiDriver::Close();
114 if (input_ports) {
115 for (int i = 0; i < fCaptureChannels; i++) {
116 delete input_ports[i];
118 delete[] input_ports;
119 input_ports = 0;
121 if (output_ports) {
122 for (int i = 0; i < fPlaybackChannels; i++) {
123 delete output_ports[i];
125 delete[] output_ports;
126 output_ports = 0;
128 if (period) {
129 if (timeEndPeriod(period) != TIMERR_NOERROR) {
130 jack_error("JackWinMMEDriver::Close - failed to unset timer "
131 "resolution.");
132 result = -1;
135 return result;
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)
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();
152 jack_log("JackWinMMEDriver::Open - num_potential_inputs %d", num_potential_inputs);
153 jack_log("JackWinMMEDriver::Open - num_potential_outputs %d", num_potential_outputs);
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);
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;
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;
190 input_count++;
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;
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 port: %s | %s, %s, %s",
208 e.what(), fAliasName, client_name, playback_driver_name);
209 continue;
211 output_count++;
215 jack_log("JackWinMMEDriver::Open - input_count %d", input_count);
216 jack_log("JackWinMMEDriver::Open - output_count %d", output_count);
218 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;
226 if (output_ports) {
227 for (int i = 0; i < output_count; i++) {
228 delete output_ports[i];
230 delete[] output_ports;
231 output_ports = 0;
233 destroy_input_ports:
234 if (input_ports) {
235 for (int i = 0; i < input_count; i++) {
236 delete input_ports[i];
238 delete[] input_ports;
239 input_ports = 0;
241 unset_timer_resolution:
242 if (period) {
243 if (timeEndPeriod(period) != TIMERR_NOERROR) {
244 jack_error("JackWinMMEDriver::Open - failed to unset timer "
245 "resolution.");
248 return -1;
252 JackWinMMEDriver::Read()
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);
259 return 0;
263 JackWinMMEDriver::Write()
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);
270 return 0;
274 JackWinMMEDriver::Start()
276 jack_log("JackWinMMEDriver::Start - Starting driver.");
278 JackMidiDriver::Start();
280 int input_count = 0;
281 int output_count = 0;
283 jack_log("JackWinMMEDriver::Start - Enabling input ports.");
285 for (; input_count < fCaptureChannels; input_count++) {
286 if (! input_ports[input_count]->Start()) {
287 jack_error("JackWinMMEDriver::Start - Failed to enable input "
288 "port.");
289 goto stop_input_ports;
293 jack_log("JackWinMMEDriver::Start - Enabling output ports.");
295 for (; output_count < fPlaybackChannels; output_count++) {
296 if (! output_ports[output_count]->Start()) {
297 jack_error("JackWinMMEDriver::Start - Failed to enable output "
298 "port.");
299 goto stop_output_ports;
303 jack_log("JackWinMMEDriver::Start - Driver started.");
304 return 0;
306 stop_output_ports:
307 for (int i = 0; i < output_count; i++) {
308 if (! output_ports[i]->Stop()) {
309 jack_error("JackWinMMEDriver::Start - Failed to disable output "
310 "port.");
313 stop_input_ports:
314 for (int i = 0; i < input_count; i++) {
315 if (! input_ports[i]->Stop()) {
316 jack_error("JackWinMMEDriver::Start - Failed to disable input "
317 "port.");
321 return -1;
325 JackWinMMEDriver::Stop()
327 int result = 0;
329 JackMidiDriver::Stop();
331 jack_log("JackWinMMEDriver::Stop - disabling input ports.");
333 for (int i = 0; i < fCaptureChannels; i++) {
334 if (! input_ports[i]->Stop()) {
335 jack_error("JackWinMMEDriver::Stop - Failed to disable input "
336 "port.");
337 result = -1;
341 jack_log("JackWinMMEDriver::Stop - disabling output ports.");
343 for (int i = 0; i < fPlaybackChannels; i++) {
344 if (! output_ports[i]->Stop()) {
345 jack_error("JackWinMMEDriver::Stop - Failed to disable output "
346 "port.");
347 result = -1;
351 return result;
354 #ifdef __cplusplus
355 extern "C"
357 #endif
359 // singleton kind of driver
360 static Jack::JackWinMMEDriver* driver = NULL;
362 SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
364 return jack_driver_descriptor_construct("winmme", JackDriverSlave, "WinMME API based MIDI backend", NULL);
367 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
370 unsigned int capture_ports = 2;
371 unsigned int playback_ports = 2;
372 unsigned long wait_time = 0;
373 const JSList * node;
374 const jack_driver_param_t * param;
375 bool monitor = false;
377 for (node = params; node; node = jack_slist_next (node)) {
378 param = (const jack_driver_param_t *) node->data;
380 switch (param->character) {
382 case 'C':
383 capture_ports = param->value.ui;
384 break;
386 case 'P':
387 playback_ports = param->value.ui;
388 break;
390 case 'r':
391 sample_rate = param->value.ui;
392 break;
394 case 'p':
395 period_size = param->value.ui;
396 break;
398 case 'w':
399 wait_time = param->value.ui;
400 break;
402 case 'm':
403 monitor = param->value.i;
404 break;
409 // singleton kind of driver
410 if (!driver) {
411 driver = new Jack::JackWinMMEDriver("system_midi", "winmme", engine, table);
412 if (driver->Open(1, 1, 0, 0, false, "in", "out", 0, 0) == 0) {
413 return driver;
414 } else {
415 delete driver;
416 return NULL;
418 } else {
419 jack_info("JackWinMMEDriver already allocated, cannot be loaded twice");
420 return NULL;
425 #ifdef __cplusplus
427 #endif