Browse Source

macOS: Added a Bluetooth MIDI pairing dialog

tags/2021-05-28
Tom Poole 6 years ago
parent
commit
0828977e5b
4 changed files with 162 additions and 8 deletions
  1. +5
    -5
      modules/juce_audio_utils/gui/juce_BluetoothMidiDevicePairingDialogue.h
  2. +1
    -0
      modules/juce_audio_utils/juce_audio_utils.cpp
  3. +1
    -1
      modules/juce_audio_utils/juce_audio_utils.h
  4. +155
    -2
      modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm

+ 5
- 5
modules/juce_audio_utils/gui/juce_BluetoothMidiDevicePairingDialogue.h View File

@@ -37,11 +37,11 @@ namespace juce
Only after a Bluetooth MIDI device has been paired will its MIDI ports
be available through JUCE's MidiInput and MidiOutput classes.
This dialogue is currently only available on iOS and Android. On OSX,
you should instead pair Bluetooth MIDI devices using the "Audio MIDI Setup"
app (located in /Applications/Utilities). On Windows, you should use
the system settings. On Linux, Bluetooth MIDI devices are currently not
supported.
This dialogue is currently only available on macOS targetting versions 10.11+,
iOS and Android. When targeting older versions of macOS you should instead
pair Bluetooth MIDI devices using the "Audio MIDI Setup" app (located in
/Applications/Utilities). On Windows, you should use the system settings. On
Linux, Bluetooth MIDI devices are currently not supported.
@tags{Audio}
*/


+ 1
- 0
modules/juce_audio_utils/juce_audio_utils.cpp View File

@@ -43,6 +43,7 @@
#if JUCE_MAC
#import <DiscRecording/DiscRecording.h>
#import <CoreAudioKit/CABTLEMIDIWindowController.h>
#elif JUCE_WINDOWS
#if JUCE_USE_CDBURNER
/* You'll need the Platform SDK for these headers - if you don't have it and don't


+ 1
- 1
modules/juce_audio_utils/juce_audio_utils.h View File

@@ -42,7 +42,7 @@
license: GPL/Commercial
dependencies: juce_gui_extra, juce_audio_processors, juce_audio_formats, juce_audio_devices
OSXFrameworks: DiscRecording
OSXFrameworks: CoreAudioKit DiscRecording
iOSFrameworks: CoreAudioKit
END_JUCE_MODULE_DECLARATION


+ 155
- 2
modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm View File

@@ -27,12 +27,163 @@
namespace juce
{
#if defined (MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
//==============================================================================
class BluetoothMidiPairingWindowClass : public ObjCClass<NSObject>
{
public:
struct Callbacks
{
std::unique_ptr<ModalComponentManager::Callback> modalExit;
std::function<void()> windowClosed;
};
BluetoothMidiPairingWindowClass() : ObjCClass<NSObject> ("JUCEBluetoothMidiPairingWindowClass_")
{
addIvar<Callbacks*> ("callbacks");
addIvar<CABTLEMIDIWindowController*> ("controller");
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
addMethod (@selector (initWithCallbacks:), initWithCallbacks, "@@:^v");
addMethod (@selector (show:), show, "v@:^v");
addMethod (@selector (receivedWindowWillClose:), receivedWindowWillClose, "v@:^v");
#pragma clang diagnostic pop
addMethod (@selector (dealloc), dealloc, "v@:");
registerClass();
}
private:
static CABTLEMIDIWindowController* getController (id self)
{
return getIvar<CABTLEMIDIWindowController*> (self, "controller");
}
static id initWithCallbacks (id self, SEL, Callbacks* cbs)
{
self = sendSuperclassMessage (self, @selector (init));
object_setInstanceVariable (self, "callbacks", cbs);
object_setInstanceVariable (self, "controller", [CABTLEMIDIWindowController new]);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector (receivedWindowWillClose:)
name: @"NSWindowWillCloseNotification"
object: [getController (self) window]];
#pragma clang diagnostic pop
return self;
}
static void dealloc (id self, SEL)
{
[getController (self) release];
sendSuperclassMessage (self, @selector (dealloc));
}
static void show (id self, SEL, Rectangle<int>* bounds)
{
if (bounds != nullptr)
{
auto nsBounds = makeNSRect (*bounds);
auto mainScreenHeight = []
{
if ([[NSScreen screens] count] == 0)
return (CGFloat) 0.0f;
return [[[NSScreen screens] objectAtIndex: 0] frame].size.height;
}();
nsBounds.origin.y = mainScreenHeight - (nsBounds.origin.y + nsBounds.size.height);
[getController (self).window setFrame: nsBounds
display: YES];
}
[getController (self) showWindow: nil];
}
static void receivedWindowWillClose (id self, SEL, NSNotification*)
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
auto* cbs = getIvar<Callbacks*> (self, "callbacks");
if (cbs->modalExit != nullptr)
cbs->modalExit->modalStateFinished (0);
cbs->windowClosed();
}
};
class BluetoothMidiSelectorWindowHelper : public DeletedAtShutdown
{
public:
BluetoothMidiSelectorWindowHelper (ModalComponentManager::Callback* exitCallback,
Rectangle<int>* bounds)
{
std::unique_ptr<ModalComponentManager::Callback> exitCB (exitCallback);
static BluetoothMidiPairingWindowClass cls;
window.reset (cls.createInstance());
WeakReference<BluetoothMidiSelectorWindowHelper> safeThis (this);
auto deletionCB = [=]
{
if (auto* t = safeThis.get())
delete t;
};
callbacks.reset (new BluetoothMidiPairingWindowClass::Callbacks { std::move (exitCB),
std::move (deletionCB) });
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
[window.get() performSelector: @selector (initWithCallbacks:)
withObject: (id) callbacks.get()];
[window.get() performSelector: @selector (show:)
withObject: (id) bounds];
#pragma clang diagnostic pop
}
private:
std::unique_ptr<NSObject, NSObjectDeleter> window;
std::unique_ptr<BluetoothMidiPairingWindowClass::Callbacks> callbacks;
JUCE_DECLARE_WEAK_REFERENCEABLE (BluetoothMidiSelectorWindowHelper)
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BluetoothMidiSelectorWindowHelper)
};
//==============================================================================
bool BluetoothMidiDevicePairingDialogue::open (ModalComponentManager::Callback* exitCallback,
Rectangle<int>* bounds)
{
new BluetoothMidiSelectorWindowHelper (exitCallback, bounds);
return true;
}
bool BluetoothMidiDevicePairingDialogue::isAvailable()
{
return true;
}
#else
bool BluetoothMidiDevicePairingDialogue::open (ModalComponentManager::Callback* exitCallback,
Rectangle<int>*)
{
std::unique_ptr<ModalComponentManager::Callback> cb (exitCallback);
// Do not call this on OSX. Instead, you should pair Bluetooth MIDI devices
// using the "Audio MIDI Setup" app (located in /Applications/Utilities).
// This functionality is unavailable when targetting OSX < 10.11. Instead,
// you should pair Bluetooth MIDI devices using the "Audio MIDI Setup" app
// (located in /Applications/Utilities).
jassertfalse;
return false;
}
@@ -42,4 +193,6 @@ bool BluetoothMidiDevicePairingDialogue::isAvailable()
return false;
}
#endif
} // namespace juce

Loading…
Cancel
Save