1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-09 23:34:20 +00:00

MIDI-CI: Simplify profile enablement API, and ensure that group/block member channels are always 0

This commit is contained in:
reuk 2024-01-02 15:39:59 +00:00
parent fac6f4cb20
commit 1506bb3454
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
8 changed files with 103 additions and 55 deletions

View file

@ -2,6 +2,26 @@
# develop
## Change
ProfileHost::enableProfile and ProfileHost::disableProfile have been combined
into a single function, ProfileHost::setProfileEnablement.
**Possible Issues**
Code that calls this function will fail to compile until it is updated.
**Workaround**
To enable a profile, call setProfileEnablement with a positive number of
channels. To disable a profile, call setProfileEnablement with zero channels.
**Rationale**
The new API is simpler, more compact, and more consistent, as it now mirrors
the signature of Device::sendProfileEnablement.
## Change
OpenGLContext::getRenderingScale() has been changed to include the effects of
@ -98,12 +118,12 @@ and FormatOptions::getMaxDecimalPlaces() as necessary. To find whether the outpu
should be multi-line, compare the result of FormatOptions::getSpacing() with
JSON::Spacing::multiLine.
Callers of the function can construct the new argument type using the old
Callers of the function can construct the new argument type using the old
arguments accordingly
```
JSON::FormatOptions{}.withIndentLevel (indentLevel)
.withSpacing (allOnOneLine ? JSON::Spacing::singleLine
.withSpacing (allOnOneLine ? JSON::Spacing::singleLine
: JSON::Spacing::multiLine)
.withMaxDecimalPlaces (maximumDecimalPlaces);
```
@ -119,7 +139,7 @@ FormatOptions type, which will not be a breaking change.
## Change
CachedValue::operator==() will now emit floating point comparison warnings if
CachedValue::operator==() will now emit floating point comparison warnings if
they are enabled for the project.
**Possible Issues**
@ -135,7 +155,7 @@ CachedValue::get().
**Rationale**
The JUCE Framework now offers the free-standing exactlyEqual() and
The JUCE Framework now offers the free-standing exactlyEqual() and
approximatelyEqual() functions to clearly express the desired semantics when
comparing floating point values. These functions are intended to eliminate
the ambiguity in code-bases regarding these types. However, when such a value

View file

@ -4088,10 +4088,7 @@ private:
else
h->addProfile (profileAtAddress, state.supported);
if (state.active == 0)
h->disableProfile (profileAtAddress);
else
h->enableProfile (profileAtAddress, state.active);
h->setProfileEnablement (profileAtAddress, state.active);
}
}
@ -4589,12 +4586,9 @@ private:
if (auto* host = demo.getProfileHost())
{
if (enabled)
host->enableProfile (profileAtAddress, numChannels);
else
host->disableProfile (profileAtAddress);
profiles.channels[profileAtAddress].active = (uint16_t) numChannels;
const auto count = enabled ? jmax (1, numChannels) : 0;
host->setProfileEnablement (profileAtAddress, count);
profiles.channels[profileAtAddress].active = (uint16_t) count;
state = profiles;
}

View file

