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.

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