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.

437 lines
13KB

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