@ -151,11 +151,15 @@ public:
if (numChannels > 0)
{
const auto channelsToSend = address == ChannelInGroup::wholeBlock || address == ChannelInGroup::wholeGroup
? 0
: numChannels;
detail::MessageTypeUtils::send (concreteBufferOutput,
options.getFunctionBlock().firstGroup,
m,
address,
Message::ProfileOn { profile, (uint16_t) numChannels });
Message::ProfileOn { profile, (uint16_t) channelsToSend });
}
else
{
@ -1045,7 +1049,7 @@ private:
return iter != device.discovered.end() ? jmin (defaultResult, (int) iter->second.discovery.maximumSysexSize) : defaultResult;
}
public:
private:
Impl& device;
};
@ -1062,13 +1066,10 @@ private:
if (! device.profileHost.has_value())
return;
if (enabled)
device.profileHost->enableProfile (profileAtAddress, numChannels);
else
device.profileHost->disableProfile (profileAtAddress);
device.profileHost->setProfileEnablement (profileAtAddress, enabled ? jmax (1, numChannels) : 0);
}
public:
private:
Impl& device;
};
@ -1127,7 +1128,7 @@ private:
d->subscriptionWillEnd (m, subscription);
}
public:
private:
Impl& device;
};
@ -1755,8 +1756,7 @@ public:
beginTest ("If a device has previously acted as a responder to profile inquiry, then modifying profiles emits events");
{
const auto numChannels = 0;
device.getProfileHost()->enableProfile ({ profile, ChannelAddress{}.withChannel (ChannelInGroup::wholeBlock) }, numChannels);
device.getProfileHost()->setProfileEnablement ({ profile, ChannelAddress{}.withChannel (ChannelInGroup::wholeBlock) }, 1);
expect (output.messages.size() == 2);
expect (output.messages.back().bytes == getMessageBytes ({ ChannelInGroup::wholeBlock,
@ -1764,7 +1764,7 @@ public:
detail::MessageMeta::implementationVersion,
device.getMuid(),
MUID::getBroadcast() },
Message::ProfileEnabledReport { profile, numChannels }));
Message::ProfileEnabledReport { profile, 0 }));
}
}
@ -1834,7 +1834,7 @@ public:
detail::MessageMeta::implementationVersion,
inquiryMUID,
device.getMuid() },
Message::ProfileOn { profile, 1 }) });
Message::ProfileOn { profile, 0 }) });
expect (output.messages.size() == 1);
expect (output.messages.back().bytes == getMessageBytes ({ ChannelInGroup::wholeBlock,
@ -1842,7 +1842,7 @@ public:
detail::MessageMeta::implementationVersion,
device.getMuid(),
MUID::getBroadcast() },
Message::ProfileEnabledReport { profile, 1 }));
Message::ProfileEnabledReport { profile, 0 }));
}
struct DoNothingProfileDelegate : public ProfileDelegate
@ -1950,7 +1950,7 @@ public:
std::byte { 0x05 } };
device.getProfileHost()->addProfile ({ profile, ChannelAddress{}.withChannel (ChannelInGroup::wholeBlock) });
device.getProfileHost()->enableProfile ({ profile, ChannelAddress{}.withChannel (ChannelInGroup::wholeBlock) }, 0);
device.getProfileHost()->setProfileEnablement ({ profile, ChannelAddress{}.withChannel (ChannelInGroup::wholeBlock) }, 0);
const auto inquiryMUID = MUID::makeRandom (random);
@ -1991,7 +1991,7 @@ public:
std::byte { 0x05 } };
device.getProfileHost()->addProfile ({ profile, ChannelAddress{}.withChannel (ChannelInGroup::wholeBlock) });
device.getProfileHost()->enableProfile ({ profile, ChannelAddress{}.withChannel (ChannelInGroup::wholeBlock) }, 1);
device.getProfileHost()->setProfileEnablement ({ profile, ChannelAddress{}.withChannel (ChannelInGroup::wholeBlock) }, 1);
const auto inquiryMUID = MUID::makeRandom (random);
@ -2008,7 +2008,7 @@ public:
detail::MessageMeta::implementationVersion,
device.getMuid(),
MUID::getBroadcast() },
Message::ProfileEnabledReport { profile, 1 }));
Message::ProfileEnabledReport { profile, 0 }));
}
beginTest ("If a device receives a set profile off for an unsupported profile, NAK is emitted");

View file

@ -127,6 +127,12 @@ public:
void sendProfileSpecificData (MUID muid, ChannelInGroup address, Profile profile, Span<const std::byte>);
/** Sets a profile on or off. Pass 0 or less to disable the profile, or a positive number to enable it.
This also goes for group/block profiles. If the request is addressed to a group/block, then
a positive number will cause a "profile on" message to be sent, and a non-positive number
will cause a "profile off" message to be sent. The channel count of the sent message will
always be zero for messages addressed to groups/blocks.regardless of the value of the
numChannels argument.
*/
void sendProfileEnablement (MUID muid, ChannelInGroup address, Profile profile, int numChannels);

