mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Added experimental WinRT MIDI support, enabling BLE MIDI on machines with Windows 10 Anniversary Update installed
This commit is contained in:
parent
78bbe49616
commit
9a38505dad
11 changed files with 1377 additions and 386 deletions
|
|
@ -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)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
|||
31
modules/juce_events/native/juce_win32_WinRTWrapper.cpp
Normal file
31
modules/juce_events/native/juce_win32_WinRTWrapper.cpp
Normal file
|
|
@ -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)
|
||||
140
modules/juce_events/native/juce_win32_WinRTWrapper.h
Normal file
140
modules/juce_events/native/juce_win32_WinRTWrapper.h
Normal file
|
|
@ -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;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue