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.

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