-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Fix knob linking / refactor linking #7883
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
3212bd8
247e348
4ba7cbb
74500d8
dba2a5a
57c24b8
eff1d2a
ffaddb1
f4678e9
368d8bf
23c99df
6bb8982
c5f9a04
e008275
db3b11a
675993a
f1f0d04
8ab1bd1
37400d4
33fa252
a8a5b3e
40c231d
f7c1d79
761b385
e89ba7d
71fe1a7
3e396ab
2680d4c
3f2e78e
0558a6b
c53f982
6cfa40c
6789da4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,7 +53,7 @@ AutomatableModel::AutomatableModel( | |
| m_valueChanged( false ), | ||
|
Comment on lines
53
to
55
This comment was marked as off-topic.
Sorry, something went wrong. |
||
| m_oldValue(val), | ||
| m_hasStrictStepSize( false ), | ||
| m_nextLink(nullptr), | ||
| m_nextLink(this), | ||
| m_controllerConnection( nullptr ), | ||
| m_valueBuffer( static_cast<int>( Engine::audioEngine()->framesPerPeriod() ) ), | ||
| m_lastUpdatedPeriod( -1 ), | ||
|
Comment on lines
57
to
61
This comment was marked as off-topic.
Sorry, something went wrong. |
||
|
|
@@ -70,8 +70,7 @@ AutomatableModel::AutomatableModel( | |
|
|
||
| AutomatableModel::~AutomatableModel() | ||
| { | ||
| // unlink this from anything else | ||
| unlinkModel(); | ||
| unlink(); | ||
|
|
||
| if (m_controllerConnection) | ||
| { | ||
|
|
@@ -290,33 +289,34 @@ void AutomatableModel::loadSettings( const QDomElement& element, const QString& | |
|
|
||
|
|
||
|
|
||
| void AutomatableModel::setValue(float value, bool isAutomated) | ||
| void AutomatableModel::setValue(const float value, const bool isAutomated) | ||
| { | ||
| float newValue = fittedValue(value); | ||
| if (newValue == m_value) { emit dataUnchanged(); return; } | ||
| if (fittedValue(value) == m_value) | ||
| { | ||
| // TODO check why we need this signal, is there a better solution? | ||
| if (!isAutomated) { emit dataUnchanged(); } | ||
| return; | ||
| } | ||
|
|
||
| if (isAutomated == false) { addJournalCheckPoint(); } | ||
| if (!isAutomated) { addJournalCheckPoint(); } | ||
|
|
||
| setValueInternal(value, isAutomated); | ||
| // set value for this and the other linked widgets | ||
| if (hasLinkedModels()) | ||
| // set value for this and the other linked models | ||
| setValueInternal(value); | ||
| for (auto model = m_nextLink; model != this; model = model->m_nextLink) | ||
| { | ||
| AutomatableModel* next = m_nextLink; | ||
| while (next != this) | ||
| { | ||
| next->setValueInternal(value, isAutomated); | ||
| next = next->m_nextLink; | ||
| } | ||
| model->setValueInternal(value); | ||
| } | ||
| } | ||
|
|
||
| void AutomatableModel::setValueInternal(float value, bool isAutomated) | ||
|
|
||
|
|
||
|
|
||
| void AutomatableModel::setValueInternal(const float value) | ||
|
szeli1 marked this conversation as resolved.
|
||
| { | ||
| float oldValue = m_value; | ||
| if (isAutomated) { m_value = fittedValue(scaledValue(value)); } | ||
| else { m_value = fittedValue(value); } | ||
| m_oldValue = m_value; | ||
| m_value = fittedValue(value); | ||
|
messmerd marked this conversation as resolved.
|
||
|
|
||
| if (oldValue != m_value) | ||
| if (m_oldValue != m_value) | ||
| { | ||
| m_valueChanged = true; | ||
| emit dataChanged(); | ||
|
|
@@ -427,103 +427,67 @@ float AutomatableModel::fittedValue( float value ) const | |
|
|
||
|
|
||
|
|
||
|
|
||
| void AutomatableModel::linkModel(AutomatableModel* model) | ||
| AutomatableModel* AutomatableModel::getLastLinkedModel() const | ||
| { | ||
| if (model == nullptr || model == this || isModelLinked(model)) { return; } | ||
|
|
||
| AutomatableModel* otherEnd = model->getLastLinkedModel(); | ||
| AutomatableModel* next = m_nextLink == nullptr ? this : m_nextLink; | ||
| if (otherEnd == nullptr) | ||
| for (auto model = m_nextLink; ; model = model->m_nextLink) | ||
| { | ||
| // linking other start to our next | ||
| model->m_nextLink = next; | ||
| // The last model in the circual reference links back to this | ||
|
szeli1 marked this conversation as resolved.
Outdated
|
||
| if (model->m_nextLink == this) { return model; } | ||
| } | ||
| else | ||
| { | ||
| // linking other end to our next | ||
| otherEnd->m_nextLink = next; | ||
| } | ||
| // linking this to other start | ||
| m_nextLink = model; | ||
| assert(m_nextLink != this); // if you change the code, be careful to not link to this | ||
| } | ||
|
|
||
| void AutomatableModel::unlinkModel() | ||
| { | ||
| if (hasLinkedModels() == false) { return; } | ||
|
|
||
| AutomatableModel* end = getLastLinkedModel(); | ||
| assert(end != nullptr); | ||
| end->m_nextLink = end == m_nextLink ? nullptr : m_nextLink; | ||
| m_nextLink = nullptr; | ||
| } | ||
|
|
||
| AutomatableModel* AutomatableModel::getLastLinkedModel() const | ||
| { | ||
| if (hasLinkedModels() == false) { return nullptr; } | ||
| AutomatableModel* output = m_nextLink; | ||
| while (output->m_nextLink != this) | ||
| { | ||
| output = output->m_nextLink; | ||
| } | ||
| return output; | ||
| } | ||
|
|
||
| bool AutomatableModel::isModelLinked(AutomatableModel* model) const | ||
| bool AutomatableModel::isLinkedToModel(AutomatableModel* model) const | ||
| { | ||
| if (hasLinkedModels() == false || model == nullptr || model == this) { return false; } | ||
| AutomatableModel* next = m_nextLink; | ||
| while (next != this) | ||
| for (auto next = m_nextLink; ; next = next->m_nextLink) | ||
| { | ||
| if (next == model) { return true; } | ||
| next = next->m_nextLink; | ||
| if (next == this) { return false; } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| size_t AutomatableModel::countLinks() const | ||
| { | ||
| if (hasLinkedModels() == false) { return 0; } | ||
| size_t output = 1; | ||
| AutomatableModel* next = m_nextLink; | ||
| while (next != this) | ||
| size_t output = 0; | ||
| for (auto model = m_nextLink; model != this; model = model->m_nextLink) | ||
| { | ||
| output++; | ||
| next = next->m_nextLink; | ||
| } | ||
| return output; | ||
| } | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
| void AutomatableModel::linkModels( AutomatableModel* model1, AutomatableModel* model2 ) | ||
| void AutomatableModel::linkToModel(AutomatableModel* other) | ||
| { | ||
| // copy data | ||
| model1->setValue(model2->m_value); | ||
| if (model1->valueBuffer() && model2->valueBuffer()) | ||
| if (isLinkedToModel(other)) { return; } | ||
|
|
||
| // copy data from other to this | ||
| setValue(other->m_value); | ||
| if (valueBuffer() && other->valueBuffer()) | ||
| { | ||
| std::copy_n(model2->valueBuffer()->data(), | ||
| model1->valueBuffer()->length(), | ||
| model1->valueBuffer()->data()); | ||
| emit model1->dataChanged(); | ||
| std::copy_n(other->valueBuffer()->data(), | ||
| valueBuffer()->length(), | ||
| valueBuffer()->data()); | ||
| emit dataChanged(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously this signal was emitted after this if-statement's body, not inside it.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The call to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I see. If the value changes, Correct me if I'm wrong, but I believe that's still different from the previous behavior, since now 0, 1, or even 2 signals are emitted rather than just 1 signal. Here's an idea for how to solve it (assuming it's worth solving): First, make -void AutomatableModel::setValueInternal(const float value)
+bool AutomatableModel::setValueInternal(const float value)
{
m_oldValue = m_value;
m_value = fittedValue(value);
if (m_oldValue != m_value)
{
m_valueChanged = true;
- emit dataChanged();
+ return true;
}
+
+ return false;
}Then emit the signal from // set value for this and the other linked models
- setValueInternal(value);
+ const bool valueChanged = setValueInternal(value);
for (auto model = m_nextLink; model != this; model = model->m_nextLink)
{
- model->setValueInternal(value);
+ if (model->setValueInternal(value)) { emit model->dataChanged(); }
}
+
+ // emit signal *after* all values have been updated (just in case)
+ if (valueChanged) { emit dataChanged(); }(If there's no point in emitting the signal after the linked models have been updated, you could remove the Lastly, this method ( void AutomatableModel::linkToModel(AutomatableModel* other)
{
if (isLinkedToModel(other)) { return; }
addJournalCheckPoint();
// copy data from other to this
setValueInternal(other->m_value);
for (auto model = m_nextLink; model != this; model = model->m_nextLink)
{
if (model->setValueInternal(other->m_value)) { emit model->dataChanged(); }
}
if (valueBuffer() && other->valueBuffer())
{
std::copy_n(other->valueBuffer()->data(),
valueBuffer()->length(),
valueBuffer()->data());
}
// send dataChanged() before linking (because linking will
// connect the two dataChanged() signals)
emit dataChanged();
// link the models
AutomatableModel* thisEnd = getLastLinkedModel();
AutomatableModel* otherEnd = other->getLastLinkedModel();
thisEnd->m_nextLink = other;
otherEnd->m_nextLink = this;
}As you can see, this method is now like a version of
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ^^^ @szeli1 What do you think about this?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @messmerd while your suggestion seems technically correct, I believe emitting void AmplifierEffect::processImpl(SampleFrame* outputFrameArray, int frameCount)
{
auto amplificationBuffer = amplificationModel.valueBuffer();
for (int f = 0; f < frameCount; ++f)
{
outputFrameArray[f] *= amplificationBuffer->value(f);
}
}Since the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you're right. The best option is to just remove the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done with 6789da4. |
||
| } | ||
| // link the models | ||
| model1->linkModel(model2); | ||
| AutomatableModel* thisEnd = getLastLinkedModel(); | ||
| AutomatableModel* otherEnd = other->getLastLinkedModel(); | ||
| thisEnd->m_nextLink = other; | ||
| otherEnd->m_nextLink = this; | ||
| } | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
| void AutomatableModel::unlinkAllModels() | ||
| void AutomatableModel::unlink() | ||
| { | ||
| unlinkModel(); | ||
| getLastLinkedModel()->m_nextLink = m_nextLink; | ||
| m_nextLink = this; | ||
| } | ||
|
|
||
|
|
||
|
|
@@ -547,8 +511,6 @@ void AutomatableModel::setControllerConnection( ControllerConnection* c ) | |
|
|
||
| float AutomatableModel::controllerValue( int frameOffset ) const | ||
| { | ||
| if (m_controllerConnection == nullptr) { return m_value; } | ||
|
|
||
| float v = 0; | ||
| switch (m_scaleType) | ||
| { | ||
|
|
@@ -584,6 +546,7 @@ ValueBuffer * AutomatableModel::valueBuffer() | |
|
|
||
| float val = m_value; // make sure our m_value doesn't change midway | ||
|
|
||
| // Get value buffer from our controller | ||
| if (m_controllerConnection && m_useControllerValue && m_controllerConnection->getController()->isSampleExact()) | ||
| { | ||
| auto vb = m_controllerConnection->valueBuffer(); | ||
|
|
@@ -616,13 +579,11 @@ ValueBuffer * AutomatableModel::valueBuffer() | |
| } | ||
| } | ||
|
|
||
| if (!m_controllerConnection) | ||
| // Get value buffer from one of the linked models' controller | ||
| if (m_useControllerValue) | ||
| { | ||
| if (hasLinkedModels()) | ||
| for (auto next = m_nextLink; next != this; next = next->m_nextLink) | ||
| { | ||
| AutomatableModel* next = this; | ||
| while (true) | ||
| { | ||
| if (next->controllerConnection() && next->useControllerValue() && | ||
| next->controllerConnection()->getController()->isSampleExact()) | ||
| { | ||
|
|
@@ -637,12 +598,10 @@ ValueBuffer * AutomatableModel::valueBuffer() | |
| m_hasSampleExactData = true; | ||
| return &m_valueBuffer; | ||
| } | ||
| next = next->m_nextLink; | ||
| if (next == this) { break; } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Populate value buffer by interpolatating between the old and new value | ||
| if (m_oldValue != val) | ||
| { | ||
| m_valueBuffer.interpolate(m_oldValue, val); | ||
|
|
@@ -754,16 +713,9 @@ float AutomatableModel::globalAutomationValueAt( const TimePos& time ) | |
|
|
||
| void AutomatableModel::setUseControllerValue(bool b) | ||
| { | ||
| if (b) | ||
| { | ||
| m_useControllerValue = true; | ||
| emit dataChanged(); | ||
| } | ||
| else if (m_controllerConnection && m_useControllerValue) | ||
| { | ||
| m_useControllerValue = false; | ||
| emit dataChanged(); | ||
| } | ||
| if (m_useControllerValue == b) { return; } | ||
| m_useControllerValue = b; | ||
| if (m_controllerConnection) { emit dataChanged(); } | ||
| } | ||
|
|
||
| float FloatModel::getRoundedValue() const | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.