@@ -0,0 +1,12 @@
#ifndef _EDIT_MODE_H_
#define _EDIT_MODE_H_

#include "stdbool.h"
#include "stdint.h"

void set_edit_mode(void);
void set_edit_mode_script(uint8_t new_script);
void process_edit_keys(uint8_t key, uint8_t mod_key, bool is_held_key);
bool screen_refresh_edit(void);

#endif
@@ -0,0 +1,56 @@
#include "flash.h"

#include <string.h>

// asf
#include "flashc.h"

// this
#include "globals.h"

#define FIRSTRUN_KEY 0x22

char scene_text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS];

// NVRAM data structure located in the flash array.
__attribute__((__section__(".flash_nvram"))) nvram_data_t f;


uint8_t flash_is_fresh(void) {
return (f.fresh != FIRSTRUN_KEY);
}

// write fresh status
void flash_unfresh(void) {
for (uint8_t preset_select = 0; preset_select < SCENE_SLOTS;
preset_select++) {
flash_write(preset_select);
}
preset_select = 0;
flashc_memset8((void*)&(f.scene), preset_select, 1, true);
flashc_memset8((void*)&(f.mode), M_LIVE, 1, true);
flashc_memset8((void*)&(f.fresh), FIRSTRUN_KEY, 1, true);
}

void flash_write(uint8_t preset_no) {
flashc_memcpy((void*)&f.s[preset_no].script, ss_script_ptr(&scene_state),
ss_script_size(), true);
flashc_memcpy((void*)&f.s[preset_no].patterns,
ss_patterns_ptr(&scene_state), ss_patterns_size(), true);
flashc_memcpy((void*)&f.s[preset_no].text, &scene_text, sizeof(scene_text),
true);
flashc_memset8((void*)&(f.scene), preset_no, 1, true);
}

void flash_read(uint8_t preset_no) {
memcpy(ss_script_ptr(&scene_state), &f.s[preset_no].script,
ss_script_size());
memcpy(ss_patterns_ptr(&scene_state), &f.s[preset_no].patterns,
ss_patterns_size());
memcpy(&scene_text, &f.s[preset_no].text, sizeof(scene_text));
flashc_memset8((void*)&(f.scene), preset_no, 1, true);
}

void flash_save_mode(tele_mode_t mode) {
flashc_memset8((void*)&(f.mode), mode, 1, true);
}
@@ -0,0 +1,38 @@
#ifndef _FLASH_H_
#define _FLASH_H_

#include <stdint.h>

#include "globals.h"
#include "line_editor.h"
#include "teletype.h"

#define SCENE_SLOTS 32

#define SCENE_TEXT_LINES 32
#define SCENE_TEXT_CHARS LINE_EDITOR_SIZE

extern char scene_text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS];

typedef const struct {
scene_script_t script[10];
scene_pattern_t patterns[4];
char text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS];
} nvram_scene_t;

typedef const struct {
nvram_scene_t s[SCENE_SLOTS];
uint8_t scene;
tele_mode_t mode;
uint8_t fresh;
} nvram_data_t;

extern nvram_data_t f;

uint8_t flash_is_fresh(void);
void flash_unfresh(void);
void flash_write(uint8_t preset_no);
void flash_read(uint8_t preset_no);
void flash_save_mode(tele_mode_t mode);

#endif
@@ -0,0 +1,33 @@
#ifndef _GLOBALS_H_
#define _GLOBALS_H_

#include <stdbool.h>
#include <stdint.h>
#include "region.h"
#include "teletype.h"

// global variables (defined in main.c)

// holds the current scene
extern scene_state_t scene_state;

// the current preset
extern uint8_t preset_select;

// holds screen data
extern region line[8];

// mode handling
typedef enum {
M_LIVE,
M_EDIT,
M_PATTERN,
M_PRESET_W,
M_PRESET_R,
M_HELP
} tele_mode_t;

void set_mode(tele_mode_t mode);
void set_last_mode(void);

#endif
@@ -1,4 +1,21 @@
#include "teletype.h"
#include "help_mode.h"

// this
#include "globals.h"
#include "keyboard_helper.h"

// libavr32
#include "font.h"
#include "region.h"

// asf
#include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h"
#include "usb_protocol_hid.h"

////////////////////////////////////////////////////////////////////////////////
// Help text ///////////////////////////////////////////////////////////////////

#define HELP_PAGES 8

#define HELP1_LENGTH 38
const char* help1[HELP1_LENGTH] = { "1/8 HELP",
@@ -216,3 +233,78 @@ const char* help8[HELP8_LENGTH] = { "8/8 REMOTE",
"ES.STOP|STOP PATTERN",
"ES.TRIPLE|RECALL SHAPE 1-4",
"ES.MAGIC|1=HALF, 2=DOUBLE" };


////////////////////////////////////////////////////////////////////////////////
// Help mode ///////////////////////////////////////////////////////////////////

const char** help_pages[HELP_PAGES] = { help1, help2, help3, help4,
help5, help6, help7, help8 };
const uint8_t help_length[HELP_PAGES] = { HELP1_LENGTH, HELP2_LENGTH,
HELP3_LENGTH, HELP4_LENGTH,
HELP5_LENGTH, HELP6_LENGTH,
HELP7_LENGTH, HELP8_LENGTH };

uint8_t page_no;
uint8_t offset;

bool dirty;

void set_help_mode() {
dirty = true;
}

void process_help_keys(uint8_t k, uint8_t m, bool is_held_key) {
// <down> or C-n: line down
if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) {
if (offset < help_length[page_no] - 8) {
offset++;
dirty = true;
}
}
// <up> or C-p: line up
else if (match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) {
if (offset) {
offset--;
dirty = true;
}
}
// <left> or [: previous page
else if (match_no_mod(m, k, HID_LEFT) ||
match_no_mod(m, k, HID_OPEN_BRACKET)) {
if (page_no) {
offset = 0;
page_no--;
dirty = true;
}
}
// <right> or ]: next page
else if (match_no_mod(m, k, HID_RIGHT) ||
match_no_mod(m, k, HID_CLOSE_BRACKET)) {
if (page_no < HELP_PAGES - 1) {
offset = 0;
page_no++;
dirty = true;
}
}
}

bool screen_refresh_help() {
if (!dirty) { return false; }

// clamp value of page_no
if (page_no >= HELP_PAGES) page_no = HELP_PAGES - 1;

// clamp value of offset
if (offset >= help_length[page_no] - 8) offset = help_length[page_no] - 8;

const char** text = help_pages[page_no];

for (uint8_t y = 0; y < 8; y++) {
region_fill(&line[y], 0);
font_string_region_clip_tab(&line[y], text[y + offset], 2, 0, 0xa, 0);
}

dirty = false;
return true;
};
@@ -0,0 +1,11 @@
#ifndef _HELP_MODE_H_
#define _HELP_MODE_H_

#include <stdbool.h>
#include <stdint.h>

void set_help_mode(void);
void process_help_keys(uint8_t key, uint8_t mod_key, bool is_held_key);
bool screen_refresh_help(void);

#endif
@@ -0,0 +1,83 @@
#ifndef _KEYBOARD_HELPER_
#define _KEYBOARD_HELPER_

#include <stdbool.h>
#include <stdint.h>

// asf
#include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h"
#include "usb_protocol_hid.h"

// small functions defined static inline, so that each compilation unit gets
// it's own copy and may inline (no LTO in gcc 4.4.7)

static inline bool no_mod(uint8_t mod) {
return mod == HID_MODIFIER_NONE;
}

static inline bool mod_only_shift(uint8_t mod) {
return mod == HID_MODIFIER_LEFT_SHIFT || mod == HID_MODIFIER_RIGHT_SHIFT ||
mod == (HID_MODIFIER_LEFT_SHIFT | HID_MODIFIER_RIGHT_SHIFT);
}

static inline bool mod_only_ctrl(uint8_t mod) {
return mod == HID_MODIFIER_LEFT_CTRL || mod == HID_MODIFIER_RIGHT_CTRL ||
mod == (HID_MODIFIER_LEFT_CTRL | HID_MODIFIER_RIGHT_CTRL);
}

static inline bool mod_only_shift_ctrl(uint8_t mod) {
const uint8_t either_sh =
HID_MODIFIER_LEFT_SHIFT | HID_MODIFIER_RIGHT_SHIFT;
const uint8_t either_ctrl =
HID_MODIFIER_LEFT_CTRL | HID_MODIFIER_RIGHT_CTRL;
// first check we only have shift and alt
if (mod & ~(either_sh | either_ctrl)) return false;
return (mod & either_sh) && (mod & either_ctrl);
}

static inline bool mod_only_alt(uint8_t mod) {
return mod == HID_MODIFIER_LEFT_ALT || mod == HID_MODIFIER_RIGHT_ALT ||
mod == (HID_MODIFIER_LEFT_ALT | HID_MODIFIER_RIGHT_ALT);
}

static inline bool mod_only_shift_alt(uint8_t mod) {
const uint8_t either_sh =
HID_MODIFIER_LEFT_SHIFT | HID_MODIFIER_RIGHT_SHIFT;
const uint8_t either_alt = HID_MODIFIER_LEFT_ALT | HID_MODIFIER_RIGHT_ALT;
// first check we only have shift and alt
if (mod & ~(either_sh | either_alt)) return false;
return (mod & either_sh) && (mod & either_alt);
}

static inline bool mod_only_win(uint8_t mod) {
return mod == HID_MODIFIER_LEFT_UI || mod == HID_MODIFIER_RIGHT_UI ||
mod == (HID_MODIFIER_LEFT_UI | HID_MODIFIER_RIGHT_UI);
}

static inline bool match_no_mod(uint8_t mod, uint8_t key,
uint8_t required_key) {
return (mod == HID_MODIFIER_NONE) && (key == required_key);
}

static inline bool match_shift(uint8_t mod, uint8_t key, uint8_t required_key) {
return mod_only_shift(mod) && key == required_key;
}

static inline bool match_ctrl(uint8_t mod, uint8_t key, uint8_t required_key) {
return mod_only_ctrl(mod) && key == required_key;
}

static inline bool match_alt(uint8_t mod, uint8_t key, uint8_t required_key) {
return mod_only_alt(mod) && key == required_key;
}

static inline bool match_shift_alt(uint8_t mod, uint8_t key,
uint8_t required_key) {
return mod_only_shift_alt(mod) && key == required_key;
}

static inline bool match_win(uint8_t mod, uint8_t key, uint8_t required_key) {
return mod_only_win(mod) && key == required_key;
}

#endif
@@ -0,0 +1,170 @@
#include "line_editor.h"

#include <string.h>

// this
#include "keyboard_helper.h"

// teletype
#include "teletype.h"

// libavr32
#include "font.h"
#include "kbd.h"
#include "region.h"

// asf
#include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h"
#include "usb_protocol_hid.h"

// global copy buffer
static char copy_buffer[LINE_EDITOR_SIZE];

void line_editor_set(line_editor_t *le, const char value[LINE_EDITOR_SIZE]) {
size_t length = strlen(value);
if (length < LINE_EDITOR_SIZE) {
strcpy(le->buffer, value);
le->cursor = length;
le->length = length;
}
else {
le->buffer[0] = 0;
le->cursor = 0;
le->length = 0;
}
}

