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.

584 lines
15KB

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