kopia lustrzana https://github.com/jameshball/osci-render
Merge pull request #46 from jameshball/translate-effect
Add translate effect and other improvementspull/170/head
commit
26535b7a69
|
@ -129,5 +129,6 @@ void MainComponent::resized() {
|
||||||
frequencyLabel.setBounds(bounds.removeFromTop(20));
|
frequencyLabel.setBounds(bounds.removeFromTop(20));
|
||||||
|
|
||||||
bounds.removeFromTop(padding);
|
bounds.removeFromTop(padding);
|
||||||
visualiser.setBounds(bounds);
|
auto minDim = juce::jmin(bounds.getWidth(), bounds.getHeight());
|
||||||
|
visualiser.setBounds(bounds.withSizeKeepingCentre(minDim, minDim));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,25 +22,9 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor
|
||||||
|
|
||||||
auto onRotationChange = [this]() {
|
auto onRotationChange = [this]() {
|
||||||
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
||||||
double x = fixedRotateX->getToggleState() ? 0 : rotateX.slider.getValue();
|
audioProcessor.rotateX->setValue(rotateX.slider.getValue());
|
||||||
double y = fixedRotateY->getToggleState() ? 0 : rotateY.slider.getValue();
|
audioProcessor.rotateY->setValue(rotateY.slider.getValue());
|
||||||
double z = fixedRotateZ->getToggleState() ? 0 : rotateZ.slider.getValue();
|
audioProcessor.rotateZ->setValue(rotateZ.slider.getValue());
|
||||||
audioProcessor.rotateX->setValue(x);
|
|
||||||
audioProcessor.rotateY->setValue(y);
|
|
||||||
audioProcessor.rotateZ->setValue(z);
|
|
||||||
|
|
||||||
if (fixedRotateX->getToggleState()) {
|
|
||||||
audioProcessor.currentRotateX->setValue(rotateX.slider.getValue());
|
|
||||||
audioProcessor.currentRotateX->apply();
|
|
||||||
}
|
|
||||||
if (fixedRotateY->getToggleState()) {
|
|
||||||
audioProcessor.currentRotateY->setValue(rotateY.slider.getValue());
|
|
||||||
audioProcessor.currentRotateY->apply();
|
|
||||||
}
|
|
||||||
if (fixedRotateZ->getToggleState()) {
|
|
||||||
audioProcessor.currentRotateZ->setValue(rotateZ.slider.getValue());
|
|
||||||
audioProcessor.currentRotateZ->apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
audioProcessor.fixedRotateX = fixedRotateX->getToggleState();
|
audioProcessor.fixedRotateX = fixedRotateX->getToggleState();
|
||||||
audioProcessor.fixedRotateY = fixedRotateY->getToggleState();
|
audioProcessor.fixedRotateY = fixedRotateY->getToggleState();
|
||||||
|
@ -73,12 +57,14 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor
|
||||||
mouseRotate.setToggleState(false, juce::NotificationType::dontSendNotification);
|
mouseRotate.setToggleState(false, juce::NotificationType::dontSendNotification);
|
||||||
|
|
||||||
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
|
||||||
audioProcessor.currentRotateX->setValue(0);
|
if (audioProcessor.getCurrentFileIndex() != -1) {
|
||||||
audioProcessor.currentRotateY->setValue(0);
|
auto obj = audioProcessor.getCurrentFileParser()->getObject();
|
||||||
audioProcessor.currentRotateZ->setValue(0);
|
if (obj != nullptr) {
|
||||||
audioProcessor.currentRotateX->apply();
|
obj->setCurrentRotationX(0);
|
||||||
audioProcessor.currentRotateY->apply();
|
obj->setCurrentRotationY(0);
|
||||||
audioProcessor.currentRotateZ->apply();
|
obj->setCurrentRotationZ(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto doc = juce::XmlDocument::parse(BinaryData::fixed_rotate_svg);
|
auto doc = juce::XmlDocument::parse(BinaryData::fixed_rotate_svg);
|
||||||
|
|
|
@ -50,15 +50,22 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
|
||||||
));
|
));
|
||||||
toggleableEffects.push_back(std::make_shared<Effect>(
|
toggleableEffects.push_back(std::make_shared<Effect>(
|
||||||
std::make_shared<VectorCancellingEffect>(),
|
std::make_shared<VectorCancellingEffect>(),
|
||||||
new EffectParameter("Vector cancelling", "vectorCancelling", 0.0, 0.0, 1.0)
|
new EffectParameter("Vector Cancelling", "vectorCancelling", 0.0, 0.0, 1.0)
|
||||||
));
|
|
||||||
toggleableEffects.push_back(std::make_shared<Effect>(
|
|
||||||
std::make_shared<DistortEffect>(true),
|
|
||||||
new EffectParameter("Vertical shift", "verticalDistort", 0.0, 0.0, 1.0)
|
|
||||||
));
|
));
|
||||||
toggleableEffects.push_back(std::make_shared<Effect>(
|
toggleableEffects.push_back(std::make_shared<Effect>(
|
||||||
std::make_shared<DistortEffect>(false),
|
std::make_shared<DistortEffect>(false),
|
||||||
new EffectParameter("Horizontal shift", "horizontalDistort", 0.0, 0.0, 1.0)
|
new EffectParameter("Horizontal Distort", "horizontalDistort", 0.0, 0.0, 1.0)
|
||||||
|
));
|
||||||
|
toggleableEffects.push_back(std::make_shared<Effect>(
|
||||||
|
std::make_shared<DistortEffect>(true),
|
||||||
|
new EffectParameter("Vertical Distort", "verticalDistort", 0.0, 0.0, 1.0)
|
||||||
|
));
|
||||||
|
toggleableEffects.push_back(std::make_shared<Effect>(
|
||||||
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
|
input.x += values[0];
|
||||||
|
input.y += values[1];
|
||||||
|
return input;
|
||||||
|
}, std::vector<EffectParameter*>{new EffectParameter("Translate x", "translateX", 0.0, -1.0, 1.0), new EffectParameter("Translate y", "translateY", 0.0, -1.0, 1.0)}
|
||||||
));
|
));
|
||||||
toggleableEffects.push_back(std::make_shared<Effect>(
|
toggleableEffects.push_back(std::make_shared<Effect>(
|
||||||
std::make_shared<SmoothEffect>(),
|
std::make_shared<SmoothEffect>(),
|
||||||
|
@ -103,19 +110,9 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
|
||||||
addParameter(parameter);
|
addParameter(parameter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hiddenEffects.push_back(currentRotateX);
|
|
||||||
hiddenEffects.push_back(currentRotateY);
|
|
||||||
hiddenEffects.push_back(currentRotateZ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OscirenderAudioProcessor::~OscirenderAudioProcessor() {
|
OscirenderAudioProcessor::~OscirenderAudioProcessor() {}
|
||||||
for (auto effect : hiddenEffects) {
|
|
||||||
for (auto parameter : effect->parameters) {
|
|
||||||
delete parameter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const juce::String OscirenderAudioProcessor::getName() const {
|
const juce::String OscirenderAudioProcessor::getName() const {
|
||||||
return JucePlugin_Name;
|
return JucePlugin_Name;
|
||||||
|
|
|
@ -105,12 +105,21 @@ public:
|
||||||
return input;
|
return input;
|
||||||
}, new EffectParameter("Focal length", "focalLength", 1.0, 0.0, 2.0)
|
}, new EffectParameter("Focal length", "focalLength", 1.0, 0.0, 2.0)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
std::atomic<bool> fixedRotateX = false;
|
||||||
|
std::atomic<bool> fixedRotateY = false;
|
||||||
|
std::atomic<bool> fixedRotateZ = false;
|
||||||
std::shared_ptr<Effect> rotateX = std::make_shared<Effect>(
|
std::shared_ptr<Effect> rotateX = std::make_shared<Effect>(
|
||||||
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
if (getCurrentFileIndex() != -1) {
|
if (getCurrentFileIndex() != -1) {
|
||||||
auto obj = getCurrentFileParser()->getObject();
|
auto obj = getCurrentFileParser()->getObject();
|
||||||
if (obj == nullptr) return input;
|
if (obj == nullptr) return input;
|
||||||
obj->setBaseRotationX(values[0] * std::numbers::pi);
|
auto rotation = values[0] * std::numbers::pi;
|
||||||
|
if (fixedRotateX) {
|
||||||
|
obj->setCurrentRotationX(rotation);
|
||||||
|
} else {
|
||||||
|
obj->setBaseRotationX(rotation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
}, new EffectParameter("Rotate x", "rotateX", 1.0, -1.0, 1.0)
|
}, new EffectParameter("Rotate x", "rotateX", 1.0, -1.0, 1.0)
|
||||||
|
@ -120,7 +129,12 @@ public:
|
||||||
if (getCurrentFileIndex() != -1) {
|
if (getCurrentFileIndex() != -1) {
|
||||||
auto obj = getCurrentFileParser()->getObject();
|
auto obj = getCurrentFileParser()->getObject();
|
||||||
if (obj == nullptr) return input;
|
if (obj == nullptr) return input;
|
||||||
obj->setBaseRotationY(values[0] * std::numbers::pi);
|
auto rotation = values[0] * std::numbers::pi;
|
||||||
|
if (fixedRotateY) {
|
||||||
|
obj->setCurrentRotationY(rotation);
|
||||||
|
} else {
|
||||||
|
obj->setBaseRotationY(rotation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
}, new EffectParameter("Rotate y", "rotateY", 1.0, -1.0, 1.0)
|
}, new EffectParameter("Rotate y", "rotateY", 1.0, -1.0, 1.0)
|
||||||
|
@ -130,41 +144,16 @@ public:
|
||||||
if (getCurrentFileIndex() != -1) {
|
if (getCurrentFileIndex() != -1) {
|
||||||
auto obj = getCurrentFileParser()->getObject();
|
auto obj = getCurrentFileParser()->getObject();
|
||||||
if (obj == nullptr) return input;
|
if (obj == nullptr) return input;
|
||||||
obj->setBaseRotationZ(values[0] * std::numbers::pi);
|
auto rotation = values[0] * std::numbers::pi;
|
||||||
|
if (fixedRotateZ) {
|
||||||
|
obj->setCurrentRotationZ(rotation);
|
||||||
|
} else {
|
||||||
|
obj->setBaseRotationZ(rotation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
}, new EffectParameter("Rotate z", "rotateZ", 0.0, -1.0, 1.0)
|
}, new EffectParameter("Rotate z", "rotateZ", 0.0, -1.0, 1.0)
|
||||||
);
|
);
|
||||||
std::shared_ptr<Effect> currentRotateX = std::make_shared<Effect>(
|
|
||||||
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
|
||||||
if (getCurrentFileIndex() != -1) {
|
|
||||||
auto obj = getCurrentFileParser()->getObject();
|
|
||||||
if (obj == nullptr) return input;
|
|
||||||
obj->setCurrentRotationX(values[0] * std::numbers::pi);
|
|
||||||
}
|
|
||||||
return input;
|
|
||||||
}, new EffectParameter("Current Rotate x", "currentRotateX", 0.0, 0.0, 1.0, 0.001, false)
|
|
||||||
);
|
|
||||||
std::shared_ptr<Effect> currentRotateY = std::make_shared<Effect>(
|
|
||||||
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
|
||||||
if (getCurrentFileIndex() != -1) {
|
|
||||||
auto obj = getCurrentFileParser()->getObject();
|
|
||||||
if (obj == nullptr) return input;
|
|
||||||
obj->setCurrentRotationY(values[0] * std::numbers::pi);
|
|
||||||
}
|
|
||||||
return input;
|
|
||||||
}, new EffectParameter("Current Rotate y", "currentRotateY", 0.0, 0.0, 1.0, 0.001, false)
|
|
||||||
);
|
|
||||||
std::shared_ptr<Effect> currentRotateZ = std::make_shared<Effect>(
|
|
||||||
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
|
||||||
if (getCurrentFileIndex() != -1) {
|
|
||||||
auto obj = getCurrentFileParser()->getObject();
|
|
||||||
if (obj == nullptr) return input;
|
|
||||||
obj->setCurrentRotationZ(values[0] * std::numbers::pi);
|
|
||||||
}
|
|
||||||
return input;
|
|
||||||
}, new EffectParameter("Current Rotate z", "currentRotateZ", 0.0, 0.0, 1.0, 0.001, false)
|
|
||||||
);
|
|
||||||
std::shared_ptr<Effect> rotateSpeed = std::make_shared<Effect>(
|
std::shared_ptr<Effect> rotateSpeed = std::make_shared<Effect>(
|
||||||
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
if (getCurrentFileIndex() != -1) {
|
if (getCurrentFileIndex() != -1) {
|
||||||
|
@ -175,9 +164,6 @@ public:
|
||||||
return input;
|
return input;
|
||||||
}, new EffectParameter("Rotate speed", "rotateSpeed", 0.0, -1.0, 1.0)
|
}, new EffectParameter("Rotate speed", "rotateSpeed", 0.0, -1.0, 1.0)
|
||||||
);
|
);
|
||||||
std::atomic<bool> fixedRotateX = false;
|
|
||||||
std::atomic<bool> fixedRotateY = false;
|
|
||||||
std::atomic<bool> fixedRotateZ = false;
|
|
||||||
|
|
||||||
std::shared_ptr<DelayEffect> delayEffect = std::make_shared<DelayEffect>();
|
std::shared_ptr<DelayEffect> delayEffect = std::make_shared<DelayEffect>();
|
||||||
|
|
||||||
|
@ -227,9 +213,6 @@ private:
|
||||||
bool invalidateFrameBuffer = false;
|
bool invalidateFrameBuffer = false;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Effect>> permanentEffects;
|
std::vector<std::shared_ptr<Effect>> permanentEffects;
|
||||||
// any effects that are not added as a plugin parameter must be deleted manually
|
|
||||||
// as JUCE will not delete them upon destruction of the AudioProcessor
|
|
||||||
std::vector<std::shared_ptr<Effect>> hiddenEffects;
|
|
||||||
|
|
||||||
std::shared_ptr<Effect> traceMax = std::make_shared<Effect>(
|
std::shared_ptr<Effect> traceMax = std::make_shared<Effect>(
|
||||||
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
|
||||||
|
|
|
@ -259,7 +259,6 @@ public:
|
||||||
if (auto* rowComp = getComponentForRow (row))
|
if (auto* rowComp = getComponentForRow (row))
|
||||||
{
|
{
|
||||||
rowComp->setBounds (0, owner.getPositionForRow (row), w, owner.getRowHeight (row));
|
rowComp->setBounds (0, owner.getPositionForRow (row), w, owner.getRowHeight (row));
|
||||||
DBG (String (i) + " " + rowComp->getBounds().toString());
|
|
||||||
rowComp->update (row, owner.isRowSelected (row));
|
rowComp->update (row, owner.isRowSelected (row));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,16 +29,12 @@ void VisualiserComponent::paint(juce::Graphics& g) {
|
||||||
g.fillAll(backgroundColour);
|
g.fillAll(backgroundColour);
|
||||||
|
|
||||||
auto r = getLocalBounds().toFloat();
|
auto r = getLocalBounds().toFloat();
|
||||||
auto channelHeight = r.getHeight() / (float)numChannels;
|
auto minDim = juce::jmin(r.getWidth(), r.getHeight());
|
||||||
|
|
||||||
g.setColour(waveformColour);
|
|
||||||
juce::SpinLock::ScopedLockType scope(lock);
|
juce::SpinLock::ScopedLockType scope(lock);
|
||||||
if (buffer.size() > 0) {
|
if (buffer.size() > 0) {
|
||||||
paintXY(g, r.removeFromRight(r.getHeight()));
|
g.setColour(waveformColour);
|
||||||
|
paintXY(g, r.withSizeKeepingCentre(minDim, minDim));
|
||||||
for (int i = 0; i < numChannels; ++i) {
|
|
||||||
paintChannel(g, r.removeFromTop(channelHeight), i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,17 +73,19 @@ void VisualiserComponent::paintChannel(juce::Graphics& g, juce::Rectangle<float>
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualiserComponent::paintXY(juce::Graphics& g, juce::Rectangle<float> area) {
|
void VisualiserComponent::paintXY(juce::Graphics& g, juce::Rectangle<float> area) {
|
||||||
juce::Path path;
|
auto transform = juce::AffineTransform::fromTargetPoints(-1.0f, -1.0f, area.getX(), area.getBottom(), 1.0f, 1.0f, area.getRight(), area.getY(), 1.0f, -1.0f, area.getRight(), area.getBottom());
|
||||||
|
std::vector<juce::Line<float>> lines;
|
||||||
path.startNewSubPath(buffer[0], buffer[1]);
|
|
||||||
|
|
||||||
for (int i = 2; i < buffer.size(); i += 2) {
|
for (int i = 2; i < buffer.size(); i += 2) {
|
||||||
path.lineTo(buffer[i + 0], buffer[i + 1]);
|
lines.emplace_back(buffer[i - 2], buffer[i - 1], buffer[i], buffer[i + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply affine transform to path to fit in area
|
for (auto& line : lines) {
|
||||||
auto transform = juce::AffineTransform::fromTargetPoints(-1.0f, -1.0f, area.getX(), area.getBottom(), 1.0f, 1.0f, area.getRight(), area.getY(), 1.0f, -1.0f, area.getRight(), area.getBottom());
|
line.applyTransform(transform);
|
||||||
path.applyTransform(transform);
|
float lengthScale = 1.0f / (line.getLength() + 1.0f);
|
||||||
|
double strength = 10;
|
||||||
g.strokePath(path, juce::PathStrokeType(1.0f));
|
lengthScale = std::log(strength * lengthScale + 1) / std::log(strength + 1);
|
||||||
|
g.setColour(waveformColour.withAlpha(lengthScale));
|
||||||
|
g.drawLine(line, 1.0f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@ private:
|
||||||
int numChannels = 2;
|
int numChannels = 2;
|
||||||
juce::Colour backgroundColour, waveformColour;
|
juce::Colour backgroundColour, waveformColour;
|
||||||
OscirenderAudioProcessor& audioProcessor;
|
OscirenderAudioProcessor& audioProcessor;
|
||||||
std::shared_ptr<BufferConsumer> consumer = std::make_shared<BufferConsumer>(2048);
|
std::shared_ptr<BufferConsumer> consumer = std::make_shared<BufferConsumer>(4096);
|
||||||
int precision = 2;
|
int precision = 4;
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VisualiserComponent)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VisualiserComponent)
|
||||||
};
|
};
|
|
@ -45,7 +45,6 @@ Vector2 LuaParser::draw() {
|
||||||
for (int i = 0; i < variableNames.size(); i++) {
|
for (int i = 0; i < variableNames.size(); i++) {
|
||||||
lua_pushnumber(L, variables[i]);
|
lua_pushnumber(L, variables[i]);
|
||||||
lua_setglobal(L, variableNames[i].toUTF8());
|
lua_setglobal(L, variableNames[i].toUTF8());
|
||||||
DBG("set " << variableNames[i] << " to " << variables[i]);
|
|
||||||
}
|
}
|
||||||
variableNames.clear();
|
variableNames.clear();
|
||||||
variables.clear();
|
variables.clear();
|
||||||
|
|
Ładowanie…
Reference in New Issue