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.

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