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.

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