Skip to content
Permalink
326a95b2f9
Go to file
 
 
Cannot retrieve contributors at this time
1776 lines (1588 sloc) 49.7 KB
#include <ctype.h> // isdigit
#include <stdint.h> // types
#include <stdio.h> // printf
#include <stdlib.h> // rand, strtol
#include <string.h>
#include "euclidean/euclidean.h"
#include "ii.h"
#include "table.h"
#include "teletype.h"
#include "util.h"
#ifdef SIM
#define DBG printf("%s", dbg);
#else
#include "print_funcs.h"
#define DBG print_dbg(dbg);
#endif
// http://stackoverflow.com/questions/3599160/unused-parameter-warnings-in-c-code
// Needs to be named NOTUSED to void conflict with UNUSED from
// libavr32/asf/avr32/utils/compiler.h
// Probably should put this macro somewhere else
#ifdef __GNUC__
#define NOTUSED(x) UNUSED_##x __attribute__((__unused__))
#else
#define NOTUSED(x) UNUSED_##x
#endif
static const char *errordesc[] = { "OK",
WELCOME,
"UNKNOWN WORD",
"COMMAND TOO LONG",
"NOT ENOUGH PARAMS",
"TOO MANY PARAMS",
"MOD NOT ALLOWED HERE",
"EXTRA SEPARATOR",
"NEED SEPARATOR",
"BAD SEPARATOR",
"MOVE LEFT" };
const char *tele_error(error_t e) {
return errordesc[e];
}
// static char dbg[32];
static char pcmd[32];
int16_t output, output_new;
char error_detail[16];
uint8_t mutes[8];
tele_pattern_t tele_patterns[4];
static uint8_t pn;
static char condition;
static tele_command_t tele_stack[TELE_STACK_SIZE];
static uint8_t tele_stack_top;
static uint8_t left;
volatile update_metro_t update_metro;
volatile update_tr_t update_tr;
volatile update_cv_t update_cv;
volatile update_cv_slew_t update_cv_slew;
volatile update_delay_t update_delay;
volatile update_s_t update_s;
volatile update_cv_off_t update_cv_off;
volatile update_ii_t update_ii;
volatile update_scene_t update_scene;
volatile update_pi_t update_pi;
volatile update_kill_t update_kill;
volatile update_mute_t update_mute;
volatile update_input_t update_input;
volatile run_script_t run_script;
volatile uint8_t input_states[8];
const char *to_v(int16_t);
/////////////////////////////////////////////////////////////////
// STACK ////////////////////////////////////////////////////////
static int16_t pop(void);
static void push(int16_t);
static int16_t top;
static int16_t stack[STACK_SIZE];
int16_t pop() {
top--;
// sprintf(dbg,"\r\npop %d", stack[top]);
return stack[top];
}
void push(int16_t data) {
stack[top] = data;
// sprintf(dbg,"\r\npush %d", stack[top]);
top++;
}
/////////////////////////////////////////////////////////////////
// VARS ARRAYS //////////////////////////////////////////////////
// ENUM IN HEADER
static void v_P_N(void);
static void v_M(void);
static void v_M_ACT(void);
static void v_P_L(void);
static void v_P_I(void);
static void v_P_HERE(void);
static void v_P_NEXT(void);
static void v_P_PREV(void);
static void v_P_WRAP(void);
static void v_P_START(void);
static void v_P_END(void);
static void v_O(void);
static void v_DRUNK(void);
static void v_Q(void);
static void v_Q_N(void);
static void v_Q_AVG(void);
static void v_SCENE(void);
static void v_FLIP(void);
static int16_t tele_q[16];
#define VARS 39
static tele_var_t tele_vars[VARS] = {
{ "I", NULL, 0 }, // gets overwritten by ITER
{ "TIME", NULL, 0 },
{ "TIME.ACT", NULL, 1 },
{ "IN", NULL, 0 },
{ "PARAM", NULL, 0 },
{ "PRESET", NULL, 0 },
{ "M", v_M, 1000 },
{ "M.ACT", v_M_ACT, 1 },
{ "X", NULL, 0 },
{ "Y", NULL, 0 },
{ "Z", NULL, 0 },
{ "T", NULL, 0 },
{ "A", NULL, 1 },
{ "B", NULL, 2 },
{ "C", NULL, 3 },
{ "D", NULL, 4 },
{ "O", v_O, 0 },
{ "DRUNK", v_DRUNK, 0 },
{ "Q", v_Q, 0 },
{ "Q.N", v_Q_N, 1 },
{ "Q.AVG", v_Q_AVG, 0 },
{ "SCENE", v_SCENE, 0 },
{ "P.N", v_P_N, 0 },
{ "P.L", v_P_L, 0 },
{ "P.I", v_P_I, 0 },
{ "P.HERE", v_P_HERE, 0 },
{ "P.NEXT", v_P_NEXT, 0 },
{ "P.PREV", v_P_PREV, 0 },
{ "P.WRAP", v_P_WRAP, 0 },
{ "P.START", v_P_START, 0 },
{ "P.END", v_P_END, 0 },
{ "FLIP", v_FLIP, 0 },
{ "O.MIN", NULL, 0 },
{ "O.MAX", NULL, 63 },
{ "O.WRAP", NULL, 1 },
{ "O.DIR", NULL, 1 },
{ "DRUNK.MIN", NULL, 0 },
{ "DRUNK.MAX", NULL, 255 },
{ "DRUNK.WRAP", NULL, 0 }
};
static void v_M() {
if (left || top == 0)
push(tele_vars[V_M].v);
else {
tele_vars[V_M].v = pop();
if (tele_vars[V_M].v < 10) tele_vars[V_M].v = 10;
(*update_metro)(tele_vars[V_M].v, tele_vars[V_M_ACT].v, 0);
}
}
static void v_M_ACT() {
if (left || top == 0)
push(tele_vars[V_M_ACT].v);
else {
tele_vars[V_M_ACT].v = pop();
if (tele_vars[V_M_ACT].v != 0) tele_vars[V_M_ACT].v = 1;
(*update_metro)(tele_vars[V_M].v, tele_vars[V_M_ACT].v, 0);
}
}
static void v_P_N() {
int16_t a;
if (left || top == 0) { push(pn); }
else {
a = pop();
if (a < 0)
pn = 0;
else if (a > 3)
pn = 3;
else
pn = a;
}
}
static void v_P_L() {
int16_t a;
if (left || top == 0) { push(tele_patterns[pn].l); }
else {
a = pop();
if (a < 0)
tele_patterns[pn].l = 0;
else if (a > 63)
tele_patterns[pn].l = 63;
else
tele_patterns[pn].l = a;
}
}
static void v_P_I() {
int16_t a;
if (left || top == 0) { push(tele_patterns[pn].i); }
else {
a = pop();
if (a < 0)
tele_patterns[pn].i = 0;
else if (a > tele_patterns[pn].l)
tele_patterns[pn].i = tele_patterns[pn].l;
else
tele_patterns[pn].i = a;
(*update_pi)();
}
}
static void v_P_HERE() {
int16_t a;
if (left || top == 0) { push(tele_patterns[pn].v[tele_patterns[pn].i]); }
else {
a = pop();
tele_patterns[pn].v[tele_patterns[pn].i] = a;
}
}
static void v_P_NEXT() {
int16_t a;
if ((tele_patterns[pn].i == (tele_patterns[pn].l - 1)) ||
(tele_patterns[pn].i == tele_patterns[pn].end)) {
if (tele_patterns[pn].wrap)
tele_patterns[pn].i = tele_patterns[pn].start;
}
else
tele_patterns[pn].i++;
if (tele_patterns[pn].i > tele_patterns[pn].l) tele_patterns[pn].i = 0;
if (left || top == 0) { push(tele_patterns[pn].v[tele_patterns[pn].i]); }
else {
a = pop();
tele_patterns[pn].v[tele_patterns[pn].i] = a;
}
(*update_pi)();
}
static void v_P_PREV() {
int16_t a;
if ((tele_patterns[pn].i == 0) ||
(tele_patterns[pn].i == tele_patterns[pn].start)) {
if (tele_patterns[pn].wrap) {
if (tele_patterns[pn].end < tele_patterns[pn].l)
tele_patterns[pn].i = tele_patterns[pn].end;
else
tele_patterns[pn].i = tele_patterns[pn].l - 1;
}
}
else
tele_patterns[pn].i--;
if (left || top == 0) { push(tele_patterns[pn].v[tele_patterns[pn].i]); }
else {
a = pop();
tele_patterns[pn].v[tele_patterns[pn].i] = a;
}
(*update_pi)();
}
static void v_P_WRAP() {
int16_t a;
if (left || top == 0) { push(tele_patterns[pn].wrap); }
else {
a = pop();
if (a < 0)
tele_patterns[pn].wrap = 0;
else if (a > 1)
tele_patterns[pn].wrap = 1;
else
tele_patterns[pn].wrap = a;
}
}
static void v_P_START() {
int16_t a;
if (left || top == 0) { push(tele_patterns[pn].start); }
else {
a = pop();
if (a < 0)
tele_patterns[pn].start = 0;
else if (a > 63)
tele_patterns[pn].start = 1;
else
tele_patterns[pn].start = a;
}
}
static void v_P_END() {
int16_t a;
if (left || top == 0) { push(tele_patterns[pn].end); }
else {
a = pop();
if (a < 0)
tele_patterns[pn].end = 0;
else if (a > 63)
tele_patterns[pn].end = 1;
else
tele_patterns[pn].end = a;
}
}
static void v_O() {
if (left || top == 0) {
tele_vars[V_O].v += tele_vars[V_O_DIR].v;
if (tele_vars[V_O].v > tele_vars[V_O_MAX].v) {
if (tele_vars[V_O_WRAP].v)
tele_vars[V_O].v = tele_vars[V_O_MIN].v;
else
tele_vars[V_O].v = tele_vars[V_O_MAX].v;
}
else if (tele_vars[V_O].v < tele_vars[V_O_MIN].v) {
if (tele_vars[V_O_WRAP].v)
tele_vars[V_O].v = tele_vars[V_O_MAX].v;
else
tele_vars[V_O].v = tele_vars[V_O_MIN].v;
}
push(tele_vars[V_O].v);
}
else {
tele_vars[V_O].v = pop();
}
}
static void v_DRUNK() {
if (left || top == 0) {
tele_vars[V_DRUNK].v += (rand() % 3) - 1;
if (tele_vars[V_DRUNK].v < tele_vars[V_DRUNK_MIN].v) {
if (tele_vars[V_DRUNK_WRAP].v)
tele_vars[V_DRUNK].v = tele_vars[V_DRUNK_MAX].v;
else
tele_vars[V_DRUNK].v = tele_vars[V_DRUNK_MIN].v;
}
else if (tele_vars[V_DRUNK].v > tele_vars[V_DRUNK_MAX].v) {
if (tele_vars[V_DRUNK_WRAP].v)
tele_vars[V_DRUNK].v = tele_vars[V_DRUNK_MIN].v;
else
tele_vars[V_DRUNK].v = tele_vars[V_DRUNK_MAX].v;
}
push(tele_vars[V_DRUNK].v);
}
else {
tele_vars[V_DRUNK].v = pop();
}
}
static void v_Q() {
if (left || top == 0) { push(tele_q[tele_vars[V_Q_N].v - 1]); }
else {
for (int16_t i = 15; i > 0; i--) tele_q[i] = tele_q[i - 1];
tele_q[0] = pop();
}
}
static void v_Q_N() {
if (left || top == 0) { push(tele_vars[V_Q_N].v); }
else {
int16_t a = pop();
if (a < 1)
a = 1;
else if (a > 16)
a = 16;
tele_vars[V_Q_N].v = a;
}
}
static void v_Q_AVG() {
if (left || top == 0) {
int32_t avg = 0;
for (int16_t i = 0; i < tele_vars[V_Q_N].v; i++) avg += tele_q[i];
avg /= tele_vars[V_Q_N].v;
push(avg);
}
else {
int16_t a = pop();
for (int16_t i = 0; i < 16; i++) tele_q[i] = a;
}
}
static void v_SCENE() {
if (left || top == 0) { push(tele_vars[V_SCENE].v); }
else {
tele_vars[V_SCENE].v = pop();
(*update_scene)(tele_vars[V_SCENE].v);
}
}
static void v_FLIP() {
if (left || top == 0) {
push(tele_vars[V_O].v);
tele_vars[V_O].v = (tele_vars[V_O].v == 0);
}
else {
tele_vars[V_O].v = (pop() != 0);
}
}
static void a_TR(uint8_t);
static void a_CV(uint8_t);
static void a_CV_SLEW(uint8_t);
static void a_CV_OFF(uint8_t);
static void a_TR_TIME(uint8_t);
static void a_TR_POL(uint8_t);
#define MAKEARRAY(name, func) \
{ #name, { 0, 0, 0, 0 }, func }
#define ARRAYS 6
static tele_array_t tele_arrays[ARRAYS] = {
MAKEARRAY(TR, a_TR),
MAKEARRAY(CV, a_CV),
MAKEARRAY(CV.SLEW, a_CV_SLEW),
MAKEARRAY(CV.OFF, a_CV_OFF),
{ "TR.TIME", { 100, 100, 100, 100 }, a_TR_TIME },
{ "TR.POL", { 1, 1, 1, 1 }, a_TR_POL }
};
static void a_TR(uint8_t i) {
int16_t a = pop();
a = (a != 0);
tele_arrays[0].v[i] = a;
(*update_tr)(i, a);
}
static void a_CV(uint8_t i) {
int16_t a = pop();
if (a < 0)
a = 0;
else if (a > 16383)
a = 16383;
tele_arrays[1].v[i] = a;
(*update_cv)(i, a, 1);
}
static void a_CV_SLEW(uint8_t i) {
int16_t a = pop();
if (a < 1)
a = 1; // min slew = 1
else if (a > 32767)
a = 32767;
tele_arrays[2].v[i] = a;
(*update_cv_slew)(i, a);
}
static void a_CV_OFF(uint8_t i) {
int16_t a = pop();
tele_arrays[3].v[i] = a;
(*update_cv_off)(i, a);
(*update_cv)(i, tele_arrays[1].v[i], 1);
}
static void a_TR_TIME(uint8_t i) {
int16_t a = pop();
if (a < 0) a = 0; // 0 = no pulse
tele_arrays[4].v[i] = a;
}
static void a_TR_POL(uint8_t i) {
int16_t a = pop();
if (a > 1)
a = 1;
else if (a < 0)
a = 0;
tele_arrays[5].v[i] = a;
}
/////////////////////////////////////////////////////////////////
// DELAY ////////////////////////////////////////////////////////
static tele_command_t delay_c[TELE_D_SIZE];
static int16_t delay_t[TELE_D_SIZE];
static uint8_t delay_count;
static int16_t tr_pulse[4];
static void process_delays(uint8_t);
void clear_delays(void);
static void process_delays(uint8_t v) {
for (int16_t i = 0; i < TELE_D_SIZE; i++) {
if (delay_t[i]) {
delay_t[i] -= v;
if (delay_t[i] <= 0) {
// sprintf(dbg,"\r\ndelay %d", i);
// DBG
process(&delay_c[i]);
delay_t[i] = 0;
delay_count--;
if (delay_count == 0) (*update_delay)(0);
}
}
}
for (int16_t i = 0; i < 4; i++) {
if (tr_pulse[i]) {
tr_pulse[i] -= v;
if (tr_pulse[i] <= 0) {
tr_pulse[i] = 0;
// if(tele_arrays[0].v[i]) tele_arrays[0].v[i] = 0;
tele_arrays[0].v[i] = (tele_arrays[5].v[i] == 0);
(*update_tr)(i, tele_arrays[0].v[i]);
}
}
}
}
void clear_delays(void) {
for (int16_t i = 0; i < 4; i++) tr_pulse[i] = 0;
for (int16_t i = 0; i < TELE_D_SIZE; i++) { delay_t[i] = 0; }
delay_count = 0;
tele_stack_top = 0;
(*update_delay)(0);
(*update_s)(0);
}
/////////////////////////////////////////////////////////////////
// MOD //////////////////////////////////////////////////////////
static void mod_PROB(tele_command_t *);
static void mod_DEL(tele_command_t *);
static void mod_S(tele_command_t *);
static void mod_IF(tele_command_t *);
static void mod_ELIF(tele_command_t *);
static void mod_ELSE(tele_command_t *);
static void mod_L(tele_command_t *);
#define MAKEMOD(name, params, doc) \
{ #name, mod_##name, params, doc }
#define MODS 7
static const tele_mod_t tele_mods[MODS] = {
MAKEMOD(PROB, 1, "PROBABILITY TO CONTINUE EXECUTING LINE"),
MAKEMOD(DEL, 1, "DELAY THIS COMMAND"),
MAKEMOD(S, 0, "ADD COMMAND TO STACK"),
MAKEMOD(IF, 1, "IF CONDITION FOR COMMAND"),
MAKEMOD(ELIF, 1, "ELSE IF"),
MAKEMOD(ELSE, 0, "ELSE"),
MAKEMOD(L, 2, "LOOPED COMMAND WITH ITERATION")
};
void mod_PROB(tele_command_t *c) {
int16_t a = pop();
tele_command_t cc;
if (rand() % 101 < a) {
cc.l = c->l - c->separator - 1;
cc.separator = -1;
memcpy(cc.data, &c->data[c->separator + 1], cc.l * sizeof(tele_data_t));
// sprintf(dbg,"\r\nsub-length: %d", cc.l);
process(&cc);
}
}
void mod_DEL(tele_command_t *c) {
int16_t i = 0;
int16_t a = pop();
if (a < 1) a = 1;
while (delay_t[i] != 0 && i != TELE_D_SIZE) i++;
if (i < TELE_D_SIZE) {
delay_count++;
if (delay_count == 1) (*update_delay)(1);
delay_t[i] = a;
delay_c[i].l = c->l - c->separator - 1;
delay_c[i].separator = -1;
memcpy(delay_c[i].data, &c->data[c->separator + 1],
delay_c[i].l * sizeof(tele_data_t));
}
}
void mod_S(tele_command_t *c) {
if (tele_stack_top < TELE_STACK_SIZE) {
tele_stack[tele_stack_top].l = c->l - c->separator - 1;
memcpy(tele_stack[tele_stack_top].data, &c->data[c->separator + 1],
tele_stack[tele_stack_top].l * sizeof(tele_data_t));
tele_stack[tele_stack_top].separator = -1;
tele_stack_top++;
if (tele_stack_top == 1) (*update_s)(1);
}
}
void mod_IF(tele_command_t *c) {
condition = FALSE;
tele_command_t cc;
if (pop()) {
condition = TRUE;
cc.l = c->l - c->separator - 1;
cc.separator = -1;
memcpy(cc.data, &c->data[c->separator + 1], cc.l * sizeof(tele_data_t));
// sprintf(dbg,"\r\nsub-length: %d", cc.l);
process(&cc);
}
}
void mod_ELIF(tele_command_t *c) {
tele_command_t cc;
if (!condition) {
if (pop()) {
condition = TRUE;
cc.l = c->l - c->separator - 1;
cc.separator = -1;
memcpy(cc.data, &c->data[c->separator + 1],
cc.l * sizeof(tele_data_t));
// sprintf(dbg,"\r\nsub-length: %d", cc.l);
process(&cc);
}
}
}
void mod_ELSE(tele_command_t *c) {
tele_command_t cc;
if (!condition) {
condition = TRUE;
cc.l = c->l - c->separator - 1;
cc.separator = -1;
memcpy(cc.data, &c->data[c->separator + 1], cc.l * sizeof(tele_data_t));
// sprintf(dbg,"\r\nsub-length: %d", cc.l);
process(&cc);
}
}
void mod_L(tele_command_t *c) {
int16_t a, b, d, i;
tele_command_t cc;
a = pop();
b = pop();
if (a < b) {
d = b - a + 1;
for (i = 0; i < d; i++) {
tele_vars[V_I].v = a + i;
cc.l = c->l - c->separator - 1;
cc.separator = -1;
memcpy(cc.data, &c->data[c->separator + 1],
cc.l * sizeof(tele_data_t));
// sprintf(dbg,"\r\nsub-length: %d", cc.l);
process(&cc);
}
}
else {
d = a - b + 1;
for (i = 0; i < d; i++) {
tele_vars[V_I].v = a - i;
cc.l = c->l - c->separator - 1;
cc.separator = -1;
memcpy(cc.data, &c->data[c->separator + 1],
cc.l * sizeof(tele_data_t));
// sprintf(dbg,"\r\nsub-length: %d", cc.l);
process(&cc);
}
}
}
/////////////////////////////////////////////////////////////////
// OPS //////////////////////////////////////////////////////////
static void op_CONSTANT(const void *data);
static void op_ADD(const void *data);
static void op_SUB(const void *data);
static void op_MUL(const void *data);
static void op_DIV(const void *data);
static void op_MOD(const void *data);
static void op_RAND(const void *data);
static void op_RRAND(const void *data);
static void op_TOSS(const void *data);
static void op_MIN(const void *data);
static void op_MAX(const void *data);
static void op_LIM(const void *data);
static void op_WRAP(const void *data);
static void op_QT(const void *data);
static void op_AVG(const void *data);
static void op_EQ(const void *data);
static void op_NE(const void *data);
static void op_LT(const void *data);
static void op_GT(const void *data);
static void op_NZ(const void *data);
static void op_EZ(const void *data);
static void op_TR_TOG(const void *data);
static void op_N(const void *data);
static void op_S_ALL(const void *data);
static void op_S_POP(const void *data);
static void op_S_CLR(const void *data);
static void op_DEL_CLR(const void *data);
static void op_M_RESET(const void *data);
static void op_V(const void *data);
static void op_VV(const void *data);
static void op_P(const void *data);
static void op_P_INS(const void *data);
static void op_P_RM(const void *data);
static void op_P_PUSH(const void *data);
static void op_P_POP(const void *data);
static void op_PN(const void *data);
static void op_TR_PULSE(const void *data);
static void op_II(const void *data);
static void op_RSH(const void *data);
static void op_LSH(const void *data);
static void op_S_L(const void *data);
static void op_CV_SET(const void *data);
static void op_EXP(const void *data);
static void op_ABS(const void *data);
static void op_AND(const void *data);
static void op_OR(const void *data);
static void op_XOR(const void *data);
static void op_JI(const void *data);
static void op_SCRIPT(const void *data);
static void op_KILL(const void *data);
static void op_MUTE(const void *data);
static void op_UNMUTE(const void *data);
static void op_SCALE(const void *data);
static void op_STATE(const void *data);
static void op_ER(const void *data);
// Get only ops
#define MAKE_GET_OP(n, f, p, r, d) \
{ \
.name = #n, .get = f, .set = NULL, .params = p, .returns = r, \
.data = NULL, .doc = d \
}
// Constant Ops
static void op_CONSTANT(const void *data) {
push((intptr_t)data);
}
#define MAKE_CONSTANT_OP(n, v, d) \
{ \
.name = #n, .get = op_CONSTANT, .set = NULL, .params = 0, \
.returns = 1, .data = (void *)v, .doc = d \
}
#define OPS 101
// clang-format off
// DO NOT INSERT in the middle. there's a hack in validate() for P and PN
static const tele_op_t tele_ops[OPS] = {
// op get fn inputs output docs
MAKE_GET_OP(ADD , op_ADD , 2, true , "[A B] ADD A TO B" ),
MAKE_GET_OP(SUB , op_SUB , 2, true , "[A B] SUBTRACT B FROM A" ),
MAKE_GET_OP(MUL , op_MUL , 2, true , "[A B] MULTIPLY TWO VALUES" ),
MAKE_GET_OP(DIV , op_DIV , 2, true , "[A B] DIVIDE FIRST BY SECOND" ),
MAKE_GET_OP(MOD , op_MOD , 2, true , "[A B] MOD FIRST BY SECOND" ),
MAKE_GET_OP(RAND , op_RAND , 1, true , "[A] RETURN RANDOM NUMBER UP TO A" ),
MAKE_GET_OP(RRAND , op_RRAND , 2, true , "[A B] RETURN RANDOM NUMBER BETWEEN A AND B"),
MAKE_GET_OP(TOSS , op_TOSS , 0, true , "RETURN RANDOM STATE" ),
MAKE_GET_OP(MIN , op_MIN , 2, true , "RETURN LESSER OF TWO VALUES" ),
MAKE_GET_OP(MAX , op_MAX , 2, true , "RETURN GREATER OF TWO VALUES" ),
MAKE_GET_OP(LIM , op_LIM , 3, true , "[A B C] LIMIT C TO RANGE A TO B" ),
MAKE_GET_OP(WRAP , op_WRAP , 3, true , "[A B C] WRAP C WITHIN RANGE A TO B" ),
MAKE_GET_OP(QT , op_QT , 2, true , "[A B] QUANTIZE A TO STEP SIZE B" ),
MAKE_GET_OP(AVG , op_AVG , 2, true , "AVERAGE TWO VALUES" ),
MAKE_GET_OP(EQ , op_EQ , 2, true , "LOGIC: EQUAL" ),
MAKE_GET_OP(NE , op_NE , 2, true , "LOGIC: NOT EQUAL" ),
MAKE_GET_OP(LT , op_LT , 2, true , "LOGIC: LESS THAN" ),
MAKE_GET_OP(GT , op_GT , 2, true , "LOGIC: GREATER THAN" ),
MAKE_GET_OP(NZ , op_NZ , 1, true , "LOGIC: NOT ZERO" ),
MAKE_GET_OP(EZ , op_EZ , 1, true , "LOGIC: EQUALS ZERO" ),
MAKE_GET_OP(TR.TOG , op_TR_TOG , 1, false, "[A] TOGGLE TRIGGER A" ),
MAKE_GET_OP(N , op_N , 1, true , "TABLE FOR NOTE VALUES" ),
MAKE_GET_OP(S.ALL , op_S_ALL , 0, false, "S: EXECUTE ALL" ),
MAKE_GET_OP(S.POP , op_S_POP , 0, false, "S: POP LAST" ),
MAKE_GET_OP(S.CLR , op_S_CLR , 0, false, "S: FLUSH" ),
MAKE_GET_OP(DEL.CLR , op_DEL_CLR , 0, false, "DELAY: FLUSH" ),
MAKE_GET_OP(M.RESET , op_M_RESET , 0, false, "METRO: RESET" ),
MAKE_GET_OP(V , op_V , 1, true , "TO VOLT" ),
MAKE_GET_OP(VV , op_VV , 1, true , "TO VOLT WITH PRECISION" ),
MAKE_GET_OP(P , op_P , 1, true , "PATTERN: GET/SET" ),
MAKE_GET_OP(P.INS , op_P_INS , 2, false, "PATTERN: INSERT" ),
MAKE_GET_OP(P.RM , op_P_RM , 1, true , "PATTERN: REMOVE" ),
MAKE_GET_OP(P.PUSH , op_P_PUSH , 1, false, "PATTERN: PUSH" ),
MAKE_GET_OP(P.POP , op_P_POP , 0, true , "PATTERN: POP" ),
MAKE_GET_OP(PN , op_PN , 2, true , "PATTERN: GET/SET N" ),
MAKE_GET_OP(TR.PULSE, op_TR_PULSE, 1, false, "PULSE TRIGGER" ),
MAKE_GET_OP(II , op_II , 2, false, "II" ),
MAKE_GET_OP(RSH , op_RSH , 2, true , "RIGHT SHIFT" ),
MAKE_GET_OP(LSH , op_LSH , 2, true , "LEFT SHIFT" ),
MAKE_GET_OP(S.L , op_S_L , 0, true , "STACK LENGTH" ),
MAKE_GET_OP(CV.SET , op_CV_SET , 2, false, "CV SET" ),
MAKE_GET_OP(EXP , op_EXP , 1, true , "EXPONENTIATE" ),
MAKE_GET_OP(ABS , op_ABS , 1, true , "ABSOLUTE VALUE" ),
MAKE_GET_OP(AND , op_AND , 2, true , "LOGIC: AND" ),
MAKE_GET_OP(OR , op_OR , 2, true , "LOGIC: OR" ),
MAKE_GET_OP(XOR , op_XOR , 2, true , "LOGIC: XOR" ),
MAKE_GET_OP(JI , op_JI , 2, true , "JUST INTONE DIVISON" ),
MAKE_GET_OP(SCRIPT , op_SCRIPT , 1, false, "CALL SCRIPT" ),
MAKE_GET_OP(KILL , op_KILL , 0, false, "CLEAR DELAYS, STACK, SLEW" ),
MAKE_GET_OP(MUTE , op_MUTE , 1, false, "MUTE INPUT" ),
MAKE_GET_OP(UNMUTE , op_UNMUTE , 1, false, "UNMUTE INPUT" ),
MAKE_GET_OP(SCALE , op_SCALE , 5, true , "SCALE NUMBER RANGES" ),
MAKE_GET_OP(STATE , op_STATE , 1, true , "GET INPUT STATE" ),
MAKE_GET_OP(ER , op_ER , 3, true , "EUCLIDEAN RHYTHMS" ),
// op constant doc
MAKE_CONSTANT_OP(WW.PRESET , WW_PRESET , "WW.PRESET" ),
MAKE_CONSTANT_OP(WW.POS , WW_POS , "WW.POS" ),
MAKE_CONSTANT_OP(WW.SYNC , WW_SYNC , "WW.SYNC" ),
MAKE_CONSTANT_OP(WW.START , WW_START , "WW.START" ),
MAKE_CONSTANT_OP(WW.END , WW_END , "WW.END" ),
MAKE_CONSTANT_OP(WW.PMODE , WW_PMODE , "WW.PMODE" ),
MAKE_CONSTANT_OP(WW.PATTERN , WW_PATTERN , "WW.PATTERN" ),
MAKE_CONSTANT_OP(WW.QPATTERN, WW_QPATTERN , "WW.QPATTERN"),
MAKE_CONSTANT_OP(WW.MUTE1 , WW_MUTE1 , "WW.MUTE1" ),
MAKE_CONSTANT_OP(WW.MUTE2 , WW_MUTE2 , "WW.MUTE2" ),
MAKE_CONSTANT_OP(WW.MUTE3 , WW_MUTE3 , "WW.MUTE3" ),
MAKE_CONSTANT_OP(WW.MUTE4 , WW_MUTE4 , "WW.MUTE4" ),
MAKE_CONSTANT_OP(WW.MUTEA , WW_MUTEA , "WW.MUTEA" ),
MAKE_CONSTANT_OP(WW.MUTEB , WW_MUTEB , "WW.MUTEB" ),
MAKE_CONSTANT_OP(MP.PRESET , MP_PRESET , "MP.PRESET" ),
MAKE_CONSTANT_OP(MP.RESET , MP_RESET , "MP.RESET" ),
MAKE_CONSTANT_OP(MP.SYNC , MP_SYNC , "MP.SYNC" ),
MAKE_CONSTANT_OP(MP.MUTE , MP_MUTE , "MP.MUTE" ),
MAKE_CONSTANT_OP(MP.UNMUTE , MP_UNMUTE , "MP.UNMUTE" ),
MAKE_CONSTANT_OP(MP.FREEZE , MP_FREEZE , "MP.FREEZE" ),
MAKE_CONSTANT_OP(MP.UNFREEZE, MP_UNFREEZE , "MP.UNFREEZE"),
MAKE_CONSTANT_OP(MP.STOP , MP_STOP , "MP.STOP" ),
MAKE_CONSTANT_OP(ES.PRESET , ES_PRESET , "ES.PRESET" ),
MAKE_CONSTANT_OP(ES.MODE , ES_MODE , "ES.MODE" ),
MAKE_CONSTANT_OP(ES.CLOCK , ES_CLOCK , "ES.CLOCK" ),
MAKE_CONSTANT_OP(ES.RESET , ES_RESET , "ES.RESET" ),
MAKE_CONSTANT_OP(ES.PATTERN , ES_PATTERN , "ES.PATTERN" ),
MAKE_CONSTANT_OP(ES.TRANS , ES_TRANS , "ES.TRANS" ),
MAKE_CONSTANT_OP(ES.STOP , ES_STOP , "ES.STOP" ),
MAKE_CONSTANT_OP(ES.TRIPLE , ES_TRIPLE , "ES.TRIPLE" ),
MAKE_CONSTANT_OP(ES.MAGIC , ES_MAGIC , "ES.MAGIC" ),
MAKE_CONSTANT_OP(OR.TRK , ORCA_TRACK , "OR.TRK" ),
MAKE_CONSTANT_OP(OR.CLK , ORCA_CLOCK , "OR.CLK" ),
MAKE_CONSTANT_OP(OR.DIV , ORCA_DIVISOR, "OR.DIV" ),
MAKE_CONSTANT_OP(OR.PHASE , ORCA_PHASE , "OR.PHASE" ),
MAKE_CONSTANT_OP(OR.RST , ORCA_RESET , "OR.RST" ),
MAKE_CONSTANT_OP(OR.WGT , ORCA_WEIGHT , "OR.WGT" ),
MAKE_CONSTANT_OP(OR.MUTE , ORCA_MUTE , "OR.MUTE" ),
MAKE_CONSTANT_OP(OR.SCALE , ORCA_SCALE , "OR.SCALE" ),
MAKE_CONSTANT_OP(OR.BANK , ORCA_BANK , "OR.BANK" ),
MAKE_CONSTANT_OP(OR.PRESET , ORCA_PRESET , "OR.PRESET" ),
MAKE_CONSTANT_OP(OR.RELOAD , ORCA_RELOAD , "OR.RELOAD" ),
MAKE_CONSTANT_OP(OR.ROTS , ORCA_ROTATES, "OR.ROTS" ),
MAKE_CONSTANT_OP(OR.ROTW , ORCA_ROTATEW, "OR.ROTW" ),
MAKE_CONSTANT_OP(OR.GRST , ORCA_GRESET , "OR.GRST" ),
MAKE_CONSTANT_OP(OR.CVA , ORCA_CVA , "OR.CVA" ),
MAKE_CONSTANT_OP(OR.CVB , ORCA_CVB , "OR.CVB" ),
};
// clang-format on
static void op_ADD(const void *NOTUSED(data)) {
push(pop() + pop());
}
static void op_SUB(const void *NOTUSED(data)) {
push(pop() - pop());
}
static void op_MUL(const void *NOTUSED(data)) {
push(pop() * pop());
}
static void op_DIV(const void *NOTUSED(data)) {
push(pop() / pop());
}
// can be optimized:
static void op_MOD(const void *NOTUSED(data)) {
push(pop() % pop());
}
static void op_RAND(const void *NOTUSED(data)) {
int16_t a = pop();
if (a == -1)
push(0);
else
push(rand() % (a + 1));
}
static void op_RRAND(const void *NOTUSED(data)) {
int16_t a, b, min, max, range;
a = pop();
b = pop();
if (a < b) {
min = a;
max = b;
}
else {
min = b;
max = a;
}
range = max - min + 1;
if (range == 0)
push(a);
else
push(rand() % range + min);
}
static void op_TOSS(const void *NOTUSED(data)) {
push(rand() & 1);
}
static void op_MIN(const void *NOTUSED(data)) {
int16_t a, b;
a = pop();
b = pop();
if (b > a)
push(a);
else
push(b);
}
static void op_MAX(const void *NOTUSED(data)) {
int16_t a, b;
a = pop();
b = pop();
if (a > b)
push(a);
else
push(b);
}
static void op_LIM(const void *NOTUSED(data)) {
int16_t a, b, i;
i = pop();
a = pop();
b = pop();
if (i < a)
push(a);
else if (i > b)
push(b);
else
push(i);
}
static void op_WRAP(const void *NOTUSED(data)) {
int16_t a, b, i, c;
i = pop();
a = pop();
b = pop();
if (a < b) {
c = b - a + 1;
while (i >= b) i -= c;
while (i < a) i += c;
}
else {
c = a - b + 1;
while (i >= a) i -= c;
while (i < b) i += c;
}
push(i);
}
static void op_QT(const void *NOTUSED(data)) {
// this rounds negative numbers rather than quantize (choose closer)
int16_t a, b, c, d, e;
b = pop();
a = pop();
c = b / a;
d = c * a;
e = (c + 1) * a;
if (abs(b - d) < abs(b - e))
push(d);
else
push(e);
}
static void op_AVG(const void *NOTUSED(data)) {
push((pop() + pop()) >> 1);
}
static void op_EQ(const void *NOTUSED(data)) {
push(pop() == pop());
}
static void op_NE(const void *NOTUSED(data)) {
push(pop() != pop());
}
static void op_LT(const void *NOTUSED(data)) {
push(pop() < pop());
}
static void op_GT(const void *NOTUSED(data)) {
push(pop() > pop());
}
static void op_NZ(const void *NOTUSED(data)) {
push(pop() != 0);
}
static void op_EZ(const void *NOTUSED(data)) {
push(pop() == 0);
}
static void op_TR_TOG(const void *NOTUSED(data)) {
int16_t a = pop();
// saturate and shift
if (a < 1)
a = 1;
else if (a > 4)
a = 4;
a--;
if (tele_arrays[0].v[a])
tele_arrays[0].v[a] = 0;
else
tele_arrays[0].v[a] = 1;
update_tr(a, tele_arrays[0].v[a]);
}
static void op_N(const void *NOTUSED(data)) {
int16_t a = pop();
if (a < 0) {
if (a < -127) a = -127;
a = -a;
push(-table_n[a]);
}
else {
if (a > 127) a = 127;
push(table_n[a]);
}
}
static void op_S_ALL(const void *NOTUSED(data)) {
for (int16_t i = 0; i < tele_stack_top; i++)
process(&tele_stack[tele_stack_top - i - 1]);
tele_stack_top = 0;
(*update_s)(0);
}
static void op_S_POP(const void *NOTUSED(data)) {
if (tele_stack_top) {
tele_stack_top--;
process(&tele_stack[tele_stack_top]);
if (tele_stack_top == 0) (*update_s)(0);
}
}
static void op_S_CLR(const void *NOTUSED(data)) {
tele_stack_top = 0;
(*update_s)(0);
}
static void op_DEL_CLR(const void *NOTUSED(data)) {
clear_delays();
}
static void op_M_RESET(const void *NOTUSED(data)) {
(*update_metro)(tele_vars[V_M].v, tele_vars[V_M_ACT].v, 1);
}
static void op_V(const void *NOTUSED(data)) {
int16_t a = pop();
if (a > 10)
a = 10;
else if (a < -10)
a = -10;
if (a < 0) {
a = -a;
push(-table_v[a]);
}
else
push(table_v[a]);
}
static void op_VV(const void *NOTUSED(data)) {
uint8_t negative = 1;
int16_t a = pop();
if (a < 0) {
negative = -1;
a = -a;
}
if (a > 1000) a = 1000;
push(negative * (table_v[a / 100] + table_vv[a % 100]));
}
static void op_P(const void *NOTUSED(data)) {
int16_t a, b;
a = pop();
if (a < 0) {
if (tele_patterns[pn].l == 0)
a = 0;
else if (a < -tele_patterns[pn].l)
a = 0;
else
a = tele_patterns[pn].l + a;
}
if (a > 63) a = 63;
if (left == 0 && top > 0) {
b = pop();
tele_patterns[pn].v[a] = b;
(*update_pi)();
}
else {
push(tele_patterns[pn].v[a]);
}
}
static void op_P_INS(const void *NOTUSED(data)) {
int16_t a, b, i;
a = pop();
b = pop();
if (a < 0) {
if (tele_patterns[pn].l == 0)
a = 0;
else if (a < -tele_patterns[pn].l)
a = 0;
else
a = tele_patterns[pn].l + a;
}
if (a > 63) a = 63;
if (tele_patterns[pn].l >= a) {
for (i = tele_patterns[pn].l; i > a; i--)
tele_patterns[pn].v[i] = tele_patterns[pn].v[i - 1];
if (tele_patterns[pn].l < 63) tele_patterns[pn].l++;
}
tele_patterns[pn].v[a] = b;
(*update_pi)();
}
static void op_P_RM(const void *NOTUSED(data)) {
int16_t a, i;
a = pop();
if (a < 0) {
if (tele_patterns[pn].l == 0)
a = 0;
else if (a < -tele_patterns[pn].l)
a = 0;
else
a = tele_patterns[pn].l + a;
}
else if (a > tele_patterns[pn].l)
a = tele_patterns[pn].l;
if (tele_patterns[pn].l > 0) {
push(tele_patterns[pn].v[a]);
for (i = a; i < tele_patterns[pn].l; i++)
tele_patterns[pn].v[i] = tele_patterns[pn].v[i + 1];
tele_patterns[pn].l--;
}
else
push(0);
(*update_pi)();
}
static void op_P_PUSH(const void *NOTUSED(data)) {
int16_t a;
a = pop();
if (tele_patterns[pn].l < 64) {
tele_patterns[pn].v[tele_patterns[pn].l] = a;
tele_patterns[pn].l++;
(*update_pi)();
}
}
static void op_P_POP(const void *NOTUSED(data)) {
if (tele_patterns[pn].l > 0) {
tele_patterns[pn].l--;
push(tele_patterns[pn].v[tele_patterns[pn].l]);
(*update_pi)();
}
else
push(0);
}
static void op_PN(const void *NOTUSED(data)) {
int16_t a, b, c;
a = pop();
b = pop();
if (a < 0)
a = 0;
else if (a > 3)
a = 3;
if (b < 0) {
if (tele_patterns[a].l == 0)
b = 0;
else if (b < -tele_patterns[a].l)
b = 0;
else
b = tele_patterns[a].l + b;
}
if (b > 63) b = 63;
if (left == 0 && top > 0) {
c = pop();
tele_patterns[a].v[b] = c;
(*update_pi)();
}
else {
push(tele_patterns[a].v[b]);
}
}
static void op_TR_PULSE(const void *NOTUSED(data)) {
int16_t a = pop();
// saturate and shift
if (a < 1)
a = 1;
else if (a > 4)
a = 4;
a--;
int16_t time = tele_arrays[4].v[a]; // pulse time
if (time <= 0) return; // if time <= 0 don't do anything
tele_arrays[0].v[a] = tele_arrays[5].v[a];
tr_pulse[a] = time; // set time
update_tr(a, tele_arrays[0].v[a]);
}
static void op_II(const void *NOTUSED(data)) {
int16_t a = pop();
int16_t b = pop();
update_ii(a, b);
}
static void op_RSH(const void *NOTUSED(data)) {
push(pop() >> pop());
}
static void op_LSH(const void *NOTUSED(data)) {
push(pop() << pop());
}
static void op_S_L(const void *NOTUSED(data)) {
push(tele_stack_top);
}
static void op_CV_SET(const void *NOTUSED(data)) {
int16_t a = pop();
int16_t b = pop();
// saturate and shift
if (a < 1)
a = 1;
else if (a > 4)
a = 4;
a--;
if (b < 0)
b = 0;
else if (b > 16383)
b = 16383;
tele_arrays[1].v[a] = b;
(*update_cv)(a, b, 0);
}
static void op_EXP(const void *NOTUSED(data)) {
int16_t a = pop();
if (a > 16383)
a = 16383;
else if (a < -16383)
a = -16383;
a = a >> 6;
if (a < 0) {
a = -a;
push(-table_exp[a]);
}
else
push(table_exp[a]);
}
static void op_ABS(const void *NOTUSED(data)) {
int16_t a = pop();
if (a < 0)
push(-a);
else
push(a);
}
static void op_AND(const void *NOTUSED(data)) {
push(pop() & pop());
}
static void op_OR(const void *NOTUSED(data)) {
push(pop() | pop());
}
static void op_XOR(const void *NOTUSED(data)) {
push(pop() ^ pop());
}
static void op_JI(const void *NOTUSED(data)) {
uint32_t ji = (((pop() << 8) / pop()) * 1684) >> 8;
while (ji > 1683) ji >>= 1;
push(ji);
}
static void op_SCRIPT(const void *NOTUSED(data)) {
uint16_t a = pop();
if (a > 0 && a < 9) (*run_script)(a);
}
static void op_KILL(const void *NOTUSED(data)) {
clear_delays();
(*update_kill)();
}
static void op_MUTE(const void *NOTUSED(data)) {
int16_t a;
a = pop();
if (a > 0 && a < 9) { (*update_mute)(a - 1, 0); }
}
static void op_UNMUTE(const void *NOTUSED(data)) {
int16_t a;
a = pop();
if (a > 0 && a < 9) { (*update_mute)(a - 1, 1); }
}
static void op_SCALE(const void *NOTUSED(data)) {
int16_t a, b, x, y, i;
a = pop();
b = pop();
x = pop();
y = pop();
i = pop();
push((i - a) * (y - x) / (b - a) + x);
}
static void op_STATE(const void *NOTUSED(data)) {
int16_t a = pop();
a--;
if (a < 0)
a = 0;
else if (a > 7)
a = 7;
(*update_input)(a);
push(input_states[a]);
}
static void op_ER(const void *NOTUSED(data)) {
int16_t fill = pop();
int16_t len = pop();
int16_t step = pop();
push(euclidean(fill, len, step));
}
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// PROCESS //////////////////////////////////////////////////////
error_t parse(char *cmd, tele_command_t *out) {
char cmd_copy[32];
strcpy(cmd_copy, cmd);
const char *delim = " \n";
const char *s = strtok(cmd_copy, delim);
uint8_t n = 0;
out->l = n;
// sprintf(dbg,"\r\nparse: ");
while (s) {
// CHECK IF NUMBER
if (isdigit(s[0]) || s[0] == '-') {
out->data[n].t = NUMBER;
out->data[n].v = strtol(s, NULL, 0);
}
else if (s[0] == ':')
out->data[n].t = SEP;
else {
// CHECK AGAINST VARS
int16_t i = VARS - 1;
do {
// print_dbg("\r\nvar '");
// print_dbg(tele_vars[i].name);
// print_dbg("'");
if (!strcmp(s, tele_vars[i].name)) {
out->data[n].t = VAR;
out->data[n].v = i;
// sprintf(dbg,"v(%d) ", out->data[n].v);
break;
}
} while (i--);
if (i == -1) {
// CHECK AGAINST ARRAYS
i = ARRAYS;
while (i--) {
// print_dbg("\r\narrays '");
// print_dbg(tele_arrays[i].name);
// print_dbg("'");
if (!strcmp(s, tele_arrays[i].name)) {
out->data[n].t = ARRAY;
out->data[n].v = i;
// sprintf(dbg,"a(%d) ", out->data[n].v);
break;
}
}
}
if (i == -1) {
// CHECK AGAINST OPS
i = OPS;
while (i--) {
// print_dbg("\r\nops '");
// print_dbg(tele_ops[i].name);
// print_dbg("'");
if (!strcmp(s, tele_ops[i].name)) {
out->data[n].t = OP;
out->data[n].v = i;
// sprintf(dbg,"f(%d) ", out->data[n].v);
break;
}
}
}
if (i == -1) {
// CHECK AGAINST MOD
i = MODS;
while (i--) {
// print_dbg("\r\nmods '");
// print_dbg(tele_mods[i].name);
// print_dbg("'");
if (!strcmp(s, tele_mods[i].name)) {
out->data[n].t = MOD;
out->data[n].v = i;
// sprintf(dbg,"f(%d) ", out->data[n].v);
break;
}
}
}
if (i == -1) {
strcpy(error_detail, s);
return E_PARSE;
}
}
s = strtok(NULL, delim);
n++;
out->l = n;
if (n == COMMAND_MAX_LENGTH) return E_LENGTH;
}
// sprintf(dbg,"// length: %d", temp.l);
return E_OK;
}
/////////////////////////////////////////////////////////////////
// VALIDATE /////////////////////////////////////////////////////
error_t validate(tele_command_t *c) {
int16_t h = 0;
uint8_t n = c->l;
c->separator = -1;
while (n--) {
if (c->data[n].t == OP) {
if (tele_ops[c->data[n].v].returns == false && n) {
if (c->data[n - 1].t != SEP) {
strcpy(error_detail, tele_ops[c->data[n].v].name);
return E_NOT_LEFT;
}
}
h -= tele_ops[c->data[n].v].params;
if (h < 0) {
strcpy(error_detail, tele_ops[c->data[n].v].name);
return E_NEED_PARAMS;
}
h += tele_ops[c->data[n].v].returns ? 1 : 0;
// hack for var-length params for P
if (c->data[n].v == 29 || c->data[n].v == 34) {
if (n == 0)
h--;
else if (c->data[n - 1].t == SEP)
h--;
}
}
else if (c->data[n].t == MOD) {
strcpy(error_detail, tele_mods[c->data[n].v].name);
if (n != 0)
return E_NO_MOD_HERE;
else if (c->separator == -1)
return E_NEED_SEP;
else if (h < tele_mods[c->data[n].v].params)
return E_NEED_PARAMS;
else if (h > tele_mods[c->data[n].v].params)
return E_EXTRA_PARAMS;
else
h = 0;
}
else if (c->data[n].t == SEP) {
if (c->separator != -1)
return E_MANY_SEP;
else if (n == 0)
return E_PLACE_SEP;
c->separator = n;
if (h > 1)
return E_EXTRA_PARAMS;
else
h = 0;
}
// RIGHT (get)
else if (n && c->data[n - 1].t != SEP) {
if (c->data[n].t == NUMBER || c->data[n].t == VAR) { h++; }
else if (c->data[n].t == ARRAY) {
if (h < 1) {
strcpy(error_detail, tele_arrays[c->data[n].v].name);
return E_NEED_PARAMS;
}
// h-- then h++
}
}
// LEFT (set)
else {
if (c->data[n].t == NUMBER) { h++; }
else if (c->data[n].t == VAR) {
if (h == 0) h++;
// else {
// h--;
// if(h > 0)
// return E_EXTRA_PARAMS;
// }
}
else if (c->data[n].t == ARRAY) {
if (h < 1) {
strcpy(error_detail, tele_arrays[c->data[n].v].name);
return E_NEED_PARAMS;
}
h--;
if (h == 0) h++;
// else if(h > 1)
// return E_EXTRA_PARAMS;
}
}
}
if (h > 1)
return E_EXTRA_PARAMS;
else
return E_OK;
}
/////////////////////////////////////////////////////////////////
// PROCESS //////////////////////////////////////////////////////
void process(tele_command_t *c) {
top = 0;
left = 0;
int16_t i;
int16_t n;
if (c->separator == -1)
n = c->l;
else
n = c->separator;
// sprintf(dbg,"\r\r\nprocess (%d): %s", n, print_command(c));
// DBG;
while (n--) {
left = n;
if (c->data[n].t == NUMBER)
push(c->data[n].v);
else if (c->data[n].t == OP) {
const void *data = tele_ops[c->data[n].v].data;
tele_ops[c->data[n].v].get(data);
}
else if (c->data[n].t == MOD)
tele_mods[c->data[n].v].func(c);
else if (c->data[n].t == VAR) {
if (tele_vars[c->data[n].v].func == NULL) {
if (n || top == 0)
push(tele_vars[c->data[n].v].v);
else
tele_vars[c->data[n].v].v = pop();
}
else
tele_vars[c->data[n].v].func();
}
else if (c->data[n].t == ARRAY) {
i = pop();
// saturate for 1-4 indexing
if (i < 1)
i = 1;
else if (i > 3)
i = 4;
i--;
if (n || top == 0) {
// sprintf(dbg,"\r\nget array %s @ %d : %d",
// tele_arrays[c->data[n].v].name, i,
// tele_arrays[c->data[n].v].v[i]);
// DBG
push(tele_arrays[c->data[n].v].v[i]);
}
else {
// sprintf(dbg,"\r\nset array %s @ %d to %d",
// tele_arrays[c->data[n].v].name, i,
// tele_arrays[c->data[n].v].v[i]);
// DBG
if (tele_arrays[c->data[n].v].func)
tele_arrays[c->data[n].v].func(i);
else
tele_arrays[c->data[n].v].v[i] = pop();
}
}
}
// PRint16_t DEBUG OUTPUT IF VAL LEFT ON STACK
if (top) {
output = pop();
output_new++;
// sprintf(dbg,"\r\n>>> %d", output);
// DBG
// to_v(output);
}
}
char *print_command(const tele_command_t *c) {
int16_t n = 0;
char number[8];
char *p = pcmd;
*p = 0;
while (n < c->l) {
switch (c->data[n].t) {
case OP:
strcpy(p, tele_ops[c->data[n].v].name);
p += strlen(tele_ops[c->data[n].v].name) - 1;
break;
case ARRAY:
strcpy(p, tele_arrays[c->data[n].v].name);
p += strlen(tele_arrays[c->data[n].v].name) - 1;
break;
case NUMBER:
itoa(c->data[n].v, number, 10);
strcpy(p, number);
p += strlen(number) - 1;
break;
case VAR:
strcpy(p, tele_vars[c->data[n].v].name);
p += strlen(tele_vars[c->data[n].v].name) - 1;
break;
case MOD:
strcpy(p, tele_mods[c->data[n].v].name);
p += strlen(tele_mods[c->data[n].v].name) - 1;
break;
case SEP: *p = ':'; break;
default: break;
}
n++;
p++;
*p = ' ';
p++;
}
p--;
*p = 0;
return pcmd;
}
int16_t tele_get_array(uint8_t a, uint8_t i) {
return tele_arrays[a].v[i];
}
void tele_set_array(uint8_t a, uint8_t i, uint16_t v) {
tele_arrays[a].v[i] = v;
}
void tele_set_val(uint8_t i, uint16_t v) {
tele_vars[i].v = v;
}
void tele_tick(uint8_t i) {
process_delays(i);
// inc time
if (tele_vars[V_TIME_ACT].v) tele_vars[V_TIME].v += i;
}
void tele_init() {
u8 i;
for (i = 0; i < 4; i++) {
tele_patterns[i].i = 0;
tele_patterns[i].l = 0;
tele_patterns[i].wrap = 1;
tele_patterns[i].start = 0;
tele_patterns[i].end = 63;
}
for (i = 0; i < 8; i++) mutes[i] = 1;
}
const char *to_v(int16_t i) {
static char n[3], v[7];
int16_t a = 0, b = 0;
if (i > table_v[8]) {
i -= table_v[8];
a += 8;
}
if (i > table_v[4]) {
i -= table_v[4];
a += 4;
}
if (i > table_v[2]) {
i -= table_v[2];
a += 2;
}
if (i > table_v[1]) {
i -= table_v[1];
a += 1;
}
if (i > table_vv[64]) {
i -= table_vv[64];
b += 64;
}
if (i > table_vv[32]) {
i -= table_vv[32];
b += 32;
}
if (i > table_vv[16]) {
i -= table_vv[16];
b += 16;
}
if (i > table_vv[8]) {
i -= table_vv[8];
b += 8;
}
if (i > table_vv[4]) {
i -= table_vv[4];
b += 4;
}
if (i > table_vv[2]) {
i -= table_vv[2];
b++;
}
if (i > table_vv[1]) {
i -= table_vv[1];
b++;
}
b++;
itoa(a, n, 10);
strcpy(v, n);
strcat(v, ".");
itoa(b, n, 10);
strcat(v, n);
strcat(v, "V");
return v;
// printf(" (VV %d %d)",a,b);
}