kopia lustrzana https://github.com/jameshball/osci-render
Refactor LuaParser and make it abort running Lua if taking too long
rodzic
faaa049b9d
commit
2e23c485b6
|
@ -30,7 +30,7 @@ OscirenderLookAndFeel::OscirenderLookAndFeel() {
|
||||||
|
|
||||||
// combo box
|
// combo box
|
||||||
setColour(juce::ComboBox::backgroundColourId, Colours::veryDark);
|
setColour(juce::ComboBox::backgroundColourId, Colours::veryDark);
|
||||||
setColour(juce::ComboBox::outlineColourId, juce::Colours::white);
|
setColour(juce::ComboBox::outlineColourId, Colours::veryDark);
|
||||||
setColour(juce::ComboBox::arrowColourId, juce::Colours::white);
|
setColour(juce::ComboBox::arrowColourId, juce::Colours::white);
|
||||||
|
|
||||||
// text box
|
// text box
|
||||||
|
@ -92,10 +92,10 @@ void OscirenderLookAndFeel::drawComboBox(juce::Graphics& g, int width, int heigh
|
||||||
juce::Rectangle<int> boxBounds{0, 0, width, height};
|
juce::Rectangle<int> boxBounds{0, 0, width, height};
|
||||||
|
|
||||||
g.setColour(box.findColour(juce::ComboBox::backgroundColourId));
|
g.setColour(box.findColour(juce::ComboBox::backgroundColourId));
|
||||||
g.fillRect(boxBounds.toFloat());
|
g.fillRoundedRectangle(boxBounds.toFloat(), RECT_RADIUS);
|
||||||
|
|
||||||
g.setColour(box.findColour(juce::ComboBox::outlineColourId).withAlpha(box.isEnabled() ? 1.0f : 0.5f));
|
g.setColour(box.findColour(juce::ComboBox::outlineColourId).withAlpha(box.isEnabled() ? 1.0f : 0.5f));
|
||||||
g.drawRect(boxBounds.toFloat(), 1.0f);
|
g.drawRoundedRectangle(boxBounds.toFloat(), RECT_RADIUS, 1.0f);
|
||||||
|
|
||||||
juce::Rectangle<int> arrowZone{width - 15, 0, 10, height};
|
juce::Rectangle<int> arrowZone{width - 15, 0, 10, height};
|
||||||
juce::Path path;
|
juce::Path path;
|
||||||
|
@ -164,8 +164,14 @@ void OscirenderLookAndFeel::drawGroupComponentOutline(juce::Graphics& g, int wid
|
||||||
|
|
||||||
auto alpha = group.isEnabled() ? 1.0f : 0.5f;
|
auto alpha = group.isEnabled() ? 1.0f : 0.5f;
|
||||||
|
|
||||||
|
juce::Path background;
|
||||||
|
background.addRoundedRectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), RECT_RADIUS, RECT_RADIUS);
|
||||||
|
auto ds = juce::DropShadow(juce::Colours::black, 3, juce::Point<int>(0, 0));
|
||||||
|
ds.drawForPath(g, background);
|
||||||
|
|
||||||
g.setColour(group.findColour(groupComponentBackgroundColourId).withMultipliedAlpha(alpha));
|
g.setColour(group.findColour(groupComponentBackgroundColourId).withMultipliedAlpha(alpha));
|
||||||
g.fillRect(bounds);
|
g.fillPath(background);
|
||||||
|
|
||||||
|
|
||||||
auto header = bounds.removeFromTop(2 * textH);
|
auto header = bounds.removeFromTop(2 * textH);
|
||||||
|
|
||||||
|
@ -192,8 +198,13 @@ void OscirenderLookAndFeel::drawLinearSlider(juce::Graphics& g, int x, int y, in
|
||||||
|
|
||||||
auto thumbWidth = getSliderThumbRadius(slider);
|
auto thumbWidth = getSliderThumbRadius(slider);
|
||||||
|
|
||||||
|
juce::Path thumb;
|
||||||
|
thumb.addEllipse(juce::Rectangle<float>(static_cast<float>(thumbWidth), static_cast<float>(thumbWidth)).withCentre(point));
|
||||||
|
juce::DropShadow ds(juce::Colours::black, 1, { 0, 1 });
|
||||||
|
|
||||||
|
ds.drawForPath(g, thumb);
|
||||||
g.setColour(slider.findColour(sliderThumbOutlineColourId).withAlpha(slider.isEnabled() ? 1.0f : 0.5f));
|
g.setColour(slider.findColour(sliderThumbOutlineColourId).withAlpha(slider.isEnabled() ? 1.0f : 0.5f));
|
||||||
g.drawEllipse(juce::Rectangle<float>(static_cast<float>(thumbWidth), static_cast<float>(thumbWidth)).withCentre(point), 1.0f);
|
g.strokePath(thumb, juce::PathStrokeType(1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OscirenderLookAndFeel::drawButtonBackground(juce::Graphics& g, juce::Button& button, const juce::Colour& backgroundColour, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) {
|
void OscirenderLookAndFeel::drawButtonBackground(juce::Graphics& g, juce::Button& button, const juce::Colour& backgroundColour, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) {
|
||||||
|
|
|
@ -69,6 +69,8 @@ class OscirenderLookAndFeel : public juce::LookAndFeel_V4 {
|
||||||
public:
|
public:
|
||||||
OscirenderLookAndFeel();
|
OscirenderLookAndFeel();
|
||||||
|
|
||||||
|
static const int RECT_RADIUS = 5;
|
||||||
|
|
||||||
void drawComboBox(juce::Graphics& g, int width, int height, bool, int, int, int, int, juce::ComboBox& box) override;
|
void drawComboBox(juce::Graphics& g, int width, int height, bool, int, int, int, int, juce::ComboBox& box) override;
|
||||||
void positionComboBoxText(juce::ComboBox& box, juce::Label& label) override;
|
void positionComboBoxText(juce::ComboBox& box, juce::Label& label) override;
|
||||||
void drawTickBox(juce::Graphics& g, juce::Component& component,
|
void drawTickBox(juce::Graphics& g, juce::Component& component,
|
||||||
|
|
|
@ -152,24 +152,24 @@ void OscirenderAudioProcessorEditor::paint(juce::Graphics& g) {
|
||||||
|
|
||||||
auto ds = juce::DropShadow(juce::Colours::black, 5, juce::Point<int>(0, 0));
|
auto ds = juce::DropShadow(juce::Colours::black, 5, juce::Point<int>(0, 0));
|
||||||
|
|
||||||
if (!usingNativeMenuBar) {
|
// if (!usingNativeMenuBar) {
|
||||||
// add drop shadow to the menu bar
|
// // add drop shadow to the menu bar
|
||||||
ds.drawForRectangle(g, menuBar.getBounds());
|
// ds.drawForRectangle(g, menuBar.getBounds());
|
||||||
}
|
// }
|
||||||
|
|
||||||
for (int i = 0; i < codeEditors.size(); i++) {
|
//for (int i = 0; i < codeEditors.size(); i++) {
|
||||||
if (codeEditors[i]->isVisible()) {
|
// if (codeEditors[i]->isVisible()) {
|
||||||
ds.drawForRectangle(g, codeEditors[i]->getBounds());
|
// ds.drawForRectangle(g, codeEditors[i]->getBounds());
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
|
//if (lua.isVisible()) {
|
||||||
|
// ds.drawForRectangle(g, lua.getBounds());
|
||||||
|
//}
|
||||||
|
|
||||||
if (lua.isVisible()) {
|
// if (console.isVisible()) {
|
||||||
ds.drawForRectangle(g, lua.getBounds());
|
// ds.drawForRectangle(g, console.getBounds());
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (console.isVisible()) {
|
|
||||||
ds.drawForRectangle(g, console.getBounds());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OscirenderAudioProcessorEditor::resized() {
|
void OscirenderAudioProcessorEditor::resized() {
|
||||||
|
|
|
@ -97,13 +97,13 @@ void SettingsComponent::mouseDown(const juce::MouseEvent& event) {
|
||||||
|
|
||||||
void SettingsComponent::paint(juce::Graphics& g) {
|
void SettingsComponent::paint(juce::Graphics& g) {
|
||||||
// add drop shadow to each component
|
// add drop shadow to each component
|
||||||
auto dc = juce::DropShadow(juce::Colours::black, 5, juce::Point<int>(0, 0));
|
//auto dc = juce::DropShadow(juce::Colours::black, 5, juce::Point<int>(0, 0));
|
||||||
dc.drawForRectangle(g, main.getBounds());
|
//dc.drawForRectangle(g, main.getBounds());
|
||||||
dc.drawForRectangle(g, effects.getBounds());
|
//dc.drawForRectangle(g, effects.getBounds());
|
||||||
dc.drawForRectangle(g, midi.getBounds());
|
//dc.drawForRectangle(g, midi.getBounds());
|
||||||
dc.drawForRectangle(g, perspective.getBounds());
|
//dc.drawForRectangle(g, perspective.getBounds());
|
||||||
|
|
||||||
if (txt.isVisible()) {
|
//if (txt.isVisible()) {
|
||||||
dc.drawForRectangle(g, txt.getBounds());
|
// dc.drawForRectangle(g, txt.getBounds());
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,23 @@
|
||||||
std::function<void(const std::string&)> LuaParser::onPrint;
|
std::function<void(const std::string&)> LuaParser::onPrint;
|
||||||
std::function<void()> LuaParser::onClear;
|
std::function<void()> LuaParser::onClear;
|
||||||
|
|
||||||
|
void LuaParser::maximumInstructionsReached(lua_State* L, lua_Debug* D) {
|
||||||
|
lua_getstack(L, 1, D);
|
||||||
|
lua_getinfo(L, "l", D);
|
||||||
|
|
||||||
|
std::string msg = std::to_string(D->currentline) + ": Maximum instructions reached! You may have an infinite loop.";
|
||||||
|
lua_pushstring(L, msg.c_str());
|
||||||
|
lua_error(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaParser::setMaximumInstructions(lua_State*& L, int count) {
|
||||||
|
lua_sethook(L, LuaParser::maximumInstructionsReached, LUA_MASKCOUNT, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaParser::resetMaximumInstructions(lua_State*& L) {
|
||||||
|
lua_sethook(L, LuaParser::maximumInstructionsReached, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static int luaPrint(lua_State* L) {
|
static int luaPrint(lua_State* L) {
|
||||||
int nargs = lua_gettop(L);
|
int nargs = lua_gettop(L);
|
||||||
|
|
||||||
|
@ -81,13 +98,68 @@ void LuaParser::parse(lua_State*& L) {
|
||||||
const char* error = lua_tostring(L, -1);
|
const char* error = lua_tostring(L, -1);
|
||||||
reportError(error);
|
reportError(error);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
revertToFallback(L);
|
||||||
|
} else {
|
||||||
|
functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaParser::setGlobalVariable(lua_State*& L, const char* name, double value) {
|
||||||
|
lua_pushnumber(L, value);
|
||||||
|
lua_setglobal(L, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaParser::setGlobalVariable(lua_State*& L, const char* name, int value) {
|
||||||
|
lua_pushnumber(L, value);
|
||||||
|
lua_setglobal(L, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaParser::setGlobalVariables(lua_State*& L, LuaVariables& vars) {
|
||||||
|
setGlobalVariable(L, "step", vars.step);
|
||||||
|
setGlobalVariable(L, "sample_rate", vars.sampleRate);
|
||||||
|
setGlobalVariable(L, "frequency", vars.frequency);
|
||||||
|
setGlobalVariable(L, "phase", vars.phase);
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_SLIDERS; i++) {
|
||||||
|
setGlobalVariable(L, SLIDER_NAMES[i], vars.sliders[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vars.isEffect) {
|
||||||
|
setGlobalVariable(L, "x", vars.x);
|
||||||
|
setGlobalVariable(L, "y", vars.y);
|
||||||
|
setGlobalVariable(L, "z", vars.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaParser::incrementVars(LuaVariables& vars) {
|
||||||
|
vars.step++;
|
||||||
|
vars.phase += 2 * std::numbers::pi * vars.frequency / vars.sampleRate;
|
||||||
|
if (vars.phase > 2 * std::numbers::pi) {
|
||||||
|
vars.phase -= 2 * std::numbers::pi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaParser::clearStack(lua_State*& L) {
|
||||||
|
lua_settop(L, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaParser::revertToFallback(lua_State*& L) {
|
||||||
functionRef = -1;
|
functionRef = -1;
|
||||||
usingFallbackScript = true;
|
usingFallbackScript = true;
|
||||||
if (script != fallbackScript) {
|
if (script != fallbackScript) {
|
||||||
reset(L, fallbackScript);
|
reset(L, fallbackScript);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
||||||
|
void LuaParser::readTable(lua_State*& L, std::vector<float>& values) {
|
||||||
|
auto length = lua_rawlen(L, -1);
|
||||||
|
|
||||||
|
for (int i = 1; i <= length; i++) {
|
||||||
|
lua_pushinteger(L, i);
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
float value = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
values.push_back(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,77 +174,37 @@ std::vector<float> LuaParser::run(lua_State*& L, LuaVariables& vars) {
|
||||||
|
|
||||||
std::vector<float> values;
|
std::vector<float> values;
|
||||||
|
|
||||||
lua_pushnumber(L, vars.step);
|
setGlobalVariables(L, vars);
|
||||||
lua_setglobal(L, "step");
|
|
||||||
|
|
||||||
lua_pushnumber(L, vars.sampleRate);
|
|
||||||
lua_setglobal(L, "sample_rate");
|
|
||||||
|
|
||||||
lua_pushnumber(L, vars.frequency);
|
|
||||||
lua_setglobal(L, "frequency");
|
|
||||||
|
|
||||||
lua_pushnumber(L, vars.phase);
|
|
||||||
lua_setglobal(L, "phase");
|
|
||||||
|
|
||||||
for (int i = 0; i < NUM_SLIDERS; i++) {
|
|
||||||
lua_pushnumber(L, vars.sliders[i]);
|
|
||||||
lua_setglobal(L, SLIDER_NAMES[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vars.isEffect) {
|
|
||||||
lua_pushnumber(L, vars.x);
|
|
||||||
lua_setglobal(L, "x");
|
|
||||||
|
|
||||||
lua_pushnumber(L, vars.y);
|
|
||||||
lua_setglobal(L, "y");
|
|
||||||
|
|
||||||
lua_pushnumber(L, vars.z);
|
|
||||||
lua_setglobal(L, "z");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Get the function from the registry
|
||||||
lua_geti(L, LUA_REGISTRYINDEX, functionRef);
|
lua_geti(L, LUA_REGISTRYINDEX, functionRef);
|
||||||
|
|
||||||
|
setMaximumInstructions(L, 1000000);
|
||||||
|
|
||||||
if (lua_isfunction(L, -1)) {
|
if (lua_isfunction(L, -1)) {
|
||||||
const int ret = lua_pcall(L, 0, LUA_MULTRET, 0);
|
const int ret = lua_pcall(L, 0, LUA_MULTRET, 0);
|
||||||
if (ret != LUA_OK) {
|
if (ret != LUA_OK) {
|
||||||
const char* error = lua_tostring(L, -1);
|
const char* error = lua_tostring(L, -1);
|
||||||
reportError(error);
|
reportError(error);
|
||||||
functionRef = -1;
|
revertToFallback(L);
|
||||||
usingFallbackScript = true;
|
} else {
|
||||||
if (script != fallbackScript) {
|
if (lua_istable(L, -1)) {
|
||||||
reset(L, fallbackScript);
|
readTable(L, values);
|
||||||
}
|
|
||||||
} else if (lua_istable(L, -1)) {
|
|
||||||
auto length = lua_rawlen(L, -1);
|
|
||||||
|
|
||||||
for (int i = 1; i <= length; i++) {
|
|
||||||
lua_pushinteger(L, i);
|
|
||||||
lua_gettable(L, -2);
|
|
||||||
float value = lua_tonumber(L, -1);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
values.push_back(value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
functionRef = -1;
|
revertToFallback(L);
|
||||||
usingFallbackScript = true;
|
|
||||||
if (script != fallbackScript) {
|
|
||||||
reset(L, fallbackScript);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetMaximumInstructions(L);
|
||||||
|
|
||||||
if (functionRef != -1 && !usingFallbackScript) {
|
if (functionRef != -1 && !usingFallbackScript) {
|
||||||
resetErrors();
|
resetErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear stack
|
clearStack(L);
|
||||||
lua_settop(L, 0);
|
|
||||||
|
|
||||||
vars.step++;
|
incrementVars(vars);
|
||||||
vars.phase += 2 * std::numbers::pi * vars.frequency / vars.sampleRate;
|
|
||||||
if (vars.phase > 2 * std::numbers::pi) {
|
|
||||||
vars.phase -= 2 * std::numbers::pi;
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ struct LuaVariables {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lua_State;
|
struct lua_State;
|
||||||
|
struct lua_Debug;
|
||||||
class LuaParser {
|
class LuaParser {
|
||||||
public:
|
public:
|
||||||
LuaParser(juce::String fileName, juce::String script, std::function<void(int, juce::String, juce::String)> errorCallback, juce::String fallbackScript = "return { 0.0, 0.0 }");
|
LuaParser(juce::String fileName, juce::String script, std::function<void(int, juce::String, juce::String)> errorCallback, juce::String fallbackScript = "return { 0.0, 0.0 }");
|
||||||
|
@ -73,15 +74,25 @@ public:
|
||||||
static std::function<void()> onClear;
|
static std::function<void()> onClear;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static void maximumInstructionsReached(lua_State* L, lua_Debug* D);
|
||||||
|
|
||||||
void reset(lua_State*& L, juce::String script);
|
void reset(lua_State*& L, juce::String script);
|
||||||
void reportError(const char* error);
|
void reportError(const char* error);
|
||||||
void parse(lua_State*& L);
|
void parse(lua_State*& L);
|
||||||
|
void setGlobalVariable(lua_State*& L, const char* name, double value);
|
||||||
|
void setGlobalVariable(lua_State*& L, const char* name, int value);
|
||||||
|
void setGlobalVariables(lua_State*& L, LuaVariables& vars);
|
||||||
|
void incrementVars(LuaVariables& vars);
|
||||||
|
void clearStack(lua_State*& L);
|
||||||
|
void revertToFallback(lua_State*& L);
|
||||||
|
void readTable(lua_State*& L, std::vector<float>& values);
|
||||||
|
void setMaximumInstructions(lua_State*& L, int count);
|
||||||
|
void resetMaximumInstructions(lua_State*& L);
|
||||||
|
|
||||||
int functionRef = -1;
|
int functionRef = -1;
|
||||||
bool usingFallbackScript = false;
|
bool usingFallbackScript = false;
|
||||||
juce::String script;
|
juce::String script;
|
||||||
juce::String fallbackScript;
|
juce::String fallbackScript;
|
||||||
std::atomic<bool> updateVariables = false;
|
|
||||||
std::function<void(int, juce::String, juce::String)> errorCallback;
|
std::function<void(int, juce::String, juce::String)> errorCallback;
|
||||||
juce::String fileName;
|
juce::String fileName;
|
||||||
std::vector<lua_State*> seenStates;
|
std::vector<lua_State*> seenStates;
|
||||||
|
|
Ładowanie…
Reference in New Issue