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.

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