Optimise Lua parsing for lower power machines

pull/82/head
James Ball 2022-06-12 17:52:28 +01:00 zatwierdzone przez James H Ball
rodzic c3df42c949
commit 9537bb2312
5 zmienionych plików z 150 dodań i 33 usunięć

Wyświetl plik

@ -201,6 +201,12 @@
<artifactId>luaj-jse</artifactId>
<version>3.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.bcel/bcel -->
<dependency>
<groupId>org.apache.bcel</groupId>
<artifactId>bcel</artifactId>
<version>6.5.0</version>
</dependency>
</dependencies>
<profiles>
<profile>

Wyświetl plik

@ -51,13 +51,11 @@ public class JavaAudioInput implements AudioInput {
byte[] data = new byte[CHUNK_SIZE];
microphone.start();
while (!stopped) {
if (microphone.available() >= CHUNK_SIZE) {
microphone.read(data, 0, CHUNK_SIZE);
for (int i = 0; i < CHUNK_SIZE / 2; i += 2 * STEP_SIZE) {
short sample = (short) ((data[2 * i + 1] << 8) + data[2 * i]);
for (AudioInputListener listener : listeners) {
listener.transmit((double) sample / Short.MAX_VALUE);
}
microphone.read(data, 0, CHUNK_SIZE);
for (int i = 0; i < CHUNK_SIZE / 2; i += 2 * STEP_SIZE) {
short sample = (short) ((data[2 * i + 1] << 8) + data[2 * i]);
for (AudioInputListener listener : listeners) {
listener.transmit((double) sample / Short.MAX_VALUE);
}
}
}

Wyświetl plik

@ -47,6 +47,7 @@ public class Gui extends Application {
@Override
public void start(Stage stage) throws Exception {
System.setProperty("prism.lcdtext", "false");
System.setProperty("org.luaj.luajc", "true");
editor = new CodeEditor();
editor.initialize();

Wyświetl plik

@ -1,5 +1,8 @@
package sh.ball.parser.lua;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.lib.jse.JsePlatform;
import sh.ball.audio.FrameSource;
import sh.ball.parser.FileParser;
import sh.ball.shapes.Vector2;
@ -10,7 +13,13 @@ import java.util.stream.Collectors;
public class LuaParser extends FileParser<FrameSource<Vector2>> {
private final LuaSampleSource sampleSource = new LuaSampleSource();
private static final Globals globals = JsePlatform.standardGlobals();
static {
org.luaj.vm2.luajc.LuaJC.install(globals);
}
private final LuaSampleSource sampleSource = new LuaSampleSource(globals);
private String script;
@ -26,11 +35,9 @@ public class LuaParser extends FileParser<FrameSource<Vector2>> {
@Override
public FrameSource<Vector2> parse() throws Exception {
ScriptEngineManager sem = new ScriptEngineManager();
Compilable e = (Compilable) sem.getEngineByName("luaj");
CompiledScript compiledScript = e.compile(script);
LuaFunction f = globals.load(new StringReader(script), "script").checkfunction();
sampleSource.setScript(script, compiledScript);
sampleSource.setFunction(script, f);
return sampleSource;
}

Wyświetl plik

@ -1,34 +1,40 @@
package sh.ball.parser.lua;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.*;
import org.luaj.vm2.lib.ThreeArgFunction;
import org.luaj.vm2.lib.TwoArgFunction;
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import sh.ball.audio.FrameSource;
import sh.ball.shapes.Vector2;
import javax.script.Bindings;
import javax.script.CompiledScript;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
public class LuaSampleSource implements FrameSource<Vector2> {
private Bindings bindings = new SimpleBindings();
private CompiledScript lastWorkingScript;
private final Globals globals;
private final Map<LuaString, LuaValue> bindings = new HashMap<>();
private final Set<LuaString> programDefinedVariables = new HashSet<>();
private LuaFunction lastWorkingFunction;
private String lastWorkingTextScript;
private CompiledScript script;
private LuaFunction function;
private String textScript;
private boolean active = true;
private long step = 1;
private Set<String> programDefinedVariables = new HashSet<>();
public void setScript(String textScript, CompiledScript script) {
if (lastWorkingScript == null) {
lastWorkingScript = script;
public LuaSampleSource(Globals globals) {
this.globals = globals;
}
public void setFunction(String textScript, LuaFunction function) {
if (lastWorkingFunction == null) {
lastWorkingFunction = function;
lastWorkingTextScript = textScript;
}
this.script = script;
this.function = function;
this.textScript = textScript;
}
@ -37,31 +43,32 @@ public class LuaSampleSource implements FrameSource<Vector2> {
try {
boolean updatedFile = false;
bindings.put("step", (double) step);
globals.setmetatable(new BindingsMetatable(bindings));
bindings.put(LuaValue.valueOf("step"), LuaValue.valueOf((double) step));
LuaValue result;
try {
result = (LuaValue) script.eval(bindings);
result = (LuaValue) LuaSampleSource.eval(function, globals);
if (!lastWorkingTextScript.equals(textScript)) {
lastWorkingScript = script;
lastWorkingFunction = function;
lastWorkingTextScript = textScript;
updatedFile = true;
}
} catch (Exception e) {
result = (LuaValue) lastWorkingScript.eval(bindings);
result = (LuaValue) LuaSampleSource.eval(lastWorkingFunction, globals);
}
step++;
if (updatedFile) {
// reset variables
step = 1;
List<String> variablesToRemove = new ArrayList<>();
List<LuaString> variablesToRemove = new ArrayList<>();
bindings.keySet().forEach(name -> {
if (!programDefinedVariables.contains(name)) {
variablesToRemove.add(name);
}
});
variablesToRemove.forEach(name -> bindings.remove(name));
variablesToRemove.forEach(bindings::remove);
}
return new Vector2(result.get(1).checkdouble(), result.get(2).checkdouble());
@ -94,11 +101,109 @@ public class LuaSampleSource implements FrameSource<Vector2> {
}
public void setVariable(String variableName, Object value) {
programDefinedVariables.add(variableName);
bindings.put(variableName, value);
programDefinedVariables.add(LuaValue.valueOf(variableName));
bindings.put(LuaValue.valueOf(variableName), toLua(value));
}
public void resetStep() {
step = 1;
}
/*
MIT License
Copyright (c) 2007 LuaJ. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit p ersons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------
The below functions have all been modified by James Ball to optimise Lua parsing
on machines with poorer performance.
*/
static class BindingsMetatable extends LuaTable {
BindingsMetatable(Map<LuaString, LuaValue> bindings) {
this.rawset(LuaValue.INDEX, new TwoArgFunction() {
public LuaValue call(LuaValue table, LuaValue key) {
LuaValue value = bindings.get(key.checkstring());
if (value == null) {
return LuaValue.NIL;
} else {
return value;
}
}
});
this.rawset(LuaValue.NEWINDEX, new ThreeArgFunction() {
public LuaValue call(LuaValue table, LuaValue key, LuaValue value) {
if (value == null || value.type() == LuaValue.TNIL) {
bindings.remove(key.checkstring());
} else {
bindings.put(key.checkstring(), value);
}
return LuaValue.NONE;
}
});
}
}
static private LuaValue toLua(Object javaValue) {
return javaValue == null? LuaValue.NIL:
javaValue instanceof LuaValue? (LuaValue) javaValue:
CoerceJavaToLua.coerce(javaValue);
}
static private Object toJava(LuaValue luajValue) {
return switch (luajValue.type()) {
case LuaValue.TNIL -> null;
case LuaValue.TSTRING -> luajValue.tojstring();
case LuaValue.TUSERDATA -> luajValue.checkuserdata(Object.class);
case LuaValue.TNUMBER -> luajValue.isinttype() ?
(Object) luajValue.toint() :
(Object) luajValue.todouble();
default -> luajValue;
};
}
static private Object toJava(Varargs v) {
final int n = v.narg();
switch (n) {
case 0: return null;
case 1: return toJava(v.arg1());
default:
Object[] o = new Object[n];
for (int i=0; i<n; ++i)
o[i] = toJava(v.arg(i+1));
return o;
}
}
static private Object eval(LuaFunction f, Globals g) throws ScriptException {
try {
f = f.getClass().newInstance();
} catch (Exception e) {
throw new ScriptException(e);
}
f.initupvalue1(g);
return toJava(f.invoke(LuaValue.NONE));
}
}