Browse Source

BLOCKS: Use unique identifier to find MIDI ports and fix some connection issues

tags/2021-05-28
ed 6 years ago
parent
commit
fcbdf0629f
7 changed files with 131 additions and 54 deletions
  1. +11
    -2
      modules/juce_blocks_basics/blocks/juce_Block.h
  2. +29
    -9
      modules/juce_blocks_basics/topology/internal/juce_BlockImplementation.cpp
  3. +11
    -4
      modules/juce_blocks_basics/topology/internal/juce_ConnectedDeviceGroup.cpp
  4. +1
    -1
      modules/juce_blocks_basics/topology/internal/juce_DepreciatedVersionReader.cpp
  5. +14
    -4
      modules/juce_blocks_basics/topology/internal/juce_Detector.cpp
  6. +62
    -21
      modules/juce_blocks_basics/topology/internal/juce_MIDIDeviceDetector.cpp
  7. +3
    -13
      modules/juce_blocks_basics/topology/internal/juce_MidiDeviceConnection.cpp

+ 11
- 2
modules/juce_blocks_basics/blocks/juce_Block.h View File

@@ -110,14 +110,23 @@ public:
/** Returns the time this block object was connected to the topology.
Only valid when isConnected == true.
@see isConnected
@see Block::isConnected
*/
virtual Time getConnectionTime() const = 0;
/** Returns true if this block or the master block this block is connected to,
is connected via bluetooth.
Only valid when isConnected == true.
@see Block::isConnected, Block::isMasterBlock
*/
virtual bool isConnectedViaBluetooth() const = 0;
/** Returns true if this block is directly connected to the application,
as opposed to only being connected to a different block via a connection port.
@see ConnectionPort
@see Block::ConnectionPort
*/
virtual bool isMasterBlock() const = 0;


+ 29
- 9
modules/juce_blocks_basics/topology/internal/juce_BlockImplementation.cpp View File

@@ -63,11 +63,7 @@ public:
~BlockImplementation()
{
if (listenerToMidiConnection != nullptr)
{
config.setDeviceComms (nullptr);
listenerToMidiConnection->removeListener (this);
}
markDisconnected();
}
void markDisconnected()
@@ -75,6 +71,7 @@ public:
if (auto surface = dynamic_cast<TouchSurfaceImplementation*> (touchSurface.get()))
surface->disableTouchSurface();
disconnectMidiConnectionListener();
connectionTime = Time();
}
@@ -121,6 +118,32 @@ public:
config.setDeviceComms (listenerToMidiConnection);
}
void disconnectMidiConnectionListener()
{
if (listenerToMidiConnection != nullptr)
{
config.setDeviceComms (nullptr);
listenerToMidiConnection->removeListener (this);
listenerToMidiConnection = nullptr;
}
}
bool isConnected() const override
{
if (detector != nullptr)
return detector->isConnected (uid);
return false;
}
bool isConnectedViaBluetooth() const override
{
if (detector != nullptr)
return detector->isConnectedViaBluetooth (*this);
return false;
}
Type getType() const override { return modelData.apiType; }
String getDeviceDescription() const override { return modelData.description; }
int getWidth() const override { return modelData.widthUnits; }
@@ -128,7 +151,6 @@ public:
float getMillimetersPerUnit() const override { return 47.0f; }
bool isHardwareBlock() const override { return true; }
juce::Array<Block::ConnectionPort> getPorts() const override { return modelData.ports; }
bool isConnected() const override { return detector && detector->isConnected (uid); }
Time getConnectionTime() const override { return connectionTime; }
bool isMasterBlock() const override { return isMaster; }
Block::UID getConnectedMasterUID() const override { return masterUID; }
@@ -696,9 +718,7 @@ private:
{
jassert (listenerToMidiConnection == &c);
ignoreUnused (c);
listenerToMidiConnection->removeListener (this);
listenerToMidiConnection = nullptr;
config.setDeviceComms (nullptr);
disconnectMidiConnectionListener();
}
void doSaveProgramAsDefault()


+ 11
- 4
modules/juce_blocks_basics/topology/internal/juce_ConnectedDeviceGroup.cpp View File

