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.

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