| @@ -43,6 +43,14 @@ | |||
| #define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 | |||
| #define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1 | |||
| #ifndef JUCE_USE_WINRT_MIDI | |||
| #define JUCE_USE_WINRT_MIDI 0 | |||
| #endif | |||
| #if JUCE_USE_WINRT_MIDI | |||
| #define JUCE_EVENTS_INCLUDE_WINRT_WRAPPER 1 | |||
| #endif | |||
| #include "juce_audio_devices.h" | |||
| //============================================================================== | |||
| @@ -70,6 +78,30 @@ | |||
| #include <mmreg.h> | |||
| #endif | |||
| #if JUCE_USE_WINRT_MIDI | |||
| /* If you cannot find any of the header files below then you are probably | |||
| attempting to use the Windows 10 Bluetooth Low Energy API. For this to work you | |||
| need to install version 10.0.14393.0 of the Windows Standalone SDK and add the | |||
| path to the WinRT headers to your build system. This path should have the form | |||
| "C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\winrt". | |||
| Also please note that Microsoft's Bluetooth MIDI stack has multiple issues, so | |||
| this API is EXPERIMENTAL - use at your own risk! | |||
| */ | |||
| #include <windows.devices.h> | |||
| #include <windows.devices.midi.h> | |||
| #include <windows.devices.enumeration.h> | |||
| #include <wrl/event.h> | |||
| #if JUCE_MSVC | |||
| #pragma warning (push) | |||
| #pragma warning (disable: 4467) | |||
| #endif | |||
| #include <robuffer.h> | |||
| #if JUCE_MSVC | |||
| #pragma warning (pop) | |||
| #endif | |||
| #endif | |||
| #if JUCE_ASIO | |||
| /* This is very frustrating - we only need to use a handful of definitions from | |||
| a couple of the header files in Steinberg's ASIO SDK, and it'd be easy to copy | |||
| @@ -123,6 +123,26 @@ | |||
| #endif | |||
| #endif | |||
| /** Config: JUCE_USE_WINRT_MIDI | |||
| *** | |||
| EXPERIMENTAL - Microsoft's Bluetooth MIDI stack has multiple issues, | |||
| use at your own risk! | |||
| *** | |||
| Enables the use of the Windows Runtime API for MIDI, which supports | |||
| Bluetooth Low Energy connections on computers with the Anniversary Update | |||
| of Windows 10. | |||
| To compile with this flag requires version 10.0.14393.0 of the Windows | |||
| Standalone SDK and you must add the path to the WinRT headers. This path | |||
| should be something similar to | |||
| "C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\winrt". | |||
| */ | |||
| #ifndef JUCE_USE_WINRT_MIDI | |||
| #define JUCE_USE_WINRT_MIDI 0 | |||
| #endif | |||
| //============================================================================== | |||
| namespace juce | |||
| { | |||
| @@ -172,7 +172,7 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| String name; | |||
| void* internal; | |||
| void* internal = nullptr; | |||
| // The input objects are created with the openDevice() method. | |||
| explicit MidiInput (const String&); | |||
| @@ -38,7 +38,7 @@ struct MidiOutput::PendingMessage | |||
| PendingMessage* next; | |||
| }; | |||
| MidiOutput::MidiOutput(const String& midiName) | |||
| MidiOutput::MidiOutput (const String& midiName) | |||
| : Thread ("midi out"), | |||
| internal (nullptr), | |||
| firstMessage (nullptr), | |||
| @@ -136,13 +136,13 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| void* internal; | |||
| void* internal = nullptr; | |||
| CriticalSection lock; | |||
| struct PendingMessage; | |||
| PendingMessage* firstMessage; | |||
| String name; | |||
| MidiOutput(const String& midiName); // These objects are created with the openDevice() method. | |||
| MidiOutput (const String& midiName); // These objects are created with the openDevice() method. | |||
| void run() override; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutput) | |||
| @@ -233,6 +233,23 @@ struct PhysicalTopologySource::Internal | |||
| return name.indexOf (" BLOCK") > 0 || name.indexOf (" Block") > 0; | |||
| } | |||
| static String cleanBlocksDeviceName (juce::String name) | |||
| { | |||
| name = name.trim(); | |||
| if (name.endsWith (" IN)")) | |||
| return name.dropLastCharacters (4); | |||
| if (name.endsWith (" OUT)")) | |||
| return name.dropLastCharacters (5); | |||
| const int openBracketPosition = name.lastIndexOfChar ('['); | |||
| if (openBracketPosition != -1 && name.endsWith ("]")) | |||
| return name.dropLastCharacters (name.length() - openBracketPosition); | |||
| return name; | |||
| } | |||
| struct MidiInputOutputPair | |||
| { | |||
| juce::String outputName, inputName; | |||
| @@ -254,9 +271,10 @@ struct PhysicalTopologySource::Internal | |||
| pair.inputName = midiInputs[j]; | |||
| pair.inputIndex = j; | |||
| String cleanedInputName = cleanBlocksDeviceName (pair.inputName); | |||
| for (int i = 0; i < midiOutputs.size(); ++i) | |||
| { | |||
| if (midiOutputs[i].trim() == pair.inputName.trim()) | |||
| if (cleanBlocksDeviceName (midiOutputs[i]) == cleanedInputName) | |||
| { | |||
| pair.outputName = midiOutputs[i]; | |||
| pair.outputIndex = i; | |||
| @@ -40,8 +40,13 @@ | |||
| #define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 | |||
| #define JUCE_CORE_INCLUDE_JNI_HELPERS 1 | |||
| #define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 | |||
| #define JUCE_CORE_INCLUDE_COM_SMART_PTR 1 | |||
| #define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1 | |||
| #if JUCE_USE_WINRT_MIDI | |||
| #define JUCE_EVENTS_INCLUDE_WINRT_WRAPPER 1 | |||
| #endif | |||
| #include "juce_events.h" | |||
| //============================================================================== | |||
| @@ -84,6 +89,9 @@ namespace juce | |||
| #elif JUCE_WINDOWS | |||
| #include "native/juce_win32_Messaging.cpp" | |||
| #if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER | |||
| #include "native/juce_win32_WinRTWrapper.cpp" | |||
| #endif | |||
| #elif JUCE_LINUX | |||
| #include "native/juce_linux_Messaging.cpp" | |||
| @@ -55,9 +55,12 @@ | |||
| #pragma once | |||
| #define JUCE_EVENTS_H_INCLUDED | |||
| //============================================================================== | |||
| #include <juce_core/juce_core.h> | |||
| #if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER && JUCE_WINDOWS | |||
| #include <hstring.h> | |||
| #endif | |||
| namespace juce | |||
| { | |||
| @@ -86,8 +89,13 @@ namespace juce | |||
| #endif | |||
| #if JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW && JUCE_WINDOWS | |||
| #include "native/juce_win32_HiddenMessageWindow.h" | |||
| #if JUCE_WINDOWS | |||
| #if JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW | |||
| #include "native/juce_win32_HiddenMessageWindow.h" | |||
| #endif | |||
| #if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER | |||
| #include "native/juce_win32_WinRTWrapper.h" | |||
| #endif | |||
| #endif | |||
| } | |||
| @@ -0,0 +1,31 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - 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. | |||
| ============================================================================== | |||
| */ | |||
| juce_ImplementSingleton (WinRTWrapper) | |||
| @@ -0,0 +1,140 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - 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. | |||
| ============================================================================== | |||
| */ | |||
| #pragma once | |||
| class WinRTWrapper : public DeletedAtShutdown | |||
| { | |||
| public: | |||
| juce_DeclareSingleton (WinRTWrapper, true) | |||
| class ScopedHString | |||
| { | |||
| public: | |||
| ScopedHString (String str) | |||
| { | |||
| if (WinRTWrapper::getInstance()->isInitialised()) | |||
| WinRTWrapper::getInstance()->createHString (str.toWideCharPointer(), | |||
| static_cast<uint32_t> (str.length()), | |||
| &hstr); | |||
| } | |||
| ~ScopedHString() | |||
| { | |||
| if (WinRTWrapper::getInstance()->isInitialised() && hstr != nullptr) | |||
| WinRTWrapper::getInstance()->deleteHString (hstr); | |||
| } | |||
| HSTRING get() const noexcept | |||
| { | |||
| return hstr; | |||
| } | |||
| private: | |||
| HSTRING hstr = nullptr; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ScopedHString) | |||
| }; | |||
| ~WinRTWrapper() | |||
| { | |||
| if (winRTHandle != nullptr) | |||
| ::FreeLibrary (winRTHandle); | |||
| } | |||
| String hStringToString (HSTRING hstr) | |||
| { | |||
| const wchar_t* str = nullptr; | |||
| if (isInitialised()) | |||
| { | |||
| str = getHStringRawBuffer (hstr, nullptr); | |||
| if (str != nullptr) | |||
| return String (str); | |||
| } | |||
| return {}; | |||
| } | |||
| bool isInitialised() const noexcept | |||
| { | |||
| return initialised; | |||
| } | |||
| template <class ComClass> | |||
| ComSmartPtr<ComClass> getWRLFactory (const wchar_t* runtimeClassID) | |||
| { | |||
| ComSmartPtr<ComClass> comPtr; | |||
| if (isInitialised()) | |||
| { | |||
| ScopedHString classID (runtimeClassID); | |||
| if (classID.get() != nullptr) | |||
| roGetActivationFactory (classID.get(), __uuidof (ComClass), (void**) comPtr.resetAndGetPointerAddress()); | |||
| } | |||
| return comPtr; | |||
| } | |||
| private: | |||
| WinRTWrapper() | |||
| { | |||
| winRTHandle = ::LoadLibraryA ("api-ms-win-core-winrt-l1-1-0"); | |||
| if (winRTHandle == nullptr) | |||
| return; | |||
| roInitialize = (RoInitializeFuncPtr) ::GetProcAddress (winRTHandle, "RoInitialize"); | |||
| createHString = (WindowsCreateStringFuncPtr) ::GetProcAddress (winRTHandle, "WindowsCreateString"); | |||
| deleteHString = (WindowsDeleteStringFuncPtr) ::GetProcAddress (winRTHandle, "WindowsDeleteString"); | |||
| getHStringRawBuffer = (WindowsGetStringRawBufferFuncPtr) ::GetProcAddress (winRTHandle, "WindowsGetStringRawBuffer"); | |||
| roGetActivationFactory = (RoGetActivationFactoryFuncPtr) ::GetProcAddress (winRTHandle, "RoGetActivationFactory"); | |||
| if (roInitialize == nullptr || createHString == nullptr || deleteHString == nullptr | |||
| || getHStringRawBuffer == nullptr || roGetActivationFactory == nullptr) | |||
| return; | |||
| HRESULT status = roInitialize (1); | |||
| initialised = ! (status != S_OK && status != S_FALSE && status != 0x80010106L); | |||
| } | |||
| HMODULE winRTHandle = nullptr; | |||
| bool initialised = false; | |||
| typedef HRESULT (WINAPI* RoInitializeFuncPtr) (int); | |||
| typedef HRESULT (WINAPI* WindowsCreateStringFuncPtr) (LPCWSTR, UINT32, HSTRING*); | |||
| typedef HRESULT (WINAPI* WindowsDeleteStringFuncPtr) (HSTRING); | |||
| typedef PCWSTR (WINAPI* WindowsGetStringRawBufferFuncPtr) (HSTRING, UINT32*); | |||
| typedef HRESULT (WINAPI* RoGetActivationFactoryFuncPtr) (HSTRING, REFIID, void**); | |||
| RoInitializeFuncPtr roInitialize = nullptr; | |||
| WindowsCreateStringFuncPtr createHString = nullptr; | |||
| WindowsDeleteStringFuncPtr deleteHString = nullptr; | |||
| WindowsGetStringRawBufferFuncPtr getHStringRawBuffer = nullptr; | |||
| RoGetActivationFactoryFuncPtr roGetActivationFactory = nullptr; | |||
| }; | |||