| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2016 - ROLI Ltd.
 - 
 -    Permission is granted to use this software under the terms of the ISC license
 -    http://www.isc.org/downloads/software-support-policy/isc-license/
 - 
 -    Permission to use, copy, modify, and/or distribute this software for any
 -    purpose with or without fee is hereby granted, provided that the above
 -    copyright notice and this permission notice appear in all copies.
 - 
 -    THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
 -    TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 -    FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
 -    OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
 -    USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 -    TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 -    OF THIS SOFTWARE.
 - 
 -    -----------------------------------------------------------------------------
 - 
 -    To release a closed-source product which uses other parts of JUCE not
 -    licensed under the ISC terms, commercial licenses are available: visit
 -    www.juce.com for more information.
 - 
 -   ==============================================================================
 - */
 - 
 - struct MidiServiceType
 - {
 -     struct InputWrapper
 -     {
 -         virtual ~InputWrapper() {}
 - 
 -         virtual String getDeviceName() = 0;
 - 
 -         virtual void start() = 0;
 -         virtual void stop() = 0;
 -     };
 - 
 -     struct OutputWrapper
 -     {
 -         virtual ~OutputWrapper () {}
 - 
 -         virtual String getDeviceName() = 0;
 - 
 -         virtual void sendMessageNow (const MidiMessage&) = 0;
 -     };
 - 
 -     MidiServiceType() {}
 -     virtual ~MidiServiceType() {}
 - 
 -     virtual StringArray getDevices (bool) = 0;
 -     virtual int getDefaultDeviceIndex (bool) = 0;
 - 
 -     virtual InputWrapper* createInputWrapper (MidiInput* const,
 -                                               const int,
 -                                               MidiInputCallback* const callback) = 0;
 -     virtual OutputWrapper* createOutputWrapper (const int) = 0;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiServiceType)
 - };
 - 
 - class MidiService :   public DeletedAtShutdown
 - {
 - public:
 -     ~MidiService();
 - 
 -     MidiServiceType* getService();
 - 
 -     juce_DeclareSingleton (MidiService, false)
 - 
 - private:
 -     MidiService();
 - 
 -     ScopedPointer<MidiServiceType> internal;
 - };
 - 
 - juce_ImplementSingleton (MidiService)
 - 
 - //==============================================================================
 - class WindowsMidiService :   public MidiServiceType
 - {
 - private:
 -     struct WindowsInputWrapper :   public InputWrapper
 -     {
 -         class MidiInCollector
 -         {
 -         public:
 -             MidiInCollector (WindowsMidiService& s,
 -                              MidiInput* const inputDevice,
 -                              MidiInputCallback& cb)
 -                 : midiService (s),
 -                   input (inputDevice),
 -                   callback (cb)
 -             {
 -             }
 - 
 -             ~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)
 -                 {
 -                     midiService.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);
 -                     midiService.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 (collector->midiService.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 = 0;
 - 
 -         private:
 -             WindowsMidiService& midiService;
 -             MidiInput* input;
 -             MidiInputCallback& callback;
 -             MidiDataConcatenator concatenator { 4096 };
 -             bool volatile isStarted = false;
 -             double startTime = 0;
 - 
 -             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)
 -         };
 - 
 -         WindowsInputWrapper (WindowsMidiService& parentService,
 -                              MidiInput* const input,
 -                              const int index,
 -                              MidiInputCallback* const callback)
 -         {
 -             UINT deviceId = MIDI_MAPPER;
 -             int n = 0;
 - 
 -             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;
 -                         deviceName = String (mc.szPname, (size_t) numElementsInArray (mc.szPname));
 -                         break;
 -                     }
 - 
 -                     ++n;
 -                 }
 -             }
 - 
 -             collector = new MidiInCollector (parentService, input, *callback);
 - 
 -             HMIDIIN h;
 -             MMRESULT err = midiInOpen (&h, deviceId,
 -                                        (DWORD_PTR) &MidiInCollector::midiInCallback,
 -                                        (DWORD_PTR) (MidiInCollector*) collector.get(),
 -                                        CALLBACK_FUNCTION);
 - 
 -             if (err != MMSYSERR_NOERROR)
 -                 throw std::runtime_error ("Failed to create Windows input device wrapper");
 - 
 -             collector->deviceHandle = h;
 -         }
 - 
 -         ~WindowsInputWrapper() {}
 - 
 -         static StringArray 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;
 -         }
 - 
 -         static int getDefaultDeviceIndex()
 -         {
 -             return 0;
 -         }
 - 
 -         void start() override   { collector->start(); }
 -         void stop() override    { collector->stop(); }
 - 
 -         String getDeviceName() override
 -         {
 -             return deviceName;
 -         }
 - 
 -         String deviceName;
 -         ScopedPointer<MidiInCollector> collector;
 - 
 -         JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsInputWrapper)
 -     };
 - 
 -     struct WindowsOutputWrapper :   public OutputWrapper
 -     {
 -         struct MidiOutHandle
 -         {
 -             int refCount;
 -             UINT deviceId;
 -             HMIDIOUT handle;
 - 
 -         private:
 -             JUCE_LEAK_DETECTOR (MidiOutHandle)
 -         };
 - 
 -         WindowsOutputWrapper (WindowsMidiService& p, const int index)
 -             : parent (p)
 -         {
 -             UINT deviceId = MIDI_MAPPER;
 -             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)
 -                 {
 -                     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 = parent.activeOutputHandles.size(); --i >= 0;)
 -             {
 -                 han = parent.activeOutputHandles.getUnchecked (i);
 - 
 -                 if (han->deviceId == deviceId)
 -                 {
 -                     han->refCount++;
 - 
 -                     return;
 -                 }
 -             }
 - 
 -             for (int i = 4; --i >= 0;)
 -             {
 -                 HMIDIOUT h = 0;
 -                 MMRESULT res = midiOutOpen (&h, deviceId, 0, 0, CALLBACK_NULL);
 - 
 -                 if (res == MMSYSERR_NOERROR)
 -                 {
 -                     han = new MidiOutHandle();
 -                     han->deviceId = deviceId;
 -                     han->refCount = 1;
 -                     han->handle = h;
 -                     parent.activeOutputHandles.add (han);
 - 
 -                     return;
 -                 }
 -                 else if (res == MMSYSERR_ALLOCATED)
 -                 {
 -                     Sleep (100);
 -                 }
 -                 else
 -                 {
 -                     break;
 -                 }
 -             }
 - 
 -             throw std::runtime_error ("Failed to create Windows output device wrapper");
 -         }
 - 
 -         ~WindowsOutputWrapper()
 -         {
 -             if (parent.activeOutputHandles.contains (han.get()) && --(han->refCount) == 0)
 -             {
 -                 midiOutClose (han->handle);
 -                 parent.activeOutputHandles.removeFirstMatchingValue (han.get());
 -             }
 -         }
 - 
 -         void sendMessageNow (const MidiMessage& message) override
 -         {
 -             if (message.getRawDataSize() > 3 || message.isSysEx())
 -             {
 -                 MIDIHDR h = { 0 };
 - 
 -                 h.lpData = (char*) message.getRawData();
 -                 h.dwBytesRecorded = h.dwBufferLength  = (DWORD) message.getRawDataSize();
 - 
 -                 if (midiOutPrepareHeader (han->handle, &h, sizeof (MIDIHDR)) == MMSYSERR_NOERROR)
 -                 {
 -                     MMRESULT res = midiOutLongMsg (han->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 (han->handle, &h, sizeof (MIDIHDR));
 - 
 -                             if (res == MIDIERR_STILLPLAYING)
 -                                 Sleep (2);
 -                             else
 -                                 break;
 -                         }
 -                     }
 -                 }
 -             }
 -             else
 -             {
 -                 for (int i = 0; i < 50; ++i)
 -                 {
 -                     if (midiOutShortMsg (han->handle, *(unsigned int*) message.getRawData()) != MIDIERR_NOTREADY)
 -                         break;
 - 
 -                     Sleep (1);
 -                 }
 -             }
 -         }
 - 
 -         static StringArray 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;
 -         }
 - 
 -         static int 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;
 -         }
 - 
 -         String getDeviceName() override
 -         {
 -             return deviceName;
 -         }
 - 
 -         WindowsMidiService& parent;
 -         String deviceName;
 - 
 -         ScopedPointer<MidiOutHandle> han;
 - 
 -         JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsOutputWrapper)
 -     };
 - 
 - public:
 -     WindowsMidiService() {}
 - 
 -     StringArray getDevices (bool isInput) override
 -     {
 -         return isInput ? WindowsInputWrapper::getDevices()
 -                        : WindowsOutputWrapper::getDevices();
 -     }
 - 
 -     int getDefaultDeviceIndex (bool isInput) override
 -     {
 -         return isInput ? WindowsInputWrapper::getDefaultDeviceIndex()
 -                        : WindowsOutputWrapper::getDefaultDeviceIndex();
 -     }
 - 
 -     InputWrapper* createInputWrapper (MidiInput* const input,
 -                                       const int index,
 -                                       MidiInputCallback* const callback) override
 -     {
 -         return new WindowsInputWrapper (*this, input, index, callback);
 -     }
 - 
 -     OutputWrapper* createOutputWrapper (const int index) override
 -     {
 -         return new WindowsOutputWrapper (*this, index);
 -     }
 - 
 - private:
 -     Array<WindowsInputWrapper::MidiInCollector*, CriticalSection> activeMidiCollectors;
 -     Array<WindowsOutputWrapper::MidiOutHandle*> activeOutputHandles;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsMidiService)
 - };
 - 
 - //==============================================================================
 - #if JUCE_USE_WINRT_MIDI
 - 
 - using namespace Microsoft::WRL;
 - 
 - using namespace ABI::Windows::Foundation;
 - using namespace ABI::Windows::Devices::Midi;
 - using namespace ABI::Windows::Devices::Enumeration;
 - using namespace ABI::Windows::Storage::Streams;
 - 
 - class WinRTMidiService :   public MidiServiceType
 - {
 - private:
 -     template <typename COMFactoryType>
 -     struct MidiIODeviceWatcher
 -     {
 -         struct DeviceInfo
 -         {
 -             String name;
 -             String id;
 -             bool isDefault = false;
 -         };
 - 
 -         MidiIODeviceWatcher (ComSmartPtr<COMFactoryType>& comFactory)
 -             : factory (comFactory)
 -         {
 -         }
 - 
 -         ~MidiIODeviceWatcher()
 -         {
 -             stop();
 -         }
 - 
 -         bool start()
 -         {
 -             HSTRING deviceSelector;
 -             HRESULT hr = factory->GetDeviceSelector (&deviceSelector);
 -             if (FAILED (hr))
 -                 return false;
 - 
 -             auto deviceInformationFactory = WinRTWrapper::getInstance()->getWRLFactory<IDeviceInformationStatics> (&RuntimeClass_Windows_Devices_Enumeration_DeviceInformation[0]);
 -             if (deviceInformationFactory == nullptr)
 -                 return false;
 - 
 -             hr = deviceInformationFactory->CreateWatcherAqsFilter (deviceSelector, watcher.resetAndGetPointerAddress());
 -             if (FAILED (hr))
 -                 return false;
 - 
 -             hr = watcher->add_Added (
 -                 Callback<ITypedEventHandler<DeviceWatcher*, DeviceInformation*>>(
 -                     [this] (IDeviceWatcher*, IDeviceInformation* info) { return addDevice (info); }
 -                 ).Get(),
 -                 &deviceAddedToken);
 -             if (FAILED (hr))
 -                 return false;
 - 
 -             hr = watcher->add_Removed (
 -                 Callback<ITypedEventHandler<DeviceWatcher*, DeviceInformationUpdate*>>(
 -                     [this] (IDeviceWatcher*, IDeviceInformationUpdate* info) { return removeDevice (info); }
 -                 ).Get(),
 -                 &deviceRemovedToken);
 -             if (FAILED (hr))
 -                 return false;
 - 
 -             hr = watcher->Start();
 -             if (FAILED (hr))
 -                 return false;
 - 
 -             return true;
 -         }
 - 
 -         bool stop()
 -         {
 -             if (watcher == nullptr)
 -                 return true;
 - 
 -             if (deviceAddedToken.value != 0)
 -             {
 -                 HRESULT hr = watcher->remove_Added (deviceAddedToken);
 -                 if (FAILED (hr))
 -                     return false;
 - 
 -                 deviceAddedToken.value = 0;
 -             }
 - 
 -             if (deviceRemovedToken.value != 0)
 -             {
 -                 HRESULT hr = watcher->remove_Removed (deviceRemovedToken);
 -                 if (FAILED (hr))
 -                     return false;
 - 
 -                 deviceRemovedToken.value = 0;
 -             }
 - 
 -             HRESULT hr = watcher->Stop();
 -             if (FAILED (hr))
 -                 return false;
 - 
 -             watcher = nullptr;
 -             return true;
 -         }
 - 
 -         HRESULT addDevice (IDeviceInformation* addedDeviceInfo)
 -         {
 -             boolean isEnabled;
 -             HRESULT hr = addedDeviceInfo->get_IsEnabled (&isEnabled);
 -             if (FAILED (hr))
 -                 return S_OK;
 - 
 -             if (! isEnabled)
 -                 return S_OK;
 - 
 -             const ScopedLock lock (deviceChanges);
 - 
 -             DeviceInfo info;
 - 
 -             HSTRING name;
 -             hr = addedDeviceInfo->get_Name (&name);
 -             if (FAILED (hr))
 -                 return S_OK;
 - 
 -             info.name = WinRTWrapper::getInstance()->hStringToString (name);
 - 
 -             HSTRING id;
 -             hr = addedDeviceInfo->get_Id (&id);
 -             if (FAILED (hr))
 -                 return S_OK;
 - 
 -             info.id = WinRTWrapper::getInstance()->hStringToString (id);
 - 
 -             boolean isDefault;
 -             hr = addedDeviceInfo->get_IsDefault (&isDefault);
 -             if (FAILED (hr))
 -                 return S_OK;
 - 
 -             info.isDefault = isDefault != 0;
 - 
 -             connectedDevices.add (info);
 - 
 -             return S_OK;
 -         }
 - 
 -         HRESULT removeDevice (IDeviceInformationUpdate* removedDeviceInfo)
 -         {
 -             const ScopedLock lock (deviceChanges);
 - 
 -             HSTRING removedDeviceIdHstr;
 -             removedDeviceInfo->get_Id (&removedDeviceIdHstr);
 -             String removedDeviceId = WinRTWrapper::getInstance()->hStringToString (removedDeviceIdHstr);
 - 
 -             for (int i = 0; i < connectedDevices.size(); ++i)
 -             {
 -                 if (connectedDevices[i].id == removedDeviceId)
 -                 {
 -                     connectedDevices.remove (i);
 -                     break;
 -                 }
 -             }
 - 
 -             return S_OK;
 -         }
 - 
 -         StringArray getDevices()
 -         {
 -             {
 -                 const ScopedLock lock (deviceChanges);
 -                 lastQueriedConnectedDevices = connectedDevices;
 -             }
 - 
 -             StringArray result;
 -             for (auto info : lastQueriedConnectedDevices.get())
 -                 result.add (info.name);
 - 
 -             return result;
 -         }
 - 
 -         int getDefaultDeviceIndex()
 -         {
 -             auto& lastDevices = lastQueriedConnectedDevices.get();
 -             for (int i = 0; i < lastDevices.size(); ++i)
 -             {
 -                 if (lastDevices[i].isDefault)
 -                     return i;
 -             }
 - 
 -             return 0;
 -         }
 - 
 -         String getDeviceNameFromIndex (const int index)
 -         {
 -             if (isPositiveAndBelow (index, lastQueriedConnectedDevices.get().size()))
 -                 return lastQueriedConnectedDevices.get()[index].name;
 - 
 -             return {};
 -         }
 - 
 -         String getDeviceID (const String name)
 -         {
 -             const ScopedLock lock (deviceChanges);
 - 
 -             for (auto info : connectedDevices)
 -                 if (info.name == name)
 -                     return info.id;
 - 
 -             return {};
 -         }
 - 
 -         ComSmartPtr<COMFactoryType>& factory;
 - 
 -         EventRegistrationToken deviceAddedToken { 0 }, deviceRemovedToken { 0 };
 - 
 -         ComSmartPtr<IDeviceWatcher> watcher;
 -         Array<DeviceInfo> connectedDevices;
 -         CriticalSection deviceChanges;
 -         ThreadLocalValue<Array<DeviceInfo>> lastQueriedConnectedDevices;
 - 
 -         JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiIODeviceWatcher);
 -     };
 - 
 -     template <typename COMFactoryType, typename COMInterfaceType, typename COMType>
 -     class OpenMidiPortThread :   public Thread
 -     {
 -     public:
 -         OpenMidiPortThread (String threadName,
 -                             String midiDeviceId,
 -                             ComSmartPtr<COMFactoryType>& comFactory,
 -                             ComSmartPtr<COMInterfaceType>& comPort)
 -             : Thread (threadName),
 -               deviceId (midiDeviceId),
 -               factory (comFactory),
 -               port (comPort)
 -         {
 -         }
 - 
 -         ~OpenMidiPortThread()
 -         {
 -         }
 - 
 -         void run() override
 -         {
 -             WinRTWrapper::ScopedHString hDeviceId (deviceId);
 -             ComSmartPtr<IAsyncOperation<COMType*>> asyncOp;
 -             HRESULT hr = factory->FromIdAsync (hDeviceId.get(), asyncOp.resetAndGetPointerAddress());
 -             if (FAILED (hr))
 -                 return;
 - 
 -             hr = asyncOp->put_Completed (Callback<IAsyncOperationCompletedHandler<COMType*>> (
 -                 [this] (IAsyncOperation<COMType*>* asyncOpPtr, AsyncStatus)
 -                 {
 -                     if (asyncOpPtr == nullptr)
 -                         return E_ABORT;
 - 
 -                     HRESULT hr = asyncOpPtr->GetResults (port.resetAndGetPointerAddress());
 -                     if (FAILED (hr))
 -                         return hr;
 - 
 -                     portOpened.signal();
 -                     return S_OK;
 -                 }
 -             ).Get());
 - 
 -             // When using Bluetooth the asynchronous port opening operation will occasionally
 -             // hang, so we use a timeout. We will be able to remove this when Microsoft
 -             // improves the Bluetooth MIDI stack.
 -             portOpened.wait (2000);
 -         }
 - 
 -         const String deviceId;
 -         ComSmartPtr<COMFactoryType>& factory;
 -         ComSmartPtr<COMInterfaceType>& port;
 - 
 -         WaitableEvent portOpened { true };
 -     };
 - 
 -     struct WinRTInputWrapper : public InputWrapper
 -     {
 -         WinRTInputWrapper (WinRTMidiService& service,
 -                            MidiInput* const input,
 -                            const int index,
 -                            MidiInputCallback& cb)
 -             : inputDevice (input),
 -               callback (cb),
 -               concatenator (4096)
 -         {
 -             const ScopedLock lock (service.inputDeviceWatcher->deviceChanges);
 - 
 -             deviceName = service.inputDeviceWatcher->getDeviceNameFromIndex (index);
 -             if (deviceName.isEmpty())
 -                 throw std::runtime_error ("Invalid device index");
 - 
 -             const auto deviceID = service.inputDeviceWatcher->getDeviceID (deviceName);
 -             if (deviceID.isEmpty())
 -                 throw std::runtime_error ("Device unavailable");
 - 
 -             OpenMidiPortThread<IMidiInPortStatics, IMidiInPort, MidiInPort> portThread ("Open WinRT MIDI input port",
 -                                                                                         deviceID,
 -                                                                                         service.midiInFactory,
 -                                                                                         midiInPort);
 -             portThread.startThread();
 -             portThread.waitForThreadToExit (-1);
 -             if (midiInPort == nullptr)
 -                 throw std::runtime_error ("Timed out waiting for midi input port creation");
 - 
 -             startTime = Time::getMillisecondCounterHiRes();
 - 
 -             HRESULT hr = midiInPort->add_MessageReceived (
 -                 Callback<ITypedEventHandler<MidiInPort*, MidiMessageReceivedEventArgs*>> (
 -                     [this] (IMidiInPort*, IMidiMessageReceivedEventArgs* args) { return midiInMessageReceived (args); }
 -                 ).Get(),
 -                 &midiInMessageToken);
 -             if (FAILED (hr))
 -                 throw std::runtime_error ("Failed to set midi input callback");
 -         }
 - 
 -         ~WinRTInputWrapper()
 -         {
 -             if (midiInMessageToken.value != 0)
 -                 midiInPort->remove_MessageReceived (midiInMessageToken);
 - 
 -             midiInPort = nullptr;
 -         }
 - 
 -         void start() override
 -         {
 -             if (!isStarted)
 -             {
 -                 concatenator.reset();
 -                 isStarted = true;
 -             }
 -         }
 - 
 -         void stop() override
 -         {
 -             if (isStarted)
 -             {
 -                 isStarted = false;
 -                 concatenator.reset();
 -             }
 -         }
 - 
 -         String getDeviceName() override
 -         {
 -             return deviceName;
 -         }
 - 
 -         HRESULT midiInMessageReceived (IMidiMessageReceivedEventArgs* args)
 -         {
 -             if (! isStarted)
 -                 return S_OK;
 - 
 -             ComSmartPtr<IMidiMessage> message;
 -             HRESULT hr = args->get_Message (message.resetAndGetPointerAddress());
 -             if (FAILED (hr))
 -                 return hr;
 - 
 -             ComSmartPtr<IBuffer> buffer;
 -             hr = message->get_RawData (buffer.resetAndGetPointerAddress());
 -             if (FAILED (hr))
 -                 return hr;
 - 
 -             ComSmartPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
 -             hr = buffer->QueryInterface (bufferByteAccess.resetAndGetPointerAddress());
 -             if (FAILED (hr))
 -                 return hr;
 - 
 -             uint8_t* bufferData = nullptr;
 -             hr = bufferByteAccess->Buffer (&bufferData);
 -             if (FAILED (hr))
 -                 return hr;
 - 
 -             uint32_t numBytes = 0;
 -             hr = buffer->get_Length (&numBytes);
 -             if (FAILED (hr))
 -                 return hr;
 - 
 -             ABI::Windows::Foundation::TimeSpan timespan;
 -             hr = message->get_Timestamp (×pan);
 -             if (FAILED (hr))
 -                 return hr;
 - 
 -             concatenator.pushMidiData (bufferData,
 -                                        numBytes,
 -                                        convertTimeStamp (timespan.Duration),
 -                                        inputDevice,
 -                                        callback);
 - 
 -             return S_OK;
 -         }
 - 
 -         double convertTimeStamp (int64 timestamp)
 -         {
 -             const auto millisecondsSinceStart = static_cast<double> (timestamp) / 10000.0;
 -             double t = startTime + millisecondsSinceStart;
 - 
 -             const double now = Time::getMillisecondCounterHiRes();
 -             if (t > now)
 -             {
 -                 if (t > now + 2.0)
 -                     startTime -= 1.0;
 - 
 -                 t = now;
 -             }
 - 
 -             return t * 0.001;
 -         }
 - 
 -         MidiInput* inputDevice;
 -         MidiInputCallback& callback;
 -         String deviceName;
 -         MidiDataConcatenator concatenator;
 -         ComSmartPtr<IMidiInPort> midiInPort;
 -         EventRegistrationToken midiInMessageToken { 0 };
 - 
 -         double startTime = 0;
 -         bool isStarted = false;
 - 
 -         JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WinRTInputWrapper);
 -     };
 - 
 -     struct WinRTOutputWrapper : public OutputWrapper
 -     {
 -         WinRTOutputWrapper (WinRTMidiService& service, const int index)
 -         {
 -             const ScopedLock lock (service.outputDeviceWatcher->deviceChanges);
 - 
 -             deviceName = service.outputDeviceWatcher->getDeviceNameFromIndex (index);
 -             if (deviceName.isEmpty())
 -                 throw std::runtime_error ("Invalid device index");
 - 
 -             const auto deviceID = service.outputDeviceWatcher->getDeviceID (deviceName);
 -             if (deviceID.isEmpty())
 -                 throw std::runtime_error ("Device unavailable");
 - 
 -             OpenMidiPortThread<IMidiOutPortStatics, IMidiOutPort, IMidiOutPort> portThread ("Open WinRT MIDI output port",
 -                                                                                             deviceID,
 -                                                                                             service.midiOutFactory,
 -                                                                                             midiOutPort);
 -             portThread.startThread();
 -             portThread.waitForThreadToExit (-1);
 -             if (midiOutPort == nullptr)
 -                 throw std::runtime_error ("Timed out waiting for midi output port creation");
 - 
 -             auto bufferFactory = WinRTWrapper::getInstance()->getWRLFactory<IBufferFactory> (&RuntimeClass_Windows_Storage_Streams_Buffer[0]);
 -             if (bufferFactory == nullptr)
 -                 throw std::runtime_error ("Failed to create output buffer factory");
 - 
 -             HRESULT hr = bufferFactory->Create (static_cast<UINT32> (256), buffer.resetAndGetPointerAddress());
 -             if (FAILED (hr))
 -                 throw std::runtime_error ("Failed to create output buffer");
 - 
 -             hr = buffer->QueryInterface (bufferByteAccess.resetAndGetPointerAddress());
 -             if (FAILED (hr))
 -                 throw std::runtime_error ("Failed to get buffer byte access");
 - 
 -             hr = bufferByteAccess->Buffer (&bufferData);
 -             if (FAILED (hr))
 -                 throw std::runtime_error ("Failed to get buffer data pointer");
 -         }
 - 
 -         ~WinRTOutputWrapper() {}
 - 
 -         void sendMessageNow (const MidiMessage& message) override
 -         {
 -             const UINT32 numBytes = message.getRawDataSize();
 -             HRESULT hr = buffer->put_Length (numBytes);
 -             if (FAILED (hr))
 -                 jassertfalse;
 - 
 -             memcpy_s (bufferData, numBytes, message.getRawData(), numBytes);
 - 
 -             midiOutPort->SendBuffer (buffer);
 -         }
 - 
 -         String getDeviceName() override
 -         {
 -             return deviceName;
 -         }
 - 
 -         String deviceName;
 -         ComSmartPtr<IMidiOutPort> midiOutPort;
 -         ComSmartPtr<IBuffer> buffer;
 -         ComSmartPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
 -         uint8_t* bufferData = nullptr;
 - 
 -         JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WinRTOutputWrapper);
 -     };
 - 
 - public:
 -     WinRTMidiService()
 -     {
 -         if (! WinRTWrapper::getInstance()->isInitialised())
 -             throw std::runtime_error ("Failed to initialise the WinRT wrapper");
 - 
 -         midiInFactory = WinRTWrapper::getInstance()->getWRLFactory<IMidiInPortStatics> (&RuntimeClass_Windows_Devices_Midi_MidiInPort[0]);
 -         if (midiInFactory == nullptr)
 -             throw std::runtime_error ("Failed to create midi in factory");
 - 
 -         midiOutFactory = WinRTWrapper::getInstance()->getWRLFactory<IMidiOutPortStatics> (&RuntimeClass_Windows_Devices_Midi_MidiOutPort[0]);
 -         if (midiOutFactory == nullptr)
 -             throw std::runtime_error ("Failed to create midi out factory");
 - 
 -         inputDeviceWatcher  = new MidiIODeviceWatcher<IMidiInPortStatics>  (midiInFactory);
 -         if (! inputDeviceWatcher->start())
 -             throw std::runtime_error ("Failed to start midi input device watcher");
 - 
 -         outputDeviceWatcher = new MidiIODeviceWatcher<IMidiOutPortStatics> (midiOutFactory);
 -         if (! outputDeviceWatcher->start())
 -             throw std::runtime_error ("Failed to start midi output device watcher");
 -     }
 - 
 -     ~WinRTMidiService()
 -     {
 -     }
 - 
 -     StringArray getDevices (bool isInput) override
 -     {
 -         return isInput ? inputDeviceWatcher ->getDevices()
 -                        : outputDeviceWatcher->getDevices();
 -     }
 - 
 -     int getDefaultDeviceIndex (bool isInput) override
 -     {
 -         return isInput ? inputDeviceWatcher ->getDefaultDeviceIndex()
 -                        : outputDeviceWatcher->getDefaultDeviceIndex();
 -     }
 - 
 -     InputWrapper* createInputWrapper (MidiInput* const input,
 -                                       const int index,
 -                                       MidiInputCallback* const callback) override
 -     {
 -         return new WinRTInputWrapper (*this, input, index, *callback);
 -     }
 - 
 -     OutputWrapper* createOutputWrapper (const int index) override
 -     {
 -         return new WinRTOutputWrapper (*this, index);
 -     }
 - 
 -     ComSmartPtr<IMidiInPortStatics>  midiInFactory;
 -     ComSmartPtr<IMidiOutPortStatics> midiOutFactory;
 - 
 -     ScopedPointer<MidiIODeviceWatcher<IMidiInPortStatics>>  inputDeviceWatcher;
 -     ScopedPointer<MidiIODeviceWatcher<IMidiOutPortStatics>> outputDeviceWatcher;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WinRTMidiService)
 - };
 - 
 - #endif   // JUCE_USE_WINRT_MIDI
 - 
 - //==============================================================================
 - MidiServiceType* MidiService::getService()
 - {
 -     return internal.get();
 - }
 - 
 - MidiService::MidiService()
 - {
 -    #if JUCE_USE_WINRT_MIDI
 -     try
 -     {
 -         internal = new WinRTMidiService();
 -         return;
 -     }
 -     catch (std::runtime_error&)
 -     {
 -     }
 -    #endif
 - 
 -     internal = new WindowsMidiService();
 - }
 - 
 - MidiService::~MidiService()
 - {
 -     clearSingletonInstance();
 - }
 - 
 - //==============================================================================
 - StringArray MidiInput::getDevices()
 - {
 -     return MidiService::getInstance()->getService()->getDevices (true);
 - }
 - 
 - int MidiInput::getDefaultDeviceIndex()
 - {
 -     return MidiService::getInstance()->getService()->getDefaultDeviceIndex (true);
 - }
 - 
 - MidiInput::MidiInput (const String& deviceName)
 -     : name (deviceName)
 - {
 - }
 - 
 - MidiInput* MidiInput::openDevice (const int index, MidiInputCallback* const callback)
 - {
 -     if (callback == nullptr)
 -         return nullptr;
 - 
 -     ScopedPointer<MidiInput> in (new MidiInput (""));
 -     ScopedPointer<MidiServiceType::InputWrapper> wrapper;
 -     try
 -     {
 -         wrapper = MidiService::getInstance()->getService()->createInputWrapper (in, index, callback);
 -     }
 -     catch (std::runtime_error&)
 -     {
 -         return nullptr;
 -     }
 - 
 -     in->setName (wrapper->getDeviceName());
 -     in->internal = wrapper.release();
 -     return in.release();
 - }
 - 
 - MidiInput::~MidiInput()
 - {
 -     delete static_cast<MidiServiceType::InputWrapper*> (internal);
 - }
 - 
 - void MidiInput::start()   { static_cast<MidiServiceType::InputWrapper*> (internal)->start(); }
 - void MidiInput::stop()    { static_cast<MidiServiceType::InputWrapper*> (internal)->stop(); }
 - 
 - //==============================================================================
 - StringArray MidiOutput::getDevices()
 - {
 -     return MidiService::getInstance()->getService()->getDevices (false);
 - }
 - 
 - int MidiOutput::getDefaultDeviceIndex()
 - {
 -     return MidiService::getInstance()->getService()->getDefaultDeviceIndex (false);
 - }
 - 
 - MidiOutput* MidiOutput::openDevice (const int index)
 - {
 -     ScopedPointer<MidiServiceType::OutputWrapper> wrapper;
 -     try
 -     {
 -         wrapper = MidiService::getInstance()->getService()->createOutputWrapper (index);
 -     }
 -     catch (std::runtime_error&)
 -     {
 -         return nullptr;
 -     }
 - 
 -     ScopedPointer<MidiOutput> out (new MidiOutput (wrapper->getDeviceName()));
 -     out->internal = wrapper.release();
 -     return out.release();
 - }
 - 
 - MidiOutput::~MidiOutput()
 - {
 -     stopBackgroundThread();
 -     delete static_cast<MidiServiceType::OutputWrapper*> (internal);
 - }
 - 
 - void MidiOutput::sendMessageNow (const MidiMessage& message)
 - {
 -     auto* const wrapper = static_cast<MidiServiceType::OutputWrapper*> (internal);
 -     wrapper->sendMessageNow (message);
 - }
 
 
  |