void line_editor_set_command(line_editor_t *le, const tele_command_t *command) {
print_command(command, le->buffer);
le->length = strlen(le->buffer);
le->cursor = le->length;
}

char *line_editor_get(line_editor_t *le) {
return le->buffer;
}

bool line_editor_process_keys(line_editor_t *le, uint8_t k, uint8_t m,
bool is_key_held) {
// <left> or ctrl-b: move cursor left
if (match_no_mod(m, k, HID_LEFT) || match_ctrl(m, k, HID_B)) {
if (le->cursor) { le->cursor--; }
return true;
}
// <right> or ctrl-f: move cursor right
else if (match_no_mod(m, k, HID_RIGHT) || match_ctrl(m, k, HID_F)) {
if (le->cursor < le->length) { le->cursor++; }
return true;
}
// <home> or ctrl-a: move to beginning of line
else if (match_no_mod(m, k, HID_HOME) || match_ctrl(m, k, HID_A)) {
le->cursor = 0;
return true;
}
// <end> or ctrl-e: move to end of line
else if (match_no_mod(m, k, HID_END) || match_ctrl(m, k, HID_E)) {
le->cursor = le->length;
return true;
}
// <backspace> or ctrl-h: backwards delete one character
else if (match_no_mod(m, k, HID_BACKSPACE) || match_ctrl(m, k, HID_H)) {
if (le->cursor) {
le->cursor--;
for (size_t x = le->cursor; x < LINE_EDITOR_SIZE - 1; x++) {
le->buffer[x] = le->buffer[x + 1];
}
le->length--;
}
return true;
}
// <delete> or ctrl-d: forwards delete one character
else if (match_no_mod(m, k, HID_DELETE) || match_ctrl(m, k, HID_D)) {
if (le->cursor < le->length) {
for (size_t x = le->cursor; x < LINE_EDITOR_SIZE - 1; x++) {
le->buffer[x] = le->buffer[x + 1];
}
le->length--;
}
return true;
}
// shift-<backspace> or ctrl-u: delete from cursor to beginning
else if (match_shift(m, k, HID_BACKSPACE) || match_ctrl(m, k, HID_U)) {
// strings will overlap, so we need to use an intermediate buffer
char temp[LINE_EDITOR_SIZE];
strcpy(temp, &le->buffer[le->cursor]);
line_editor_set(le, temp);
le->cursor = 0;
return true;
}
// shift-<delete> or ctrl-e: delete from cursor to end
else if (match_shift(m, k, HID_DELETE) || match_ctrl(m, k, HID_K)) {
le->buffer[le->cursor] = 0;
le->length = le->cursor;
return true;
}
// alt-<backspace> or ctrl-w: delete from cursor to beginning of word
else if (match_alt(m, k, HID_DELETE) || match_ctrl(m, k, HID_W)) {
while (le->cursor) {
// delete a character
le->cursor--;
for (size_t x = le->cursor; x < LINE_EDITOR_SIZE - 1; x++) {
le->buffer[x] = le->buffer[x + 1];
}
le->length--;

// place the check at the bottom so that we can chain invocations to
// delete multiple words
if (le->buffer[le->cursor - 1] == ' ') break;
}
return true;
}
// ctrl-x or alt-x: cut
else if (match_ctrl(m, k, HID_X) || match_alt(m, k, HID_X)) {
strcpy(copy_buffer, le->buffer);
line_editor_set(le, "");
return true;
}
// ctrl-c or alt-c: copy
else if (match_ctrl(m, k, HID_C) || match_alt(m, k, HID_C)) {
strcpy(copy_buffer, le->buffer);
return true;
}
// ctrl-v or alt-v: paste
else if (match_ctrl(m, k, HID_V) || match_alt(m, k, HID_V)) {
line_editor_set(le, copy_buffer);
return true;
}
else if (no_mod(m) || mod_only_shift(m)) {
if (le->length < LINE_EDITOR_SIZE - 2) { // room for another char & 0
uint8_t n = hid_to_ascii(k, m);
if (n) {
for (size_t x = LINE_EDITOR_SIZE - 1; x > le->cursor; x--) {
le->buffer[x] = le->buffer[x - 1]; // shuffle forwards
}

le->buffer[le->cursor] = n;
le->cursor++;
le->length++;
return true;
}
}
}

// did't process a key
return false;
}

void line_editor_draw(line_editor_t *le, char prefix, region *reg) {
// LINE_EDITOR_SIZE includes space for null, need to also include space for
// the prefix, the space after the prefix and a space at the very end
char s[LINE_EDITOR_SIZE + 3] = { prefix, ' ', 0 };
strcat(s, le->buffer);
strcat(s, " ");

region_fill(reg, 0);
font_string_region_clip_hi(reg, s, 0, 0, 0xf, 0, le->cursor + 2);
}

void line_editor_set_copy_buffer(const char *value) {
strcpy(copy_buffer, value);
}
@@ -0,0 +1,26 @@
#ifndef _LINE_EDITOR_H_
#define _LINE_EDITOR_H_

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#include "region.h"
#include "teletype.h"

#define LINE_EDITOR_SIZE 32 // 31 characters + null termination

typedef struct {
char buffer[LINE_EDITOR_SIZE];
size_t cursor;
size_t length;
} line_editor_t;

void line_editor_set(line_editor_t *le, const char value[LINE_EDITOR_SIZE]);
void line_editor_set_command(line_editor_t *le, const tele_command_t *command);
char *line_editor_get(line_editor_t *le);
bool line_editor_process_keys(line_editor_t *le, uint8_t key, uint8_t mod_key,
bool is_key_held);
void line_editor_draw(line_editor_t *le, char prefix, region *reg);
void line_editor_set_copy_buffer(const char *value);
#endif
@@ -0,0 +1,277 @@
#include "live_mode.h"

#include <string.h>

// this
#include "flash.h"
#include "gitversion.h"
#include "globals.h"
#include "keyboard_helper.h"
#include "line_editor.h"

// teletype
#include "teletype_io.h"

// libavr32
#include "font.h"
#include "region.h"
#include "util.h"

// asf
#include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h"
#include "usb_protocol_hid.h"

#define HISTORY_SIZE 16
tele_command_t history[HISTORY_SIZE];
uint8_t history_line;
line_editor_t le;
process_result_t output;
error_t status;
char error_msg[TELE_ERROR_MSG_LENGTH];
bool show_welcome_message;

static const uint8_t D_INPUT = 1 << 0;
static const uint8_t D_LIST = 1 << 1;
static const uint8_t D_MESSAGE = 1 << 2;
static const uint8_t D_ALL = 0xFF;
uint8_t dirty;

static const uint8_t A_METRO = 1 << 0;
static const uint8_t A_SLEW = 1 << 1;
static const uint8_t A_DELAY = 1 << 2;
static const uint8_t A_STACK = 1 << 3;
static const uint8_t A_MUTES = 1 << 4;
uint8_t activity_prev;
uint8_t activity;

// teletype_io.h
void tele_has_delays(bool has_delays) {
if (has_delays)
activity |= A_DELAY;
else
activity &= ~A_DELAY;
}

void tele_has_stack(bool has_stack) {
if (has_stack)
activity |= A_STACK;
else
activity &= ~A_STACK;
}

void tele_mute() {
activity |= A_MUTES;
}

// set icons
void set_slew_icon(bool display) {
if (display)
activity |= A_SLEW;
else
activity &= ~A_SLEW;
}

void set_metro_icon(bool display) {
if (display)
activity |= A_METRO;
else
activity &= ~A_METRO;
}

// main mode functions
void init_live_mode() {
status = E_OK;
show_welcome_message = true;
activity_prev = 0xFF;
}

void set_live_mode() {
line_editor_set(&le, "");
history_line = HISTORY_SIZE;
dirty = D_ALL;
}

void process_live_keys(uint8_t k, uint8_t m, bool is_held_key) {
// <down> or C-n: history next
if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) {
if (history_line < (HISTORY_SIZE - 1)) {
history_line++;
line_editor_set_command(&le, &history[history_line]);
dirty |= D_INPUT;
}
else {
history_line = HISTORY_SIZE;
line_editor_set(&le, "");
dirty |= D_INPUT;
}
}
// <up> or C-p: history previous
else if (match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) {
if (history_line) {
history_line--;
line_editor_set_command(&le, &history[history_line]);
dirty |= D_INPUT;
}
}
// <enter>: execute command
else if (match_no_mod(m, k, HID_ENTER)) {
dirty |= D_MESSAGE; // something will definitely happen
dirty |= D_INPUT;

tele_command_t command;

status = parse(line_editor_get(&le), &command, error_msg);
if (status != E_OK)
return; // quit, screen_refresh_live will display the error message

status = validate(&command, error_msg);
if (status != E_OK)
return; // quit, screen_refresh_live will display the error message

history_line = HISTORY_SIZE;
if (command.length) {
// shuffle the history up
// should really use some sort of ring buffer
for (size_t i = 0; i < HISTORY_SIZE - 1; i++) {
memcpy(&history[i], &history[i + 1], sizeof(command));
}
memcpy(&history[HISTORY_SIZE - 1], &command, sizeof(command));

output = run_command(&scene_state, &command);
}
line_editor_set(&le, "");
}
// [ or ]: switch to edit mode
else if (match_no_mod(m, k, HID_OPEN_BRACKET) ||
match_no_mod(m, k, HID_CLOSE_BRACKET)) {
set_mode(M_EDIT);
}
else { // pass the key though to the line editor
bool processed = line_editor_process_keys(&le, k, m, is_held_key);
if (processed) dirty |= D_INPUT;
}
}


