From 318cee79deb40abfe4e12e10f324a220206f7c9d Mon Sep 17 00:00:00 2001 From: James H Ball Date: Thu, 22 Aug 2024 13:12:46 +0100 Subject: [PATCH 1/3] Add several Lua functions --- Source/lua/LuaParser.cpp | 312 ++++++++++++++++++++++++++++++++++++++- Source/shape/Line.cpp | 15 ++ Source/shape/Line.h | 1 + osci-render.jucer | 4 +- 4 files changed, 327 insertions(+), 5 deletions(-) diff --git a/Source/lua/LuaParser.cpp b/Source/lua/LuaParser.cpp index aa64cc8..091cb61 100644 --- a/Source/lua/LuaParser.cpp +++ b/Source/lua/LuaParser.cpp @@ -1,5 +1,8 @@ #include "LuaParser.h" #include "luaimport.h" +#include "../shape/Line.h" +#include "../shape/CircleArc.h" +#include "../shape/QuadraticBezierCurve.h" std::function LuaParser::onPrint; std::function LuaParser::onClear; @@ -21,6 +24,293 @@ void LuaParser::resetMaximumInstructions(lua_State*& L) { lua_sethook(L, LuaParser::maximumInstructionsReached, 0, 0); } +static int pointToTable(lua_State* L, Point point, int numDims) { + lua_newtable(L); + if (numDims == 1) { + lua_pushnumber(L, point.x); + lua_rawseti(L, -2, 1); + } else if (numDims == 2) { + lua_pushnumber(L, point.x); + lua_rawseti(L, -2, 1); + lua_pushnumber(L, point.y); + lua_rawseti(L, -2, 2); + } else { + lua_pushnumber(L, point.x); + lua_rawseti(L, -2, 1); + lua_pushnumber(L, point.y); + lua_rawseti(L, -2, 2); + lua_pushnumber(L, point.z); + lua_rawseti(L, -2, 3); + } + + return 1; +} + +static Point tableToPoint(lua_State* L, int index) { + Point point; + lua_pushinteger(L, 1); + lua_gettable(L, index); + point.x = lua_tonumber(L, -1); + lua_pop(L, 1); + + lua_pushinteger(L, 2); + lua_gettable(L, index); + point.y = lua_tonumber(L, -1); + lua_pop(L, 1); + + lua_pushinteger(L, 3); + lua_gettable(L, index); + point.z = lua_tonumber(L, -1); + lua_pop(L, 1); + + return point; +} + +static int luaLine(lua_State* L) { + double t = lua_tonumber(L, 1) / juce::MathConstants::twoPi; + Point point1 = tableToPoint(L, 2); + Point point2 = tableToPoint(L, 3); + + Line line = Line(point1, point2); + Point point = line.nextVector(t); + + return pointToTable(L, point, 3); +} + +static Point genericRect(double phase, Point topLeft, double width, double height) { + double t = phase / juce::MathConstants::twoPi; + double totalLength = 2 * (width + height); + double progress = t * totalLength; + + Line line = Line(0, 0); + double adjustedProgress; + double x = topLeft.x; + double y = topLeft.y; + + if (progress < width) { + line = Line(x, y, x + width, y); + adjustedProgress = progress / width; + } else if (progress < width + height) { + line = Line(x + width, y, x + width, y + height); + adjustedProgress = (progress - width) / height; + } else if (progress < 2 * width + height) { + line = Line(x + width, y + height, x, y + height); + adjustedProgress = (progress - width - height) / width; + } else { + line = Line(x, y + height, x, y); + adjustedProgress = (progress - 2 * width - height) / height; + } + + return line.nextVector(adjustedProgress); +} + +static int luaRect(lua_State* L) { + int nargs = lua_gettop(L); + + double phase = lua_tonumber(L, 1); + double width = lua_tonumber(L, 2); + double height = lua_tonumber(L, 3); + + Point topLeft = nargs == 4 ? tableToPoint(L, 4) : Point(-width / 2, -height / 2); + Point point = genericRect(phase, topLeft, width, height); + + return pointToTable(L, point, 2); +} + +static int luaSquare(lua_State* L) { + int nargs = lua_gettop(L); + + double phase = lua_tonumber(L, 1); + double width = lua_tonumber(L,2); + + Point topLeft = nargs == 3 ? tableToPoint(L, 3) : Point(-width / 2, -width / 2); + Point point = genericRect(phase, topLeft, width, width); + + return pointToTable(L, point, 2); +} + +static int luaEllipse(lua_State* L) { + double t = lua_tonumber(L, 1) / juce::MathConstants::twoPi; + double radiusX = lua_tonumber(L, 2); + double radiuxY = lua_tonumber(L, 3); + + CircleArc ellipse = CircleArc(0, 0, radiusX, radiuxY, 0, juce::MathConstants::twoPi); + Point point = ellipse.nextVector(t); + + return pointToTable(L, point, 2); +} + +static int luaCircle(lua_State* L) { + double t = lua_tonumber(L, 1) / juce::MathConstants::twoPi; + double radius = lua_tonumber(L, 2); + + CircleArc ellipse = CircleArc(0, 0, radius, radius, 0, juce::MathConstants::twoPi); + Point point = ellipse.nextVector(t); + + return pointToTable(L, point, 2); +} + +static int luaArc(lua_State* L) { + double t = lua_tonumber(L, 1) / juce::MathConstants::twoPi; + double radiusX = lua_tonumber(L, 2); + double radiusY = lua_tonumber(L, 3); + double startAngle = lua_tonumber(L, 4); + double endAngle = lua_tonumber(L, 5); + + CircleArc arc = CircleArc(0, 0, radiusX, radiusY, startAngle, endAngle); + Point point = arc.nextVector(t); + + return pointToTable(L, point, 2); +} + +static int luaPolygon(lua_State* L) { + double n = lua_tonumber(L, 2); + double t = n * lua_tonumber(L, 1) / juce::MathConstants::twoPi; + + int floor_t = (int) t; + + double pi_n = juce::MathConstants::pi / n; + double two_floor_t_plus_one = 2 * floor_t + 1; + double inner_cos = cos(pi_n * two_floor_t_plus_one); + double inner_sin = sin(pi_n * two_floor_t_plus_one); + double multiplier = 2 * t - 2 * floor_t - 1; + + double x = cos(pi_n) * inner_cos - multiplier * sin(pi_n) * inner_sin; + double y = cos(pi_n) * inner_sin + multiplier * sin(pi_n) * inner_cos; + + return pointToTable(L, Point(x, y), 2); +} + +static int luaBezier(lua_State* L) { + int nargs = lua_gettop(L); + + double t = lua_tonumber(L, 1) / juce::MathConstants::twoPi; + Point point1 = tableToPoint(L, 2); + Point point2 = tableToPoint(L, 3); + Point point3 = tableToPoint(L, 4); + + Point point; + + if (nargs == 4) { + QuadraticBezierCurve curve = QuadraticBezierCurve(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y); + point = curve.nextVector(t); + } else { + Point point4 = tableToPoint(L, 5); + + CubicBezierCurve curve = CubicBezierCurve(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y, point4.x, point4.y); + point = curve.nextVector(t); + } + + return pointToTable(L, point, 2); +} + +static int luaLissajous(lua_State* L) { + int nargs = lua_gettop(L); + + double theta = lua_tonumber(L, 1); + double radius = lua_tonumber(L, 2); + double ratioA = lua_tonumber(L, 3); + double ratioB = lua_tonumber(L, 4); + double phase = lua_tonumber(L, 5); + + double x = radius * sin(ratioA * theta); + double y = radius * cos(ratioB * theta + phase); + + return pointToTable(L, Point(x, y), 2); +} + +static double squareWave(double phase) { + double t = phase / juce::MathConstants::twoPi; + return (t - (int) t < 0.5) ? 1 : 0; +} + +static double sawWave(double phase) { + double t = phase / juce::MathConstants::twoPi; + return t - std::floor(t); +} + +static double triangleWave(double phase) { + double t = phase / juce::MathConstants::twoPi; + return abs(2 * (t - std::floor(t)) - 1); +} + +static int luaSquareWave(lua_State* L) { + double phase = lua_tonumber(L, 1); + lua_pushnumber(L, squareWave(phase)); + return 1; +} + +static int luaSawWave(lua_State* L) { + double phase = lua_tonumber(L, 1); + lua_pushnumber(L, sawWave(phase)); + return 1; +} + +static int luaTriangleWave(lua_State* L) { + double phase = lua_tonumber(L, 1); + lua_pushnumber(L, triangleWave(phase)); + return 1; +} + +static int luaMix(lua_State* L) { + int nargs = lua_gettop(L); + + Point point1 = tableToPoint(L, 1); + Point point2 = tableToPoint(L, 2); + double weight = lua_tonumber(L, 3); + + Point point = Point( + point1.x * (1 - weight) + point2.x * weight, + point1.y * (1 - weight) + point2.y * weight, + point1.z * (1 - weight) + point2.z * weight + ); + + return pointToTable(L, point, 3); +} + +static int luaTranslate(lua_State* L) { + Point point = tableToPoint(L, 1); + Point translation = tableToPoint(L, 2); + + point.translate(translation.x, translation.y, translation.z); + + return pointToTable(L, point, 3); +} + +static int luaScale(lua_State* L) { + Point point = tableToPoint(L, 1); + Point scale = tableToPoint(L, 2); + + point.scale(scale.x, scale.y, scale.z); + + return pointToTable(L, point, 3); +} + +static int luaRotate(lua_State* L) { + double nargs = lua_gettop(L); + bool twoDimRotate = nargs == 2; + + Point point; + + if (twoDimRotate) { + Point point = tableToPoint(L, 1); + double angle = lua_tonumber(L, 2); + + point.rotate(0, 0, angle); + + return pointToTable(L, point, 2); + } else { + Point point = tableToPoint(L, 1); + double xRotate = lua_tonumber(L, 2); + double yRotate = lua_tonumber(L, 3); + double zRotate = lua_tonumber(L, 4); + + point.rotate(xRotate, yRotate, zRotate); + + return pointToTable(L, point, 3); + } +} + static int luaPrint(lua_State* L) { int nargs = lua_gettop(L); @@ -38,9 +328,25 @@ static int luaClear(lua_State* L) { } static const struct luaL_Reg luaLib[] = { - {"print", luaPrint}, - {"clear", luaClear}, - {NULL, NULL} /* end of array */ + {"osci_line", luaLine}, + {"osci_rect", luaRect}, + {"osci_ellipse", luaEllipse}, + {"osci_circle", luaCircle}, + {"osci_arc", luaArc}, + {"osci_polygon", luaPolygon}, + {"osci_bezier", luaBezier}, + {"osci_square", luaSquare}, + {"osci_lissajous", luaLissajous}, + {"osci_square_wave", luaSquareWave}, + {"osci_saw_wave", luaSawWave}, + {"osci_triangle_wave", luaTriangleWave}, + {"osci_mix", luaMix}, + {"osci_translate", luaTranslate}, + {"osci_scale", luaScale}, + {"osci_rotate", luaRotate}, + {"print", luaPrint}, + {"clear", luaClear}, + {NULL, NULL} /* end of array */ }; extern int luaopen_customprintlib(lua_State* L) { diff --git a/Source/shape/Line.cpp b/Source/shape/Line.cpp index e25dd94..dc812db 100644 --- a/Source/shape/Line.cpp +++ b/Source/shape/Line.cpp @@ -50,3 +50,18 @@ std::unique_ptr Line::clone() { std::string Line::type() { return std::string("Line"); } + +Line& Line::operator=(const Line& other) { + if (this == &other) { + return *this; + } + + this->x1 = other.x1; + this->y1 = other.y1; + this->z1 = other.z1; + this->x2 = other.x2; + this->y2 = other.y2; + this->z2 = other.z2; + + return *this; +} diff --git a/Source/shape/Line.h b/Source/shape/Line.h index 7f8a744..e55286a 100644 --- a/Source/shape/Line.h +++ b/Source/shape/Line.h @@ -16,6 +16,7 @@ public: double length() override; std::unique_ptr clone() override; std::string type() override; + Line& operator=(const Line& other); double x1, y1, z1, x2, y2, z2; diff --git a/osci-render.jucer b/osci-render.jucer index b3c18e0..48c3f14 100644 --- a/osci-render.jucer +++ b/osci-render.jucer @@ -654,9 +654,9 @@ - + + debugInformationFormat="ProgramDatabase" enablePluginBinaryCopyStep="1"/> From 0ea3c319d784537bf78e86475d61d50e23e204b8 Mon Sep 17 00:00:00 2001 From: James H Ball Date: Thu, 22 Aug 2024 14:18:04 +0100 Subject: [PATCH 2/3] Add default implementations for all Lua functions if no additional parameters are provided --- Source/lua/LuaParser.cpp | 64 +++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/Source/lua/LuaParser.cpp b/Source/lua/LuaParser.cpp index 091cb61..a996d5a 100644 --- a/Source/lua/LuaParser.cpp +++ b/Source/lua/LuaParser.cpp @@ -67,9 +67,11 @@ static Point tableToPoint(lua_State* L, int index) { } static int luaLine(lua_State* L) { + int nargs = lua_gettop(L); + double t = lua_tonumber(L, 1) / juce::MathConstants::twoPi; - Point point1 = tableToPoint(L, 2); - Point point2 = tableToPoint(L, 3); + Point point1 = nargs == 3 ? tableToPoint(L, 2) : Point(-1, -1); + Point point2 = nargs == 3 ? tableToPoint(L, 3) : Point(1, 1); Line line = Line(point1, point2); Point point = line.nextVector(t); @@ -108,8 +110,8 @@ static int luaRect(lua_State* L) { int nargs = lua_gettop(L); double phase = lua_tonumber(L, 1); - double width = lua_tonumber(L, 2); - double height = lua_tonumber(L, 3); + double width = nargs == 1 ? 1 : lua_tonumber(L, 2); + double height = nargs == 1 ? 1.5 : lua_tonumber(L, 3); Point topLeft = nargs == 4 ? tableToPoint(L, 4) : Point(-width / 2, -height / 2); Point point = genericRect(phase, topLeft, width, height); @@ -121,7 +123,7 @@ static int luaSquare(lua_State* L) { int nargs = lua_gettop(L); double phase = lua_tonumber(L, 1); - double width = lua_tonumber(L,2); + double width = nargs == 1 ? 1 : lua_tonumber(L,2); Point topLeft = nargs == 3 ? tableToPoint(L, 3) : Point(-width / 2, -width / 2); Point point = genericRect(phase, topLeft, width, width); @@ -130,9 +132,11 @@ static int luaSquare(lua_State* L) { } static int luaEllipse(lua_State* L) { + int nargs = lua_gettop(L); + double t = lua_tonumber(L, 1) / juce::MathConstants::twoPi; - double radiusX = lua_tonumber(L, 2); - double radiuxY = lua_tonumber(L, 3); + double radiusX = nargs == 1 ? 0.6 : lua_tonumber(L, 2); + double radiuxY = nargs == 1 ? 0.8 : lua_tonumber(L, 3); CircleArc ellipse = CircleArc(0, 0, radiusX, radiuxY, 0, juce::MathConstants::twoPi); Point point = ellipse.nextVector(t); @@ -141,8 +145,10 @@ static int luaEllipse(lua_State* L) { } static int luaCircle(lua_State* L) { + int nargs = lua_gettop(L); + double t = lua_tonumber(L, 1) / juce::MathConstants::twoPi; - double radius = lua_tonumber(L, 2); + double radius = nargs == 1 ? 0.8 : lua_tonumber(L, 2); CircleArc ellipse = CircleArc(0, 0, radius, radius, 0, juce::MathConstants::twoPi); Point point = ellipse.nextVector(t); @@ -151,11 +157,13 @@ static int luaCircle(lua_State* L) { } static int luaArc(lua_State* L) { + int nargs = lua_gettop(L); + double t = lua_tonumber(L, 1) / juce::MathConstants::twoPi; - double radiusX = lua_tonumber(L, 2); - double radiusY = lua_tonumber(L, 3); - double startAngle = lua_tonumber(L, 4); - double endAngle = lua_tonumber(L, 5); + double radiusX = nargs == 1 ? 1 : lua_tonumber(L, 2); + double radiusY = nargs == 1 ? 1 : lua_tonumber(L, 3); + double startAngle = nargs == 1 ? 0 : lua_tonumber(L, 4); + double endAngle = nargs == 1 ? juce::MathConstants::halfPi : lua_tonumber(L, 5); CircleArc arc = CircleArc(0, 0, radiusX, radiusY, startAngle, endAngle); Point point = arc.nextVector(t); @@ -164,7 +172,9 @@ static int luaArc(lua_State* L) { } static int luaPolygon(lua_State* L) { - double n = lua_tonumber(L, 2); + int nargs = lua_gettop(L); + + double n = nargs == 1 ? 5 : lua_tonumber(L, 2); double t = n * lua_tonumber(L, 1) / juce::MathConstants::twoPi; int floor_t = (int) t; @@ -185,20 +195,20 @@ static int luaBezier(lua_State* L) { int nargs = lua_gettop(L); double t = lua_tonumber(L, 1) / juce::MathConstants::twoPi; - Point point1 = tableToPoint(L, 2); - Point point2 = tableToPoint(L, 3); - Point point3 = tableToPoint(L, 4); + Point point1 = nargs == 1 ? Point(-1, -1) : tableToPoint(L, 2); + Point point2 = nargs == 1 ? Point(-1, 1) : tableToPoint(L, 3); + Point point3 = nargs == 1 ? Point(1, 1) : tableToPoint(L, 4); Point point; - if (nargs == 4) { - QuadraticBezierCurve curve = QuadraticBezierCurve(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y); - point = curve.nextVector(t); - } else { + if (nargs == 5) { Point point4 = tableToPoint(L, 5); CubicBezierCurve curve = CubicBezierCurve(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y, point4.x, point4.y); point = curve.nextVector(t); + } else { + QuadraticBezierCurve curve = QuadraticBezierCurve(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y); + point = curve.nextVector(t); } return pointToTable(L, point, 2); @@ -207,14 +217,14 @@ static int luaBezier(lua_State* L) { static int luaLissajous(lua_State* L) { int nargs = lua_gettop(L); - double theta = lua_tonumber(L, 1); - double radius = lua_tonumber(L, 2); - double ratioA = lua_tonumber(L, 3); - double ratioB = lua_tonumber(L, 4); - double phase = lua_tonumber(L, 5); + double phase = lua_tonumber(L, 1); + double radius = nargs == 1 ? 1 : lua_tonumber(L, 2); + double ratioA = nargs == 1 ? 1 : lua_tonumber(L, 3); + double ratioB = nargs == 1 ? 5 : lua_tonumber(L, 4); + double theta = nargs == 1 ? 0 : lua_tonumber(L, 5); - double x = radius * sin(ratioA * theta); - double y = radius * cos(ratioB * theta + phase); + double x = radius * sin(ratioA * phase); + double y = radius * cos(ratioB * phase + theta); return pointToTable(L, Point(x, y), 2); } From 08a196fb2c5b4a264236d560c0c93e75d505a3a4 Mon Sep 17 00:00:00 2001 From: James H Ball Date: Thu, 22 Aug 2024 14:42:54 +0100 Subject: [PATCH 3/3] Save visualiser fullscreen state to project --- Source/MainComponent.cpp | 12 ++++++------ Source/PluginEditor.cpp | 2 +- Source/PluginEditor.h | 1 - Source/PluginProcessor.cpp | 1 + Source/PluginProcessor.h | 2 ++ osci-render.jucer | 4 ++-- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Source/MainComponent.cpp b/Source/MainComponent.cpp index b1af041..3f6cad4 100644 --- a/Source/MainComponent.cpp +++ b/Source/MainComponent.cpp @@ -124,19 +124,19 @@ MainComponent::MainComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess createFile.triggerClick(); }; - if (!pluginEditor.visualiserFullScreen) { + if (!audioProcessor.visualiserFullScreen->getBoolValue()) { addAndMakeVisible(pluginEditor.visualiser); } pluginEditor.visualiser.setFullScreenCallback([this](FullScreenMode mode) { if (mode == FullScreenMode::TOGGLE) { - pluginEditor.visualiserFullScreen = !pluginEditor.visualiserFullScreen; + audioProcessor.visualiserFullScreen->setBoolValueNotifyingHost(!audioProcessor.visualiserFullScreen->getBoolValue()); } else if (mode == FullScreenMode::FULL_SCREEN) { - pluginEditor.visualiserFullScreen = true; + audioProcessor.visualiserFullScreen->setBoolValueNotifyingHost(true); } else if (mode == FullScreenMode::MAIN_COMPONENT) { - pluginEditor.visualiserFullScreen = false; + audioProcessor.visualiserFullScreen->setBoolValueNotifyingHost(false); } - pluginEditor.visualiser.setFullScreen(pluginEditor.visualiserFullScreen); + pluginEditor.visualiser.setFullScreen(audioProcessor.visualiserFullScreen->getBoolValue()); pluginEditor.resized(); pluginEditor.repaint(); @@ -234,7 +234,7 @@ void MainComponent::resized() { frequencyLabel.setBounds(bounds.removeFromTop(20)); bounds.removeFromTop(padding); - if (!pluginEditor.visualiserFullScreen) { + if (!audioProcessor.visualiserFullScreen->getBoolValue()) { auto minDim = juce::jmin(bounds.getWidth(), bounds.getHeight()); juce::Point localTopLeft = {bounds.getX(), bounds.getY()}; juce::Point topLeft = pluginEditor.getLocalPoint(this, localTopLeft); diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 9661f4d..7f1769b 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -143,7 +143,7 @@ void OscirenderAudioProcessorEditor::paint(juce::Graphics& g) { void OscirenderAudioProcessorEditor::resized() { auto area = getLocalBounds(); - if (visualiserFullScreen) { + if (audioProcessor.visualiserFullScreen->getBoolValue()) { visualiser.setBounds(area); return; } diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index 2d43787..8f367e6 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -49,7 +49,6 @@ public: std::atomic editingCustomFunction = false; VisualiserComponent visualiser{audioProcessor, nullptr, audioProcessor.legacyVisualiserEnabled->getBoolValue()}; - std::atomic visualiserFullScreen = false; SettingsComponent settings{audioProcessor, *this}; juce::ComponentAnimator codeEditorAnimator; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index ce9baaf..6e44d0a 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -179,6 +179,7 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() booleanParameters.push_back(smudgesEnabled); booleanParameters.push_back(upsamplingEnabled); booleanParameters.push_back(legacyVisualiserEnabled); + booleanParameters.push_back(visualiserFullScreen); for (auto parameter : booleanParameters) { addParameter(parameter); diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 55ddf32..3cbe9ca 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -162,6 +162,8 @@ public: BooleanParameter* smudgesEnabled = new BooleanParameter("Show Smudges", "smudgesEnabled", VERSION_HINT, true, "Adds a subtle layer of dirt/smudges to the oscilloscope display to make it look more realistic."); BooleanParameter* upsamplingEnabled = new BooleanParameter("Upsample Audio", "upsamplingEnabled", VERSION_HINT, false, "Upsamples the audio before visualising it to make it appear more realistic, at the expense of performance."); BooleanParameter* legacyVisualiserEnabled = new BooleanParameter("Use Legacy Visualiser", "legacyVisualiserEnabled", VERSION_HINT, false, "Replaces the realistic oscilloscope visualiser with the legacy visualiser. This may improve performance."); + BooleanParameter* visualiserFullScreen = new BooleanParameter("Visualiser Fullscreen", "visualiserFullScreen", VERSION_HINT, false, "Makes the software visualiser fullscreen."); + std::shared_ptr persistenceEffect = std::make_shared( new EffectParameter( "Persistence", diff --git a/osci-render.jucer b/osci-render.jucer index 48c3f14..59e19f7 100644 --- a/osci-render.jucer +++ b/osci-render.jucer @@ -654,9 +654,9 @@ - + + debugInformationFormat="ProgramDatabase"/>