diff --git a/package.json b/package.json
index 590e92625..3c738719a 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
"interactive-shader-format": "github:vcync/interactive-shader-format-js#feat/ImageBitmap",
"lfo-for-modv": "0.0.1",
"lodash.get": "^4.4.2",
+ "mathjs": "^3.20.2",
"meyda": "^5.0.1",
"mkdirp": "^0.5.1",
"npm": "6.14.6",
diff --git a/src/application/worker/store/modules/expressions.js b/src/application/worker/store/modules/expressions.js
new file mode 100644
index 000000000..90099345e
--- /dev/null
+++ b/src/application/worker/store/modules/expressions.js
@@ -0,0 +1,128 @@
+import math from "mathjs";
+import uuidv4 from "uuid/v4";
+
+const state = {
+ assignments: {}
+};
+
+// getters
+const getters = {
+ getByInputId: state => inputId => {
+ const assignmentValues = Object.values(state.assignments);
+
+ return assignmentValues.find(assignment => assignment.inputId === inputId);
+ }
+};
+
+function compileExpression(expression) {
+ const scope = { value: 0, time: 0 };
+
+ let newFunction;
+ try {
+ const node = math.parse(expression, scope);
+
+ newFunction = node.compile();
+ newFunction.eval(scope);
+ } catch (e) {
+ throw e;
+ }
+
+ return newFunction;
+}
+
+// actions
+const actions = {
+ create({ commit }, { expression = "value", id, inputId }) {
+ if (!inputId) {
+ throw new Error("Input ID required");
+ }
+
+ if (expression.trim() === "value") {
+ return null;
+ }
+
+ const expressionId = id || uuidv4();
+
+ const func = compileExpression(expression);
+
+ if (!func) {
+ throw new Error("Unable to compile Expression");
+ }
+
+ const assignment = {
+ id: expressionId,
+ inputId,
+ func,
+ expression
+ };
+
+ commit("ADD_EXPRESSION", { assignment });
+
+ return expressionId;
+ },
+
+ update({ commit }, { id, expression = "value" }) {
+ if (!id) {
+ throw new Error("Expression ID required");
+ }
+
+ const existingExpression = state.assignments[id];
+
+ if (!existingExpression) {
+ throw new Error(`Existing expression with ID ${id} not found`);
+ }
+
+ if (expression.trim() === "value") {
+ commit("REMOVE_EXPRESSION", { id });
+ return null;
+ }
+
+ const func = compileExpression(expression);
+
+ if (!func) {
+ throw new Error("Unable to compile Expression");
+ }
+
+ existingExpression.func = func;
+ existingExpression.expression = expression;
+
+ commit("ADD_EXPRESSION", { assignment: existingExpression });
+ return existingExpression.id;
+ },
+
+ remove({ commit }, args) {
+ commit("REMOVE_EXPRESSION", args);
+ },
+
+ createPresetData() {
+ return state;
+ },
+
+ async loadPresetData({ dispatch }, data) {
+ const assignments = Object.values(data.assignments);
+ for (let i = 0, len = assignments.length; i < len; i++) {
+ const assignment = assignments[i];
+
+ await dispatch("create", assignment);
+ }
+ }
+};
+
+// mutations
+const mutations = {
+ ADD_EXPRESSION(state, { assignment }) {
+ state.assignments[assignment.id] = assignment;
+ },
+
+ REMOVE_EXPRESSION(state, { id }) {
+ delete state.assignments[id];
+ }
+};
+
+export default {
+ namespaced: true,
+ state,
+ getters,
+ actions,
+ mutations
+};
diff --git a/src/application/worker/store/modules/modules.js b/src/application/worker/store/modules/modules.js
index 7aec22a2e..b6acccc1c 100644
--- a/src/application/worker/store/modules/modules.js
+++ b/src/application/worker/store/modules/modules.js
@@ -333,6 +333,7 @@ const actions = {
{ moduleId, prop, data, group, groupName, writeToSwap }
) {
const moduleName = state.active[moduleId].$moduleName;
+ const inputId = state.active[moduleId].$props[prop].id;
const propData = state.registered[moduleName].props[prop];
const currentValue = state.active[moduleId][prop];
const { type } = propData;
@@ -347,18 +348,18 @@ const actions = {
let dataOut = data;
- // store.getters['plugins/enabledPlugins']
- // .filter(plugin => 'processValue' in plugin.plugin)
- // .forEach(plugin => {
- // const newValue = plugin.plugin.processValue({
- // currentValue: data,
- // controlVariable: prop,
- // delta: modV.delta,
- // moduleName: name
- // })
-
- // if (typeof newValue !== 'undefined') dataOut = newValue
- // })
+ const expressionAssignment = store.getters["expressions/getByInputId"](
+ inputId
+ );
+
+ if (expressionAssignment) {
+ const scope = {
+ value: dataOut,
+ time: Date.now()
+ };
+
+ dataOut = expressionAssignment.func.eval(scope);
+ }
if (store.state.dataTypes[type] && store.state.dataTypes[type].create) {
dataOut = await store.state.dataTypes[type].create(dataOut);
diff --git a/src/components/InputConfig.vue b/src/components/InputConfig.vue
index ed3eafb21..c443540ef 100644
--- a/src/components/InputConfig.vue
+++ b/src/components/InputConfig.vue
@@ -65,6 +65,18 @@
+
+