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
17KB

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