@@ -41,8 +41,6 @@ struct ConnectedDeviceGroup : private AsyncUpdater,
{
if (auto midiDeviceConnection = static_cast<MIDIDeviceConnection*> (deviceConnection.get()))
{
depreciatedVersionReader = std::make_unique<DepreciatedVersionReader> (*midiDeviceConnection);
ScopedLock lock (midiDeviceConnection->criticalSecton);
setMidiMessageCallback();
}
@@ -300,7 +298,8 @@ private:
struct TouchStart { float x, y; };
TouchList<TouchStart> touchStartPositions;
Block::UID masterBlock = 0;
static constexpr Block::UID invalidUid = 0;
Block::UID masterBlock = invalidUid;
//==============================================================================
void timerCallback() override
@@ -499,6 +498,9 @@ private:
removeDevice (uid);
if (uid == masterBlock)
masterBlock = invalidUid;
scheduleNewTopologyRequest();
}
@@ -643,9 +645,14 @@ private:
if (! getDeviceInfoFromUID (uid))
{
// For backwards compatibility we assume the first device we see in a group is the master and won't change
if (masterBlock == 0)
if (masterBlock == invalidUid)
{
masterBlock = uid;
if (auto midiDeviceConnection = static_cast<MIDIDeviceConnection*> (deviceConnection.get()))
depreciatedVersionReader = std::make_unique<DepreciatedVersionReader> (*midiDeviceConnection);
}
currentDeviceInfo.add ({ uid,
device.index,
device.serialNumber,


+ 1
- 1
modules/juce_blocks_basics/topology/internal/juce_DepreciatedVersionReader.cpp View File

@@ -24,7 +24,7 @@ namespace juce
{
/**
Firmware below 0.2.5 does not report its version over the Blocks API.
Firmware below 0.3.0 does not report its version over the Blocks API.
This class can make requests and process responses to retreive the master Block version.
*/
class DepreciatedVersionReader : private MIDIDeviceConnection::Listener,


+ 14
- 4
modules/juce_blocks_basics/topology/internal/juce_Detector.cpp View File

@@ -94,6 +94,16 @@ struct Detector : public ReferenceCountedObject,
return false;
}
bool isConnectedViaBluetooth (const Block& block) const noexcept
{
if (const auto connection = getDeviceConnectionFor (block))
if (const auto midiConnection = dynamic_cast<const MIDIDeviceConnection*> (connection))
if (midiConnection->midiInput != nullptr)
return midiConnection->midiInput->getName().containsIgnoreCase ("bluetooth");
return false;
}
void handleDeviceAdded (const DeviceInfo& info)
{
JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
@@ -146,9 +156,9 @@ struct Detector : public ReferenceCountedObject,
if (blockIt != currentTopology.blocks.end())
{
const auto block = *blockIt;
const Block::Ptr block { *blockIt };
if (auto blockImpl = BlockImpl::getFrom (block))
if (auto blockImpl = BlockImpl::getFrom (block.get()))
blockImpl->markDisconnected();
currentTopology.blocks.removeObject (block);
@@ -177,9 +187,9 @@ struct Detector : public ReferenceCountedObject,
if (blockIt != currentTopology.blocks.end())
{
const auto block = *blockIt;
const Block::Ptr block { *blockIt };
if (auto blockImpl = BlockImpl::getFrom (block))
if (auto blockImpl = BlockImpl::getFrom (block.get()))
blockImpl->markReconnected (info);
if (! containsBlockWithUID (blocksToAdd, info.uid))


+ 62
- 21
modules/juce_blocks_basics/topology/internal/juce_MIDIDeviceDetector.cpp View File

@@ -32,25 +32,27 @@ struct MIDIDeviceDetector : public PhysicalTopologySource::DeviceDetector
StringArray result;
for (auto& pair : findDevices())
result.add (pair.inputName + " & " + pair.outputName);
result.add (pair.input.identifier + " & " + pair.output.identifier);
return result;
}
PhysicalTopologySource::DeviceConnection* openDevice (int index) override
{
auto pair = findDevices()[index];
const auto allDevices = findDevices();
if (pair.inputIndex >= 0 && pair.outputIndex >= 0)
if (allDevices.size() > index)
{
std::unique_ptr<MIDIDeviceConnection> dev (new MIDIDeviceConnection());
const auto pair = allDevices[index];
auto dev = std::make_unique<MIDIDeviceConnection>();
if (dev->lockAgainstOtherProcesses (pair.inputName, pair.outputName))
if (auto lock = createMidiPortLock (pair.input.name, pair.output.name))
{
lockedFromOutside = false;
dev->midiInput.reset (MidiInput::openDevice (pair.inputIndex, dev.get()));
dev->midiOutput.reset (MidiOutput::openDevice (pair.outputIndex));
dev->setLockAgainstOtherProcesses (lock);
dev->midiInput.reset (MidiInput::openDevice (pair.input.identifier, dev.get()));
dev->midiOutput.reset (MidiOutput::openDevice (pair.output.identifier));
if (dev->midiInput != nullptr)
{
@@ -96,33 +98,43 @@ struct MIDIDeviceDetector : public PhysicalTopologySource::DeviceDetector
struct MidiInputOutputPair
{
String outputName, inputName;
int outputIndex = -1, inputIndex = -1;
MidiDeviceInfo input, output;
};
static Array<MidiInputOutputPair> findDevices()
{
Array<MidiInputOutputPair> result;
auto midiInputs = MidiInput::getDevices();
auto midiOutputs = MidiOutput::getDevices();
auto midiInputs = MidiInput::getAvailableDevices();
auto midiOutputs = MidiOutput::getAvailableDevices();
for (int j = 0; j < midiInputs.size(); ++j)
for (const auto& input : midiInputs)
{
if (isBlocksMidiDeviceName (midiInputs[j]))
if (isBlocksMidiDeviceName (input.name))
{
MidiInputOutputPair pair;
pair.inputName = midiInputs[j];
pair.inputIndex = j;
pair.input = input;
String cleanedInputName = cleanBlocksDeviceName (pair.inputName);
for (int i = 0; i < midiOutputs.size(); ++i)
String cleanedInputName = cleanBlocksDeviceName (input.name);
int inputOccurences = 0;
int outputOccurences = 0;
for (const auto& p : result)
if (cleanBlocksDeviceName (p.input.name) == cleanedInputName)
++inputOccurences;
for (const auto& output : midiOutputs)
{
if (cleanBlocksDeviceName (midiOutputs[i]) == cleanedInputName)
if (cleanBlocksDeviceName (output.name) == cleanedInputName)
{
pair.outputName = midiOutputs[i];
pair.outputIndex = i;
break;
if (outputOccurences == inputOccurences)
{
pair.output = output;
break;
}
++outputOccurences;
}
}
@@ -136,6 +148,35 @@ struct MIDIDeviceDetector : public PhysicalTopologySource::DeviceDetector
private:
bool lockedFromOutside = true;
/** For backwards compatibility, the block interprocess lock has to use the midi input name.
The below is necceccary because blocks of the same type might duplicate a port name, so
must share an interporcess lock.
*/
std::shared_ptr<InterProcessLock> createMidiPortLock (const String& midiInName, const String& midiOutName)
{
const juce::String lockIdentifier = "blocks_sdk_"
+ File::createLegalFileName (midiInName)
+ "_" + File::createLegalFileName (midiOutName);
const auto existingLock = midiPortLocks.find (lockIdentifier);
if (existingLock != midiPortLocks.end())
if (existingLock->second.use_count() > 0)
return existingLock->second.lock();
auto interprocessLock = std::make_shared<InterProcessLock> (lockIdentifier);
if (interprocessLock->enter (500))
{
midiPortLocks[lockIdentifier] = interprocessLock;
return interprocessLock;
}
return nullptr;
}
std::map<juce::String, std::weak_ptr<InterProcessLock>> midiPortLocks;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MIDIDeviceDetector)
};


+ 3
- 13
modules/juce_blocks_basics/topology/internal/juce_MidiDeviceConnection.cpp View File

@@ -36,21 +36,11 @@ struct MIDIDeviceConnection : public PhysicalTopologySource::DeviceConnection,
if (midiInput != nullptr)
midiInput->stop();
if (interprocessLock != nullptr)
interprocessLock->exit();
}
bool lockAgainstOtherProcesses (const String& midiInName, const String& midiOutName)
void setLockAgainstOtherProcesses (std::shared_ptr<InterProcessLock> newLock)
{
interprocessLock.reset (new InterProcessLock ("blocks_sdk_"
+ File::createLegalFileName (midiInName)
+ "_" + File::createLegalFileName (midiOutName)));
if (interprocessLock->enter (500))
return true;
interprocessLock = nullptr;
return false;
midiPortLock = newLock;
}
struct Listener
@@ -115,7 +105,7 @@ struct MIDIDeviceConnection : public PhysicalTopologySource::DeviceConnection,
private:
ListenerList<Listener> listeners;
std::unique_ptr<InterProcessLock> interprocessLock;
std::shared_ptr<InterProcessLock> midiPortLock;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MIDIDeviceConnection)
};


Loading…
Cancel
Save