| @@ -43,6 +43,14 @@ | |||||
| #define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 | #define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 | ||||
| #define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 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" | #include "juce_audio_devices.h" | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -70,6 +78,30 @@ | |||||
| #include <mmreg.h> | #include <mmreg.h> | ||||
| #endif | #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 | #if JUCE_ASIO | ||||
| /* This is very frustrating - we only need to use a handful of definitions from | /* 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 | a couple of the header files in Steinberg's ASIO SDK, and it'd be easy to copy | ||||
| @@ -123,6 +123,26 @@ | |||||
| #endif | #endif | ||||
| #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 | namespace juce | ||||
| { | { | ||||
| @@ -172,7 +172,7 @@ public: | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| String name; | String name; | ||||
| void* internal; | |||||
| void* internal = nullptr; | |||||
| // The input objects are created with the openDevice() method. | // The input objects are created with the openDevice() method. | ||||
| explicit MidiInput (const String&); | explicit MidiInput (const String&); | ||||
| @@ -38,7 +38,7 @@ struct MidiOutput::PendingMessage | |||||
| PendingMessage* next; | PendingMessage* next; | ||||
| }; | }; | ||||
| MidiOutput::MidiOutput(const String& midiName) | |||||
| MidiOutput::MidiOutput (const String& midiName) | |||||
| : Thread ("midi out"), | : Thread ("midi out"), | ||||
| internal (nullptr), | internal (nullptr), | ||||
| firstMessage (nullptr), | firstMessage (nullptr), | ||||
| @@ -136,13 +136,13 @@ public: | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| void* internal; | |||||
| void* internal = nullptr; | |||||
| CriticalSection lock; | CriticalSection lock; | ||||
| struct PendingMessage; | struct PendingMessage; | ||||
| PendingMessage* firstMessage; | PendingMessage* firstMessage; | ||||
| String name; | 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; | void run() override; | ||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutput) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutput) | ||||
| @@ -233,6 +233,23 @@ struct PhysicalTopologySource::Internal | |||||
| return name.indexOf (" BLOCK") > 0 || name.indexOf (" Block") > 0; | 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 | struct MidiInputOutputPair | ||||
| { | { | ||||
| juce::String outputName, inputName; | juce::String outputName, inputName; | ||||
| @@ -254,9 +271,10 @@ struct PhysicalTopologySource::Internal | |||||
| pair.inputName = midiInputs[j]; | pair.inputName = midiInputs[j]; | ||||
| pair.inputIndex = j; | pair.inputIndex = j; | ||||
| String cleanedInputName = cleanBlocksDeviceName (pair.inputName); | |||||
| for (int i = 0; i < midiOutputs.size(); ++i) | 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.outputName = midiOutputs[i]; | ||||
| pair.outputIndex = i; | pair.outputIndex = i; | ||||
| @@ -40,8 +40,13 @@ | |||||
| #define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 | #define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 | ||||
| #define JUCE_CORE_INCLUDE_JNI_HELPERS 1 | #define JUCE_CORE_INCLUDE_JNI_HELPERS 1 | ||||
| #define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 | #define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 | ||||
| #define JUCE_CORE_INCLUDE_COM_SMART_PTR 1 | |||||
| #define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 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" | #include "juce_events.h" | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -84,6 +89,9 @@ namespace juce | |||||
| #elif JUCE_WINDOWS | #elif JUCE_WINDOWS | ||||
| #include "native/juce_win32_Messaging.cpp" | #include "native/juce_win32_Messaging.cpp" | ||||
| #if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER | |||||
| #include "native/juce_win32_WinRTWrapper.cpp" | |||||
| #endif | |||||
| #elif JUCE_LINUX | #elif JUCE_LINUX | ||||
| #include "native/juce_linux_Messaging.cpp" | #include "native/juce_linux_Messaging.cpp" | ||||
| @@ -55,9 +55,12 @@ | |||||
| #pragma once | #pragma once | ||||
| #define JUCE_EVENTS_H_INCLUDED | #define JUCE_EVENTS_H_INCLUDED | ||||
| //============================================================================== | |||||
| #include <juce_core/juce_core.h> | #include <juce_core/juce_core.h> | ||||
| #if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER && JUCE_WINDOWS | |||||
| #include <hstring.h> | |||||
| #endif | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| @@ -86,8 +89,13 @@ namespace juce | |||||
| #endif | #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 | #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; | |||||
| }; | |||||