Skip to content

Commit

Permalink
227: Save (and restore) number of sources and first source ID in pres…
Browse files Browse the repository at this point in the history
…ets (#229)
  • Loading branch information
vberthiaume authored Feb 27, 2025
1 parent 1456499 commit ed5db28
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 64 deletions.
2 changes: 0 additions & 2 deletions Source/cg_ControlGrisAudioProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,6 @@ void ControlGrisAudioProcessor::setNumberOfSources(int const numOfSources, bool
mPositionSourceLinkEnforcer.numberOfSourcesChanged();
mElevationSourceLinkEnforcer.numberOfSourcesChanged();

mPresetManager.numberOfSourcesChanged();

auto const positionSourceLink{ mPositionTrajectoryManager.getSourceLink() };
auto const isSymmetricLink{ positionSourceLink == PositionSourceLink::symmetricX
|| positionSourceLink == PositionSourceLink::symmetricY };
Expand Down
3 changes: 2 additions & 1 deletion Source/cg_ControlGrisAudioProcessor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ class ControlGrisAudioProcessor final
PresetsManager mPresetManager{ mFixPositionData,
mSources,
mPositionSourceLinkEnforcer,
mElevationSourceLinkEnforcer };
mElevationSourceLinkEnforcer,
mFirstSourceId };

PositionTrajectoryManager mPositionTrajectoryManager{ *this, mSources.getPrimarySource() };
ElevationTrajectoryManager mElevationTrajectoryManager{ *this, mSources.getPrimarySource() };
Expand Down
50 changes: 25 additions & 25 deletions Source/cg_ControlGrisAudioProcessorEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,33 +364,29 @@ void ControlGrisAudioProcessorEditor::oscStateChangedCallback(bool const state)
//==============================================================================
void ControlGrisAudioProcessorEditor::numberOfSourcesChangedCallback(int const numOfSources)
{
if (mProcessor.getSources().size() != numOfSources || mIsInsideSetPluginState) {
auto const initSourcePlacement{ mProcessor.getSources().size() != numOfSources };
auto const currentPositionSourceLink{ mPositionTrajectoryManager.getSourceLink() };
auto const symmetricLinkAllowed{ numOfSources == 2 };
mSectionTrajectory.setSymmetricLinkComboState(symmetricLinkAllowed);
if (!symmetricLinkAllowed) {
auto const isCurrentPositionSourceLinkSymmetric{ currentPositionSourceLink == PositionSourceLink::symmetricX
|| currentPositionSourceLink
== PositionSourceLink::symmetricY };
if (isCurrentPositionSourceLinkSymmetric) {
mProcessor.setPositionSourceLink(PositionSourceLink::independent,
SourceLinkEnforcer::OriginOfChange::user);
}
}

mSelectedSource = {};
mProcessor.setNumberOfSources(numOfSources);
mSectionGeneralSettings.setNumberOfSources(numOfSources);
mSectionTrajectory.setNumberOfSources(numOfSources);
mSectionSourceSpan.setSelectedSource(&mProcessor.getSources()[mSelectedSource]);
mPositionField.refreshSources();
mElevationField.refreshSources();
mSectionSourcePosition.setNumberOfSources(numOfSources, mProcessor.getFirstSourceId());
if (initSourcePlacement) {
sourcesPlacementChangedCallback(SourcePlacement::leftAlternate);
auto const initSourcePlacement{ mProcessor.getSources().size() != numOfSources };
auto const currentPositionSourceLink{ mPositionTrajectoryManager.getSourceLink() };
auto const symmetricLinkAllowed{ numOfSources == 2 };
mSectionTrajectory.setSymmetricLinkComboState(symmetricLinkAllowed);
if (!symmetricLinkAllowed) {
auto const isCurrentPositionSourceLinkSymmetric{ currentPositionSourceLink == PositionSourceLink::symmetricX
|| currentPositionSourceLink
== PositionSourceLink::symmetricY };
if (isCurrentPositionSourceLinkSymmetric) {
mProcessor.setPositionSourceLink(PositionSourceLink::independent, SourceLinkEnforcer::OriginOfChange::user);
}
}
mSelectedSource = {};
mProcessor.setNumberOfSources(numOfSources);
mSectionGeneralSettings.setNumberOfSources(numOfSources);
mSectionTrajectory.setNumberOfSources(numOfSources);
mSectionSourceSpan.setSelectedSource(&mProcessor.getSources()[mSelectedSource]);
mPositionField.refreshSources();
mElevationField.refreshSources();
mSectionSourcePosition.setNumberOfSources(numOfSources, mProcessor.getFirstSourceId());
if (initSourcePlacement) {
sourcesPlacementChangedCallback(SourcePlacement::leftAlternate);
}
}

//==============================================================================
Expand Down Expand Up @@ -719,6 +715,10 @@ void ControlGrisAudioProcessorEditor::fieldSourcePositionChangedCallback(SourceI
void ControlGrisAudioProcessorEditor::positionPresetChangedCallback(int const presetNumber)
{
mProcessor.getPresetsManager().forceLoad(presetNumber);
numberOfSourcesChangedCallback(mProcessor.getSources().size());

if (auto const presetSourceId {mProcessor.getPresetsManager().getPresetSourceId(presetNumber)})
firstSourceIdChangedCallback(SourceId{*presetSourceId});

auto * parameter{ mAudioProcessorValueTreeState.getParameter(Automation::Ids::POSITION_PRESET) };
auto const newValue{ static_cast<float>(presetNumber) / static_cast<float>(NUMBER_OF_POSITION_PRESETS) };
Expand Down
4 changes: 2 additions & 2 deletions Source/cg_LinkStrategies.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class Base
}; // class Base

//==============================================================================
// only use full to recall saved positions
// only useful to recall saved positions
class PositionIndependent final : public Base
{
void computeParameters_implementation(Sources const &, SourcesSnapshots const &) override {}
Expand Down Expand Up @@ -240,7 +240,7 @@ class PositionDeltaLock final : public Base
};

//==============================================================================
// only usefuLl to recall saved positions
// only useful to recall saved positions
class ElevationIndependent final : public Base
{
void computeParameters_implementation(Sources const &, SourcesSnapshots const &) override {}
Expand Down
80 changes: 49 additions & 31 deletions Source/cg_PresetsManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,13 @@ juce::String
PresetsManager::PresetsManager(juce::XmlElement & data,
Sources & sources,
SourceLinkEnforcer & positionLinkEnforcer,
SourceLinkEnforcer & elevationLinkEnforcer)
SourceLinkEnforcer & elevationLinkEnforcer,
SourceId & firstSourceId)
: mData(data)
, mSources(sources)
, mPositionLinkEnforcer(positionLinkEnforcer)
, mElevationLinkEnforcer(elevationLinkEnforcer)
, mFirstSourceId(firstSourceId)
{
}

Expand All @@ -64,6 +66,15 @@ int PresetsManager::getCurrentPreset() const
return mLastLoadedPreset;
}

std::optional<int> PresetsManager::getPresetSourceId(int presetNumber)
{
auto const presetData { getPresetData(presetNumber) };
if (!presetData || ! (*presetData)->hasAttribute("firstSourceId"))
return {};

return (*presetData)->getIntAttribute("firstSourceId");
}

//==============================================================================
bool PresetsManager::loadIfPresetChanged(int const presetNumber)
{
Expand Down Expand Up @@ -91,6 +102,13 @@ bool PresetsManager::load(int const presetNumber)

auto const * presetData{ *maybe_presetData };

if (presetData->hasAttribute ("numberOfSources"))
mSources.setSize(presetData->getIntAttribute("numberOfSources"));

if (presetData->hasAttribute("firstSourceId"))
mFirstSourceId = SourceId{ presetData->getIntAttribute("firstSourceId") };

// Store the preset's source positions in a new SourcesSnapshots
SourcesSnapshots snapshots{};
for (auto & source : mSources) {
SourceSnapshot snapshot{};
Expand All @@ -107,8 +125,8 @@ bool PresetsManager::load(int const presetNumber)
snapshot.position = position;
auto const zPosId{ getFixedPosSourceName(FixedPositionType::initial, index, 2) };
if (presetData->hasAttribute(zPosId)) {
auto const inversedNormalizedElevation{ static_cast<float>(
presetData->getDoubleAttribute(getFixedPosSourceName(FixedPositionType::initial, index, 2))) };
auto const elevation {getFixedPosSourceName(FixedPositionType::initial, index, 2)};
auto const inversedNormalizedElevation{ static_cast<float>(presetData->getDoubleAttribute(elevation)) };
snapshot.z = MAX_ELEVATION * (1.0f - inversedNormalizedElevation);
}
}
Expand All @@ -119,6 +137,7 @@ bool PresetsManager::load(int const presetNumber)
}
}

//load the snapshots into the enforcers, which are references to the ControlGrisAudioProcessor members
mPositionLinkEnforcer.loadSnapshots(snapshots);
if (mSources.getPrimarySource().getSpatMode() == SpatMode::cube) {
mElevationLinkEnforcer.loadSnapshots(snapshots);
Expand All @@ -128,6 +147,7 @@ bool PresetsManager::load(int const presetNumber)
auto const yTerminalPositionId{ getFixedPosSourceName(FixedPositionType::terminal, SourceIndex{ 0 }, 1) };
auto const zTerminalPositionId{ getFixedPosSourceName(FixedPositionType::terminal, SourceIndex{ 0 }, 2) };

// position the first source
juce::Point<float> terminalPosition;
if (presetData->hasAttribute(xTerminalPositionId) && presetData->hasAttribute(yTerminalPositionId)) {
juce::Point<float> const inversedNormalizedTerminalPosition{
Expand Down Expand Up @@ -157,6 +177,9 @@ bool PresetsManager::load(int const presetNumber)
}
}
mLastLoadedPreset = presetNumber;

// send a change message, which will end up calling SourceLinkEnforcer::enforceSourceLink()
// to position the secondary sources
sendChangeMessage();

return true;
Expand Down Expand Up @@ -185,17 +208,21 @@ std::optional<juce::XmlElement *> PresetsManager::getPresetData(int const preset
std::unique_ptr<juce::XmlElement> PresetsManager::createPresetData(int const presetNumber) const
{
// Build a new fixed position element.
auto result{ std::make_unique<juce::XmlElement>("ITEM") };
result->setAttribute("ID", presetNumber);
auto preset{ std::make_unique<juce::XmlElement>("ITEM") };
preset->setAttribute("ID", presetNumber);

auto const & positionSnapshots{ mPositionLinkEnforcer.getSnapshots() };
auto const & elevationsSnapshots{ mElevationLinkEnforcer.getSnapshots() };

//save the number and initial position of all sources
SourceIndex const numberOfSources{ mSources.size() };
preset->setAttribute("numberOfSources", numberOfSources.get());
preset->setAttribute("firstSourceId", mFirstSourceId.get());

for (SourceIndex sourceIndex{}; sourceIndex < numberOfSources; ++sourceIndex) {
auto const xName{ getFixedPosSourceName(FixedPositionType::initial, sourceIndex, 0) };
auto const yName{ getFixedPosSourceName(FixedPositionType::initial, sourceIndex, 1) };
auto const zName{ getFixedPosSourceName(FixedPositionType::initial, sourceIndex, 2) };
auto const curSourceX{ getFixedPosSourceName(FixedPositionType::initial, sourceIndex, 0) };
auto const curSourceY{ getFixedPosSourceName(FixedPositionType::initial, sourceIndex, 1) };
auto const curSourceZ{ getFixedPosSourceName(FixedPositionType::initial, sourceIndex, 2) };

auto const position{ positionSnapshots[sourceIndex].position };
auto const elevation{ elevationsSnapshots[sourceIndex].z };
Expand All @@ -206,30 +233,27 @@ std::unique_ptr<juce::XmlElement> PresetsManager::createPresetData(int const pre
auto const mirroredNormalizedPosition{ (mirroredPosition + juce::Point<float>{ 1.0f, 1.0f }) / 2.0f };
auto const inversedNormalizedElevation{ 1.0f - normalizedElevation };

result->setAttribute(xName, mirroredNormalizedPosition.getX());
result->setAttribute(yName, mirroredNormalizedPosition.getY());
result->setAttribute(zName, inversedNormalizedElevation);
preset->setAttribute(curSourceX, mirroredNormalizedPosition.getX());
preset->setAttribute(curSourceY, mirroredNormalizedPosition.getY());
preset->setAttribute(curSourceZ, inversedNormalizedElevation);
}

auto const xName{ getFixedPosSourceName(FixedPositionType::terminal, SourceIndex{ 0 }, 0) };
auto const yName{ getFixedPosSourceName(FixedPositionType::terminal, SourceIndex{ 0 }, 1) };
auto const zName{ getFixedPosSourceName(FixedPositionType::terminal, SourceIndex{ 0 }, 2) };
//save the terminal position of only the first source
auto const firstSourceX{ getFixedPosSourceName(FixedPositionType::terminal, SourceIndex{ 0 }, 0) };
auto const firstSourceY{ getFixedPosSourceName(FixedPositionType::terminal, SourceIndex{ 0 }, 1) };
auto const firstSourceZ{ getFixedPosSourceName(FixedPositionType::terminal, SourceIndex{ 0 }, 2) };

//The position is stored normalized with inversed Y and elevation
auto const position{ mSources.getPrimarySource().getPos() };
juce::Point<float> const mirroredPosition{
position.getX(),
position.getY() * -1.0f
}; // For some legacy reason, we store a normalized value with inversed Y.
juce::Point<float> const mirroredPosition{ position.getX(), position.getY() * -1.0f };
auto const inversedNormalizedPosition{ (mirroredPosition + juce::Point<float>{ 1.0f, 1.0f }) / 2.0f };
auto const inversedNormalizedElevation{
1.0f - mSources.getPrimarySource().getNormalizedElevation().get()
}; // Same this happens with elevation.
auto const inversedNormalizedElevation{ 1.0f - mSources.getPrimarySource().getNormalizedElevation().get() };

result->setAttribute(xName, inversedNormalizedPosition.getX());
result->setAttribute(yName, inversedNormalizedPosition.getY());
result->setAttribute(zName, inversedNormalizedElevation);
preset->setAttribute(firstSourceX, inversedNormalizedPosition.getX());
preset->setAttribute(firstSourceY, inversedNormalizedPosition.getY());
preset->setAttribute(firstSourceZ, inversedNormalizedElevation);

return result;
return preset;
}

//==============================================================================
Expand Down Expand Up @@ -265,12 +289,6 @@ bool PresetsManager::deletePreset(int const presetNumber) const
return true;
}

//==============================================================================
void PresetsManager::numberOfSourcesChanged()
{
// TODO
}

//==============================================================================
std::array<bool, NUMBER_OF_POSITION_PRESETS> PresetsManager::getSavedPresets() const
{
Expand Down
6 changes: 4 additions & 2 deletions Source/cg_PresetsManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class PresetsManager final : public juce::ChangeBroadcaster
Sources & mSources;
SourceLinkEnforcer & mPositionLinkEnforcer;
SourceLinkEnforcer & mElevationLinkEnforcer;
SourceId & mFirstSourceId;

public:
//==============================================================================
Expand All @@ -57,16 +58,17 @@ class PresetsManager final : public juce::ChangeBroadcaster
PresetsManager(juce::XmlElement & data,
Sources & sources,
SourceLinkEnforcer & positionLinkEnforcer,
SourceLinkEnforcer & elevationLinkEnforcer);
SourceLinkEnforcer & elevationLinkEnforcer,
SourceId & firstSourceId);
//==============================================================================
[[nodiscard]] int getCurrentPreset() const;
[[nodiscard]] std::array<bool, NUMBER_OF_POSITION_PRESETS> getSavedPresets() const;

std::optional<int> getPresetSourceId(int presetNumber);
bool loadIfPresetChanged(int presetNumber);
bool forceLoad(int presetNumber);
void save(int presetNumber) const;
[[nodiscard]] bool deletePreset(int presetNumber) const;
void numberOfSourcesChanged();

private:
//==============================================================================
Expand Down
2 changes: 1 addition & 1 deletion Source/cg_SectionPositionPresets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ void PresetButton::internalClickCallback(juce::ModifierKeys const & mods)
setToggleState(false, juce::NotificationType::dontSendNotification);
mLoaded = mSaved = false;
} else if (mSaved) {
TextButton::internalClickCallback(mods);
TextButton::internalClickCallback(mods); //this will cause PresetButton::clicked() to be called right above
}
refresh();
}
Expand Down
9 changes: 9 additions & 0 deletions Source/cg_SourceSnapshot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ struct SourcesSnapshots {
SourceSnapshot & operator[](SourceIndex const index);
int size() const { return secondaries.size() + 1; }

juce::String toString () const
{
juce::String ret;
ret += primary.position.toString() + ", " + primary.z.toString() + "; ";
for (auto const & snapshot : secondaries)
ret += snapshot.position.toString() + ", " + snapshot.z.toString() + "; ";
return ret;
}

private:
JUCE_LEAK_DETECTOR(SourceSnapshot)
}; // class SourcesSnapshots
Expand Down

0 comments on commit ed5db28

Please sign in to comment.