View file

@ -47,6 +47,10 @@ struct ProfileDelegate
is enabled with zero channels active - in this situation, it is
recommended that you use ProfileHost::enableProfile to enable the
default number of channels for that profile.
Additionally, profiles for entire groups or function blocks may be enabled with zero
active channels. In this case, the profile should be enabled on the entire group or
function block.
*/
virtual void profileEnablementRequested ([[maybe_unused]] MUID x,
[[maybe_unused]] ProfileAtAddress profileAtAddress,

View file

@ -136,11 +136,11 @@ private:
.withChannel (output->getIncomingHeader().deviceID);
if (auto* state = host->states.getStateForDestination (destination))
{
if (state->get (request.profile).isSupported())
const auto previousState = state->get (request.profile);
if (previousState.isSupported())
{
const auto address = ChannelAddress{}.withGroup (output->getIncomingGroup())
.withChannel (output->getIncomingHeader().deviceID);
const ProfileAtAddress profileAtAddress { request.profile, address };
const ProfileAtAddress profileAtAddress { request.profile, destination };
{
const ScopedValueSetter scope { host->currentEnablementMessage,
@ -167,10 +167,16 @@ private:
detail::MessageTypeUtils::send (*output, profileAtAddress.address.getGroup(), header, response);
};
const auto numIndividualChannels = (std::is_same_v<Message::ProfileOn, Body> ? currentState : previousState).active;
const auto numChannelsToSend = destination.isSingleChannel()
? numIndividualChannels
: uint16_t{};
if (currentState.isActive())
sendResponse (Message::ProfileEnabledReport { profileAtAddress.profile, currentState.active });
sendResponse (Message::ProfileEnabledReport { profileAtAddress.profile, numChannelsToSend });
else
sendResponse (Message::ProfileDisabledReport { profileAtAddress.profile, 0 });
sendResponse (Message::ProfileDisabledReport { profileAtAddress.profile, numChannelsToSend });
host->isResponder = true;
return true;
@ -196,6 +202,14 @@ private:
bool* handled = nullptr;
};
void ProfileHost::setProfileEnablement (ProfileAtAddress profileAtAddress, int numChannels)
{
if (numChannels > 0)
enableProfileImpl (profileAtAddress, numChannels);
else
disableProfileImpl (profileAtAddress);
}
void ProfileHost::addProfile (ProfileAtAddress profileAtAddress, int maxNumChannels)
{
auto* state = states.getStateForDestination (profileAtAddress.address);
@ -206,7 +220,7 @@ void ProfileHost::addProfile (ProfileAtAddress profileAtAddress, int maxNumChann
// There are only 256 channels on a UMP endpoint, so requesting more probably doesn't make sense!
jassert (maxNumChannels <= 256);
state->set (profileAtAddress.profile, { (uint16_t) maxNumChannels, 0 });
state->set (profileAtAddress.profile, { (uint16_t) jmax (1, maxNumChannels), 0 });
if (! isResponder || profileAtAddress == currentEnablementMessage)
return;
@ -233,7 +247,7 @@ void ProfileHost::removeProfile (ProfileAtAddress profileAtAddress)
if (state == nullptr)
return;
disableProfile (profileAtAddress);
setProfileEnablement (profileAtAddress, 0);
if (! state->get (profileAtAddress.profile).isSupported())
return;
@ -258,7 +272,7 @@ void ProfileHost::removeProfile (ProfileAtAddress profileAtAddress)
Message::ProfileRemoved { profileAtAddress.profile });
}
void ProfileHost::enableProfile (ProfileAtAddress profileAtAddress, int numChannels)
void ProfileHost::enableProfileImpl (ProfileAtAddress profileAtAddress, int numChannels)
{
auto* state = states.getStateForDestination (profileAtAddress.address);
@ -273,7 +287,7 @@ void ProfileHost::enableProfile (ProfileAtAddress profileAtAddress, int numChann
// There are only 256 channels on a UMP endpoint, so requesting more probably doesn't make sense!
jassert (numChannels <= 256);
const auto enabledChannels = jmin (old.supported, (uint16_t) numChannels);
const auto enabledChannels = jmax ((uint16_t) 1, jmin (old.supported, (uint16_t) numChannels));
state->set (profileAtAddress.profile, { old.supported, enabledChannels });
if (! isResponder || profileAtAddress == currentEnablementMessage)
@ -288,13 +302,15 @@ void ProfileHost::enableProfile (ProfileAtAddress profileAtAddress, int numChann
MUID::getBroadcast(),
};
const auto numChannelsToSend = profileAtAddress.address.isSingleChannel() ? enabledChannels : uint16_t{};
detail::MessageTypeUtils::send (output,
profileAtAddress.address.getGroup(),
header,
Message::ProfileEnabledReport { profileAtAddress.profile, enabledChannels });
Message::ProfileEnabledReport { profileAtAddress.profile, numChannelsToSend });
}
void ProfileHost::disableProfile (ProfileAtAddress profileAtAddress)
void ProfileHost::disableProfileImpl (ProfileAtAddress profileAtAddress)
{
auto* state = states.getStateForDestination (profileAtAddress.address);
@ -320,10 +336,12 @@ void ProfileHost::disableProfile (ProfileAtAddress profileAtAddress)
MUID::getBroadcast(),
};
const auto numChannelsToSend = profileAtAddress.address.isSingleChannel() ? old.active : uint16_t{};
detail::MessageTypeUtils::send (output,
profileAtAddress.address.getGroup(),
header,
Message::ProfileDisabledReport { profileAtAddress.profile, old.active });
Message::ProfileDisabledReport { profileAtAddress.profile, numChannelsToSend });
}
bool ProfileHost::tryRespond (ResponderOutput& responderOutput, const Message::Parsed& message)

View file

@ -58,18 +58,14 @@ public:
*/
void removeProfile (ProfileAtAddress);
/** Activates a profile on the specified group/channel with the provided
number of channels.
/** Activates or deactivates a profile on the specified group/channel.
The profile should previously have been added with addProfile(), and
numChannels should be in the closed range between 1 and the maximum
number of channels allowed for that profile.
The profile should previously have been added with addProfile().
A positive value of numChannels will enable the profile, and a non-positive value
will disable it. This includes group and function-block profiles; passing any positive
value will enable the profile on the entire group or block.
*/
void enableProfile (ProfileAtAddress, int numChannels);
/** Deactivates a profile on the specified group/channel.
*/
void disableProfile (ProfileAtAddress);
void setProfileEnablement (ProfileAtAddress, int numChannels);
/** Returns the profile states (supported/active) for all groups and channels.
*/
@ -98,6 +94,9 @@ public:
private:
class Visitor;
void enableProfileImpl (ProfileAtAddress, int);
void disableProfileImpl (ProfileAtAddress);
template <typename Body>
bool profileEnablementReceived (ResponderOutput&, const Body&);

View file

@ -34,8 +34,15 @@ namespace juce::midi_ci
*/
struct SupportedAndActive
{
uint16_t supported{}; ///< The maximum number of member channels for a profile. 0 indicates that the profile is unsupported.
uint16_t active{}; ///< The number of member channels currently active for a profile. 0 indicates that the profile is inactive.
uint16_t supported{}; ///< The maximum number of member channels for a profile.
///< 0 indicates that the profile is unsupported.
///< For group/block profiles, 1/0 indicates that the
///< profile is supported/unsupported respectively.
uint16_t active{}; ///< The number of member channels currently active for a profile.
///< 0 indicates that the profile is inactive.
///< For group/block profiles, 1/0 indicates that the
///< profile is supported/unsupported respectively.
/** Returns true if supported is non-zero. */
bool isSupported() const { return supported != 0; }