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.

507 lines
16KB

  1. /*
  2. Copyright (C) 2009 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "JackWinMMEDriver.h"
  16. #include "JackGraphManager.h"
  17. #include "JackEngineControl.h"
  18. #include "JackDriverLoader.h"
  19. #include <assert.h>
  20. #include <iostream>
  21. #include <sstream>
  22. #include <string>
  23. #include <windows.h>
  24. #include <windowsx.h>
  25. #include <mmsystem.h>
  26. namespace Jack
  27. {
  28. static bool InitHeaders(MidiSlot* slot)
  29. {
  30. slot->fHeader = (LPMIDIHDR)GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE|GMEM_ZEROINIT, sizeof(MIDIHDR) + kBuffSize);
  31. if (!slot->fHeader)
  32. return false;
  33. slot->fHeader->lpData = (LPSTR)((LPBYTE)slot->fHeader + sizeof(MIDIHDR));
  34. slot->fHeader->dwBufferLength = kBuffSize;
  35. slot->fHeader->dwFlags = 0;
  36. slot->fHeader->dwUser = 0;
  37. slot->fHeader->lpNext = 0;
  38. slot->fHeader->dwBytesRecorded = 0;
  39. return true;
  40. }
  41. void CALLBACK JackWinMMEDriver::MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD userData, DWORD dwParam1, DWORD dwParam2)
  42. {
  43. jack_ringbuffer_t* ringbuffer = (jack_ringbuffer_t*)userData;
  44. //jack_info("JackWinMMEDriver::MidiInProc 0\n");
  45. switch (wMsg) {
  46. case MIM_OPEN:
  47. break;
  48. case MIM_ERROR:
  49. case MIM_DATA: {
  50. //jack_info("JackWinMMEDriver::MidiInProc");
  51. // One event
  52. unsigned int num_packet = 1;
  53. jack_ringbuffer_write(ringbuffer, (char*)&num_packet, sizeof(unsigned int));
  54. // Write event actual data
  55. jack_ringbuffer_write(ringbuffer, (char*)&dwParam1, 3);
  56. break;
  57. }
  58. case MIM_LONGERROR:
  59. case MIM_LONGDATA:
  60. /*
  61. Nothing for now
  62. */
  63. break;
  64. }
  65. }
  66. JackWinMMEDriver::JackWinMMEDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
  67. : JackMidiDriver(name, alias, engine, table),
  68. fRealCaptureChannels(0),
  69. fRealPlaybackChannels(0),
  70. fMidiSource(NULL),
  71. fMidiDestination(NULL)
  72. {}
  73. JackWinMMEDriver::~JackWinMMEDriver()
  74. {}
  75. int JackWinMMEDriver::Open(bool capturing,
  76. bool playing,
  77. int inchannels,
  78. int outchannels,
  79. bool monitor,
  80. const char* capture_driver_name,
  81. const char* playback_driver_name,
  82. jack_nframes_t capture_latency,
  83. jack_nframes_t playback_latency)
  84. {
  85. jack_log("JackWinMMEDriver::Open");
  86. fRealCaptureChannels = midiInGetNumDevs();
  87. fRealPlaybackChannels = midiOutGetNumDevs();
  88. // Generic JackMidiDriver Open
  89. if (JackMidiDriver::Open(capturing, playing, fRealCaptureChannels, fRealPlaybackChannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0)
  90. return -1;
  91. fMidiDestination = new MidiSlot[fRealCaptureChannels];
  92. assert(fMidiDestination);
  93. // Real input
  94. int devindex = 0;
  95. for (int i = 0; i < fRealCaptureChannels; i++) {
  96. HMIDIIN handle;
  97. fMidiDestination[devindex].fIndex = i;
  98. MMRESULT ret = midiInOpen(&handle, fMidiDestination[devindex].fIndex, (DWORD)MidiInProc, (DWORD)fRingBuffer[devindex], CALLBACK_FUNCTION);
  99. if (ret == MMSYSERR_NOERROR) {
  100. fMidiDestination[devindex].fHandle = handle;
  101. if (!InitHeaders(&fMidiDestination[devindex])) {
  102. jack_error("memory allocation failed");
  103. midiInClose(handle);
  104. continue;
  105. }
  106. ret = midiInPrepareHeader(handle, fMidiDestination[devindex].fHeader, sizeof(MIDIHDR));
  107. if (ret == MMSYSERR_NOERROR) {
  108. fMidiDestination[devindex].fHeader->dwUser = 1;
  109. ret = midiInAddBuffer(handle, fMidiDestination[devindex].fHeader, sizeof(MIDIHDR));
  110. if (ret == MMSYSERR_NOERROR) {
  111. ret = midiInStart(handle);
  112. if (ret != MMSYSERR_NOERROR) {
  113. jack_error("midiInStart error");
  114. CloseInput(&fMidiDestination[devindex]);
  115. continue;
  116. }
  117. } else {
  118. jack_error ("midiInAddBuffer error");
  119. CloseInput(&fMidiDestination[devindex]);
  120. continue;
  121. }
  122. } else {
  123. jack_error("midiInPrepareHeader error");
  124. midiInClose(handle);
  125. continue;
  126. }
  127. } else {
  128. jack_error ("midiInOpen error");
  129. continue;
  130. }
  131. devindex += 1;
  132. }
  133. fRealCaptureChannels = devindex;
  134. fCaptureChannels = devindex;
  135. fMidiSource = new MidiSlot[fRealPlaybackChannels];
  136. assert(fMidiSource);
  137. // Real output
  138. devindex = 0;
  139. for (int i = 0; i < fRealPlaybackChannels; i++) {
  140. MMRESULT res;
  141. HMIDIOUT handle;
  142. fMidiSource[devindex].fIndex = i;
  143. UINT ret = midiOutOpen(&handle, fMidiSource[devindex].fIndex, 0L, 0L, CALLBACK_NULL);
  144. if (ret == MMSYSERR_NOERROR) {
  145. fMidiSource[devindex].fHandle = handle;
  146. if (!InitHeaders(&fMidiSource[devindex])) {
  147. jack_error("memory allocation failed");
  148. midiOutClose(handle);
  149. continue;
  150. }
  151. res = midiOutPrepareHeader(handle, fMidiSource[devindex].fHeader, sizeof(MIDIHDR));
  152. if (res != MMSYSERR_NOERROR) {
  153. jack_error("midiOutPrepareHeader error %d %d %d", i, handle, res);
  154. continue;
  155. } else {
  156. fMidiSource[devindex].fHeader->dwUser = 1;
  157. }
  158. } else {
  159. jack_error("midiOutOpen error");
  160. continue;
  161. }
  162. devindex += 1;
  163. }
  164. fRealPlaybackChannels = devindex;
  165. fPlaybackChannels = devindex;
  166. return 0;
  167. }
  168. void JackWinMMEDriver::CloseInput(MidiSlot* slot)
  169. {
  170. MMRESULT res;
  171. int retry = 0;
  172. if (slot->fHandle == 0)
  173. return;
  174. HMIDIIN handle = (HMIDIIN)slot->fHandle;
  175. slot->fHeader->dwUser = 0;
  176. res = midiInStop(handle);
  177. if (res != MMSYSERR_NOERROR) {
  178. jack_error("midiInStop error");
  179. }
  180. res = midiInReset(handle);
  181. if (res != MMSYSERR_NOERROR) {
  182. jack_error("midiInReset error");
  183. }
  184. res = midiInUnprepareHeader(handle, slot->fHeader, sizeof(MIDIHDR));
  185. if (res != MMSYSERR_NOERROR) {
  186. jack_error("midiInUnprepareHeader error");
  187. }
  188. do {
  189. res = midiInClose(handle);
  190. if (res != MMSYSERR_NOERROR) {
  191. jack_error("midiInClose error");
  192. }
  193. if (res == MIDIERR_STILLPLAYING)
  194. midiInReset(handle);
  195. Sleep (10);
  196. retry++;
  197. } while ((res == MIDIERR_STILLPLAYING) && (retry < 10));
  198. if (slot->fHeader) {
  199. GlobalFreePtr(slot->fHeader);
  200. }
  201. }
  202. void JackWinMMEDriver::CloseOutput(MidiSlot* slot)
  203. {
  204. MMRESULT res;
  205. int retry = 0;
  206. if (slot->fHandle == 0)
  207. return;
  208. HMIDIOUT handle = (HMIDIOUT)slot->fHandle;
  209. res = midiOutReset(handle);
  210. if (res != MMSYSERR_NOERROR)
  211. jack_error("midiOutReset error");
  212. midiOutUnprepareHeader(handle, slot->fHeader, sizeof(MIDIHDR));
  213. do {
  214. res = midiOutClose(handle);
  215. if (res != MMSYSERR_NOERROR)
  216. jack_error("midiOutClose error");
  217. Sleep(10);
  218. retry++;
  219. } while ((res == MIDIERR_STILLPLAYING) && (retry < 10));
  220. if (slot->fHeader) {
  221. GlobalFreePtr(slot->fHeader);
  222. }
  223. }
  224. int JackWinMMEDriver::Close()
  225. {
  226. jack_log("JackWinMMEDriver::Close");
  227. // Generic midi driver close
  228. int res = JackMidiDriver::Close();
  229. // Close input
  230. if (fMidiDestination) {
  231. for (int i = 0; i < fRealCaptureChannels; i++) {
  232. CloseInput(&fMidiDestination[i]);
  233. }
  234. delete[] fMidiDestination;
  235. }
  236. // Close output
  237. if (fMidiSource) {
  238. for (int i = 0; i < fRealPlaybackChannels; i++) {
  239. CloseOutput(&fMidiSource[i]);
  240. }
  241. delete[] fMidiSource;
  242. }
  243. return res;
  244. }
  245. int JackWinMMEDriver::Attach()
  246. {
  247. JackPort* port;
  248. jack_port_id_t port_index;
  249. char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  250. char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  251. MMRESULT res;
  252. int i;
  253. jack_log("JackMidiDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
  254. for (i = 0; i < fCaptureChannels; i++) {
  255. MIDIINCAPS caps;
  256. res = midiInGetDevCaps(fMidiDestination[i].fIndex, &caps, sizeof(caps));
  257. if (res == MMSYSERR_NOERROR) {
  258. snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, caps.szPname, i + 1);
  259. } else {
  260. snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1);
  261. }
  262. snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1);
  263. if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, CaptureDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
  264. jack_error("driver: cannot register port for %s", name);
  265. return -1;
  266. }
  267. port = fGraphManager->GetPort(port_index);
  268. port->SetAlias(alias);
  269. fCapturePortList[i] = port_index;
  270. jack_log("JackMidiDriver::Attach fCapturePortList[i] port_index = %ld", port_index);
  271. }
  272. for (i = 0; i < fPlaybackChannels; i++) {
  273. MIDIOUTCAPS caps;
  274. res = midiOutGetDevCaps(fMidiSource[i].fIndex, &caps, sizeof(caps));
  275. if (res == MMSYSERR_NOERROR) {
  276. snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, caps.szPname, i + 1);
  277. } else {
  278. snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fPlaybackDriverName, i + 1);
  279. }
  280. snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1);
  281. if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, PlaybackDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
  282. jack_error("driver: cannot register port for %s", name);
  283. return -1;
  284. }
  285. port = fGraphManager->GetPort(port_index);
  286. port->SetAlias(alias);
  287. fPlaybackPortList[i] = port_index;
  288. jack_log("JackMidiDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index);
  289. }
  290. return 0;
  291. }
  292. int JackWinMMEDriver::Read()
  293. {
  294. size_t size;
  295. for (int chan = 0; chan < fCaptureChannels; chan++) {
  296. if (fGraphManager->GetConnectionsNum(fCapturePortList[chan]) > 0) {
  297. JackMidiBuffer* midi_buffer = GetInputBuffer(chan);
  298. if (jack_ringbuffer_read_space (fRingBuffer[chan]) == 0) {
  299. // Reset buffer
  300. midi_buffer->Reset(midi_buffer->nframes);
  301. } else {
  302. while ((size = jack_ringbuffer_read_space (fRingBuffer[chan])) > 0) {
  303. //jack_info("jack_ringbuffer_read_space %d", size);
  304. int ev_count = 0;
  305. jack_ringbuffer_read(fRingBuffer[chan], (char*)&ev_count, sizeof(int));
  306. if (ev_count > 0) {
  307. for (int j = 0; j < ev_count; j++) {
  308. unsigned int event_len = 3;
  309. // Read event actual data
  310. jack_midi_data_t* dest = midi_buffer->ReserveEvent(0, event_len);
  311. jack_ringbuffer_read(fRingBuffer[chan], (char*)dest, event_len);
  312. }
  313. }
  314. }
  315. }
  316. } else {
  317. //jack_info("Consume ring buffer");
  318. jack_ringbuffer_read_advance(fRingBuffer[chan], jack_ringbuffer_read_space(fRingBuffer[chan]));
  319. }
  320. }
  321. return 0;
  322. }
  323. int JackWinMMEDriver::Write()
  324. {
  325. for (int chan = 0; chan < fPlaybackChannels; chan++) {
  326. if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chan]) > 0) {
  327. JackMidiBuffer* midi_buffer = GetOutputBuffer(chan);
  328. // TODO : use timestamp
  329. for (unsigned int j = 0; j < midi_buffer->event_count; j++) {
  330. JackMidiEvent* ev = &midi_buffer->events[j];
  331. if (ev->size <= 3) {
  332. jack_midi_data_t *d = ev->GetData(midi_buffer);
  333. DWORD winev = 0;
  334. if (ev->size > 0) winev |= d[0];
  335. if (ev->size > 1) winev |= (d[1] << 8);
  336. if (ev->size > 2) winev |= (d[2] << 16);
  337. MMRESULT res = midiOutShortMsg((HMIDIOUT)fMidiSource[chan].fHandle, winev);
  338. if (res != MMSYSERR_NOERROR)
  339. jack_error ("midiOutShortMsg error res %d", res);
  340. } else {
  341. }
  342. }
  343. }
  344. }
  345. return 0;
  346. }
  347. } // end of namespace
  348. #ifdef __cplusplus
  349. extern "C"
  350. {
  351. #endif
  352. SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
  353. {
  354. jack_driver_desc_t * desc;
  355. //unsigned int i;
  356. desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
  357. strcpy(desc->name, "winmme"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
  358. strcpy(desc->desc, "WinMME API based MIDI backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
  359. desc->nparams = 0;
  360. desc->params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
  361. return desc;
  362. }
  363. SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
  364. {
  365. /*
  366. unsigned int capture_ports = 2;
  367. unsigned int playback_ports = 2;
  368. unsigned long wait_time = 0;
  369. const JSList * node;
  370. const jack_driver_param_t * param;
  371. bool monitor = false;
  372. for (node = params; node; node = jack_slist_next (node)) {
  373. param = (const jack_driver_param_t *) node->data;
  374. switch (param->character) {
  375. case 'C':
  376. capture_ports = param->value.ui;
  377. break;
  378. case 'P':
  379. playback_ports = param->value.ui;
  380. break;
  381. case 'r':
  382. sample_rate = param->value.ui;
  383. break;
  384. case 'p':
  385. period_size = param->value.ui;
  386. break;
  387. case 'w':
  388. wait_time = param->value.ui;
  389. break;
  390. case 'm':
  391. monitor = param->value.i;
  392. break;
  393. }
  394. }
  395. */
  396. Jack::JackDriverClientInterface* driver = new Jack::JackWinMMEDriver("system_midi", "winmme", engine, table);
  397. if (driver->Open(1, 1, 0, 0, false, "in", "out", 0, 0) == 0) {
  398. return driver;
  399. } else {
  400. delete driver;
  401. return NULL;
  402. }
  403. }
  404. #ifdef __cplusplus
  405. }
  406. #endif
  407. /*
  408. jack_connect system:midi_capture_1 system_midi:playback_1
  409. jack_connect system:midi_capture_1 system_midi:playback_2
  410. jack_connect system:midi_capture_1 system_midi:playback_1
  411. jack_connect system:midi_capture_1 system_midi:playback_1
  412. jack_connect system:midi_capture_1 system_midi:playback_1
  413. jack_connect system_midi:capture_1 system:midi_playback_1
  414. jack_connect system_midi:capture_2 system:midi_playback_1
  415. jack_connect system_midi:capture_1 system_midi:playback_1
  416. */