diff -Naur ../2021_02_04/src/match_token.rl ./src/match_token.rl --- ../2021_02_04/src/match_token.rl 2021-02-04 07:53:51.000000000 +0100 +++ ./src/match_token.rl 2021-02-04 16:50:05.047099030 +0100 @@ -212,6 +212,7 @@ "N.S" => { MATCH_OP(E_OP_N_S); }; "N.C" => { MATCH_OP(E_OP_N_C); }; "N.CS" => { MATCH_OP(E_OP_N_CS); }; + "N.Q" => { MATCH_OP(E_OP_N_Q); }; "V" => { MATCH_OP(E_OP_V); }; "VV" => { MATCH_OP(E_OP_VV); }; "ER" => { MATCH_OP(E_OP_ER); }; diff -Naur ../2021_02_04/src/ops/maths.c ./src/ops/maths.c --- ../2021_02_04/src/ops/maths.c 2021-02-04 07:53:51.000000000 +0100 +++ ./src/ops/maths.c 2021-02-04 16:50:05.047099030 +0100 @@ -100,6 +100,8 @@ command_state_t *cs); static void op_N_CS_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_N_Q_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); static void op_V_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_VV_get(const void *data, scene_state_t *ss, exec_state_t *es, @@ -190,6 +192,7 @@ const tele_op_t op_N_S = MAKE_GET_OP(N.S , op_N_S_get , 3, true); const tele_op_t op_N_C = MAKE_GET_OP(N.C , op_N_C_get , 3, true); const tele_op_t op_N_CS = MAKE_GET_OP(N.CS , op_N_CS_get , 4, true); +const tele_op_t op_N_Q = MAKE_GET_OP(N.Q , op_N_Q_get , 3, true); const tele_op_t op_V = MAKE_GET_OP(V , op_V_get , 1, true); const tele_op_t op_VV = MAKE_GET_OP(VV , op_VV_get , 1, true); const tele_op_t op_ER = MAKE_GET_OP(ER , op_ER_get , 3, true); @@ -859,6 +862,39 @@ } } +static void op_N_Q_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a; // midi note value to lookup + int16_t octave; + int16_t root = cs_pop(cs); + int16_t scale = (cs_pop(cs) + 900) % 9; + int16_t degree = cs_pop(cs); + + // odd fix for first negative octave + if (degree < 0 && degree > -7){ + octave = (degree / 7) - 1; + } else { + octave = degree / 7; + } + + degree = (degree + 700) % 7; + int16_t transpose = table_n_s[scale][degree]; + + // put everything into a + a = root + transpose + (octave * 12); + + // lookup and push out + if (a < 0) { + if (a < -127) a = -127; + a = -a; + cs_push(cs, -table_n[a]); + } + else { + if (a > 127) a = 127; + cs_push(cs, table_n[a]); + } +} + static void op_N_C_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t root = cs_pop(cs); diff -Naur ../2021_02_04/src/ops/maths.h ./src/ops/maths.h --- ../2021_02_04/src/ops/maths.h 2021-02-04 07:53:51.000000000 +0100 +++ ./src/ops/maths.h 2021-02-04 16:50:05.047099030 +0100 @@ -51,6 +51,7 @@ extern const tele_op_t op_N_S; extern const tele_op_t op_N_C; extern const tele_op_t op_N_CS; +extern const tele_op_t op_N_Q; extern const tele_op_t op_V; extern const tele_op_t op_VV; extern const tele_op_t op_ER; diff -Naur ../2021_02_04/src/ops/op.c ./src/ops/op.c --- ../2021_02_04/src/ops/op.c 2021-02-04 07:53:51.000000000 +0100 +++ ./src/ops/op.c 2021-02-04 16:50:05.047099030 +0100 @@ -86,7 +86,7 @@ &op_WRAP, &op_WRP, &op_QT, &op_QT_S, &op_QT_CS, &op_QT_B, &op_AVG, &op_EQ, &op_NE, &op_LT, &op_GT, &op_LTE, &op_GTE, &op_NZ, &op_EZ, &op_RSH, &op_LSH, &op_LROT, &op_RROT, &op_EXP, &op_ABS, &op_SGN, &op_AND, &op_OR, &op_JI, - &op_SCALE, &op_SCL, &op_N, &op_VN, &op_N_S, &op_N_C, &op_N_CS, &op_V, + &op_SCALE, &op_SCL, &op_N, &op_VN, &op_N_S, &op_N_C, &op_N_CS, &op_N_Q, &op_V, &op_VV, &op_ER, &op_NR, &op_BPM, &op_BIT_OR, &op_BIT_AND, &op_BIT_NOT, &op_BIT_XOR, &op_BSET, &op_BGET, &op_BCLR, &op_BTOG, &op_XOR, &op_CHAOS, &op_CHAOS_R, &op_CHAOS_ALG, &op_SYM_PLUS, &op_SYM_DASH, &op_SYM_STAR, diff -Naur ../2021_02_04/src/ops/op_enum.h ./src/ops/op_enum.h --- ../2021_02_04/src/ops/op_enum.h 2021-02-04 07:53:51.000000000 +0100 +++ ./src/ops/op_enum.h 2021-02-04 16:50:05.047099030 +0100 @@ -185,6 +185,7 @@ E_OP_N_S, E_OP_N_C, E_OP_N_CS, + E_OP_N_Q, E_OP_V, E_OP_VV, E_OP_ER,