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.

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