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.

450 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. input_ports = 0;
  26. output_ports = 0;
  27. period = 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. ((jack_nframes_t) std::ceil((period / 1000.0) *
  42. fEngineControl->fSampleRate));
  43. latency_range.min = latency;
  44. jack_info("JackWinMMEDriver::Attach - fCaptureChannels %d", fCaptureChannels);
  45. jack_info("JackWinMMEDriver::Attach - fPlaybackChannels %d", fPlaybackChannels);
  46. // Inputs
  47. for (int i = 0; i < fCaptureChannels; i++) {
  48. JackWinMMEInputPort *input_port = input_ports[i];
  49. name = input_port->GetName();
  50. if (fEngine->PortRegister(fClientControl.fRefNum, name,
  51. JACK_DEFAULT_MIDI_TYPE,
  52. CaptureDriverFlags, buffer_size, &index) < 0) {
  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. if (fEngine->PortRegister(fClientControl.fRefNum, name,
  73. JACK_DEFAULT_MIDI_TYPE,
  74. PlaybackDriverFlags, buffer_size, &index) < 0) {
  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) {
  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. period = 0;
  131. TIMECAPS caps;
  132. if (timeGetDevCaps(&caps, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
  133. jack_error("JackWinMMEDriver::Open - could not get timer device "
  134. "capabilities. Continuing anyway ...");
  135. } else {
  136. period = caps.wPeriodMin;
  137. if (timeBeginPeriod(period) != TIMERR_NOERROR) {
  138. jack_error("JackWinMMEDriver::Open - could not set minimum timer "
  139. "resolution. Continuing anyway ...");
  140. period = 0;
  141. } else {
  142. jack_info("JackWinMMEDriver::Open - multimedia timer resolution "
  143. "set to %d milliseconds.", period);
  144. }
  145. }
  146. if (num_potential_inputs) {
  147. try {
  148. input_ports = new JackWinMMEInputPort *[num_potential_inputs];
  149. } catch (std::exception e) {
  150. jack_error("JackWinMMEDriver::Open - while creating input port "
  151. "array: %s", e.what());
  152. goto unset_timer_resolution;
  153. }
  154. for (int i = 0; i < num_potential_inputs; i++) {
  155. try {
  156. input_ports[input_count] =
  157. new JackWinMMEInputPort(fAliasName, client_name,
  158. capture_driver_name, i);
  159. } catch (std::exception e) {
  160. jack_error("JackWinMMEDriver::Open - while creating input "
  161. "port: %s", e.what());
  162. continue;
  163. }
  164. input_count++;
  165. }
  166. }
  167. if (num_potential_outputs) {
  168. try {
  169. output_ports = new JackWinMMEOutputPort *[num_potential_outputs];
  170. } catch (std::exception e) {
  171. jack_error("JackWinMMEDriver::Open - while creating output port "
  172. "array: %s", e.what());
  173. goto destroy_input_ports;
  174. }
  175. for (int i = 0; i < num_potential_outputs; i++) {
  176. try {
  177. output_ports[output_count] =
  178. new JackWinMMEOutputPort(fAliasName, client_name,
  179. playback_driver_name, i);
  180. } catch (std::exception e) {
  181. jack_error("JackWinMMEDriver::Open - while creating output "
  182. "port: %s", e.what());
  183. continue;
  184. }
  185. output_count++;
  186. }
  187. }
  188. jack_info("JackWinMMEDriver::Open - input_count %d", input_count);
  189. jack_info("JackWinMMEDriver::Open - output_count %d", output_count);
  190. if (! (input_count || output_count)) {
  191. jack_error("JackWinMMEDriver::Open - no WinMME inputs or outputs "
  192. "allocated.");
  193. } else if (! JackMidiDriver::Open(capturing, playing, input_count,
  194. output_count, monitor,
  195. capture_driver_name,
  196. playback_driver_name, capture_latency,
  197. playback_latency)) {
  198. return 0;
  199. }
  200. if (output_ports) {
  201. for (int i = 0; i < output_count; i++) {
  202. delete output_ports[i];
  203. }
  204. delete[] output_ports;
  205. output_ports = 0;
  206. }
  207. destroy_input_ports:
  208. if (input_ports) {
  209. for (int i = 0; i < input_count; i++) {
  210. delete input_ports[i];
  211. }
  212. delete[] input_ports;
  213. input_ports = 0;
  214. }
  215. unset_timer_resolution:
  216. if (period) {
  217. if (timeEndPeriod(period) != TIMERR_NOERROR) {
  218. jack_error("JackWinMMEDriver::Open - failed to unset timer "
  219. "resolution.");
  220. }
  221. }
  222. return -1;
  223. }
  224. int
  225. JackWinMMEDriver::Read()
  226. {
  227. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  228. for (int i = 0; i < fCaptureChannels; i++) {
  229. input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
  230. }
  231. return 0;
  232. }
  233. int
  234. JackWinMMEDriver::Write()
  235. {
  236. jack_nframes_t buffer_size = fEngineControl->fBufferSize;
  237. for (int i = 0; i < fPlaybackChannels; i++) {
  238. output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
  239. }
  240. return 0;
  241. }
  242. int
  243. JackWinMMEDriver::Start()
  244. {
  245. jack_info("JackWinMMEDriver::Start - Starting driver.");
  246. JackMidiDriver::Start();
  247. int input_count = 0;
  248. int output_count = 0;
  249. jack_info("JackWinMMEDriver::Start - Enabling input ports.");
  250. for (; input_count < fCaptureChannels; input_count++) {
  251. if (input_ports[input_count]->Start() < 0) {
  252. jack_error("JackWinMMEDriver::Start - Failed to enable input "
  253. "port.");
  254. goto stop_input_ports;
  255. }
  256. }
  257. jack_info("JackWinMMEDriver::Start - Enabling output ports.");
  258. for (; output_count < fPlaybackChannels; output_count++) {
  259. if (output_ports[output_count]->Start() < 0) {
  260. jack_error("JackWinMMEDriver::Start - Failed to enable output "
  261. "port.");
  262. goto stop_output_ports;
  263. }
  264. }
  265. jack_info("JackWinMMEDriver::Start - Driver started.");
  266. return 0;
  267. stop_output_ports:
  268. for (int i = 0; i < output_count; i++) {
  269. if (output_ports[i]->Stop() < 0) {
  270. jack_error("JackWinMMEDriver::Start - Failed to disable output "
  271. "port.");
  272. }
  273. }
  274. stop_input_ports:
  275. for (int i = 0; i < input_count; i++) {
  276. if (input_ports[i]->Stop() < 0) {
  277. jack_error("JackWinMMEDriver::Start - Failed to disable input "
  278. "port.");
  279. }
  280. }
  281. return -1;
  282. }
  283. int
  284. JackWinMMEDriver::Stop()
  285. {
  286. int result = 0;
  287. JackMidiDriver::Stop();
  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. // singleton kind of driver
  311. static Jack::JackDriverClientInterface* driver = NULL;
  312. SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
  313. {
  314. jack_driver_desc_t * desc;
  315. return jack_driver_descriptor_construct("winmme", JackDriverSlave, "WinMME API based MIDI backend", NULL);
  316. }
  317. SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
  318. {
  319. /*
  320. unsigned int capture_ports = 2;
  321. unsigned int playback_ports = 2;
  322. unsigned long wait_time = 0;
  323. const JSList * node;
  324. const jack_driver_param_t * param;
  325. bool monitor = false;
  326. for (node = params; node; node = jack_slist_next (node)) {
  327. param = (const jack_driver_param_t *) node->data;
  328. switch (param->character) {
  329. case 'C':
  330. capture_ports = param->value.ui;
  331. break;
  332. case 'P':
  333. playback_ports = param->value.ui;
  334. break;
  335. case 'r':
  336. sample_rate = param->value.ui;
  337. break;
  338. case 'p':
  339. period_size = param->value.ui;
  340. break;
  341. case 'w':
  342. wait_time = param->value.ui;
  343. break;
  344. case 'm':
  345. monitor = param->value.i;
  346. break;
  347. }
  348. }
  349. */
  350. // singleton kind of driver
  351. if (!driver) {
  352. driver = new Jack::JackWinMMEDriver("system_midi", "winmme", engine, table);
  353. if (driver->Open(1, 1, 0, 0, false, "in", "out", 0, 0) == 0) {
  354. return driver;
  355. } else {
  356. delete driver;
  357. return NULL;
  358. }
  359. } else {
  360. jack_info("JackWinMMEDriver already allocated, cannot be loaded twice");
  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. */