| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2015 - ROLI Ltd.
 - 
 -    Permission is granted to use this software under the terms of either:
 -    a) the GPL v2 (or any later version)
 -    b) the Affero GPL v3
 - 
 -    Details of these licenses can be found at: www.gnu.org/licenses
 - 
 -    JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
 -    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 -    A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 - 
 -    ------------------------------------------------------------------------------
 - 
 -    To release a closed-source product which uses JUCE, commercial licenses are
 -    available: visit www.juce.com for more information.
 - 
 -   ==============================================================================
 - */
 - 
 - class MidiInCollector
 - {
 - public:
 -     MidiInCollector (MidiInput* const input_,
 -                      MidiInputCallback& callback_)
 -         : deviceHandle (0),
 -           input (input_),
 -           callback (callback_),
 -           concatenator (4096),
 -           isStarted (false),
 -           startTime (0)
 -     {
 -     }
 - 
 -     ~MidiInCollector()
 -     {
 -         stop();
 - 
 -         if (deviceHandle != 0)
 -         {
 -             for (int count = 5; --count >= 0;)
 -             {
 -                 if (midiInClose (deviceHandle) == MMSYSERR_NOERROR)
 -                     break;
 - 
 -                 Sleep (20);
 -             }
 -         }
 -     }
 - 
 -     //==============================================================================
 -     void handleMessage (const uint8* bytes, const uint32 timeStamp)
 -     {
 -         if (bytes[0] >= 0x80 && isStarted)
 -         {
 -             concatenator.pushMidiData (bytes, MidiMessage::getMessageLengthFromFirstByte (bytes[0]),
 -                                        convertTimeStamp (timeStamp), input, callback);
 -             writeFinishedBlocks();
 -         }
 -     }
 - 
 -     void handleSysEx (MIDIHDR* const hdr, const uint32 timeStamp)
 -     {
 -         if (isStarted && hdr->dwBytesRecorded > 0)
 -         {
 -             concatenator.pushMidiData (hdr->lpData, (int) hdr->dwBytesRecorded,
 -                                        convertTimeStamp (timeStamp), input, callback);
 -             writeFinishedBlocks();
 -         }
 -     }
 - 
 -     void start()
 -     {
 -         if (deviceHandle != 0 && ! isStarted)
 -         {
 -             activeMidiCollectors.addIfNotAlreadyThere (this);
 - 
 -             for (int i = 0; i < (int) numHeaders; ++i)
 -             {
 -                 headers[i].prepare (deviceHandle);
 -                 headers[i].write (deviceHandle);
 -             }
 - 
 -             startTime = Time::getMillisecondCounterHiRes();
 -             MMRESULT res = midiInStart (deviceHandle);
 - 
 -             if (res == MMSYSERR_NOERROR)
 -             {
 -                 concatenator.reset();
 -                 isStarted = true;
 -             }
 -             else
 -             {
 -                 unprepareAllHeaders();
 -             }
 -         }
 -     }
 - 
 -     void stop()
 -     {
 -         if (isStarted)
 -         {
 -             isStarted = false;
 -             midiInReset (deviceHandle);
 -             midiInStop (deviceHandle);
 -             activeMidiCollectors.removeFirstMatchingValue (this);
 -             unprepareAllHeaders();
 -             concatenator.reset();
 -         }
 -     }
 - 
 -     static void CALLBACK midiInCallback (HMIDIIN, UINT uMsg, DWORD_PTR dwInstance,
 -                                          DWORD_PTR midiMessage, DWORD_PTR timeStamp)
 -     {
 -         MidiInCollector* const collector = reinterpret_cast<MidiInCollector*> (dwInstance);
 - 
 -         if (activeMidiCollectors.contains (collector))
 -         {
 -             if (uMsg == MIM_DATA)
 -                 collector->handleMessage ((const uint8*) &midiMessage, (uint32) timeStamp);
 -             else if (uMsg == MIM_LONGDATA)
 -                 collector->handleSysEx ((MIDIHDR*) midiMessage, (uint32) timeStamp);
 -         }
 -     }
 - 
 -     HMIDIIN deviceHandle;
 - 
 - private:
 -     static Array <MidiInCollector*, CriticalSection> activeMidiCollectors;
 - 
 -     MidiInput* input;
 -     MidiInputCallback& callback;
 -     MidiDataConcatenator concatenator;
 -     bool volatile isStarted;
 -     double startTime;
 - 
 -     class MidiHeader
 -     {
 -     public:
 -         MidiHeader() {}
 - 
 -         void prepare (HMIDIIN device)
 -         {
 -             zerostruct (hdr);
 -             hdr.lpData = data;
 -             hdr.dwBufferLength = (DWORD) numElementsInArray (data);
 - 
 -             midiInPrepareHeader (device, &hdr, sizeof (hdr));
 -         }
 - 
 -         void unprepare (HMIDIIN device)
 -         {
 -             if ((hdr.dwFlags & WHDR_DONE) != 0)
 -             {
 -                 int c = 10;
 -                 while (--c >= 0 && midiInUnprepareHeader (device, &hdr, sizeof (hdr)) == MIDIERR_STILLPLAYING)
 -                     Thread::sleep (20);
 - 
 -                 jassert (c >= 0);
 -             }
 -         }
 - 
 -         void write (HMIDIIN device)
 -         {
 -             hdr.dwBytesRecorded = 0;
 -             midiInAddBuffer (device, &hdr, sizeof (hdr));
 -         }
 - 
 -         void writeIfFinished (HMIDIIN device)
 -         {
 -             if ((hdr.dwFlags & WHDR_DONE) != 0)
 -                 write (device);
 -         }
 - 
 -     private:
 -         MIDIHDR hdr;
 -         char data [256];
 - 
 -         JUCE_DECLARE_NON_COPYABLE (MidiHeader)
 -     };
 - 
 -     enum { numHeaders = 32 };
 -     MidiHeader headers [numHeaders];
 - 
 -     void writeFinishedBlocks()
 -     {
 -         for (int i = 0; i < (int) numHeaders; ++i)
 -             headers[i].writeIfFinished (deviceHandle);
 -     }
 - 
 -     void unprepareAllHeaders()
 -     {
 -         for (int i = 0; i < (int) numHeaders; ++i)
 -             headers[i].unprepare (deviceHandle);
 -     }
 - 
 -     double convertTimeStamp (uint32 timeStamp)
 -     {
 -         double t = startTime + timeStamp;
 - 
 -         const double now = Time::getMillisecondCounterHiRes();
 -         if (t > now)
 -         {
 -             if (t > now + 2.0)
 -                 startTime -= 1.0;
 - 
 -             t = now;
 -         }
 - 
 -         return t * 0.001;
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiInCollector)
 - };
 - 
 - Array <MidiInCollector*, CriticalSection> MidiInCollector::activeMidiCollectors;
 - 
 - 
 - //==============================================================================
 - StringArray MidiInput::getDevices()
 - {
 -     StringArray s;
 -     const UINT num = midiInGetNumDevs();
 - 
 -     for (UINT i = 0; i < num; ++i)
 -     {
 -         MIDIINCAPS mc = { 0 };
 - 
 -         if (midiInGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
 -             s.add (String (mc.szPname, sizeof (mc.szPname)));
 -     }
 - 
 -     return s;
 - }
 - 
 - int MidiInput::getDefaultDeviceIndex()
 - {
 -     return 0;
 - }
 - 
 - MidiInput* MidiInput::openDevice (const int index, MidiInputCallback* const callback)
 - {
 -     if (callback == nullptr)
 -         return nullptr;
 - 
 -     UINT deviceId = MIDI_MAPPER;
 -     int n = 0;
 -     String name;
 - 
 -     const UINT num = midiInGetNumDevs();
 - 
 -     for (UINT i = 0; i < num; ++i)
 -     {
 -         MIDIINCAPS mc = { 0 };
 - 
 -         if (midiInGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
 -         {
 -             if (index == n)
 -             {
 -                 deviceId = i;
 -                 name = String (mc.szPname, (size_t) numElementsInArray (mc.szPname));
 -                 break;
 -             }
 - 
 -             ++n;
 -         }
 -     }
 - 
 -     ScopedPointer<MidiInput> in (new MidiInput (name));
 -     ScopedPointer<MidiInCollector> collector (new MidiInCollector (in, *callback));
 - 
 -     HMIDIIN h;
 -     MMRESULT err = midiInOpen (&h, deviceId,
 -                                (DWORD_PTR) &MidiInCollector::midiInCallback,
 -                                (DWORD_PTR) (MidiInCollector*) collector,
 -                                CALLBACK_FUNCTION);
 - 
 -     if (err == MMSYSERR_NOERROR)
 -     {
 -         collector->deviceHandle = h;
 -         in->internal = collector.release();
 -         return in.release();
 -     }
 - 
 -     return nullptr;
 - }
 - 
 - MidiInput::MidiInput (const String& name_)
 -     : name (name_),
 -       internal (0)
 - {
 - }
 - 
 - MidiInput::~MidiInput()
 - {
 -     delete static_cast<MidiInCollector*> (internal);
 - }
 - 
 - void MidiInput::start()     { static_cast<MidiInCollector*> (internal)->start(); }
 - void MidiInput::stop()      { static_cast<MidiInCollector*> (internal)->stop(); }
 - 
 - 
 - //==============================================================================
 - struct MidiOutHandle
 - {
 -     int refCount;
 -     UINT deviceId;
 -     HMIDIOUT handle;
 - 
 -     static Array<MidiOutHandle*> activeHandles;
 - 
 - private:
 -     JUCE_LEAK_DETECTOR (MidiOutHandle)
 - };
 - 
 - Array<MidiOutHandle*> MidiOutHandle::activeHandles;
 - 
 - //==============================================================================
 - StringArray MidiOutput::getDevices()
 - {
 -     StringArray s;
 -     const UINT num = midiOutGetNumDevs();
 - 
 -     for (UINT i = 0; i < num; ++i)
 -     {
 -         MIDIOUTCAPS mc = { 0 };
 - 
 -         if (midiOutGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
 -             s.add (String (mc.szPname, sizeof (mc.szPname)));
 -     }
 - 
 -     return s;
 - }
 - 
 - int MidiOutput::getDefaultDeviceIndex()
 - {
 -     const UINT num = midiOutGetNumDevs();
 -     int n = 0;
 - 
 -     for (UINT i = 0; i < num; ++i)
 -     {
 -         MIDIOUTCAPS mc = { 0 };
 - 
 -         if (midiOutGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
 -         {
 -             if ((mc.wTechnology & MOD_MAPPER) != 0)
 -                 return n;
 - 
 -              ++n;
 -         }
 -     }
 - 
 -     return 0;
 - }
 - 
 - MidiOutput* MidiOutput::openDevice (int index)
 - {
 -     UINT deviceId = MIDI_MAPPER;
 -     const UINT num = midiOutGetNumDevs();
 -     int n = 0;
 -     String deviceName;
 - 
 -     for (UINT i = 0; i < num; ++i)
 -     {
 -         MIDIOUTCAPS mc = { 0 };
 - 
 -         if (midiOutGetDevCaps (i, &mc, sizeof (mc)) == MMSYSERR_NOERROR)
 -         {
 -             String name = String (mc.szPname, sizeof (mc.szPname));
 - 
 -             // use the microsoft sw synth as a default - best not to allow deviceId
 -             // to be MIDI_MAPPER, or else device sharing breaks
 -             if (name.containsIgnoreCase ("microsoft"))
 -                 deviceId = i;
 - 
 -             if (index == n)
 -             {
 -                 deviceName = name;
 -                 deviceId = i;
 -                 break;
 -             }
 - 
 -             ++n;
 -         }
 -     }
 - 
 -     for (int i = MidiOutHandle::activeHandles.size(); --i >= 0;)
 -     {
 -         MidiOutHandle* const han = MidiOutHandle::activeHandles.getUnchecked(i);
 - 
 -         if (han->deviceId == deviceId)
 -         {
 -             han->refCount++;
 - 
 -             MidiOutput* const out = new MidiOutput (deviceName);
 -             out->internal = han;
 -             return out;
 -         }
 -     }
 - 
 -     for (int i = 4; --i >= 0;)
 -     {
 -         HMIDIOUT h = 0;
 -         MMRESULT res = midiOutOpen (&h, deviceId, 0, 0, CALLBACK_NULL);
 - 
 -         if (res == MMSYSERR_NOERROR)
 -         {
 -             MidiOutHandle* const han = new MidiOutHandle();
 -             han->deviceId = deviceId;
 -             han->refCount = 1;
 -             han->handle = h;
 -             MidiOutHandle::activeHandles.add (han);
 - 
 -             MidiOutput* const out = new MidiOutput (deviceName);
 -             out->internal = han;
 -             return out;
 -         }
 -         else if (res == MMSYSERR_ALLOCATED)
 -         {
 -             Sleep (100);
 -         }
 -         else
 -         {
 -             break;
 -         }
 -     }
 - 
 -     return nullptr;
 - }
 - 
 - MidiOutput::~MidiOutput()
 - {
 -     stopBackgroundThread();
 - 
 -     MidiOutHandle* const h = static_cast<MidiOutHandle*> (internal);
 - 
 -     if (MidiOutHandle::activeHandles.contains (h) && --(h->refCount) == 0)
 -     {
 -         midiOutClose (h->handle);
 -         MidiOutHandle::activeHandles.removeFirstMatchingValue (h);
 -         delete h;
 -     }
 - }
 - 
 - void MidiOutput::sendMessageNow (const MidiMessage& message)
 - {
 -     const MidiOutHandle* const handle = static_cast<const MidiOutHandle*> (internal);
 - 
 -     if (message.getRawDataSize() > 3 || message.isSysEx())
 -     {
 -         MIDIHDR h = { 0 };
 - 
 -         h.lpData = (char*) message.getRawData();
 -         h.dwBytesRecorded = h.dwBufferLength  = (DWORD) message.getRawDataSize();
 - 
 -         if (midiOutPrepareHeader (handle->handle, &h, sizeof (MIDIHDR)) == MMSYSERR_NOERROR)
 -         {
 -             MMRESULT res = midiOutLongMsg (handle->handle, &h, sizeof (MIDIHDR));
 - 
 -             if (res == MMSYSERR_NOERROR)
 -             {
 -                 while ((h.dwFlags & MHDR_DONE) == 0)
 -                     Sleep (1);
 - 
 -                 int count = 500; // 1 sec timeout
 - 
 -                 while (--count >= 0)
 -                 {
 -                     res = midiOutUnprepareHeader (handle->handle, &h, sizeof (MIDIHDR));
 - 
 -                     if (res == MIDIERR_STILLPLAYING)
 -                         Sleep (2);
 -                     else
 -                         break;
 -                 }
 -             }
 -         }
 -     }
 -     else
 -     {
 -         for (int i = 0; i < 50; ++i)
 -         {
 -             if (midiOutShortMsg (handle->handle, *(unsigned int*) message.getRawData()) != MIDIERR_NOTREADY)
 -                 break;
 - 
 -             Sleep (1);
 -         }
 -     }
 - }
 
 
  |