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.

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