jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

449 lines
14KB

  1. /*
  2. Copyright (C) 2009 Grame
  3. Copyright (C) 2011 Devin Anderson
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include <cmath>
  17. #include "JackEngineControl.h"
  18. #include "JackWinMMEDriver.h"
  19. using Jack::JackWinMMEDriver;
  20. JackWinMMEDriver::JackWinMMEDriver(const char *name, const char *alias,
  21. JackLockedEngine *engine,
  22. JackSynchro *table):
  23. JackMidiDriver(name, alias, engine, table)
  24. {
  25. fCaptureChannels = 0;
  26. fPlaybackChannels = 0;
  27. input_ports = 0;
  28. output_ports = 0;
  29. period = 0;
  30. }
  31. JackWinMMEDriver::~JackWinMMEDriver()
  32. {}
  33. int
  34. JackWinMMEDriver::Attach()
  35. {
  36. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  37. jack_port_id_t index;
  38. jack_nframes_t latency = buffer_size;
  39. jack_latency_range_t latency_range;
  40. const char *name;
  41. JackPort *port;
  42. latency_range.max = latency +
  43. ((jack_nframes_t) std::ceil((period / 1000.0) *
  44. fEngineControl->fSampleRate));
  45. latency_range.min = latency;
  46. jack_info("JackWinMMEDriver::Attach - fCaptureChannels %d", fCaptureChannels);
  47. jack_info("JackWinMMEDriver::Attach - fPlaybackChannels %d", fPlaybackChannels);
  48. // Inputs
  49. for (int i = 0; i < fCaptureChannels; i++) {
  50. JackWinMMEInputPort *input_port = input_ports[i];
  51. name = input_port->GetName();
  52. index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
  53. JACK_DEFAULT_MIDI_TYPE,
  54. CaptureDriverFlags, buffer_size);
  55. if (index == NO_PORT) {
  56. jack_error("JackWinMMEDriver::Attach - cannot register input port "
  57. "with name '%s'.", name);
  58. // X: Do we need to deallocate ports?
  59. return -1;
  60. }
  61. port = fGraphManager->GetPort(index);
  62. port->SetAlias(input_port->GetAlias());
  63. port->SetLatencyRange(JackCaptureLatency, &latency_range);
  64. fCapturePortList[i] = index;
  65. }
  66. if (! fEngineControl->fSyncMode) {
  67. latency += buffer_size;
  68. latency_range.max = latency;
  69. latency_range.min = latency;
  70. }
  71. // Outputs
  72. for (int i = 0; i < fPlaybackChannels; i++) {
  73. JackWinMMEOutputPort *output_port = output_ports[i];
  74. name = output_port->GetName();
  75. index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
  76. JACK_DEFAULT_MIDI_TYPE,
  77. PlaybackDriverFlags, buffer_size);
  78. if (index == NO_PORT) {
  79. jack_error("JackWinMMEDriver::Attach - cannot register output "
  80. "port with name '%s'.", name);
  81. // X: Do we need to deallocate ports?
  82. return -1;
  83. }
  84. port = fGraphManager->GetPort(index);
  85. port->SetAlias(output_port->GetAlias());
  86. port->SetLatencyRange(JackPlaybackLatency, &latency_range);
  87. fPlaybackPortList[i] = index;
  88. }
  89. return 0;
  90. }
  91. int
  92. JackWinMMEDriver::Close()
  93. {
  94. // Generic MIDI driver close
  95. int result = JackMidiDriver::Close();
  96. if (input_ports) {
  97. for (int i = 0; i < fCaptureChannels; i++) {
  98. delete input_ports[i];
  99. }
  100. delete[] input_ports;
  101. input_ports = 0;
  102. }
  103. if (output_ports) {
  104. for (int i = 0; i < fPlaybackChannels; i++) {
  105. delete output_ports[i];
  106. }
  107. delete[] output_ports;
  108. output_ports = 0;
  109. }
  110. if (period) {
  111. if (timeEndPeriod(period) != TIMERR_NOERROR) {
  112. jack_error("JackWinMMEDriver::Close - failed to unset timer "
  113. "resolution.");
  114. result = -1;
  115. }
  116. }
  117. return result;
  118. }
  119. int
  120. JackWinMMEDriver::Open(bool capturing, bool playing, int in_channels,
  121. int out_channels, bool monitor,
  122. const char* capture_driver_name,
  123. const char* playback_driver_name,
  124. jack_nframes_t capture_latency,
  125. jack_nframes_t playback_latency)
  126. {
  127. const char *client_name = fClientControl.fName;
  128. int input_count = 0;
  129. int output_count = 0;
  130. int num_potential_inputs = midiInGetNumDevs();
  131. int num_potential_outputs = midiOutGetNumDevs();
  132. jack_info("JackWinMMEDriver::Open - num_potential_inputs %d", num_potential_inputs);
  133. jack_info("JackWinMMEDriver::Open - num_potential_outputs %d", num_potential_outputs);
  134. period = 0;
  135. TIMECAPS caps;
  136. if (timeGetDevCaps(&caps, sizeof(TIMECAPS)) != TIMEERR_NOERROR) {
  137. jack_error("JackWinMMEDriver::Open - could not get timer device "
  138. "capabilities. Continuing anyway ...");
  139. } else {
  140. period = caps.wPeriodMin;
  141. if (timeBeginPeriod(period) != TIMERR_NOERROR) {
  142. jack_error("JackWinMMEDriver::Open - could not set minimum timer "
  143. "resolution. Continuing anyway ...");
  144. period = 0;
  145. } else {
  146. jack_info("JackWinMMEDriver::Open - multimedia timer resolution "
  147. "set to %d milliseconds.", period);
  148. }
  149. }
  150. if (num_potential_inputs) {
  151. try {
  152. input_ports = new JackWinMMEInputPort *[num_potential_inputs];
  153. } catch (std::exception e) {
  154. jack_error("JackWinMMEDriver::Open - while creating input port "
  155. "array: %s", e.what());
  156. goto unset_timer_resolution;
  157. }
  158. for (int i = 0; i < num_potential_inputs; i++) {
  159. try {
  160. input_ports[input_count] =
  161. new JackWinMMEInputPort(fAliasName, client_name,
  162. capture_driver_name, i);
  163. } catch (std::exception e) {
  164. jack_error("JackWinMMEDriver::Open - while creating input "
  165. "port: %s", e.what());
  166. continue;
  167. }
  168. input_count++;
  169. }
  170. }
  171. if (num_potential_outputs) {
  172. try {
  173. output_ports = new JackWinMMEOutputPort *[num_potential_outputs];
  174. } catch (std::exception e) {
  175. jack_error("JackWinMMEDriver::Open - while creating output port "
  176. "array: %s", e.what());
  177. goto destroy_input_ports;
  178. }
  179. for (int i = 0; i < num_potential_outputs; i++) {
  180. try {
  181. output_ports[output_count] =
  182. new JackWinMMEOutputPort(fAliasName, client_name,
  183. playback_driver_name, i);
  184. } catch (std::exception e) {
  185. jack_error("JackWinMMEDriver::Open - while creating output "
  186. "port: %s", e.what());
  187. continue;
  188. }
  189. output_count++;
  190. }
  191. }
  192. jack_info("JackWinMMEDriver::Open - input_count %d", input_count);
  193. jack_info("JackWinMMEDriver::Open - output_count %d", output_count);
  194. if (! (input_count || output_count)) {
  195. jack_error("JackWinMMEDriver::Open - no WinMME inputs or outputs "
  196. "allocated.");
  197. } else if (! JackMidiDriver::Open(capturing, playing, input_count,
  198. output_count, monitor,
  199. capture_driver_name,
  200. playback_driver_name, capture_latency,
  201. playback_latency)) {
  202. return 0;
  203. }
  204. if (output_ports) {
  205. for (int i = 0; i < output_count; i++) {
  206. delete output_ports[i];
  207. }
  208. delete[] output_ports;
  209. output_ports = 0;
  210. }
  211. destroy_input_ports:
  212. if (input_ports) {
  213. for (int i = 0; i < input_count; i++) {
  214. delete input_ports[i];
  215. }
  216. delete[] input_ports;
  217. input_ports = 0;
  218. }
  219. unset_timer_resolution:
  220. if (period) {
  221. if (timeEndPeriod(period) != TIMERR_NOERROR) {
  222. jack_error("JackWinMMEDriver::Open - failed to unset timer "
  223. "resolution.");
  224. }
  225. }
  226. return -1;
  227. }
  228. int
  229. JackWinMMEDriver::Read()
  230. {
  231. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  232. for (int i = 0; i < fCaptureChannels; i++) {
  233. input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
  234. }
  235. return 0;
  236. }
  237. int
  238. JackWinMMEDriver::Write()
  239. {
  240. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  241. for (int i = 0; i < fPlaybackChannels; i++) {
  242. output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
  243. }
  244. return 0;
  245. }
  246. int
  247. JackWinMMEDriver::Start()
  248. {
  249. jack_info("JackWinMMEDriver::Start - Starting driver.");
  250. JackMidiDriver::Start();
  251. int input_count = 0;
  252. int output_count = 0;
  253. jack_info("JackWinMMEDriver::Start - Enabling input ports.");
  254. for (; input_count < fCaptureChannels; input_count++) {
  255. if (input_ports[input_count]->Start() < 0) {
  256. jack_error("JackWinMMEDriver::Start - Failed to enable input "
  257. "port.");
  258. goto stop_input_ports;
  259. }
  260. }
  261. jack_info("JackWinMMEDriver::Start - Enabling output ports.");
  262. for (; output_count < fPlaybackChannels; output_count++) {
  263. if (output_ports[output_count]->Start() < 0) {
  264. jack_error("JackWinMMEDriver::Start - Failed to enable output "
  265. "port.");
  266. goto stop_output_ports;
  267. }
  268. }
  269. jack_info("JackWinMMEDriver::Start - Driver started.");
  270. return 0;
  271. stop_output_ports:
  272. for (int i = 0; i < output_count; i++) {
  273. if (output_ports[i]->Stop() < 0) {
  274. jack_error("JackWinMMEDriver::Start - Failed to disable output "
  275. "port.");
  276. }
  277. }
  278. stop_input_ports:
  279. for (int i = 0; i < input_count; i++) {
  280. if (input_ports[i]->Stop() < 0) {
  281. jack_error("JackWinMMEDriver::Start - Failed to disable input "
  282. "port.");
  283. }
  284. }
  285. return -1;
  286. }
  287. int
  288. JackWinMMEDriver::Stop()
  289. {
  290. int result = 0;
  291. jack_info("JackWinMMEDriver::Stop - disabling input ports.");
  292. for (int i = 0; i < fCaptureChannels; i++) {
  293. if (input_ports[i]->Stop() < 0) {
  294. jack_error("JackWinMMEDriver::Stop - Failed to disable input "
  295. "port.");
  296. result = -1;
  297. }
  298. }
  299. jack_info("JackWinMMEDriver::Stop - disabling output ports.");
  300. for (int i = 0; i < fPlaybackChannels; i++) {
  301. if (output_ports[i]->Stop() < 0) {
  302. jack_error("JackWinMMEDriver::Stop - Failed to disable output "
  303. "port.");
  304. result = -1;
  305. }
  306. }
  307. return result;
  308. }
  309. #ifdef __cplusplus
  310. extern "C"
  311. {
  312. #endif
  313. SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
  314. {
  315. jack_driver_desc_t * desc;
  316. //unsigned int i;
  317. desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
  318. strcpy(desc->name, "winmme"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
  319. strcpy(desc->desc, "WinMME API based MIDI backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
  320. desc->nparams = 0;
  321. desc->params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
  322. return desc;
  323. }
  324. SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
  325. {
  326. /*
  327. unsigned int capture_ports = 2;
  328. unsigned int playback_ports = 2;
  329. unsigned long wait_time = 0;
  330. const JSList * node;
  331. const jack_driver_param_t * param;
  332. bool monitor = false;
  333. for (node = params; node; node = jack_slist_next (node)) {
  334. param = (const jack_driver_param_t *) node->data;
  335. switch (param->character) {
  336. case 'C':
  337. capture_ports = param->value.ui;
  338. break;
  339. case 'P':
  340. playback_ports = param->value.ui;
  341. break;
  342. case 'r':
  343. sample_rate = param->value.ui;
  344. break;
  345. case 'p':
  346. period_size = param->value.ui;
  347. break;
  348. case 'w':
  349. wait_time = param->value.ui;
  350. break;
  351. case 'm':
  352. monitor = param->value.i;
  353. break;
  354. }
  355. }
  356. */
  357. Jack::JackDriverClientInterface* driver = new Jack::JackWinMMEDriver("system_midi", "winmme", engine, table);
  358. if (driver->Open(1, 1, 0, 0, false, "in", "out", 0, 0) == 0) {
  359. return driver;
  360. } else {
  361. delete driver;
  362. return NULL;
  363. }
  364. }
  365. #ifdef __cplusplus
  366. }
  367. #endif
  368. /*
  369. jack_connect system:midi_capture_1 system_midi:playback_1
  370. jack_connect system:midi_capture_1 system_midi:playback_2
  371. jack_connect system:midi_capture_1 system_midi:playback_1
  372. jack_connect system:midi_capture_1 system_midi:playback_1
  373. jack_connect system:midi_capture_1 system_midi:playback_1
  374. jack_connect system_midi:capture_1 system:midi_playback_1
  375. jack_connect system_midi:capture_2 system:midi_playback_1
  376. jack_connect system_midi:capture_1 system_midi:playback_1
  377. */