The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

631 lines
16KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. // (This file gets included by juce_win32_NativeCode.cpp, rather than being
  19. // compiled on its own).
  20. #if JUCE_INCLUDED_FILE
  21. //==============================================================================
  22. static const int midiBufferSize = 1024 * 10;
  23. static const int numInHeaders = 32;
  24. static const int inBufferSize = 256;
  25. static Array <void*, CriticalSection> activeMidiThreads;
  26. using ::free;
  27. class MidiInThread : public Thread
  28. {
  29. public:
  30. //==============================================================================
  31. MidiInThread (MidiInput* const input_,
  32. MidiInputCallback* const callback_)
  33. : Thread ("Juce Midi"),
  34. hIn (0),
  35. input (input_),
  36. callback (callback_),
  37. isStarted (false),
  38. startTime (0),
  39. pendingLength(0)
  40. {
  41. for (int i = numInHeaders; --i >= 0;)
  42. {
  43. zeromem (&hdr[i], sizeof (MIDIHDR));
  44. hdr[i].lpData = inData[i];
  45. hdr[i].dwBufferLength = inBufferSize;
  46. }
  47. };
  48. ~MidiInThread()
  49. {
  50. stop();
  51. if (hIn != 0)
  52. {
  53. int count = 5;
  54. while (--count >= 0)
  55. {
  56. if (midiInClose (hIn) == MMSYSERR_NOERROR)
  57. break;
  58. Sleep (20);
  59. }
  60. }
  61. }
  62. //==============================================================================
  63. void handle (const uint32 message, const uint32 timeStamp) throw()
  64. {
  65. const int byte = message & 0xff;
  66. if (byte < 0x80)
  67. return;
  68. const int numBytes = MidiMessage::getMessageLengthFromFirstByte ((uint8) byte);
  69. const double time = timeStampToTime (timeStamp);
  70. lock.enter();
  71. if (pendingLength < midiBufferSize - 12)
  72. {
  73. char* const p = pending + pendingLength;
  74. *(double*) p = time;
  75. *(uint32*) (p + 8) = numBytes;
  76. *(uint32*) (p + 12) = message;
  77. pendingLength += 12 + numBytes;
  78. }
  79. else
  80. {
  81. jassertfalse // midi buffer overflow! You might need to increase the size..
  82. }
  83. lock.exit();
  84. notify();
  85. }
  86. void handleSysEx (MIDIHDR* const hdr, const uint32 timeStamp) throw()
  87. {
  88. const int num = hdr->dwBytesRecorded;
  89. if (num > 0)
  90. {
  91. const double time = timeStampToTime (timeStamp);
  92. lock.enter();
  93. if (pendingLength < midiBufferSize - (8 + num))
  94. {
  95. char* const p = pending + pendingLength;
  96. *(double*) p = time;
  97. *(uint32*) (p + 8) = num;
  98. memcpy (p + 12, hdr->lpData, num);
  99. pendingLength += 12 + num;
  100. }
  101. else
  102. {
  103. jassertfalse // midi buffer overflow! You might need to increase the size..
  104. }
  105. lock.exit();
  106. notify();
  107. }
  108. }
  109. void writeBlock (const int i) throw()
  110. {
  111. hdr[i].dwBytesRecorded = 0;
  112. MMRESULT res = midiInPrepareHeader (hIn, &hdr[i], sizeof (MIDIHDR));
  113. jassert (res == MMSYSERR_NOERROR);
  114. res = midiInAddBuffer (hIn, &hdr[i], sizeof (MIDIHDR));
  115. jassert (res == MMSYSERR_NOERROR);
  116. }
  117. void run()
  118. {
  119. MemoryBlock pendingCopy (64);
  120. while (! threadShouldExit())
  121. {
  122. for (int i = 0; i < numInHeaders; ++i)
  123. {
  124. if ((hdr[i].dwFlags & WHDR_DONE) != 0)
  125. {
  126. MMRESULT res = midiInUnprepareHeader (hIn, &hdr[i], sizeof (MIDIHDR));
  127. (void) res;
  128. jassert (res == MMSYSERR_NOERROR);
  129. writeBlock (i);
  130. }
  131. }
  132. lock.enter();
  133. int len = pendingLength;
  134. if (len > 0)
  135. {
  136. pendingCopy.ensureSize (len);
  137. pendingCopy.copyFrom (pending, 0, len);
  138. pendingLength = 0;
  139. }
  140. lock.exit();
  141. //xxx needs to figure out if blocks are broken up or not
  142. if (len == 0)
  143. {
  144. wait (500);
  145. }
  146. else
  147. {
  148. const char* p = (const char*) pendingCopy.getData();
  149. while (len > 0)
  150. {
  151. const double time = *(const double*) p;
  152. const int messageLen = *(const int*) (p + 8);
  153. const MidiMessage message ((const uint8*) (p + 12), messageLen, time);
  154. callback->handleIncomingMidiMessage (input, message);
  155. p += 12 + messageLen;
  156. len -= 12 + messageLen;
  157. }
  158. }
  159. }
  160. }
  161. void start() throw()
  162. {
  163. jassert (hIn != 0);
  164. if (hIn != 0 && ! isStarted)
  165. {
  166. stop();
  167. activeMidiThreads.addIfNotAlreadyThere (this);
  168. int i;
  169. for (i = 0; i < numInHeaders; ++i)
  170. writeBlock (i);
  171. startTime = Time::getMillisecondCounter();
  172. MMRESULT res = midiInStart (hIn);
  173. jassert (res == MMSYSERR_NOERROR);
  174. if (res == MMSYSERR_NOERROR)
  175. {
  176. isStarted = true;
  177. pendingLength = 0;
  178. startThread (6);
  179. }
  180. }
  181. }
  182. void stop() throw()
  183. {
  184. if (isStarted)
  185. {
  186. stopThread (5000);
  187. midiInReset (hIn);
  188. midiInStop (hIn);
  189. activeMidiThreads.removeValue (this);
  190. lock.enter();
  191. lock.exit();
  192. for (int i = numInHeaders; --i >= 0;)
  193. {
  194. if ((hdr[i].dwFlags & WHDR_DONE) != 0)
  195. {
  196. int c = 10;
  197. while (--c >= 0 && midiInUnprepareHeader (hIn, &hdr[i], sizeof (MIDIHDR)) == MIDIERR_STILLPLAYING)
  198. Sleep (20);
  199. jassert (c >= 0);
  200. }
  201. }
  202. isStarted = false;
  203. pendingLength = 0;
  204. }
  205. }
  206. juce_UseDebuggingNewOperator
  207. HMIDIIN hIn;
  208. private:
  209. MidiInput* input;
  210. MidiInputCallback* callback;
  211. bool isStarted;
  212. uint32 startTime;
  213. CriticalSection lock;
  214. MIDIHDR hdr [numInHeaders];
  215. char inData [numInHeaders] [inBufferSize];
  216. int pendingLength;
  217. char pending [midiBufferSize];
  218. double timeStampToTime (uint32 timeStamp) throw()
  219. {
  220. timeStamp += startTime;
  221. const uint32 now = Time::getMillisecondCounter();
  222. if (timeStamp > now)
  223. {
  224. if (timeStamp > now + 2)
  225. --startTime;
  226. timeStamp = now;
  227. }
  228. return 0.001 * timeStamp;
  229. }
  230. MidiInThread (const MidiInThread&);
  231. const MidiInThread& operator= (const MidiInThread&);
  232. };
  233. static void CALLBACK midiInCallback (HMIDIIN,
  234. UINT uMsg,
  235. DWORD_PTR dwInstance,
  236. DWORD_PTR midiMessage,
  237. DWORD_PTR timeStamp)
  238. {
  239. MidiInThread* const thread = (MidiInThread*) dwInstance;
  240. if (thread != 0 && activeMidiThreads.contains (thread))
  241. {
  242. if (uMsg == MIM_DATA)
  243. thread->handle ((uint32) midiMessage, (uint32) timeStamp);
  244. else if (uMsg == MIM_LONGDATA)
  245. thread->handleSysEx ((MIDIHDR*) midiMessage, (uint32) timeStamp);
  246. }
  247. }
  248. //==============================================================================
  249. const StringArray MidiInput::getDevices()
  250. {
  251. StringArray s;
  252. const int num = midiInGetNumDevs();
  253. for (int i = 0; i < num; ++i)
  254. {
  255. MIDIINCAPS mc;
  256. zerostruct (mc);
  257. if (midiInGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
  258. s.add (String (mc.szPname, sizeof (mc.szPname)));
  259. }
  260. return s;
  261. }
  262. int MidiInput::getDefaultDeviceIndex()
  263. {
  264. return 0;
  265. }
  266. MidiInput* MidiInput::openDevice (const int index, MidiInputCallback* const callback)
  267. {
  268. if (callback == 0)
  269. return 0;
  270. UINT deviceId = MIDI_MAPPER;
  271. int n = 0;
  272. String name;
  273. const int num = midiInGetNumDevs();
  274. for (int i = 0; i < num; ++i)
  275. {
  276. MIDIINCAPS mc;
  277. zerostruct (mc);
  278. if (midiInGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
  279. {
  280. if (index == n)
  281. {
  282. deviceId = i;
  283. name = String (mc.szPname, sizeof (mc.szPname));
  284. break;
  285. }
  286. ++n;
  287. }
  288. }
  289. MidiInput* const in = new MidiInput (name);
  290. MidiInThread* const thread = new MidiInThread (in, callback);
  291. HMIDIIN h;
  292. HRESULT err = midiInOpen (&h, deviceId,
  293. (DWORD_PTR) &midiInCallback,
  294. (DWORD_PTR) thread,
  295. CALLBACK_FUNCTION);
  296. if (err == MMSYSERR_NOERROR)
  297. {
  298. thread->hIn = h;
  299. in->internal = (void*) thread;
  300. return in;
  301. }
  302. else
  303. {
  304. delete in;
  305. delete thread;
  306. return 0;
  307. }
  308. }
  309. MidiInput::MidiInput (const String& name_)
  310. : name (name_),
  311. internal (0)
  312. {
  313. }
  314. MidiInput::~MidiInput()
  315. {
  316. if (internal != 0)
  317. {
  318. MidiInThread* const thread = (MidiInThread*) internal;
  319. delete thread;
  320. }
  321. }
  322. void MidiInput::start()
  323. {
  324. ((MidiInThread*) internal)->start();
  325. }
  326. void MidiInput::stop()
  327. {
  328. ((MidiInThread*) internal)->stop();
  329. }
  330. //==============================================================================
  331. struct MidiOutHandle
  332. {
  333. int refCount;
  334. UINT deviceId;
  335. HMIDIOUT handle;
  336. juce_UseDebuggingNewOperator
  337. };
  338. static VoidArray handles (4);
  339. //==============================================================================
  340. const StringArray MidiOutput::getDevices()
  341. {
  342. StringArray s;
  343. const int num = midiOutGetNumDevs();
  344. for (int i = 0; i < num; ++i)
  345. {
  346. MIDIOUTCAPS mc;
  347. zerostruct (mc);
  348. if (midiOutGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
  349. s.add (String (mc.szPname, sizeof (mc.szPname)));
  350. }
  351. return s;
  352. }
  353. int MidiOutput::getDefaultDeviceIndex()
  354. {
  355. const int num = midiOutGetNumDevs();
  356. int n = 0;
  357. for (int i = 0; i < num; ++i)
  358. {
  359. MIDIOUTCAPS mc;
  360. zerostruct (mc);
  361. if (midiOutGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
  362. {
  363. if ((mc.wTechnology & MOD_MAPPER) != 0)
  364. return n;
  365. ++n;
  366. }
  367. }
  368. return 0;
  369. }
  370. MidiOutput* MidiOutput::openDevice (int index)
  371. {
  372. UINT deviceId = MIDI_MAPPER;
  373. const int num = midiOutGetNumDevs();
  374. int i, n = 0;
  375. for (i = 0; i < num; ++i)
  376. {
  377. MIDIOUTCAPS mc;
  378. zerostruct (mc);
  379. if (midiOutGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
  380. {
  381. // use the microsoft sw synth as a default - best not to allow deviceId
  382. // to be MIDI_MAPPER, or else device sharing breaks
  383. if (String (mc.szPname, sizeof (mc.szPname)).containsIgnoreCase (T("microsoft")))
  384. deviceId = i;
  385. if (index == n)
  386. {
  387. deviceId = i;
  388. break;
  389. }
  390. ++n;
  391. }
  392. }
  393. for (i = handles.size(); --i >= 0;)
  394. {
  395. MidiOutHandle* const han = (MidiOutHandle*) handles.getUnchecked(i);
  396. if (han != 0 && han->deviceId == deviceId)
  397. {
  398. han->refCount++;
  399. MidiOutput* const out = new MidiOutput();
  400. out->internal = (void*) han;
  401. return out;
  402. }
  403. }
  404. for (i = 4; --i >= 0;)
  405. {
  406. HMIDIOUT h = 0;
  407. MMRESULT res = midiOutOpen (&h, deviceId, 0, 0, CALLBACK_NULL);
  408. if (res == MMSYSERR_NOERROR)
  409. {
  410. MidiOutHandle* const han = new MidiOutHandle();
  411. han->deviceId = deviceId;
  412. han->refCount = 1;
  413. han->handle = h;
  414. handles.add (han);
  415. MidiOutput* const out = new MidiOutput();
  416. out->internal = (void*) han;
  417. return out;
  418. }
  419. else if (res == MMSYSERR_ALLOCATED)
  420. {
  421. Sleep (100);
  422. }
  423. else
  424. {
  425. break;
  426. }
  427. }
  428. return 0;
  429. }
  430. MidiOutput::~MidiOutput()
  431. {
  432. MidiOutHandle* const h = (MidiOutHandle*) internal;
  433. if (handles.contains ((void*) h) && --(h->refCount) == 0)
  434. {
  435. midiOutClose (h->handle);
  436. handles.removeValue ((void*) h);
  437. delete h;
  438. }
  439. }
  440. void MidiOutput::reset()
  441. {
  442. const MidiOutHandle* const h = (MidiOutHandle*) internal;
  443. midiOutReset (h->handle);
  444. }
  445. bool MidiOutput::getVolume (float& leftVol,
  446. float& rightVol)
  447. {
  448. const MidiOutHandle* const handle = (const MidiOutHandle*) internal;
  449. DWORD n;
  450. if (midiOutGetVolume (handle->handle, &n) == MMSYSERR_NOERROR)
  451. {
  452. const unsigned short* const nn = (const unsigned short*) &n;
  453. rightVol = nn[0] / (float) 0xffff;
  454. leftVol = nn[1] / (float) 0xffff;
  455. return true;
  456. }
  457. else
  458. {
  459. rightVol = leftVol = 1.0f;
  460. return false;
  461. }
  462. }
  463. void MidiOutput::setVolume (float leftVol,
  464. float rightVol)
  465. {
  466. const MidiOutHandle* const handle = (MidiOutHandle*) internal;
  467. DWORD n;
  468. unsigned short* const nn = (unsigned short*) &n;
  469. nn[0] = (unsigned short) jlimit (0, 0xffff, (int)(rightVol * 0xffff));
  470. nn[1] = (unsigned short) jlimit (0, 0xffff, (int)(leftVol * 0xffff));
  471. midiOutSetVolume (handle->handle, n);
  472. }
  473. void MidiOutput::sendMessageNow (const MidiMessage& message)
  474. {
  475. const MidiOutHandle* const handle = (const MidiOutHandle*) internal;
  476. if (message.getRawDataSize() > 3
  477. || message.isSysEx())
  478. {
  479. MIDIHDR h;
  480. zerostruct (h);
  481. h.lpData = (char*) message.getRawData();
  482. h.dwBufferLength = message.getRawDataSize();
  483. h.dwBytesRecorded = message.getRawDataSize();
  484. if (midiOutPrepareHeader (handle->handle, &h, sizeof (MIDIHDR)) == MMSYSERR_NOERROR)
  485. {
  486. MMRESULT res = midiOutLongMsg (handle->handle, &h, sizeof (MIDIHDR));
  487. if (res == MMSYSERR_NOERROR)
  488. {
  489. while ((h.dwFlags & MHDR_DONE) == 0)
  490. Sleep (1);
  491. int count = 500; // 1 sec timeout
  492. while (--count >= 0)
  493. {
  494. res = midiOutUnprepareHeader (handle->handle, &h, sizeof (MIDIHDR));
  495. if (res == MIDIERR_STILLPLAYING)
  496. Sleep (2);
  497. else
  498. break;
  499. }
  500. }
  501. }
  502. }
  503. else
  504. {
  505. midiOutShortMsg (handle->handle,
  506. *(unsigned int*) message.getRawData());
  507. }
  508. }
  509. #endif