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.

657 lines
17KB

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