bool screen_refresh_live() {
bool screen_dirty = false;
if (dirty & D_INPUT) {
line_editor_draw(&le, '>', &line[7]);
screen_dirty = true;
dirty &= ~D_INPUT;
}

if (dirty & D_MESSAGE) {
char s[32];
if (status != E_OK) {
strcpy(s, tele_error(status));
if (error_msg[0]) {
strcat(s, ": ");
strcat(s, error_msg);
error_msg[0] = 0;
}
status = E_OK;
}
else if (output.has_value) {
itoa(output.value, s, 10);
output.has_value = false;
}
else if (show_welcome_message) {
strcpy(s, TELETYPE_VERSION ": ");
strcat(s, git_version);
show_welcome_message = false;
}
else {
s[0] = 0;
}

region_fill(&line[6], 0);
font_string_region_clip(&line[6], s, 0, 0, 0x4, 0);

screen_dirty = true;
dirty &= ~D_MESSAGE;
}

if (dirty & D_LIST) {
for (int i = 0; i < 6; i++) region_fill(&line[i], 0);

screen_dirty = true;
dirty &= ~D_LIST;
}

if ((activity != activity_prev)) {
region_fill(&line[0], 0);

// slew icon
uint8_t slew_fg = activity & A_SLEW ? 15 : 1;
line[0].data[98 + 0 + 512] = slew_fg;
line[0].data[98 + 1 + 384] = slew_fg;
line[0].data[98 + 2 + 256] = slew_fg;
line[0].data[98 + 3 + 128] = slew_fg;
line[0].data[98 + 4 + 0] = slew_fg;

// delay icon
uint8_t delay_fg = activity & A_DELAY ? 15 : 1;
line[0].data[106 + 0 + 0] = delay_fg;
line[0].data[106 + 1 + 0] = delay_fg;
line[0].data[106 + 2 + 0] = delay_fg;
line[0].data[106 + 3 + 0] = delay_fg;
line[0].data[106 + 4 + 0] = delay_fg;
line[0].data[106 + 0 + 128] = delay_fg;
line[0].data[106 + 0 + 256] = delay_fg;
line[0].data[106 + 0 + 384] = delay_fg;
line[0].data[106 + 0 + 512] = delay_fg;
line[0].data[106 + 4 + 128] = delay_fg;
line[0].data[106 + 4 + 256] = delay_fg;
line[0].data[106 + 4 + 384] = delay_fg;
line[0].data[106 + 4 + 512] = delay_fg;

// queue icon
uint8_t stack_fg = activity & A_STACK ? 15 : 1;
line[0].data[114 + 0 + 0] = stack_fg;
line[0].data[114 + 1 + 0] = stack_fg;
line[0].data[114 + 2 + 0] = stack_fg;
line[0].data[114 + 3 + 0] = stack_fg;
line[0].data[114 + 4 + 0] = stack_fg;
line[0].data[114 + 0 + 256] = stack_fg;
line[0].data[114 + 1 + 256] = stack_fg;
line[0].data[114 + 2 + 256] = stack_fg;
line[0].data[114 + 3 + 256] = stack_fg;
line[0].data[114 + 4 + 256] = stack_fg;
line[0].data[114 + 0 + 512] = stack_fg;
line[0].data[114 + 1 + 512] = stack_fg;
line[0].data[114 + 2 + 512] = stack_fg;
line[0].data[114 + 3 + 512] = stack_fg;
line[0].data[114 + 4 + 512] = stack_fg;

// metro icon
uint8_t metro_fg = activity & A_METRO ? 15 : 1;
line[0].data[122 + 0 + 0] = metro_fg;
line[0].data[122 + 0 + 128] = metro_fg;
line[0].data[122 + 0 + 256] = metro_fg;
line[0].data[122 + 0 + 384] = metro_fg;
line[0].data[122 + 0 + 512] = metro_fg;
line[0].data[122 + 1 + 128] = metro_fg;
line[0].data[122 + 2 + 256] = metro_fg;
line[0].data[122 + 3 + 128] = metro_fg;
line[0].data[122 + 4 + 0] = metro_fg;
line[0].data[122 + 4 + 128] = metro_fg;
line[0].data[122 + 4 + 256] = metro_fg;
line[0].data[122 + 4 + 384] = metro_fg;
line[0].data[122 + 4 + 512] = metro_fg;

// mutes
for (size_t i = 0; i < 8; i++) {
// make it staggered to match how the device looks
size_t stagger = i % 2 ? 384 : 128;
uint8_t mute_fg = ss_get_mute(&scene_state, i) ? 15 : 1;
line[0].data[87 + i + stagger] = mute_fg;
}

activity_prev = activity;
screen_dirty = true;
activity &= ~A_MUTES;
}

return screen_dirty;
}
@@ -0,0 +1,14 @@
#ifndef _LIVE_MODE_H_
#define _LIVE_MODE_H_

#include "stdbool.h"
#include "stdint.h"

void set_slew_icon(bool display);
void set_metro_icon(bool display);
void init_live_mode(void);
void set_live_mode(void);
void process_live_keys(uint8_t key, uint8_t mod_key, bool is_held_key);
bool screen_refresh_live(void);

#endif

Large diffs are not rendered by default.

@@ -0,0 +1,350 @@
#include "pattern_mode.h"

// this
#include "globals.h"
#include "keyboard_helper.h"

// teletype
#include "teletype.h"
#include "teletype_io.h"

// libavr32
#include "font.h"
#include "region.h"
#include "util.h"

// asf
#include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h"
#include "usb_protocol_hid.h"

int16_t copy_buffer;
uint8_t pattern; // which pattern are we editting
uint8_t base; // base + offset determine what we are editting
uint8_t offset;

bool dirty;

// teletype_io.h
void tele_pattern_updated() {
dirty = true;
}

void set_pattern_mode() {
dirty = true;
}

void process_pattern_keys(uint8_t k, uint8_t m, bool is_held_key) {
// <down>: move down
if (match_no_mod(m, k, HID_DOWN)) {
base++;
if (base == 8) {
base = 7;
if (offset < 56) { offset++; }
}
dirty = true;
}
// alt-<down>: move a page down
else if (match_alt(m, k, HID_DOWN)) {
if (offset < 48)
offset += 8;
else {
offset = 56;
base = 7;
}
dirty = true;
}
// <up>: move up
else if (match_no_mod(m, k, HID_UP)) {
if (base)
base--;
else if (offset)
offset--;
dirty = true;
}
// alt-<up>: move a page up
else if (match_alt(m, k, HID_UP)) {
if (offset > 8) { offset -= 8; }
else {
offset = 0;
base = 0;
}
dirty = true;
}
// <left>: move left
else if (match_no_mod(m, k, HID_LEFT)) {
if (pattern > 0) pattern--;
dirty = true;
}
// alt-<left>: move to the very left
else if (match_alt(m, k, HID_LEFT)) {
base = 0;
offset = 0;
dirty = true;
}
// <right>: move right
else if (match_no_mod(m, k, HID_RIGHT)) {
if (pattern < 3) pattern++;
dirty = true;
}
// alt-<right>: move to the very right
else if (match_alt(m, k, HID_RIGHT)) {
base = 7;
offset = 56;
}
// [: decrement by 1
else if (match_no_mod(m, k, HID_OPEN_BRACKET)) {
int16_t v = ss_get_pattern_val(&scene_state, pattern, base + offset);
if (v > INT16_MIN) { // -32767
ss_set_pattern_val(&scene_state, pattern, base + offset, v - 1);
dirty = true;
}
}
// ]: increment by 1
else if (match_no_mod(m, k, HID_CLOSE_BRACKET)) {
int16_t v = ss_get_pattern_val(&scene_state, pattern, base + offset);
if (v < INT16_MAX) { // 32766
ss_set_pattern_val(&scene_state, pattern, base + offset, v + 1);
dirty = true;
}
}
// <backspace>: delete a digit
else if (match_no_mod(m, k, HID_BACKSPACE)) {
int16_t v =
ss_get_pattern_val(&scene_state, pattern, base + offset) / 10;
ss_set_pattern_val(&scene_state, pattern, base + offset, v);
dirty = true;
}
// shift-<backspace>: delete an entry, shift numbers up
else if (match_shift(m, k, HID_BACKSPACE)) {
for (size_t i = base + offset; i < 63; i++) {
int16_t v = ss_get_pattern_val(&scene_state, pattern, i + 1);
ss_set_pattern_val(&scene_state, pattern, i, v);
}

uint16_t l = ss_get_pattern_len(&scene_state, pattern);
if (l > base + offset) ss_set_pattern_len(&scene_state, pattern, l - 1);
dirty = true;
}
// <enter>: move down (increase length only if on the entry immediately
// after the current length)
else if (match_no_mod(m, k, HID_ENTER)) {
uint16_t l = ss_get_pattern_len(&scene_state, pattern);
if (base + offset == l && l < 64)
ss_set_pattern_len(&scene_state, pattern, l + 1);
base++;
if (base == 8) {
base = 7;
if (offset < 56) { offset++; }
}
dirty = true;
}
// shift-<enter>: duplicate entry and shift downwards (increase length only
// if on the entry immediately after the current length)
else if (match_shift(m, k, HID_ENTER)) {
for (int i = 63; i > base + offset; i--) {
int16_t v = ss_get_pattern_val(&scene_state, pattern, i - 1);
ss_set_pattern_val(&scene_state, pattern, i, v);
}
uint16_t l = ss_get_pattern_len(&scene_state, pattern);
if (base + offset == l && l < 64) {
ss_set_pattern_len(&scene_state, pattern, l + 1);
}
dirty = true;
}
// alt-x: cut value (n.b. ctrl-x not supported)
else if (match_alt(m, k, HID_X)) {
copy_buffer = ss_get_pattern_val(&scene_state, pattern, base + offset);
for (int i = base + offset; i < 63; i++) {
int16_t v = ss_get_pattern_val(&scene_state, pattern, i + 1);
ss_set_pattern_val(&scene_state, pattern, i, v);
}

uint16_t l = ss_get_pattern_len(&scene_state, pattern);
if (l > base + offset) {
ss_set_pattern_len(&scene_state, pattern, l - 1);
}
dirty = true;
}
// alt-c: copy value (n.b. ctrl-c not supported)
else if (match_alt(m, k, HID_C)) {
copy_buffer = ss_get_pattern_val(&scene_state, pattern, base + offset);
}
// alt-v: paste value (n.b. ctrl-v not supported)
else if (match_alt(m, k, HID_V)) {
ss_set_pattern_val(&scene_state, pattern, base + offset, copy_buffer);
dirty = true;
}
// shift-alt-v: insert value
else if (match_shift_alt(m, k, HID_V)) {
for (int i = 63; i > base + offset; i--) {
int16_t v = ss_get_pattern_val(&scene_state, pattern, i - 1);
ss_set_pattern_val(&scene_state, pattern, i, v);
}
uint16_t l = ss_get_pattern_len(&scene_state, pattern);
if (l >= base + offset && l < 63) {
ss_set_pattern_len(&scene_state, pattern, l + 1);
}
ss_set_pattern_val(&scene_state, pattern, base + offset, copy_buffer);
dirty = true;
}
// shift-l: set length to current position
else if (match_shift(m, k, HID_L)) {
ss_set_pattern_len(&scene_state, pattern, base + offset + 1);
dirty = true;
}
// alt-l: go to current length entry
else if (match_alt(m, k, HID_L)) {
uint16_t l = ss_get_pattern_len(&scene_state, pattern);
if (l) {
offset = ((l - 1) >> 3) << 3;
base = (l - 1) & 0x7;
int8_t delta = base - 3;
if ((offset + delta > 0) && (offset + delta < 56)) {
offset += delta;
base = 3;
}
}
else {
offset = 0;
base = 0;
}
dirty = true;
}
// shift-s: set start to current position
else if (match_shift(m, k, HID_S)) {
ss_set_pattern_start(&scene_state, pattern, offset + base);
dirty = true;
}
// alt-s: go to start entry
else if (match_alt(m, k, HID_S)) {
int16_t start = ss_get_pattern_start(&scene_state, pattern);
if (start) {
offset = (start >> 3) << 3;
base = start & 0x7;
int8_t delta = base - 3;
if ((offset + delta > 0) && (offset + delta < 56)) {
offset += delta;
base = 3;
}
}
else {
offset = 0;
base = 0;
}
dirty = true;
}
// shift-e: set end to current position
else if (match_shift(m, k, HID_E)) {
ss_set_pattern_end(&scene_state, pattern, offset + base);
dirty = true;
}
// alt-e: go to end entry
else if (match_alt(m, k, HID_E)) {
int16_t end = ss_get_pattern_end(&scene_state, pattern);
if (end) {
offset = (end >> 3) << 3;
base = end & 0x7;
int8_t delta = base - 3;
if ((offset + delta > 0) && (offset + delta < 56)) {
offset += delta;
base = 3;
}
}
else {
offset = 0;
base = 0;
}
dirty = true;
}
// -: negate value
else if (match_no_mod(m, k, HID_UNDERSCORE)) {
int16_t v = ss_get_pattern_val(&scene_state, pattern, base + offset);
ss_set_pattern_val(&scene_state, pattern, base + offset, -v);
dirty = true;
}
// <space>: toggle non-zero to zero, and zero to 1
else if (match_no_mod(m, k, HID_SPACEBAR)) {
if (ss_get_pattern_val(&scene_state, pattern, base + offset))
ss_set_pattern_val(&scene_state, pattern, base + offset, 0);
else
ss_set_pattern_val(&scene_state, pattern, base + offset, 1);
dirty = true;
}
// 0-9: numeric entry
else if (no_mod(m) && k >= HID_1 && k <= HID_0) {
uint8_t n = (k - HID_1 + 1) % 10; // convert HID numbers to decimal,
// taking care of HID_0
int16_t v = ss_get_pattern_val(&scene_state, pattern, base + offset);
if (v && v < 3276 && v > -3276) {
v = v * 10;
if (v > 0)
ss_set_pattern_val(&scene_state, pattern, base + offset, v + n);
else
ss_set_pattern_val(&scene_state, pattern, base + offset, v - n);
}
else
ss_set_pattern_val(&scene_state, pattern, base + offset, n);
dirty = true;
}
}

