Browse Source

Added experimental WinRT MIDI support, enabling BLE MIDI on machines with Windows 10 Anniversary Update installed

tags/2021-05-28
tpoole 8 years ago
parent
commit
9a38505dad
11 changed files with 1313 additions and 322 deletions
  1. +32
    -0
      modules/juce_audio_devices/juce_audio_devices.cpp
  2. +20
    -0
      modules/juce_audio_devices/juce_audio_devices.h
  3. +1
    -1
      modules/juce_audio_devices/midi_io/juce_MidiInput.h
  4. +1
    -1
      modules/juce_audio_devices/midi_io/juce_MidiOutput.cpp
  5. +2
    -2
      modules/juce_audio_devices/midi_io/juce_MidiOutput.h
  6. +1048
    -314
      modules/juce_audio_devices/native/juce_win32_Midi.cpp
  7. +19
    -1
      modules/juce_blocks_basics/topology/juce_PhysicalTopologySource.cpp
  8. +8
    -0
      modules/juce_events/juce_events.cpp
  9. +11
    -3
      modules/juce_events/juce_events.h
  10. +31
    -0
      modules/juce_events/native/juce_win32_WinRTWrapper.cpp
  11. +140
    -0
      modules/juce_events/native/juce_win32_WinRTWrapper.h

+ 32
- 0
modules/juce_audio_devices/juce_audio_devices.cpp View File

@@ -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


+ 20
- 0
modules/juce_audio_devices/juce_audio_devices.h View File

@@ -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
{


+ 1
- 1
modules/juce_audio_devices/midi_io/juce_MidiInput.h View File

@@ -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&);


+ 1
- 1
modules/juce_audio_devices/midi_io/juce_MidiOutput.cpp View File

@@ -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),


+ 2
- 2
modules/juce_audio_devices/midi_io/juce_MidiOutput.h View File

@@ -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)


+ 1048
- 314
modules/juce_audio_devices/native/juce_win32_Midi.cpp
File diff suppressed because it is too large
View File


+ 19
- 1
modules/juce_blocks_basics/topology/juce_PhysicalTopologySource.cpp View File

@@ -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;


+ 8
- 0
modules/juce_events/juce_events.cpp View File

@@ -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"


+ 11
- 3
modules/juce_events/juce_events.h View File

@@ -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
- 0
modules/juce_events/native/juce_win32_WinRTWrapper.cpp View 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
- 0
modules/juce_events/native/juce_win32_WinRTWrapper.h View 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…
Cancel
Save