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.

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