void process_pattern_knob(uint16_t knob, uint8_t m) {
if (mod_only_ctrl(m)) {
ss_set_pattern_val(&scene_state, pattern, base + offset, knob >> 7);
dirty = true;
}
else if (mod_only_shift_ctrl(m)) {
ss_set_pattern_val(&scene_state, pattern, base + offset, knob >> 2);
dirty = true;
}
}

bool screen_refresh_pattern() {
if (!dirty) { return false; }

char s[32];
for (uint8_t y = 0; y < 8; y++) {
region_fill(&line[y], 0);
itoa(y + offset, s, 10);
font_string_region_clip_right(&line[y], s, 4, 0, 0x1, 0);

for (uint8_t x = 0; x < 4; x++) {
uint8_t a = 1;
if (ss_get_pattern_len(&scene_state, x) > y + offset) a = 6;

itoa(ss_get_pattern_val(&scene_state, x, y + offset), s, 10);
font_string_region_clip_right(&line[y], s, (x + 1) * 30 + 4, 0, a,
0);

if (y + offset >= ss_get_pattern_start(&scene_state, x)) {
if (y + offset <= ss_get_pattern_end(&scene_state, x)) {
for (uint8_t i = 0; i < 8; i += 2) {
line[y].data[i * 128 + (x + 1) * 30 + 6] = 1;
}
}
}

if (y + offset == ss_get_pattern_idx(&scene_state, x)) {
line[y].data[2 * 128 + (x + 1) * 30 + 6] = 11;
line[y].data[3 * 128 + (x + 1) * 30 + 6] = 11;
line[y].data[4 * 128 + (x + 1) * 30 + 6] = 11;
}
}
}

itoa(ss_get_pattern_val(&scene_state, pattern, base + offset), s, 10);
font_string_region_clip_right(&line[base], s, (pattern + 1) * 30 + 4, 0,
0xf, 0);

for (uint8_t y = 0; y < 64; y += 2) {
line[y >> 3].data[(y & 0x7) * 128 + 8] = 1;
}

for (uint8_t y = 0; y < 8; y++) {
line[(offset + y) >> 3].data[((offset + y) & 0x7) * 128 + 8] = 6;
}

dirty = false;

return true;
}
@@ -0,0 +1,12 @@
#ifndef _PATTERN_MODE_H_
#define _PATTERN_MODE_H_

#include <stdbool.h>
#include <stdint.h>

void set_pattern_mode(void);
void process_pattern_keys(uint8_t key, uint8_t mod_key, bool is_held_key);
void process_pattern_knob(uint16_t knob, uint8_t mod_key);
bool screen_refresh_pattern(void);

#endif
@@ -0,0 +1,92 @@
#include "preset_r_mode.h"

// this
#include "flash.h"
#include "globals.h"
#include "keyboard_helper.h"

// libavr32
#include "font.h"
#include "region.h"
#include "util.h"

// asf
#include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h"
#include "usb_protocol_hid.h"

uint8_t offset;
uint8_t knob_last;
bool dirty;

void set_preset_r_mode(uint16_t knob) {
knob_last = knob >> 7;
offset = 0;
dirty = true;
}

void process_preset_r_knob(uint16_t knob, uint8_t mod_key) {
uint8_t knob_now = knob >> 7;
if (knob_now != knob_last) {
preset_select = knob_now;
knob_last = knob_now;
dirty = true;
}
}

void process_preset_r_keys(uint8_t k, uint8_t m, bool is_held_key) {
// <down> or C-n: line down
if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) {
if (offset < SCENE_TEXT_LINES - 8) {
offset++;
dirty = true;
}
}
// <up> or C-p: line up
else if (match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) {
if (offset) {
offset--;
dirty = true;
}
}
// <left> or [: preset down
else if (match_no_mod(m, k, HID_LEFT) ||
match_no_mod(m, k, HID_OPEN_BRACKET)) {
if (preset_select) preset_select--;
dirty = true;
}
// <right> or ]: preset up
else if (match_no_mod(m, k, HID_RIGHT) ||
match_no_mod(m, k, HID_CLOSE_BRACKET)) {
if (preset_select < SCENE_SLOTS - 1) preset_select++;
dirty = true;
}
// <enter>: load preset
else if (match_no_mod(m, k, HID_ENTER) && !is_held_key) {
flash_read(preset_select);
ss_set_scene(&scene_state, preset_select);

run_script(&scene_state, INIT_SCRIPT);

set_last_mode();
}
}

bool screen_refresh_preset_r() {
if (!dirty) { return false; }

char s[32];
itoa(preset_select, s, 10);
region_fill(&line[0], 1);
font_string_region_clip_right(&line[0], s, 126, 0, 0xf, 1);
font_string_region_clip(&line[0], f.s[preset_select].text[0], 2, 0, 0xf, 1);


for (uint8_t y = 1; y < 8; y++) {
region_fill(&line[y], 0);
font_string_region_clip(&line[y], f.s[preset_select].text[offset + y],
2, 0, 0xa, 0);
}

dirty = false;
return true;
};
@@ -0,0 +1,12 @@
#ifndef _PRESET_R_MODE_H_
#define _PRESET_R_MODE_H_

#include <stdbool.h>
#include <stdint.h>

void set_preset_r_mode(uint16_t knob);
void process_preset_r_knob(uint16_t knob, uint8_t mod_key);
void process_preset_r_keys(uint8_t key, uint8_t mod_key, bool is_held_key);
bool screen_refresh_preset_r(void);

#endif
@@ -0,0 +1,125 @@
#include "preset_w_mode.h"

#include <string.h>

// this
#include "flash.h"
#include "globals.h"
#include "keyboard_helper.h"
#include "line_editor.h"

// libavr32
#include "font.h"
#include "kbd.h"
#include "region.h"
#include "util.h"

// asf
#include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h"
#include "usb_protocol_hid.h"

uint8_t edit_line;
uint8_t edit_offset;
line_editor_t le;

static const uint8_t D_INPUT = 1 << 0;
static const uint8_t D_LIST = 1 << 1;
static const uint8_t D_ALL = 0xFF;
uint8_t dirty;

void set_preset_w_mode() {
edit_line = 0;
edit_offset = 0;
line_editor_set(&le, scene_text[0]);
dirty = D_ALL;
}

void process_preset_w_keys(uint8_t k, uint8_t m, bool is_held_key) {
// <down> or C-n: line down
if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) {
if ((edit_offset + edit_line) < 31) {
if (edit_line == 5)
edit_offset++;
else
edit_line++;
line_editor_set(&le, scene_text[edit_line + edit_offset]);
dirty |= D_LIST;
dirty |= D_INPUT;
}
}
// <up> or C-p: line up
else if (match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) {
if (edit_line + edit_offset) {
if (edit_line)
edit_line--;
else
edit_offset--;
line_editor_set(&le, scene_text[edit_line + edit_offset]);
dirty |= D_LIST;
dirty |= D_INPUT;
}
}
// [: preset down
else if (match_no_mod(m, k, HID_OPEN_BRACKET)) {
if (preset_select) preset_select--;
dirty |= D_LIST;
}
// ]: preset up
else if (match_no_mod(m, k, HID_CLOSE_BRACKET)) {
if (preset_select < SCENE_SLOTS - 1) preset_select++;
dirty |= D_LIST;
}
// <enter>: enter text
else if (match_no_mod(m, k, HID_ENTER)) {
strcpy(scene_text[edit_line + edit_offset], line_editor_get(&le));
if (edit_line + edit_offset < 31) {
if (edit_line == 5)
edit_offset++;
else
edit_line++;
}
line_editor_set(&le, scene_text[edit_line + edit_offset]);
dirty |= D_LIST;
dirty |= D_INPUT;
}
// alt-<enter>: save preset
else if (match_alt(m, k, HID_ENTER)) {
if (!is_held_key) {
strcpy(scene_text[edit_line + edit_offset], line_editor_get(&le));
flash_write(preset_select);
set_last_mode();
}
}
else { // pass to line editor
bool processed = line_editor_process_keys(&le, k, m, is_held_key);
if (processed) dirty |= D_INPUT;
}
}


bool screen_refresh_preset_w() {
if (!(dirty & D_ALL)) { return false; }

if (dirty & D_LIST) {
char header[6] = ">>> ";
itoa(preset_select, header + 4, 10);
region_fill(&line[0], 1);
font_string_region_clip_right(&line[0], header, 126, 0, 0xf, 1);
font_string_region_clip(&line[0], "WRITE", 2, 0, 0xf, 1);

for (uint8_t y = 1; y < 7; y++) {
uint8_t a = edit_line == (y - 1);
region_fill(&line[y], a);
font_string_region_clip(&line[y], scene_text[edit_offset + y - 1],
2, 0, 0xa + a * 5, a);
}
dirty &= ~D_LIST;
}

if (dirty & D_INPUT) {
line_editor_draw(&le, '+', &line[7]);
dirty &= ~D_INPUT;
}

return true;
}
@@ -0,0 +1,11 @@
#ifndef _PRESET_W_MODE_H_
#define _PRESET_W_MODE_H_

#include <stdbool.h>
#include <stdint.h>

void set_preset_w_mode(void);
void process_preset_w_keys(uint8_t key, uint8_t mod_key, bool is_held_key);
bool screen_refresh_preset_w(void);

#endif

Large diffs are not rendered by default.

@@ -0,0 +1,6 @@
#ifndef _USB_DISK_MODE_H_
#define _USB_DISK_MODE_H_

void tele_usb_disk(void);

