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