#endif
@@ -4,11 +4,12 @@ DEPS =
OBJ = tt.o ../src/teletype.o ../src/command.o ../src/helpers.o \
../src/match_token.o ../src/scanner.o \
../src/state.o ../src/table.o \
../src/ops/op.o ../src/ops/ansible.c ../src/ops/constants.o \
../src/ops/controlflow.o ../src/ops/delay.o ../src/ops/hardware.o \
../src/ops/justfriends.o ../src/ops/metronome.o ../src/ops/maths.o \
../src/ops/op.o ../src/ops/ansible.c ../src/ops/controlflow.o \
../src/ops/delay.o ../src/ops/earthsea.o ../src/ops/hardware.o \
../src/ops/justfriends.o ../src/ops/meadowphysics.o \
../src/ops/metronome.o ../src/ops/maths.o ../src/ops/orca.o \
../src/ops/patterns.o ../src/ops/queue.o ../src/ops/stack.o \
../src/ops/telex.o ../src/ops/variables.o \
../src/ops/telex.o ../src/ops/variables.o ../src/ops/whitewhale.c \
../libavr32/src/euclidean/euclidean.o ../libavr32/src/euclidean/data.o \
../libavr32/src/util.o

@@ -11,9 +11,13 @@
#include "util.h"


void tele_metro(int16_t m, int16_t m_act, uint8_t m_reset) {
printf("METRO m:%" PRIi16 " m_act:%" PRIi16 "m_reset:%" PRIu8, m, m_act,
m_reset);
void tele_metro_updated() {
printf("METRO UPDATED");
printf("\n");
}

void tele_metro_reset() {
printf("METRO RESET");
printf("\n");
}

@@ -32,13 +36,13 @@ void tele_cv_slew(uint8_t i, int16_t v) {
printf("\n");
}

void tele_delay(uint8_t i) {
printf("DELAY i:%" PRIu8, i);
void tele_has_delays(bool i) {
printf("DELAY i:%s", i ? "true" : "false");
printf("\n");
}

void tele_s(uint8_t i) {
printf("S i:%" PRIu8, i);
void tele_has_stack(bool i) {
printf("STACK i:%s", i ? "true" : "false");
printf("\n");
}

@@ -72,12 +76,8 @@ void tele_scene(uint8_t i) {
printf("\n");
}

void tele_pi() {
printf("PI");
printf("\n");
}
void tele_script(uint8_t a) {
printf("SCRIPT a:%" PRIu8, a);
void tele_pattern_updated() {
printf("PATTERN UPDATED");
printf("\n");
}

@@ -86,8 +86,8 @@ void tele_kill() {
printf("\n");
}

void tele_mute(uint8_t i, uint8_t s) {
printf("MUTE i:%" PRIu8 " s:%" PRIu8, i, s);
void tele_mute() {
printf("MUTE");
printf("\n");
}

@@ -119,10 +119,11 @@ int main() {

in = malloc(256);

tele_init();

printf("teletype. (blank line quits)\n\n");

scene_state_t ss;
ss_init(&ss);

do {
printf("> ");
fgets(in, 256, stdin);
@@ -136,15 +137,15 @@ int main() {
tele_command_t temp;
exec_state_t es;
es_init(&es);
char error_msg[ERROR_MSG_LENGTH];
char error_msg[TELE_ERROR_MSG_LENGTH];
status = parse(in, &temp, error_msg);
if (status == E_OK) {
status = validate(&temp, error_msg);
printf("validate: %s", tele_error(status));
if (error_msg[0]) printf(": %s", error_msg);
printf("\n");
if (status == E_OK) {
process_result_t output = process_command(&es, &temp);
process_result_t output = process_command(&ss, &es, &temp);
if (output.has_value) { printf(">>> %i\n", output.value); }
}
}
@@ -17,24 +17,33 @@ void copy_post_command(tele_command_t *dst, const tele_command_t *src) {
dst->length * sizeof(tele_data_t));
}

void print_command(const tele_command_t *c, char *out) {
*out = 0;
for (int n = 0; n < c->length; n++) {
switch (c->data[n].tag) {
case OP: strcat(out, tele_ops[c->data[n].value]->name); break;
void print_command(const tele_command_t *cmd, char *out) {
out[0] = 0;
for (size_t i = 0; i < cmd->length; i++) {
tele_word_t tag = cmd->data[i].tag;
int16_t value = cmd->data[i].value;

switch (tag) {
case OP: strcat(out, tele_ops[value]->name); break;
case NUMBER: {
char number[8];
itoa(c->data[n].value, number, 10);
itoa(value, number, 10);
strcat(out, number);
break;
}
case MOD: strcat(out, tele_mods[c->data[n].value]->name); break;
case MOD: strcat(out, tele_mods[value]->name); break;
case PRE_SEP: strcat(out, ":"); break;
case SUB_SEP: strcat(out, ";"); break;
default: break;
}
strcat(out, " ");

// do we need to add a space?
// first check if we're not at the end
if (i < cmd->length - 1) {
// otherwise, only add a space if the next tag is a not a seperator
tele_word_t next_tag = cmd->data[i + 1].tag;
if (next_tag != PRE_SEP && next_tag != SUB_SEP) {
strcat(out, " ");
}
}
}
size_t out_len = strlen(out);
if (out_len > 0) out[out_len - 1] = 0;
}
@@ -93,61 +93,9 @@
"TR.TOG" => { MATCH_OP(E_OP_TR_TOG); };
"TR.PULSE" => { MATCH_OP(E_OP_TR_PULSE); };
"TR.P" => { MATCH_OP(E_OP_TR_P); };
"II" => { MATCH_OP(E_OP_II); };
"CV.SET" => { MATCH_OP(E_OP_CV_SET); };
"MUTE" => { MATCH_OP(E_OP_MUTE); };
"UNMUTE" => { MATCH_OP(E_OP_UNMUTE); };
"STATE" => { MATCH_OP(E_OP_STATE); };
"JF.TR" => { MATCH_OP(E_OP_JF_TR); };
"JF.RMODE" => { MATCH_OP(E_OP_JF_RMODE); };
"JF.RUN" => { MATCH_OP(E_OP_JF_RUN); };
"JF.SHIFT" => { MATCH_OP(E_OP_JF_SHIFT); };
"JF.VTR" => { MATCH_OP(E_OP_JF_VTR); };
"JF.MODE" => { MATCH_OP(E_OP_JF_MODE); };
"JF.TICK" => { MATCH_OP(E_OP_JF_TICK); };
"JF.VOX" => { MATCH_OP(E_OP_JF_VOX); };
"JF.NOTE" => { MATCH_OP(E_OP_JF_NOTE); };
"JF.GOD" => { MATCH_OP(E_OP_JF_GOD); };
"JF.TUNE" => { MATCH_OP(E_OP_JF_TUNE); };
"JF.QT" => { MATCH_OP(E_OP_JF_QT); };
"KR.PRE" => { MATCH_OP(E_OP_KR_PRESET); };
"KR.PAT" => { MATCH_OP(E_OP_KR_PATTERN); };
"KR.SCALE" => { MATCH_OP(E_OP_KR_SCALE); };
"KR.PERIOD" => { MATCH_OP(E_OP_KR_PERIOD); };
"KR.POS" => { MATCH_OP(E_OP_KR_POS); };
"KR.L.ST" => { MATCH_OP(E_OP_KR_LOOP_ST); };
"KR.L.LEN" => { MATCH_OP(E_OP_KR_LOOP_LEN); };
"KR.RES" => { MATCH_OP(E_OP_KR_RESET); };
"MP.PRE" => { MATCH_OP(E_OP_MP_PRESET1); };
"MP.RES" => { MATCH_OP(E_OP_MP_RESET1); };
"MP.OFF" => { MATCH_OP(E_OP_MP_STOP1); };
"MP.SCALE" => { MATCH_OP(E_OP_MP_SCALE); };
"MP.PERIOD" => { MATCH_OP(E_OP_MP_PERIOD); };
"LV.PRE" => { MATCH_OP(E_OP_LV_PRESET); };
"LV.RES" => { MATCH_OP(E_OP_LV_RESET); };
"LV.POS" => { MATCH_OP(E_OP_LV_POS); };
"LV.L.ST" => { MATCH_OP(E_OP_LV_L_ST); };
"LV.L.LEN" => { MATCH_OP(E_OP_LV_L_LEN); };
"LV.L.DIR" => { MATCH_OP(E_OP_LV_L_DIR); };
"LV.CV" => { MATCH_OP(E_OP_LV_CV); };
"CY.PRE" => { MATCH_OP(E_OP_CY_PRESET); };
"CY.RES" => { MATCH_OP(E_OP_CY_RESET); };
"CY.POS" => { MATCH_OP(E_OP_CY_POS); };
"CY.REV" => { MATCH_OP(E_OP_CY_REV); };
"CY.CV" => { MATCH_OP(E_OP_CY_CV); };
"MID.SHIFT" => { MATCH_OP(E_OP_MID_SHIFT); };
"MID.SLEW" => { MATCH_OP(E_OP_MID_SLEW); };
"ARP.STY" => { MATCH_OP(E_OP_ARP_STYLE); };
"ARP.HLD" => { MATCH_OP(E_OP_ARP_HOLD); };
"ARP.RPT" => { MATCH_OP(E_OP_ARP_RPT); };
"ARP.GT" => { MATCH_OP(E_OP_ARP_GATE); };
"ARP.DIV" => { MATCH_OP(E_OP_ARP_DIV); };
"ARP.RES" => { MATCH_OP(E_OP_ARP_RESET); };
"ARP.SHIFT" => { MATCH_OP(E_OP_ARP_SHIFT); };
"ARP.SLEW" => { MATCH_OP(E_OP_ARP_SLEW); };
"ARP.FIL" => { MATCH_OP(E_OP_ARP_FILL); };
"ARP.ROT" => { MATCH_OP(E_OP_ARP_ROT); };
"ARP.ER" => { MATCH_OP(E_OP_ARP_ER); };

# maths
"ADD" => { MATCH_OP(E_OP_ADD); };
@@ -214,7 +162,7 @@
# delay
"DEL.CLR" => { MATCH_OP(E_OP_DEL_CLR); };

# constants
# whitewhale
"WW.PRESET" => { MATCH_OP(E_OP_WW_PRESET); };
"WW.POS" => { MATCH_OP(E_OP_WW_POS); };
"WW.SYNC" => { MATCH_OP(E_OP_WW_SYNC); };
@@ -229,6 +177,8 @@
"WW.MUTE4" => { MATCH_OP(E_OP_WW_MUTE4); };
"WW.MUTEA" => { MATCH_OP(E_OP_WW_MUTEA); };
"WW.MUTEB" => { MATCH_OP(E_OP_WW_MUTEB); };

# earthsea
"MP.PRESET" => { MATCH_OP(E_OP_MP_PRESET); };
"MP.RESET" => { MATCH_OP(E_OP_MP_RESET); };
"MP.SYNC" => { MATCH_OP(E_OP_MP_SYNC); };
@@ -237,6 +187,8 @@
"MP.FREEZE" => { MATCH_OP(E_OP_MP_FREEZE); };
"MP.UNFREEZE" => { MATCH_OP(E_OP_MP_UNFREEZE); };
"MP.STOP" => { MATCH_OP(E_OP_MP_STOP); };

# earthsea
"ES.PRESET" => { MATCH_OP(E_OP_ES_PRESET); };
"ES.MODE" => { MATCH_OP(E_OP_ES_MODE); };
"ES.CLOCK" => { MATCH_OP(E_OP_ES_CLOCK); };
@@ -246,6 +198,8 @@
"ES.STOP" => { MATCH_OP(E_OP_ES_STOP); };
"ES.TRIPLE" => { MATCH_OP(E_OP_ES_TRIPLE); };
"ES.MAGIC" => { MATCH_OP(E_OP_ES_MAGIC); };

# orca
"OR.TRK" => { MATCH_OP(E_OP_OR_TRK); };
"OR.CLK" => { MATCH_OP(E_OP_OR_CLK); };
"OR.DIV" => { MATCH_OP(E_OP_OR_DIV); };
@@ -263,6 +217,60 @@
"OR.CVA" => { MATCH_OP(E_OP_OR_CVA); };
"OR.CVB" => { MATCH_OP(E_OP_OR_CVB); };

# ansible
"KR.PRE" => { MATCH_OP(E_OP_KR_PRESET); };
"KR.PAT" => { MATCH_OP(E_OP_KR_PATTERN); };
"KR.SCALE" => { MATCH_OP(E_OP_KR_SCALE); };
"KR.PERIOD" => { MATCH_OP(E_OP_KR_PERIOD); };
"KR.POS" => { MATCH_OP(E_OP_KR_POS); };
"KR.L.ST" => { MATCH_OP(E_OP_KR_LOOP_ST); };
"KR.L.LEN" => { MATCH_OP(E_OP_KR_LOOP_LEN); };
"KR.RES" => { MATCH_OP(E_OP_KR_RESET); };
"MP.PRE" => { MATCH_OP(E_OP_MP_PRESET1); };
"MP.RES" => { MATCH_OP(E_OP_MP_RESET1); };
"MP.OFF" => { MATCH_OP(E_OP_MP_STOP1); };
"MP.SCALE" => { MATCH_OP(E_OP_MP_SCALE); };
"MP.PERIOD" => { MATCH_OP(E_OP_MP_PERIOD); };
"LV.PRE" => { MATCH_OP(E_OP_LV_PRESET); };
"LV.RES" => { MATCH_OP(E_OP_LV_RESET); };
"LV.POS" => { MATCH_OP(E_OP_LV_POS); };
"LV.L.ST" => { MATCH_OP(E_OP_LV_L_ST); };
"LV.L.LEN" => { MATCH_OP(E_OP_LV_L_LEN); };
"LV.L.DIR" => { MATCH_OP(E_OP_LV_L_DIR); };
"LV.CV" => { MATCH_OP(E_OP_LV_CV); };
"CY.PRE" => { MATCH_OP(E_OP_CY_PRESET); };
"CY.RES" => { MATCH_OP(E_OP_CY_RESET); };
"CY.POS" => { MATCH_OP(E_OP_CY_POS); };
"CY.REV" => { MATCH_OP(E_OP_CY_REV); };
"CY.CV" => { MATCH_OP(E_OP_CY_CV); };
"MID.SHIFT" => { MATCH_OP(E_OP_MID_SHIFT); };
"MID.SLEW" => { MATCH_OP(E_OP_MID_SLEW); };
"ARP.STY" => { MATCH_OP(E_OP_ARP_STYLE); };
"ARP.HLD" => { MATCH_OP(E_OP_ARP_HOLD); };
"ARP.RPT" => { MATCH_OP(E_OP_ARP_RPT); };
"ARP.GT" => { MATCH_OP(E_OP_ARP_GATE); };
"ARP.DIV" => { MATCH_OP(E_OP_ARP_DIV); };
"ARP.RES" => { MATCH_OP(E_OP_ARP_RESET); };
"ARP.SHIFT" => { MATCH_OP(E_OP_ARP_SHIFT); };
"ARP.SLEW" => { MATCH_OP(E_OP_ARP_SLEW); };
"ARP.FIL" => { MATCH_OP(E_OP_ARP_FILL); };
"ARP.ROT" => { MATCH_OP(E_OP_ARP_ROT); };
"ARP.ER" => { MATCH_OP(E_OP_ARP_ER); };

# justfriends
"JF.TR" => { MATCH_OP(E_OP_JF_TR); };
"JF.RMODE" => { MATCH_OP(E_OP_JF_RMODE); };
"JF.RUN" => { MATCH_OP(E_OP_JF_RUN); };
"JF.SHIFT" => { MATCH_OP(E_OP_JF_SHIFT); };
"JF.VTR" => { MATCH_OP(E_OP_JF_VTR); };
"JF.MODE" => { MATCH_OP(E_OP_JF_MODE); };
"JF.TICK" => { MATCH_OP(E_OP_JF_TICK); };
"JF.VOX" => { MATCH_OP(E_OP_JF_VOX); };
"JF.NOTE" => { MATCH_OP(E_OP_JF_NOTE); };
"JF.GOD" => { MATCH_OP(E_OP_JF_GOD); };
"JF.TUNE" => { MATCH_OP(E_OP_JF_TUNE); };
"JF.QT" => { MATCH_OP(E_OP_JF_QT); };

# telex
"TO.TR" => { MATCH_OP(E_OP_TO_TR); };
"TO.TR.TOG" => { MATCH_OP(E_OP_TO_TR_TOG); };

This file was deleted.

This file was deleted.

@@ -43,41 +43,41 @@ const tele_op_t op_SCENE =
MAKE_GET_SET_OP(SCENE, op_SCENE_get, op_SCENE_set, 0, true);


static void mod_PROB_func(scene_state_t *NOTUSED(ss), exec_state_t *es,
static void mod_PROB_func(scene_state_t *ss, exec_state_t *es,
command_state_t *cs,
const tele_command_t *post_command) {
int16_t a = cs_pop(cs);

if (rand() % 101 < a) { process_command(es, post_command); }
if (rand() % 101 < a) { process_command(ss, es, post_command); }
}

static void mod_IF_func(scene_state_t *NOTUSED(ss), exec_state_t *es,
static void mod_IF_func(scene_state_t *ss, exec_state_t *es,
command_state_t *cs,
const tele_command_t *post_command) {
es->if_else_condition = false;
if (cs_pop(cs)) {
es->if_else_condition = true;
process_command(es, post_command);
process_command(ss, es, post_command);
}
}

static void mod_ELIF_func(scene_state_t *NOTUSED(ss), exec_state_t *es,
static void mod_ELIF_func(scene_state_t *ss, exec_state_t *es,
command_state_t *cs,
const tele_command_t *post_command) {
if (!es->if_else_condition) {
if (cs_pop(cs)) {
es->if_else_condition = true;
process_command(es, post_command);
process_command(ss, es, post_command);
}
}
}

static void mod_ELSE_func(scene_state_t *NOTUSED(ss), exec_state_t *es,
static void mod_ELSE_func(scene_state_t *ss, exec_state_t *es,
command_state_t *NOTUSED(cs),
const tele_command_t *post_command) {
if (!es->if_else_condition) {
es->if_else_condition = true;
process_command(es, post_command);
process_command(ss, es, post_command);
}
}

@@ -89,7 +89,7 @@ static void mod_L_func(scene_state_t *ss, exec_state_t *es, command_state_t *cs,

for (int16_t i = 0; i <= loop_size; i++) {
ss->variables.i = a < b ? a + i : a - i;
process_command(es, post_command);
process_command(ss, es, post_command);
}
}

@@ -105,14 +105,17 @@ static void op_SCENE_set(const void *NOTUSED(data), scene_state_t *ss,
tele_scene(scene);
}

static void op_SCRIPT_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss),
exec_state_t *NOTUSED(es), command_state_t *cs) {
uint16_t a = cs_pop(cs);
if (a > 0 && a < 9) tele_script(a);
static void op_SCRIPT_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *es, command_state_t *cs) {
uint16_t a = cs_pop(cs) - 1;
if (a >= SCRIPT_COUNT || a == INIT_SCRIPT || a == METRO_SCRIPT) return;

run_script_with_exec_state(ss, es, a);
}
static void op_KILL_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss),

static void op_KILL_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es),
command_state_t *NOTUSED(cs)) {
clear_delays();
clear_delays(ss);
tele_kill();
}
@@ -27,16 +27,15 @@ static void mod_DEL_func(scene_state_t *ss, exec_state_t *NOTUSED(es),

if (i < DELAY_SIZE) {
ss->delay.count++;
if (ss->delay.count == 1) tele_delay(1);
tele_has_delays(ss->delay.count > 0);
ss->delay.time[i] = a;

copy_command(&ss->delay.commands[i], post_command);
}
}

static void op_DEL_CLR_get(const void *NOTUSED(data),
scene_state_t *NOTUSED(ss),
static void op_DEL_CLR_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es),
command_state_t *NOTUSED(cs)) {
clear_delays();
clear_delays(ss);
}
@@ -0,0 +1,13 @@
#include "earthsea.h"

#include "ii.h"

const tele_op_t op_ES_PRESET = MAKE_SIMPLE_I2C_OP(ES.PRESET, ES_PRESET);
const tele_op_t op_ES_MODE = MAKE_SIMPLE_I2C_OP(ES.MODE, ES_MODE);
const tele_op_t op_ES_CLOCK = MAKE_SIMPLE_I2C_OP(ES.CLOCK, ES_CLOCK);
const tele_op_t op_ES_RESET = MAKE_SIMPLE_I2C_OP(ES.RESET, ES_RESET);
const tele_op_t op_ES_PATTERN = MAKE_SIMPLE_I2C_OP(ES.PATTERN, ES_PATTERN);
const tele_op_t op_ES_TRANS = MAKE_SIMPLE_I2C_OP(ES.TRANS, ES_TRANS);
const tele_op_t op_ES_STOP = MAKE_SIMPLE_I2C_OP(ES.STOP, ES_STOP);
const tele_op_t op_ES_TRIPLE = MAKE_SIMPLE_I2C_OP(ES.TRIPLE, ES_TRIPLE);
const tele_op_t op_ES_MAGIC = MAKE_SIMPLE_I2C_OP(ES.MAGIC, ES_MAGIC);
@@ -0,0 +1,16 @@
#ifndef _OPS_EARTHSEA_H_
#define _OPS_EARTHSEA_H_

#include "ops/op.h"

extern const tele_op_t op_ES_PRESET;
extern const tele_op_t op_ES_MODE;
extern const tele_op_t op_ES_CLOCK;
extern const tele_op_t op_ES_RESET;
extern const tele_op_t op_ES_PATTERN;
extern const tele_op_t op_ES_TRANS;
extern const tele_op_t op_ES_STOP;
extern const tele_op_t op_ES_TRIPLE;
extern const tele_op_t op_ES_MAGIC;

#endif
@@ -36,14 +36,12 @@ static void op_TR_TOG_get(const void *data, scene_state_t *ss, exec_state_t *es,
command_state_t *cs);
static void op_TR_PULSE_get(const void *data, scene_state_t *ss,
exec_state_t *es, command_state_t *cs);
static void op_II_get(const void *data, scene_state_t *ss, exec_state_t *es,
command_state_t *cs);
static void op_CV_SET_get(const void *data, scene_state_t *ss, exec_state_t *es,
command_state_t *cs);
static void op_MUTE_get(const void *data, scene_state_t *ss, exec_state_t *es,
command_state_t *cs);
static void op_UNMUTE_get(const void *data, scene_state_t *ss, exec_state_t *es,
command_state_t *cs);
static void op_MUTE_set(const void *data, scene_state_t *ss, exec_state_t *es,
command_state_t *cs);
static void op_STATE_get(const void *data, scene_state_t *ss, exec_state_t *es,
command_state_t *cs);

@@ -61,19 +59,14 @@ const tele_op_t op_TR_TIME = MAKE_GET_SET_OP(TR.TIME , op_TR_TIME_get , op_TR_T
const tele_op_t op_TR_TOG = MAKE_GET_OP (TR.TOG , op_TR_TOG_get , 1, false);
const tele_op_t op_TR_PULSE = MAKE_GET_OP (TR.PULSE, op_TR_PULSE_get, 1, false);
const tele_op_t op_TR_P = MAKE_ALIAS_OP (TR.P , op_TR_PULSE_get, NULL, 1, false);
const tele_op_t op_II = MAKE_GET_OP (II , op_II_get , 2, false);
const tele_op_t op_CV_SET = MAKE_GET_OP (CV.SET , op_CV_SET_get , 2, false);
const tele_op_t op_MUTE = MAKE_GET_OP (MUTE , op_MUTE_get , 1, false);
const tele_op_t op_UNMUTE = MAKE_GET_OP (UNMUTE , op_UNMUTE_get , 1, false);
const tele_op_t op_MUTE = MAKE_GET_SET_OP(MUTE , op_MUTE_get , op_MUTE_set , 1, true);
const tele_op_t op_STATE = MAKE_GET_OP (STATE , op_STATE_get , 1, true );
// clang-format on

static void op_CV_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
// a = normalise_value(0, CV_COUNT - 1, 0, a - 1);
// cs_push(cs, ss->variables.cv[a]);

a--;
if (a < 0)
cs_push(cs, 0);
@@ -96,11 +89,7 @@ static void op_CV_set(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
int16_t b = cs_pop(cs);
// a = normalise_value(0, CV_COUNT - 1, 0, a - 1);
b = normalise_value(0, 16383, 0, b);
// ss->variables.cv[a] = b;
// tele_cv(a, b, 1);

a--;
if (a < 0)
return;
@@ -119,9 +108,6 @@ static void op_CV_set(const void *NOTUSED(data), scene_state_t *ss,
static void op_CV_SLEW_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
// a = normalise_value(0, CV_COUNT - 1, 0, a - 1);
// cs_push(cs, ss->variables.cv_slew[a]);

a--;
if (a < 0)
cs_push(cs, 0);
@@ -144,11 +130,7 @@ static void op_CV_SLEW_set(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
int16_t b = cs_pop(cs);
// a = normalise_value(0, CV_COUNT - 1, 0, a - 1);
b = normalise_value(1, 32767, 0, b); // min slew = 1
// ss->variables.cv_slew[a] = b;
// tele_cv_slew(a, b);

a--;
if (a < 0)
return;
@@ -166,9 +148,6 @@ static void op_CV_SLEW_set(const void *NOTUSED(data), scene_state_t *ss,
static void op_CV_OFF_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
// a = normalise_value(0, CV_COUNT - 1, 0, a - 1);
// cs_push(cs, ss->variables.cv_off[a]);

a--;
if (a < 0)
cs_push(cs, 0);
@@ -191,11 +170,7 @@ static void op_CV_OFF_set(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
int16_t b = cs_pop(cs);
// a = normalise_value(0, CV_COUNT - 1, 0, a - 1);
ss->variables.cv_off[a] = b;
// tele_cv_off(a, b);
// tele_cv(a, ss->variables.cv[a], 1);

a--;
if (a < 0)
return;
@@ -224,7 +199,6 @@ static void op_PARAM_get(const void *NOTUSED(data), scene_state_t *ss,
static void op_TR_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
// a = normalise_value(0, TR_COUNT - 1, 0, a - 1);
a--;
if (a < 0)
cs_push(cs, 0);
@@ -246,7 +220,6 @@ static void op_TR_set(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
int16_t b = cs_pop(cs);
// a = normalise_value(0, TR_COUNT - 1, 0, a - 1);
a--;
if (a < 0)
return;
@@ -264,8 +237,6 @@ static void op_TR_set(const void *NOTUSED(data), scene_state_t *ss,
static void op_TR_POL_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
// a = normalise_value(0, TR_COUNT - 1, 0, a - 1);
// cs_push(cs, ss->variables.tr_pol[a]);
a--;
if (a < 0)
cs_push(cs, 0);
@@ -287,8 +258,6 @@ static void op_TR_POL_set(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
int16_t b = cs_pop(cs);
// a = normalise_value(0, TR_COUNT - 1, 0, a - 1);
// ss->variables.tr_pol[a] = b > 0;
a--;
if (a < 0)
return;
@@ -305,8 +274,6 @@ static void op_TR_POL_set(const void *NOTUSED(data), scene_state_t *ss,
static void op_TR_TIME_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
// a = normalise_value(0, TR_COUNT - 1, 0, a - 1);
// cs_push(cs, ss->variables.tr_time[a]);
a--;
if (a < 0)
cs_push(cs, 0);
@@ -329,9 +296,7 @@ static void op_TR_TIME_set(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
int16_t b = cs_pop(cs);
// a = normalise_value(0, TR_COUNT - 1, 0, a - 1);
if (b < 0) b = 0;
// ss->variables.tr_time[a] = b;
a--;
if (a < 0)
return;
@@ -348,14 +313,6 @@ static void op_TR_TIME_set(const void *NOTUSED(data), scene_state_t *ss,
static void op_TR_TOG_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
// saturate and shift
// a--;
// if (ss->variables.tr[a])
// ss->variables.tr[a] = 0;
// else
// ss->variables.tr[a] = 1;
// tele_tr(a, ss->variables.tr[a]);

a--;
if (a < 0)
return;
@@ -376,19 +333,6 @@ static void op_TR_TOG_get(const void *NOTUSED(data), scene_state_t *ss,
static void op_TR_PULSE_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
// saturate and shift
// if (a < 1)
// a = 1;
// else if (a > 4)
// a = 4;
// a--;
// int16_t time = ss->variables.tr_time[a]; // pulse time
// if (time <= 0) return; // if time <= 0 don't do
// anything
// ss->variables.tr[a] = ss->variables.tr_pol[a];
// ss->tr_pulse_timer[a] = time; // set time
// tele_tr(a, ss->variables.tr[a]);

a--;
if (a < 0)
return;
@@ -406,29 +350,15 @@ static void op_TR_PULSE_get(const void *NOTUSED(data), scene_state_t *ss,
}
}

static void op_II_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss),
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
int16_t b = cs_pop(cs);
tele_ii(a, b);
}

static void op_CV_SET_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
int16_t b = cs_pop(cs);
// 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;
// ss->variables.cv[a] = b;
// tele_cv(a, b, 0);

a--;
if (a < 0)
@@ -444,31 +374,25 @@ static void op_CV_SET_get(const void *NOTUSED(data), scene_state_t *ss,
}
}

static void op_MUTE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss),
static void op_MUTE_get(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a;
a = cs_pop(cs);
if (a > 0 && a < 9) { tele_mute(a - 1, 0); }
int16_t a = cs_pop(cs) - 1;
if (a >= 0 && a < TRIGGER_INPUTS) { cs_push(cs, ss_get_mute(ss, a)); }
else {
cs_push(cs, 0);
}
}

static void op_UNMUTE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss),
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a;
a = cs_pop(cs);
if (a > 0 && a < 9) { tele_mute(a - 1, 1); }
static void op_MUTE_set(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs) - 1;
bool b = cs_pop(cs) > 0;
if (a >= 0 && a < TRIGGER_INPUTS) { ss_set_mute(ss, a, b); }
}

static void op_STATE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss),
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t a = cs_pop(cs);
// a--;
// if (a < 0)
// a = 0;
// else if (a > 7)
// a = 7;

// cs_push(cs, tele_get_input_state(a));

a--;
if (a < 0)
cs_push(cs, 0);
@@ -15,10 +15,8 @@ extern const tele_op_t op_TR_TIME;
extern const tele_op_t op_TR_TOG;
extern const tele_op_t op_TR_PULSE;
extern const tele_op_t op_TR_P;
extern const tele_op_t op_II;
extern const tele_op_t op_CV_SET;
extern const tele_op_t op_MUTE;
extern const tele_op_t op_UNMUTE;
extern const tele_op_t op_STATE;

#endif
@@ -126,7 +126,7 @@ const tele_op_t op_SYM_LEFT_ANGLED = MAKE_ALIAS_OP(< , op_LT_get , NULL,
const tele_op_t op_SYM_RIGHT_ANGLED = MAKE_ALIAS_OP(> , op_GT_get , NULL, 2, true);
const tele_op_t op_SYM_LEFT_ANGLED_EQUAL = MAKE_ALIAS_OP(<=, op_LTE_get, NULL, 2, true);
const tele_op_t op_SYM_RIGHT_ANGLED_EQUAL = MAKE_ALIAS_OP(>=, op_GTE_get, NULL, 2, true);
const tele_op_t op_SYM_EXCLAMATION = MAKE_ALIAS_OP(! , op_NZ_get , NULL, 1, true);
const tele_op_t op_SYM_EXCLAMATION = MAKE_ALIAS_OP(! , op_EZ_get , NULL, 1, true);
const tele_op_t op_SYM_LEFT_ANGLED_x2 = MAKE_ALIAS_OP(<<, op_LSH_get, NULL, 2, true);
const tele_op_t op_SYM_RIGHT_ANGLED_x2 = MAKE_ALIAS_OP(>>, op_RSH_get, NULL, 2, true);
const tele_op_t op_AMPERSAND_x2 = MAKE_ALIAS_OP(&&, op_AND_get, NULL, 2, true);
@@ -0,0 +1,12 @@
#include "meadowphysics.h"

#include "ii.h"

const tele_op_t op_MP_PRESET = MAKE_SIMPLE_I2C_OP(MP.PRESET, MP_PRESET);
const tele_op_t op_MP_RESET = MAKE_SIMPLE_I2C_OP(MP.RESET, MP_RESET);
const tele_op_t op_MP_SYNC = MAKE_SIMPLE_I2C_OP(MP.SYNC, MP_SYNC);
const tele_op_t op_MP_MUTE = MAKE_SIMPLE_I2C_OP(MP.MUTE, MP_MUTE);
const tele_op_t op_MP_UNMUTE = MAKE_SIMPLE_I2C_OP(MP.UNMUTE, MP_UNMUTE);
const tele_op_t op_MP_FREEZE = MAKE_SIMPLE_I2C_OP(MP.FREEZE, MP_FREEZE);
const tele_op_t op_MP_UNFREEZE = MAKE_SIMPLE_I2C_OP(MP.UNFREEZE, MP_UNFREEZE);
const tele_op_t op_MP_STOP = MAKE_SIMPLE_I2C_OP(MP.STOP, MP_STOP);
@@ -0,0 +1,15 @@
#ifndef _OPS_MEADOWPHYSICS_H_
#define _OPS_MEADOWPHYSICS_H_

#include "ops/op.h"

extern const tele_op_t op_MP_PRESET;
extern const tele_op_t op_MP_RESET;
extern const tele_op_t op_MP_SYNC;
extern const tele_op_t op_MP_MUTE;
extern const tele_op_t op_MP_UNMUTE;
extern const tele_op_t op_MP_FREEZE;
extern const tele_op_t op_MP_UNFREEZE;
extern const tele_op_t op_MP_STOP;

#endif
@@ -26,7 +26,7 @@ static void op_M_set(const void *NOTUSED(data), scene_state_t *ss,
int16_t m = cs_pop(cs);
if (m < 10) m = 10;
ss->variables.m = m;
tele_metro(m, ss->variables.m_act, 0);
tele_metro_updated();
}

const tele_op_t op_M_ACT =
@@ -40,16 +40,16 @@ static void op_M_ACT_get(const void *NOTUSED(data), scene_state_t *ss,

static void op_M_ACT_set(const void *NOTUSED(data), scene_state_t *ss,
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t m_act = cs_pop(cs);
if (m_act != 0) m_act = 1;
bool m_act = cs_pop(cs) > 0;
ss->variables.m_act = m_act;
tele_metro(ss->variables.m, m_act, 0);
tele_metro_updated();
}

const tele_op_t op_M_RESET = MAKE_GET_OP(M.RESET, op_M_RESET_get, 0, false);

static void op_M_RESET_get(const void *NOTUSED(data), scene_state_t *ss,
static void op_M_RESET_get(const void *NOTUSED(data),
scene_state_t *NOTUSED(ss),
exec_state_t *NOTUSED(es),
command_state_t *NOTUSED(cs)) {
tele_metro(ss->variables.m, ss->variables.m_act, 1);
tele_metro_reset();
}
@@ -3,20 +3,24 @@
#include <stddef.h> // offsetof

#include "helpers.h"
#include "teletype_io.h"

#include "ops/ansible.h"
#include "ops/constants.h"
#include "ops/controlflow.h"
#include "ops/delay.h"
#include "ops/earthsea.h"
#include "ops/hardware.h"
#include "ops/justfriends.h"
#include "ops/maths.h"
#include "ops/meadowphysics.h"
#include "ops/metronome.h"
#include "ops/orca.h"
#include "ops/patterns.h"
#include "ops/queue.h"
#include "ops/stack.h"
#include "ops/telex.h"
#include "ops/variables.h"
#include "ops/whitewhale.h"


/////////////////////////////////////////////////////////////////
@@ -45,8 +49,8 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = {

// hardware
&op_CV, &op_CV_OFF, &op_CV_SLEW, &op_IN, &op_PARAM, &op_PRM, &op_TR,
&op_TR_POL, &op_TR_TIME, &op_TR_TOG, &op_TR_PULSE, &op_TR_P, &op_II,
&op_CV_SET, &op_MUTE, &op_UNMUTE, &op_STATE,
&op_TR_POL, &op_TR_TIME, &op_TR_TOG, &op_TR_PULSE, &op_TR_P, &op_CV_SET,
&op_MUTE, &op_STATE,

// maths
&op_ADD, &op_SUB, &op_MUL, &op_DIV, &op_MOD, &op_RAND, &op_RRAND, &op_TOSS,
@@ -68,17 +72,23 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = {
// delay
&op_DEL_CLR,

// constants
// whitewhale
&op_WW_PRESET, &op_WW_POS, &op_WW_SYNC, &op_WW_START, &op_WW_END,
&op_WW_PMODE, &op_WW_PATTERN, &op_WW_QPATTERN, &op_WW_MUTE1, &op_WW_MUTE2,
&op_WW_MUTE3, &op_WW_MUTE4, &op_WW_MUTEA, &op_WW_MUTEB, &op_MP_PRESET,
&op_MP_RESET, &op_MP_SYNC, &op_MP_MUTE, &op_MP_UNMUTE, &op_MP_FREEZE,
&op_MP_UNFREEZE, &op_MP_STOP, &op_ES_PRESET, &op_ES_MODE, &op_ES_CLOCK,
&op_ES_RESET, &op_ES_PATTERN, &op_ES_TRANS, &op_ES_STOP, &op_ES_TRIPLE,
&op_ES_MAGIC, &op_OR_TRK, &op_OR_CLK, &op_OR_DIV, &op_OR_PHASE, &op_OR_RST,
&op_OR_WGT, &op_OR_MUTE, &op_OR_SCALE, &op_OR_BANK, &op_OR_PRESET,
&op_OR_RELOAD, &op_OR_ROTS, &op_OR_ROTW, &op_OR_GRST, &op_OR_CVA,
&op_OR_CVB,
&op_WW_MUTE3, &op_WW_MUTE4, &op_WW_MUTEA, &op_WW_MUTEB,

// meadowphysics
&op_MP_PRESET, &op_MP_RESET, &op_MP_SYNC, &op_MP_MUTE, &op_MP_UNMUTE,
&op_MP_FREEZE, &op_MP_UNFREEZE, &op_MP_STOP,

// earthsea
&op_ES_PRESET, &op_ES_MODE, &op_ES_CLOCK, &op_ES_RESET, &op_ES_PATTERN,
&op_ES_TRANS, &op_ES_STOP, &op_ES_TRIPLE, &op_ES_MAGIC,

// orca
&op_OR_TRK, &op_OR_CLK, &op_OR_DIV, &op_OR_PHASE, &op_OR_RST, &op_OR_WGT,
&op_OR_MUTE, &op_OR_SCALE, &op_OR_BANK, &op_OR_PRESET, &op_OR_RELOAD,
&op_OR_ROTS, &op_OR_ROTW, &op_OR_GRST, &op_OR_CVA, &op_OR_CVB,

// ansible
&op_KR_PRESET, &op_KR_PATTERN, &op_KR_SCALE, &op_KR_PERIOD, &op_KR_POS,
@@ -141,11 +151,6 @@ const tele_mod_t *tele_mods[E_MOD__LENGTH] = {
/////////////////////////////////////////////////////////////////
// HELPERS //////////////////////////////////////////////////////

void op_constant(const void *data, scene_state_t *NOTUSED(ss),
exec_state_t *NOTUSED(es), command_state_t *cs) {
cs_push(cs, (intptr_t)data);
}

void op_peek_i16(const void *data, scene_state_t *ss, exec_state_t *NOTUSED(es),
command_state_t *cs) {
char *base = (char *)ss;
@@ -161,3 +166,10 @@ void op_poke_i16(const void *data, scene_state_t *ss, exec_state_t *NOTUSED(es),
int16_t *ptr = (int16_t *)(base + offset);
*ptr = cs_pop(cs);
}

void op_simple_i2c(const void *data, scene_state_t *NOTUSED(ss),
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t address = (intptr_t)data;
int16_t value = cs_pop(cs);
tele_ii(address, value);
}
@@ -42,17 +42,6 @@ extern const tele_mod_t *tele_mods[E_MOD__LENGTH];
{ .name = #n, .get = g, .set = s, .params = p, .returns = r, .data = NULL }


// Constant Ops
#define MAKE_CONSTANT_OP(n, v) \
{ \
.name = #n, .get = op_constant, .set = NULL, .params = 0, \
.returns = 1, .data = (void *)v \
}

void op_constant(const void *data, scene_state_t *ss, exec_state_t *es,
command_state_t *cs);


// Variables, peek & poke
#define MAKE_SIMPLE_VARIABLE_OP(n, v) \
{ \
@@ -65,9 +54,23 @@ void op_peek_i16(const void *data, scene_state_t *ss, exec_state_t *es,
void op_poke_i16(const void *data, scene_state_t *ss, exec_state_t *es,
command_state_t *cs);


// Alias one OP to another
#define MAKE_ALIAS_OP(n, g, s, p, r) \
{ .name = #n, .get = g, .set = s, .params = p, .returns = r, .data = NULL }


// Simple I2C op (to support the original Trilogy modules)
#define MAKE_SIMPLE_I2C_OP(n, v) \
{ \
.name = #n, .get = op_simple_i2c, .set = NULL, .params = 1, \
.returns = 0, .data = (void *)v \
}

void op_simple_i2c(const void *data, scene_state_t *ss, exec_state_t *es,
command_state_t *cs);


// Mods
#define MAKE_MOD(n, f, p) \
{ .name = #n, .func = f, .params = p }
@@ -72,10 +72,8 @@ typedef enum {
E_OP_TR_TOG,
E_OP_TR_PULSE,
E_OP_TR_P,
E_OP_II,
E_OP_CV_SET,
E_OP_MUTE,
E_OP_UNMUTE,
E_OP_STATE,
E_OP_ADD,
E_OP_SUB,
@@ -0,0 +1,20 @@
#include "orca.h"

#include "ii.h"

const tele_op_t op_OR_TRK = MAKE_SIMPLE_I2C_OP(OR.TRK, ORCA_TRACK);
const tele_op_t op_OR_CLK = MAKE_SIMPLE_I2C_OP(OR.CLK, ORCA_CLOCK);
const tele_op_t op_OR_DIV = MAKE_SIMPLE_I2C_OP(OR.DIV, ORCA_DIVISOR);
const tele_op_t op_OR_PHASE = MAKE_SIMPLE_I2C_OP(OR.PHASE, ORCA_PHASE);
const tele_op_t op_OR_RST = MAKE_SIMPLE_I2C_OP(OR.RST, ORCA_RESET);
const tele_op_t op_OR_WGT = MAKE_SIMPLE_I2C_OP(OR.WGT, ORCA_WEIGHT);
const tele_op_t op_OR_MUTE = MAKE_SIMPLE_I2C_OP(OR.MUTE, ORCA_MUTE);
const tele_op_t op_OR_SCALE = MAKE_SIMPLE_I2C_OP(OR.SCALE, ORCA_SCALE);
const tele_op_t op_OR_BANK = MAKE_SIMPLE_I2C_OP(OR.BANK, ORCA_BANK);
const tele_op_t op_OR_PRESET = MAKE_SIMPLE_I2C_OP(OR.PRESET, ORCA_PRESET);
const tele_op_t op_OR_RELOAD = MAKE_SIMPLE_I2C_OP(OR.RELOAD, ORCA_RELOAD);
const tele_op_t op_OR_ROTS = MAKE_SIMPLE_I2C_OP(OR.ROTS, ORCA_ROTATES);
const tele_op_t op_OR_ROTW = MAKE_SIMPLE_I2C_OP(OR.ROTW, ORCA_ROTATEW);
const tele_op_t op_OR_GRST = MAKE_SIMPLE_I2C_OP(OR.GRST, ORCA_GRESET);
const tele_op_t op_OR_CVA = MAKE_SIMPLE_I2C_OP(OR.CVA, ORCA_CVA);
const tele_op_t op_OR_CVB = MAKE_SIMPLE_I2C_OP(OR.CVB, ORCA_CVB);
@@ -0,0 +1,23 @@
#ifndef _OPS_ORCA_H_
#define _OPS_ORCA_H_

#include "ops/op.h"

extern const tele_op_t op_OR_TRK;
extern const tele_op_t op_OR_CLK;
extern const tele_op_t op_OR_DIV;
extern const tele_op_t op_OR_PHASE;
extern const tele_op_t op_OR_RST;
extern const tele_op_t op_OR_WGT;
extern const tele_op_t op_OR_MUTE;
extern const tele_op_t op_OR_SCALE;
extern const tele_op_t op_OR_BANK;
extern const tele_op_t op_OR_PRESET;
extern const tele_op_t op_OR_RELOAD;
extern const tele_op_t op_OR_ROTS;
extern const tele_op_t op_OR_ROTW;
extern const tele_op_t op_OR_GRST;
extern const tele_op_t op_OR_CVA;
extern const tele_op_t op_OR_CVB;

#endif