From 28b12bbf5601d14e7dae88c342f5d6441dd25c53 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 13 Oct 2017 19:36:15 -0700 Subject: [PATCH 001/117] grid rebased --- module/config.mk | 3 + module/flash.c | 42 +++ module/grid.c | 160 +++++++++ module/grid.h | 18 ++ module/main.c | 73 +++++ module/preset_r_mode.c | 1 + module/usb_disk_mode.c | 60 +++- src/match_token.rl | 48 +++ src/ops/grid_ops.c | 718 +++++++++++++++++++++++++++++++++++++++++ src/ops/grid_ops.h | 53 +++ src/ops/op.c | 13 +- src/ops/op_enum.h | 41 +++ src/state.c | 54 ++++ src/state.h | 68 +++- 14 files changed, 1349 insertions(+), 3 deletions(-) create mode 100644 module/grid.c create mode 100644 module/grid.h create mode 100644 src/ops/grid_ops.c create mode 100644 src/ops/grid_ops.h diff --git a/module/config.mk b/module/config.mk index 1a20778b..b6668c7e 100644 --- a/module/config.mk +++ b/module/config.mk @@ -65,6 +65,7 @@ CSRCS = \ ../module/edit_mode.c \ ../module/flash.c \ ../module/gitversion.c \ + ../module/grid.c \ ../module/help_mode.c \ ../module/line_editor.c \ ../module/live_mode.c \ @@ -88,6 +89,7 @@ CSRCS = \ ../src/ops/controlflow.c \ ../src/ops/delay.c \ ../src/ops/earthsea.c \ + ../src/ops/grid_ops.c \ ../src/ops/hardware.c \ ../src/ops/init.c \ ../src/ops/justfriends.c \ @@ -113,6 +115,7 @@ CSRCS = \ ../libavr32/src/init_common.c \ ../libavr32/src/interrupts.c \ ../libavr32/src/kbd.c \ + ../libavr32/src/monome.c \ ../libavr32/src/region.c \ ../libavr32/src/screen.c \ ../libavr32/src/timers.c \ diff --git a/module/flash.c b/module/flash.c index 376714a2..67c82c1a 100644 --- a/module/flash.c +++ b/module/flash.c @@ -11,10 +11,17 @@ #define FIRSTRUN_KEY 0x22 +typedef struct { + uint8_t button_states[GRID_BUTTON_COUNT >> 3]; + uint8_t fader_states[GRID_FADER_COUNT >> 1]; +} grid_data_t; +static grid_data_t grid_data; + // NVRAM data structure located in the flash array. typedef const struct { scene_script_t scripts[SCRIPT_COUNT - 1]; // Exclude TEMP script scene_pattern_t patterns[PATTERN_COUNT]; + grid_data_t grid_data; char text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; } nvram_scene_t; @@ -28,6 +35,9 @@ typedef const struct { static __attribute__((__section__(".flash_nvram"))) nvram_data_t f; +static void pack_grid(scene_state_t *scene); +static void unpack_grid(scene_state_t *scene); + void flash_prepare() { // if it's not empty return if (f.fresh == FIRSTRUN_KEY) return; @@ -58,6 +68,9 @@ void flash_write(uint8_t preset_no, scene_state_t *scene, ss_scripts_size() - sizeof(scene_script_t), true); flashc_memcpy((void *)&f.scenes[preset_no].patterns, ss_patterns_ptr(scene), ss_patterns_size(), true); + pack_grid(scene); + flashc_memcpy((void *)&f.scenes[preset_no].grid_data, &grid_data, + sizeof(grid_data_t), true); flashc_memcpy((void *)&f.scenes[preset_no].text, text, SCENE_TEXT_LINES * SCENE_TEXT_CHARS, true); } @@ -69,6 +82,8 @@ void flash_read(uint8_t preset_no, scene_state_t *scene, ss_scripts_size() - sizeof(scene_script_t)); memcpy(ss_patterns_ptr(scene), &f.scenes[preset_no].patterns, ss_patterns_size()); + memcpy(&grid_data, &f.scenes[preset_no].grid_data, sizeof(grid_data_t)); + unpack_grid(scene); memcpy(text, &f.scenes[preset_no].text, SCENE_TEXT_LINES * SCENE_TEXT_CHARS); } @@ -92,3 +107,30 @@ void flash_update_cal(cal_data_t *cal) { void flash_get_cal(cal_data_t *cal) { *cal = f.cal; } + +static void pack_grid(scene_state_t *scene) { + uint8_t byte = 0; + uint8_t byte_count = 0; + for (uint16_t i = 0; i < GRID_BUTTON_COUNT; i++) { + byte |= (scene->grid.button[i].state != 0) << (i & 7); + if ((i & 7) == 7) { + grid_data.button_states[byte_count++] = byte; + byte = 0; + } + } + for (uint16_t i = 0; i < GRID_FADER_COUNT; i += 2) { + grid_data.fader_states[i >> 1] = (scene->grid.fader[i].value << 4) + + scene->grid.fader[i+1].value; + } +} + +static void unpack_grid(scene_state_t *scene) { + for (uint16_t i = 0; i < GRID_BUTTON_COUNT; i++) { + scene->grid.button[i].state = + 0 != (grid_data.button_states[i >> 3] & (1 << (i & 7))); + } + for (uint16_t i = 0; i < GRID_FADER_COUNT; i += 2) { + scene->grid.fader[i].value = grid_data.fader_states[i >> 1] >> 4; + scene->grid.fader[i+1].value = grid_data.fader_states[i >> 1] & 0b1111; + } +} diff --git a/module/grid.c b/module/grid.c new file mode 100644 index 00000000..bf35391c --- /dev/null +++ b/module/grid.c @@ -0,0 +1,160 @@ +#include "grid.h" +#include "state.h" +#include "teletype.h" + +static bool grid_within_area(u8 x, u8 y, grid_common_t *gc); +static void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level); + +void grid_refresh(scene_state_t *ss) { + s16 size_x = monome_size_x(); + s16 size_y = monome_size_y(); + + grid_fill_area(0, 0, size_x, size_y, 0); + + u16 x, y; + for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { + if (GXYC.enabled && SG.group[GXYC.group].enabled) { + if (GXY.value_x || GXY.value_y) { + x = GXYC.x + GXY.value_x; + y = GXYC.y + GXY.value_y; + grid_fill_area(GXYC.x, y, GXYC.w, 1, GXYC.background); + grid_fill_area(x, GXYC.y, 1, GXYC.h, GXYC.background); + grid_fill_area(x, y, 1, 1, 15); + } + } + } + + for (u8 i = 0; i < GRID_FADER_COUNT; i++) { + if (GFC.enabled && SG.group[GFC.group].enabled) { + if (GF.dir) { + grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.background); + grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, 15); + } else { + grid_fill_area(GFC.x, GFC.y, GF.value + 1, GFC.h, 15); + grid_fill_area(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.background); + } + } + } + + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) + if (GBC.enabled && SG.group[GBC.group].enabled) grid_fill_area(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.background); + + u16 led; + for (u16 i = 0; i < size_x; i++) + for (u16 j = 0; j < size_y; j++) { + led = j * size_x + i; + if (SG.leds[i][j] >= 0) + monomeLedBuffer[led] = SG.leds[i][j]; + else if (SG.leds[i][j] == LED_DIM) + monomeLedBuffer[led] >>= 1; + else if (SG.leds[i][j] == LED_BRI) { + monomeLedBuffer[led] <<= 1; + if (monomeLedBuffer[led] > 15) monomeLedBuffer[led] = 15; + else if (monomeLedBuffer[led] < 1) monomeLedBuffer[led] = 1; + } + + if (monomeLedBuffer[led] < SG.dim) + monomeLedBuffer[led] = 0; + else + monomeLedBuffer[led] -= SG.dim; + } + + if (SG.rotate) { + u16 total = size_x * size_y; + u8 temp; + for (u16 i = 0; i < (total >> 1); i++) { + temp = monomeLedBuffer[i]; + monomeLedBuffer[i] = monomeLedBuffer[total - i - 1]; + monomeLedBuffer[total - i - 1] = temp; + } + } + + + SG.refresh = 0; +} + +void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z) { + u8 x = SG.rotate ? monome_size_x() - _x - 1 : _x; + u8 y = SG.rotate ? monome_size_y() - _y - 1 : _y; + u8 refresh = 0; + u8 scripts[SCRIPT_COUNT]; + for (u8 i = 0; i < SCRIPT_COUNT; i++) scripts[i] = 0; + + for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { + if (z && GXYC.enabled && SG.group[GXYC.group].enabled && grid_within_area(x, y, &GXYC)) { + GXY.value_x = x - GXYC.x; + GXY.value_y = y - GXYC.y; + if (GXYC.script != -1) scripts[GXYC.script] = 1; + SG.latest_group = GXYC.group; + if (SG.group[GXYC.group].script != -1) scripts[SG.group[GXYC.group].script] = 1; + refresh = 1; + } + } + + for (u8 i = 0; i < GRID_FADER_COUNT; i++) { + if (GFC.enabled && SG.group[GFC.group].enabled && grid_within_area(x, y, &GFC)) { + GF.value = GF.dir ? GFC.h + GFC.y - y - 1 : x - GFC.x; + if (GFC.script != -1) scripts[GFC.script] = 1; + SG.latest_fader = i; + SG.latest_group = GFC.group; + if (SG.group[GFC.group].script != -1) scripts[SG.group[GFC.group].script] = 1; + refresh = 1; + } + } + + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { + if (GBC.enabled && SG.group[GBC.group].enabled && grid_within_area(x, y, &GBC)) { + if (GB.latch) { + if (z) { + if (++GB.press_count == 1) { + GB.state = !GB.state; + if (GBC.script != -1) scripts[GBC.script] = 1; + } + } else { + GB.press_count--; + } + } else { + GB.state = z; + if (GBC.script != -1) scripts[GBC.script] = 1; + } + SG.latest_button = i; + SG.latest_group = GBC.group; + if (SG.group[GBC.group].script != -1) scripts[SG.group[GBC.group].script] = 1; + refresh = 1; + } + } + + for (u8 i = 0; i < SCRIPT_COUNT; i++) + if (scripts[i]) run_script(ss, i); + + SG.refresh = refresh; +} + +bool grid_within_area(u8 x, u8 y, grid_common_t *gc) { + return x >= gc->x && x < (gc->x + gc->w) && y >= gc->y && y < (gc->y + gc->h); +} + +void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level) { + s16 size_x = monome_size_x(); + s16 size_y = monome_size_y(); + + if (level == LED_OFF) return; + + if (level == LED_DIM) { + for (u16 _x = max(0, x); _x < min(size_x, x + w); _x++) + for (u16 _y = max(0, y); _y < min(size_y, y + h); _y++) + monomeLedBuffer[_x + _y * size_x] >>= 1; + + } else if (level == LED_BRI) { + for (u16 _x = max(0, x); _x < min(size_x, x + w); _x++) + for (u16 _y = max(0, y); _y < min(size_y, y + h); _y++) { + monomeLedBuffer[_x + _y * size_x] <<= 1; + if (monomeLedBuffer[_x + _y * size_x] > 15) monomeLedBuffer[_x + _y * size_x] = 15; + } + + } else { + for (u16 _x = max(0, x); _x < min(size_x, x + w); _x++) + for (u16 _y = max(0, y); _y < min(size_y, y + h); _y++) + monomeLedBuffer[_x + _y * size_x] = level; + } +} diff --git a/module/grid.h b/module/grid.h new file mode 100644 index 00000000..0350d8f4 --- /dev/null +++ b/module/grid.h @@ -0,0 +1,18 @@ +#ifndef _GRID_H_ +#define _GRID_H_ + +#include "monome.h" +#include "state.h" + +#define SG ss->grid +#define GB ss->grid.button[i] +#define GBC ss->grid.button[i].common +#define GF ss->grid.fader[i] +#define GFC ss->grid.fader[i].common +#define GXY ss->grid.xypad[i] +#define GXYC ss->grid.xypad[i].common + +extern void grid_refresh(scene_state_t *ss); +extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z); + +#endif diff --git a/module/main.c b/module/main.c index 7ba52a33..14f3d377 100644 --- a/module/main.c +++ b/module/main.c @@ -24,6 +24,7 @@ #include "init_teletype.h" #include "interrupts.h" #include "kbd.h" +#include "monome.h" #include "region.h" #include "screen.h" #include "timers.h" @@ -35,6 +36,7 @@ #include "edit_mode.h" #include "flash.h" #include "globals.h" +#include "grid.h" #include "help_mode.h" #include "keyboard_helper.h" #include "live_mode.h" @@ -122,6 +124,8 @@ static softTimer_t cvTimer = { .next = NULL, .prev = NULL }; static softTimer_t adcTimer = { .next = NULL, .prev = NULL }; static softTimer_t hidTimer = { .next = NULL, .prev = NULL }; static softTimer_t metroTimer = { .next = NULL, .prev = NULL }; +static softTimer_t monomePollTimer = {.next = NULL, .prev = NULL }; +static softTimer_t monomeRefreshTimer = {.next = NULL, .prev = NULL }; //////////////////////////////////////////////////////////////////////////////// @@ -135,6 +139,8 @@ static void keyTimer_callback(void* o); static void adcTimer_callback(void* o); static void hidTimer_callback(void* o); static void metroTimer_callback(void* o); +static void monome_poll_timer_callback(void* obj); +static void monome_refresh_timer_callback(void* obj); // event handler prototypes static void handler_None(int32_t data); @@ -160,6 +166,10 @@ static void check_events(void); static void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key); static bool process_global_keys(uint8_t key, uint8_t mod_key, bool is_held_key); +// start/stop monome polling/refresh timers +void timers_set_monome(void); +void timers_unset_monome(void); + // other static void render_init(void); @@ -250,6 +260,34 @@ void metroTimer_callback(void* o) { event_post(&e); } +// monome polling callback +static void monome_poll_timer_callback(void* obj) { + // asynchronous, non-blocking read + // UHC callback spawns appropriate events + ftdi_read(); +} + +// monome refresh callback +static void monome_refresh_timer_callback(void* obj) { + if (scene_state.grid.refresh) { + static event_t e; + e.type = kEventMonomeRefresh; + event_post(&e); + } +} + +// monome: start polling +void timers_set_monome(void) { + timer_add(&monomePollTimer, 20, &monome_poll_timer_callback, NULL); + timer_add(&monomeRefreshTimer, 30, &monome_refresh_timer_callback, NULL); +} + +// monome stop polling +void timers_unset_monome(void) { + timer_remove(&monomePollTimer); + timer_remove(&monomeRefreshTimer); +} + //////////////////////////////////////////////////////////////////////////////// // event handlers @@ -431,6 +469,33 @@ void handler_AppCustom(int32_t data) { set_metro_icon(false); } +static void handler_FtdiConnect(s32 data) { + ftdi_setup(); +} +static void handler_FtdiDisconnect(s32 data) { + timers_unset_monome(); +} + +static void handler_MonomeConnect(s32 data) { + timers_set_monome(); + scene_state.grid.refresh = true; +} + +static void handler_MonomePoll(s32 data) { + monome_read_serial(); +} +static void handler_MonomeRefresh(s32 data) { + grid_refresh(&scene_state); + monomeFrameDirty = 0b1111; + (*monome_refresh)(); +} + +static void handler_MonomeGridKey(s32 data) { + u8 x, y, z; + monome_grid_key_parse_event_data(data, &x, &y, &z); + grid_process_key(&scene_state, x, y, z); +} + //////////////////////////////////////////////////////////////////////////////// // event queue @@ -455,6 +520,13 @@ void assign_main_event_handlers() { app_event_handlers[kEventScreenRefresh] = &handler_ScreenRefresh; app_event_handlers[kEventTimer] = &handler_EventTimer; app_event_handlers[kEventAppCustom] = &handler_AppCustom; + app_event_handlers[kEventFtdiConnect] = &handler_FtdiConnect; + app_event_handlers[kEventFtdiDisconnect] = &handler_FtdiDisconnect; + app_event_handlers[kEventMonomeConnect] = &handler_MonomeConnect; + app_event_handlers[kEventMonomeDisconnect] = &handler_None; + app_event_handlers[kEventMonomePoll] = &handler_MonomePoll; + app_event_handlers[kEventMonomeRefresh] = &handler_MonomeRefresh; + app_event_handlers[kEventMonomeGridKey] = &handler_MonomeGridKey; } static void assign_msc_event_handlers(void) { @@ -796,6 +868,7 @@ int main(void) { cpu_irq_enable(); init_usb_host(); + init_monome(); init_oled(); init_i2c_master(); diff --git a/module/preset_r_mode.c b/module/preset_r_mode.c index e0bd4628..055c8577 100644 --- a/module/preset_r_mode.c +++ b/module/preset_r_mode.c @@ -95,6 +95,7 @@ uint8_t screen_refresh_preset_r() { }; void do_preset_read() { + ss_grid_init(&scene_state); flash_read(preset_select, &scene_state, &scene_text); flash_update_last_saved_scene(preset_select); ss_set_scene(&scene_state, preset_select); diff --git a/module/usb_disk_mode.c b/module/usb_disk_mode.c index a7127f1a..d00a8e83 100644 --- a/module/usb_disk_mode.c +++ b/module/usb_disk_mode.c @@ -26,6 +26,14 @@ #include "usb_protocol_msc.h" +static uint8_t grid_state = 0; +static uint16_t grid_count = 0; +static uint8_t grid_num = 0; + +static void grid_usb_write(scene_state_t *scene); +static void grid_usb_read(scene_state_t *scene, char c); + + void tele_usb_disk() { char input_buffer[32]; print_dbg("\r\nusb"); @@ -186,6 +194,8 @@ void tele_usb_disk() { } } + grid_usb_write(&scene); + file_close(); lun_state |= (1 << lun); // LUN test is done. @@ -253,7 +263,10 @@ void tele_usb_disk() { s = 9; else if (c == 'P') s = 10; - else { + else if (c == 'G') { + grid_state = grid_num = grid_count = 0; + s = 11; + } else { s = c - 49; if (s < 0 || s > 7) s = -1; } @@ -376,6 +389,10 @@ void tele_usb_disk() { p++; } } + // GRID + else if (s == 11) { + grid_usb_read(&scene, c); + } } @@ -398,3 +415,44 @@ void tele_usb_disk() { nav_exit(); } + +static void grid_usb_write(scene_state_t *scene) { + file_putc('\n'); + file_putc('#'); + file_putc('G'); + file_putc('\n'); + for (uint16_t i = 0; i < GRID_BUTTON_COUNT; i++) { + file_putc('0' + scene->grid.button[i].state); + if ((i & 15) == 15) file_putc('\n'); + } + file_putc('\n'); + for (uint16_t i = 0; i < GRID_FADER_COUNT; i++) { + if (scene->grid.fader[i].value >= 10) file_putc('1'); + file_putc('0' + (scene->grid.fader[i].value % 10)); + file_putc((i & 15) == 15 ? '\n' : '\t'); + } +} + +static void grid_usb_read(scene_state_t *scene, char c) { + if (grid_state == 0) { + if (c >= '0' && c <= '9') { + scene->grid.button[grid_count].state = c != '0'; + if (++grid_count >= GRID_BUTTON_COUNT) { + grid_count = 0; + grid_state = 1; + if (!file_eof()) file_getc(); + if (!file_eof()) file_getc(); // eat \n\n + } + } + } else if (grid_state == 1) { + if (c >= '0' && c <= '9') { + grid_num = grid_num * 10 + c - '0'; + } else if (c == '\t' || c == '\n') { + if (grid_count < GRID_FADER_COUNT) { + scene->grid.fader[grid_count].value = grid_num; + grid_num = 0; + grid_count++; + } + } + } +} \ No newline at end of file diff --git a/src/match_token.rl b/src/match_token.rl index 70229c47..092fd8e2 100644 --- a/src/match_token.rl +++ b/src/match_token.rl @@ -446,6 +446,54 @@ "TI.PRM.MAP" => { MATCH_OP(E_OP_TI_PRM_MAP); }; "TI.PRM.INIT" => { MATCH_OP(E_OP_TI_PRM_INIT); }; + # grid + "G.RST" => { MATCH_OP(E_OP_G_RST); }; + "G.CLR" => { MATCH_OP(E_OP_G_CLR); }; + "G.ROTATE" => { MATCH_OP(E_OP_G_ROTATE); }; + "G.DIM" => { MATCH_OP(E_OP_G_DIM); }; + + "G.GRP" => { MATCH_OP(E_OP_G_GRP); }; + "G.GRP.EN" => { MATCH_OP(E_OP_G_GRP_EN); }; + "G.GRP.RST" => { MATCH_OP(E_OP_G_GRP_RST); }; + "G.GRP.SW" => { MATCH_OP(E_OP_G_GRP_SW); }; + "G.GRP.SC" => { MATCH_OP(E_OP_G_GRP_SC); }; + "G.GRPI" => { MATCH_OP(E_OP_G_GRPI); }; + + "G.LED" => { MATCH_OP(E_OP_G_LED); }; + "G.LED.C" => { MATCH_OP(E_OP_G_LED_C); }; + "G.REC" => { MATCH_OP(E_OP_G_REC); }; + + "G.BTN" => { MATCH_OP(E_OP_G_BTN); }; + "G.BTX" => { MATCH_OP(E_OP_G_BTX); }; + "G.BTN.EN" => { MATCH_OP(E_OP_G_BTN_EN); }; + "G.BTN.V" => { MATCH_OP(E_OP_G_BTN_V); }; + "G.BTN.L" => { MATCH_OP(E_OP_G_BTN_L); }; + "G.BTNI" => { MATCH_OP(E_OP_G_BTNI); }; + "G.BTNV" => { MATCH_OP(E_OP_G_BTNV); }; + "G.BTNL" => { MATCH_OP(E_OP_G_BTNL); }; + "G.BTN.SW" => { MATCH_OP(E_OP_G_BTN_SW); }; + "G.GBTN.V" => { MATCH_OP(E_OP_G_GBTN_V); }; + "G.GBTN.L" => { MATCH_OP(E_OP_G_GBTN_L); }; + + "G.FDR" => { MATCH_OP(E_OP_G_FDR); }; + "G.FDX" => { MATCH_OP(E_OP_G_FDX); }; + "G.FDR.EN" => { MATCH_OP(E_OP_G_FDR_EN); }; + "G.FDR.V" => { MATCH_OP(E_OP_G_FDR_V); }; + "G.FDR.N" => { MATCH_OP(E_OP_G_FDR_N); }; + "G.FDR.L" => { MATCH_OP(E_OP_G_FDR_L); }; + "G.FDRI" => { MATCH_OP(E_OP_G_FDRI); }; + "G.FDRV" => { MATCH_OP(E_OP_G_FDRV); }; + "G.FDRN" => { MATCH_OP(E_OP_G_FDRN); }; + "G.FDRL" => { MATCH_OP(E_OP_G_FDRL); }; + "G.GFDR.V" => { MATCH_OP(E_OP_G_GFDR_V); }; + "G.GFDR.N" => { MATCH_OP(E_OP_G_GFDR_N); }; + "G.GFDR.L" => { MATCH_OP(E_OP_G_GFDR_L); }; + "G.GFDR.RN" => { MATCH_OP(E_OP_G_GFDR_RN); }; + + "G.XYP" => { MATCH_OP(E_OP_G_XYP); }; + "G.XYP.X" => { MATCH_OP(E_OP_G_XYP_X); }; + "G.XYP.Y" => { MATCH_OP(E_OP_G_XYP_Y); }; + # MODS # controlflow "IF" => { MATCH_MOD(E_MOD_IF); }; diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c new file mode 100644 index 00000000..e4269e50 --- /dev/null +++ b/src/ops/grid_ops.c @@ -0,0 +1,718 @@ +#include "ops/grid_ops.h" + +#include "helpers.h" +#include "monome.h" +#include "teletype_io.h" + +#define SG ss->grid +#define GB ss->grid.button[i] +#define GBC ss->grid.button[i].common +#define GF ss->grid.fader[i] +#define GFC ss->grid.fader[i].common +#define GXY ss->grid.xypad[i] +#define GXYC ss->grid.xypad[i].common + +#define GET_AND_CLAMP(value, min, max) \ + s16 value = cs_pop(cs); \ + if (value < (min)) \ + value = (min); \ + else if (value > (max)) \ + value = (max); + +#define GET_LEVEL(level) \ + s16 level = cs_pop(cs); \ + if (level < LED_OFF) \ + level = LED_OFF; \ + else if (level > 15) \ + level = 15; + +static void grid_common_init(grid_common_t *gc); +static s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value); + +// clang-format off + +static void op_G_RST_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_ROTATE_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_DIM_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_CLR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); + +static void op_G_GRP_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GRP_EN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GRP_RST_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GRP_SW_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GRP_SC_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GRPI_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); + +static void op_G_LED_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_LED_C_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_REC_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); + +static void op_G_BTN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTX_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTN_EN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTN_V_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTN_V_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTN_L_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTNI_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTNV_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTNL_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTN_SW_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GBTN_V_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GBTN_L_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); + +static void op_G_FDR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDX_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_EN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_V_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_V_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_N_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_N_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_L_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDRI_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDRV_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDRN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDRL_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GFDR_V_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GFDR_N_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GFDR_L_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GFDR_RN_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); + +static void op_G_XYP_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_XYP_X_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_XYP_Y_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); + +const tele_op_t op_G_RST = MAKE_GET_OP(G.RST, op_G_RST_get, 0, false); +const tele_op_t op_G_ROTATE = MAKE_GET_OP(G.ROTATE, op_G_ROTATE_get, 1, false); +const tele_op_t op_G_DIM = MAKE_GET_OP(G.DIM, op_G_DIM_get, 1, false); +const tele_op_t op_G_CLR = MAKE_GET_OP(G.CLR, op_G_CLR_get, 0, false); + +const tele_op_t op_G_GRP = MAKE_GET_OP(G.GRP, op_G_GRP_get, 1, false); +const tele_op_t op_G_GRP_EN = MAKE_GET_OP(G.GRP.EN, op_G_GRP_EN_get, 2, false); +const tele_op_t op_G_GRP_RST = MAKE_GET_OP(G.GRP.RST, op_G_GRP_RST_get, 1, false); +const tele_op_t op_G_GRP_SW = MAKE_GET_OP(G.GRP.SW, op_G_GRP_SW_get, 1, false); +const tele_op_t op_G_GRP_SC = MAKE_GET_OP(G.GRP.SC, op_G_GRP_SC_get, 2, false); +const tele_op_t op_G_GRPI = MAKE_GET_OP(G.GRPI, op_G_GRPI_get, 1, true); + +const tele_op_t op_G_LED = MAKE_GET_OP(G.LED, op_G_LED_get, 3, false); +const tele_op_t op_G_LED_C = MAKE_GET_OP(G.LED.C, op_G_LED_C_get, 2, false); +const tele_op_t op_G_REC = MAKE_GET_OP(G.REC, op_G_REC_get, 6, false); + +const tele_op_t op_G_BTN = MAKE_GET_OP(G.BTN, op_G_BTN_get, 8, false); +const tele_op_t op_G_BTX = MAKE_GET_OP(G.BTX, op_G_BTX_get, 10, false); +const tele_op_t op_G_BTN_EN = MAKE_GET_OP(G.BTN.EN, op_G_BTN_EN_get, 2, false); +const tele_op_t op_G_BTN_V = MAKE_GET_SET_OP(G.BTN.V, op_G_BTN_V_get, op_G_BTN_V_set, 1, true); +const tele_op_t op_G_BTN_L = MAKE_GET_OP(G.BTN.L, op_G_BTN_L_get, 2, false); +const tele_op_t op_G_BTNI = MAKE_GET_OP(G.BTNI, op_G_BTNI_get, 0, true); +const tele_op_t op_G_BTNV = MAKE_GET_OP(G.BTNV, op_G_BTNV_get, 0, true); +const tele_op_t op_G_BTNL = MAKE_GET_OP(G.BTNL, op_G_BTNL_get, 1, false); +const tele_op_t op_G_BTN_SW = MAKE_GET_OP(G.BTN.SW, op_G_BTN_SW_get, 1, false); +const tele_op_t op_G_GBTN_V = MAKE_GET_OP(G.GBTN.V, op_G_GBTN_V_get, 2, false); +const tele_op_t op_G_GBTN_L = MAKE_GET_OP(G.GBTN.L, op_G_GBTN_L_get, 3, false); + +const tele_op_t op_G_FDR = MAKE_GET_OP(G.FDR, op_G_FDR_get, 8, false); +const tele_op_t op_G_FDX = MAKE_GET_OP(G.FDX, op_G_FDX_get, 10, false); +const tele_op_t op_G_FDR_EN = MAKE_GET_OP(G.FDR.EN, op_G_FDR_EN_get, 2, false); +const tele_op_t op_G_FDR_V = MAKE_GET_SET_OP(G.FDR.V, op_G_FDR_V_get, op_G_FDR_V_set, 1, true); +const tele_op_t op_G_FDR_N = MAKE_GET_SET_OP(G.FDR.N, op_G_FDR_N_get, op_G_FDR_N_set, 1, true); +const tele_op_t op_G_FDR_L = MAKE_GET_OP(G.FDR.L, op_G_FDR_L_get, 2, false); +const tele_op_t op_G_FDRI = MAKE_GET_OP(G.FDRI, op_G_FDRI_get, 0, false); +const tele_op_t op_G_FDRV = MAKE_GET_OP(G.FDRV, op_G_FDRV_get, 0, false); +const tele_op_t op_G_FDRN = MAKE_GET_OP(G.FDRN, op_G_FDRN_get, 0, false); +const tele_op_t op_G_FDRL = MAKE_GET_OP(G.FDRL, op_G_FDRL_get, 1, true); +const tele_op_t op_G_GFDR_V = MAKE_GET_OP(G.GFDR.V, op_G_GFDR_V_get, 2, false); +const tele_op_t op_G_GFDR_N = MAKE_GET_OP(G.GFDR.N, op_G_GFDR_N_get, 2, false); +const tele_op_t op_G_GFDR_L = MAKE_GET_OP(G.GFDR.L, op_G_GFDR_L_get, 3, false); +const tele_op_t op_G_GFDR_RN = MAKE_GET_OP(G.GFDR.RN, op_G_GFDR_RN_get, 3, false); + +const tele_op_t op_G_XYP = MAKE_GET_OP(G.XYP, op_G_XYP_get, 7, false); +const tele_op_t op_G_XYP_X = MAKE_GET_OP(G.XYP.X, op_G_XYP_X_get, 1, true); +const tele_op_t op_G_XYP_Y = MAKE_GET_OP(G.XYP.Y, op_G_XYP_Y_get, 1, true); + +// clang-format on + +static void op_G_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *NOTUSED(cs)) { + SG.rotate = 0; + SG.dim = 0; + + SG.current_group = 0; + SG.latest_group = 0; + SG.latest_button = 0; + SG.latest_fader = 0; + + for (u8 i = 0; i < GRID_MAX_DIMENSION; i++) + for (u8 j = 0; j < GRID_MAX_DIMENSION; j++) + SG.leds[i][j] = LED_OFF; + + for (u8 i = 0; i < GRID_GROUP_COUNT; i++) { + SG.group[i].enabled = true; + SG.group[i].script = -1; + SG.group[i].fader_min = 0; + SG.group[i].fader_max = 16383; + } + + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { + grid_common_init(&(GBC)); + GB.latch = 0; + GB.state = 0; + } + + for (u8 i = 0; i < GRID_FADER_COUNT; i++) { + grid_common_init(&(GFC)); + GF.dir = 0; + GF.value = 0; + } + + for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { + grid_common_init(&(GXYC)); + GXY.value_x = 0; + GXY.value_y = 0; + } + + SG.refresh = true; +} + +static void op_G_CLR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *NOTUSED(cs)) { + for (u8 i = 0; i < GRID_MAX_DIMENSION; i++) + for (u8 j = 0; j < GRID_MAX_DIMENSION; j++) + SG.leds[i][j] = LED_OFF; + SG.refresh = true; +} + +static void op_G_ROTATE_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 rotate = cs_pop(cs); + SG.rotate = rotate; + SG.refresh = true; +} + +static void op_G_DIM_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + GET_AND_CLAMP(dim, 0, 14); + SG.dim = dim; + SG.refresh = true; +} + +static void op_G_GRP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + if (group < 0 || group >= GRID_BUTTON_COUNT) return; + SG.current_group = group; +} + +static void op_G_GRP_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + s16 en = cs_pop(cs); + if (group < 0 || group >= GRID_BUTTON_COUNT) return; + SG.group[group].enabled = en; + SG.refresh = true; +} + +static void op_G_GRP_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + if (group < 0 || group >= GRID_BUTTON_COUNT) return; + + SG.group[group].enabled = true; + SG.group[group].script = -1; + SG.group[group].fader_min = 0; + SG.group[group].fader_max = 0; + + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) + if (GBC.group == group) { + grid_common_init(&(GBC)); + GB.latch = 0; + GB.state = 0; + } + + for (u8 i = 0; i < GRID_FADER_COUNT; i++) + if (GFC.group == group) { + grid_common_init(&(GFC)); + GF.dir = 0; + GF.value = 0; + } + + for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) + if (GXYC.group == group) { + grid_common_init(&(GXYC)); + GXY.value_x = 0; + GXY.value_y = 0; + } + + SG.refresh = true; +} + +static void op_G_GRP_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + if (group < 0 || group >= GRID_BUTTON_COUNT) return; + + for (u8 i = 0; i < GRID_GROUP_COUNT; i++) SG.group[i].enabled = false; + SG.group[group].enabled = true; + + SG.refresh = true; +} + +static void op_G_GRP_SC_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + s16 script = cs_pop(cs) - 1; + + if (group < 0 || group >= GRID_BUTTON_COUNT) return; + if (script < 0 || script > INIT_SCRIPT) script = -1; + + SG.group[group].script = script; +} + +static void op_G_GRPI_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, SG.latest_group); +} + +static void op_G_LED_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + GET_LEVEL(level); + + if (x < 0 || x >= GRID_MAX_DIMENSION) return; + if (y < 0 || y >= GRID_MAX_DIMENSION) return; + + SG.leds[x][y] = level; + SG.refresh = true; +} + +static void op_G_LED_C_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + + if (x < 0 || x >= GRID_MAX_DIMENSION) return; + if (y < 0 || y >= GRID_MAX_DIMENSION) return; + + SG.leds[x][y] = LED_OFF; + SG.refresh = true; +} + +static void op_G_REC_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + s16 w = cs_pop(cs); + s16 h = cs_pop(cs); + GET_LEVEL(fill); + GET_LEVEL(border); + + for (s16 col = max(0, x + 1); col < min(GRID_MAX_DIMENSION, x + w - 1); col++) + for (s16 row = max(0, y + 1); row < min(GRID_MAX_DIMENSION, y + h - 1); row++) + SG.leds[col][row] = fill; + + if (y >= 0 && y < GRID_MAX_DIMENSION) + for (s16 col = max(0, x); col < min(GRID_MAX_DIMENSION, x + w); col++) + SG.leds[col][y] = border; + + s16 row = y + h - 1; + if (row >= 0 && row < GRID_MAX_DIMENSION) + for (s16 col = max(0, x); col < min(GRID_MAX_DIMENSION, x + w); col++) + SG.leds[col][row] = border; + + if (x >= 0 && x < GRID_MAX_DIMENSION) + for (s16 row = max(0, y); row < min(GRID_MAX_DIMENSION, y + h); row++) + SG.leds[x][row] = border; + + s16 col = x + w - 1; + if (col >= 0 && col < GRID_MAX_DIMENSION) + for (s16 row = max(0, y); row < min(GRID_MAX_DIMENSION, y + h); row++) + SG.leds[col][row] = border; + + SG.refresh = true; +} + +static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + s16 w = cs_pop(cs); + s16 h = cs_pop(cs); + s16 latch = cs_pop(cs); + GET_LEVEL(level); + s16 script = cs_pop(cs) - 1; + + if (i < 0 || i >= GRID_BUTTON_COUNT) return; + if (script < 0 || script > INIT_SCRIPT) script = -1; + + GBC.enabled = true; + GBC.group = SG.current_group; + GBC.x = x; + GBC.y = y; + GBC.w = w; + GBC.h = h; + GBC.background = level; + GBC.script = script; + GB.latch = latch != 0; + // GB.state = 0; + + SG.refresh = 1; +} + +static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 id = cs_pop(cs); + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + s16 w = cs_pop(cs); + s16 h = cs_pop(cs); + s16 latch = cs_pop(cs); + GET_LEVEL(level); + s16 script = cs_pop(cs) - 1; + s16 count_x = cs_pop(cs); + s16 count_y = cs_pop(cs); + + if (id < 0 || id >= GRID_BUTTON_COUNT) return; + if (script < 0 || script > INIT_SCRIPT) script = -1; + if (count_x <= 0) return; + if (count_x > 16) count_x = 16; + if (count_y <= 0) return; + if (count_y > 16) count_y = 16; + + u16 i; + for (u16 cy = 0; cy < count_y; cy++) + for (u16 cx = 0; cx < count_x; cx++) { + i = id + cy * count_x + cx; + if (i >= GRID_BUTTON_COUNT) break; + GBC.enabled = true; + GBC.group = SG.current_group; + GBC.x = x + w * cx; + GBC.y = y + h * cy; + GBC.w = w; + GBC.h = h; + GBC.background = level; + GBC.script = script; + GB.latch = latch != 0; + // GB.state = 0; + } + + SG.refresh = 1; +} + +static void op_G_BTN_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + s16 en = cs_pop(cs); + + if (i < 0 || i >= GRID_BUTTON_COUNT) return; + GBC.enabled = en; + SG.refresh = 1; +} + +static void op_G_BTN_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + cs_push(cs, i < 0 || i >= GRID_BUTTON_COUNT ? 0 : GB.state); +} + +static void op_G_BTN_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + s16 value = cs_pop(cs); + if (i < 0 || i >= GRID_BUTTON_COUNT) return; + GB.state = value != 0; + SG.refresh = 1; +} + +static void op_G_BTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + GET_LEVEL(level); + if (i < 0 || i >= GRID_BUTTON_COUNT) return; + GBC.background = level; + SG.refresh = 1; +} + +static void op_G_BTNI_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, SG.latest_button); +} + +static void op_G_BTNV_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, SG.button[SG.latest_button].state); +} + +static void op_G_BTNL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + GET_LEVEL(level); + SG.button[SG.latest_button].common.background = level; + SG.refresh = 1; +} + +static void op_G_BTN_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 id = cs_pop(cs); + if (id < 0 || id >= GRID_BUTTON_COUNT) return; + + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) + if (GBC.group == SG.button[id].common.group) GB.state = 0; + + SG.button[id].state = 1; + SG.refresh = 1; +} + +static void op_G_GBTN_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + s16 value = cs_pop(cs); + + if (group < 0 || group > GRID_GROUP_COUNT) return; + value = value != 0; + + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) + if (GBC.group == group) GB.state = value; + SG.refresh = 1; +} + +static void op_G_GBTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + GET_LEVEL(odd); + GET_LEVEL(even); + + if (group < 0 || group > GRID_GROUP_COUNT) return; + + u8 is_odd = 1; + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) + if (GBC.group == group) { + GBC.background = is_odd ? odd : even; + is_odd = !is_odd; + } + SG.refresh = 1; +} + +static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + s16 w = cs_pop(cs); + s16 h = cs_pop(cs); + s16 dir = cs_pop(cs); + GET_LEVEL(level); + s16 script = cs_pop(cs) - 1; + + if (i < 0 || i >= GRID_FADER_COUNT) return; + if (script < 0 || script > INIT_SCRIPT) script = -1; + + GFC.enabled = true; + GFC.group = SG.current_group; + GFC.x = x; + GFC.y = y; + GFC.w = w; + GFC.h = h; + GFC.background = level; + GFC.script = script; + GF.dir = dir != 0; + // GF.value = 0; + + SG.refresh = 1; +} + +static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 id = cs_pop(cs); + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + s16 w = cs_pop(cs); + s16 h = cs_pop(cs); + s16 dir = cs_pop(cs); + GET_LEVEL(level); + s16 script = cs_pop(cs) - 1; + s16 count_x = cs_pop(cs); + s16 count_y = cs_pop(cs); + + if (id < 0 || id >= GRID_FADER_COUNT) return; + if (script < 0 || script > INIT_SCRIPT) script = -1; + if (count_x <= 0) return; + if (count_x > 16) count_x = 16; + if (count_y <= 0) return; + if (count_y > 16) count_y = 16; + + u16 i; + for (u16 cy = 0; cy < count_y; cy++) + for (u16 cx = 0; cx < count_x; cx++) { + i = id + cy * count_x + cx; + if (i >= GRID_FADER_COUNT) break; + GFC.enabled = true; + GFC.group = SG.current_group; + GFC.x = x + w * cx; + GFC.y = y + h * cy; + GFC.w = w; + GFC.h = h; + GFC.background = level; + GFC.script = script; + GF.dir = dir != 0; + // GF.value = 0; + } + + SG.refresh = 1; +} + +static void op_G_FDR_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + s16 en = cs_pop(cs); + + if (i < 0 || i >= GRID_FADER_COUNT) return; + GFC.enabled = en; + SG.refresh = 1; +} + +static void op_G_FDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + if (i < 0 || i >= GRID_FADER_COUNT) { + cs_push(cs, 0); + return; + } + + s16 value = scale(0, GF.dir ? GFC.h - 1 : GFC.w - 1, SG.group[GFC.group].fader_min, + SG.group[GFC.group].fader_max, GF.value); + cs_push(cs, value); +} + +static void op_G_FDR_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + s16 value = cs_pop(cs); + + if (i < 0 || i >= GRID_FADER_COUNT) return; + if (value < SG.group[GFC.group].fader_min) value = SG.group[GFC.group].fader_min; + else if (value > SG.group[GFC.group].fader_max) value = SG.group[GFC.group].fader_max; + + GF.value = scale(SG.group[GFC.group].fader_min, + SG.group[GFC.group].fader_max, 0, GF.dir ? GFC.h - 1 : GFC.w - 1, value); + SG.refresh = 1; +} + +static void op_G_FDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + cs_push(cs, i < 0 || i >= GRID_FADER_COUNT ? 1 : GF.value + 1); +} + +static void op_G_FDR_N_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + s16 value = cs_pop(cs) - 1; + + if (i < 0 || i >= GRID_FADER_COUNT) return; + if (value < 0) value = 0; + else if (GF.dir && value >= GFC.h) value = GFC.h - 1; + else if (!GF.dir && value >= GFC.w) value = GFC.w - 1; + + GF.value = value; + SG.refresh = 1; +} + +static void op_G_FDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + GET_LEVEL(level); + if (i < 0 || i >= GRID_FADER_COUNT) return; + GFC.background = level; + SG.refresh = 1; +} + +static void op_G_FDRI_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, SG.latest_fader); +} + +static void op_G_FDRV_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + u8 i = SG.latest_fader; + s16 value = scale(0, GF.dir ? GFC.h - 1 : GFC.w - 1, SG.group[GFC.group].fader_min, + SG.group[GFC.group].fader_max, GF.value); + cs_push(cs, value); +} + +static void op_G_FDRN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, SG.fader[SG.latest_fader].value); +} + +static void op_G_FDRL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + GET_LEVEL(level); + SG.fader[SG.latest_fader].common.background = level; + SG.refresh = 1; +} + +static void op_G_GFDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + s16 value = cs_pop(cs); + + if (group < 0 || group > GRID_GROUP_COUNT) return; + if (value < SG.group[group].fader_min) value = SG.group[group].fader_min; + else if (value > SG.group[group].fader_max) value = SG.group[group].fader_max; + + for (u16 i = 0; i < GRID_FADER_COUNT; i++) + if (GFC.group == group) + GF.value = scale(SG.group[group].fader_min, + SG.group[group].fader_max, 0, GF.dir ? GFC.h - 1 : GFC.w - 1, value); + + SG.refresh = 1; +} + +static void op_G_GFDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + s16 value = cs_pop(cs) - 1; + + if (group < 0 || group > GRID_GROUP_COUNT) return; + if (value < 0) value = 0; + + for (u16 i = 0; i < GRID_FADER_COUNT; i++) + if (GFC.group == group) GF.value = min(GF.dir ? GFC.h - 1 : GFC.w - 1, value); + SG.refresh = 1; +} + +static void op_G_GFDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + GET_LEVEL(odd); + GET_LEVEL(even); + + if (group < 0 || group > GRID_GROUP_COUNT) return; + + u8 is_odd = 1; + for (u16 i = 0; i < GRID_FADER_COUNT; i++) + if (GFC.group == group) { + GFC.background = is_odd ? odd : even; + is_odd = !is_odd; + } + SG.refresh = 1; +} + +static void op_G_GFDR_RN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + s16 min = cs_pop(cs); + s16 max = cs_pop(cs); + + if (group < 0 || group > GRID_GROUP_COUNT) return; + SG.group[group].fader_min = min; + SG.group[group].fader_max = max; +} + +static void op_G_XYP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + s16 w = cs_pop(cs); + s16 h = cs_pop(cs); + GET_LEVEL(level); + s16 script = cs_pop(cs) - 1; + + if (i < 0 || i >= GRID_XYPAD_COUNT) return; + if (script < 0 || script > INIT_SCRIPT) script = -1; + + GXYC.enabled = true; + GXYC.group = SG.current_group; + GXYC.x = x; + GXYC.y = y; + GXYC.w = w; + GXYC.h = h; + GXYC.background = level; + GXYC.script = script; + GXY.value_x = 0; + GXY.value_y = 0; + + SG.refresh = 1; +} + +static void op_G_XYP_X_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + cs_push(cs, i < 0 || i >= GRID_XYPAD_COUNT ? 0 : GXY.value_x); +} + +static void op_G_XYP_Y_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + cs_push(cs, i < 0 || i >= GRID_XYPAD_COUNT ? 0 : GXY.value_y); +} + +void grid_common_init(grid_common_t *gc) { + gc->enabled = false; + gc->group = 0; + gc->x = gc->y = 0; + gc->w = gc->h = 1; + gc->background = 5; + gc->script = -1; +} + +s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value) { + if (a == b) return x; + return (value - a) * (y - x) / (b - a) + x; +} \ No newline at end of file diff --git a/src/ops/grid_ops.h b/src/ops/grid_ops.h new file mode 100644 index 00000000..e2b2dc81 --- /dev/null +++ b/src/ops/grid_ops.h @@ -0,0 +1,53 @@ +#ifndef _OPS_GRID_H_ +#define _OPS_GRID_H_ + +#include "ops/op.h" + +extern const tele_op_t op_G_RST; +extern const tele_op_t op_G_CLR; +extern const tele_op_t op_G_ROTATE; +extern const tele_op_t op_G_DIM; + +extern const tele_op_t op_G_GRP; +extern const tele_op_t op_G_GRP_EN; +extern const tele_op_t op_G_GRP_RST; +extern const tele_op_t op_G_GRP_SW; +extern const tele_op_t op_G_GRP_SC; +extern const tele_op_t op_G_GRPI; + +extern const tele_op_t op_G_LED; +extern const tele_op_t op_G_LED_C; +extern const tele_op_t op_G_REC; + +extern const tele_op_t op_G_BTN; +extern const tele_op_t op_G_BTX; +extern const tele_op_t op_G_BTN_EN; +extern const tele_op_t op_G_BTN_V; +extern const tele_op_t op_G_BTN_L; +extern const tele_op_t op_G_BTNI; +extern const tele_op_t op_G_BTNV; +extern const tele_op_t op_G_BTNL; +extern const tele_op_t op_G_BTN_SW; +extern const tele_op_t op_G_GBTN_V; +extern const tele_op_t op_G_GBTN_L; + +extern const tele_op_t op_G_FDR; +extern const tele_op_t op_G_FDX; +extern const tele_op_t op_G_FDR_EN; +extern const tele_op_t op_G_FDR_V; +extern const tele_op_t op_G_FDR_N; +extern const tele_op_t op_G_FDR_L; +extern const tele_op_t op_G_FDRI; +extern const tele_op_t op_G_FDRV; +extern const tele_op_t op_G_FDRN; +extern const tele_op_t op_G_FDRL; +extern const tele_op_t op_G_GFDR_V; +extern const tele_op_t op_G_GFDR_N; +extern const tele_op_t op_G_GFDR_L; +extern const tele_op_t op_G_GFDR_RN; + +extern const tele_op_t op_G_XYP; +extern const tele_op_t op_G_XYP_X; +extern const tele_op_t op_G_XYP_Y; + +#endif diff --git a/src/ops/op.c b/src/ops/op.c index a6f142c7..aa44f29a 100644 --- a/src/ops/op.c +++ b/src/ops/op.c @@ -9,6 +9,7 @@ #include "ops/controlflow.h" #include "ops/delay.h" #include "ops/earthsea.h" +#include "ops/grid_ops.h" #include "ops/hardware.h" #include "ops/init.h" #include "ops/justfriends.h" @@ -159,7 +160,17 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_TI_PARAM_INIT, &op_TI_IN_INIT, &op_TI_INIT, &op_TI_PRM, &op_TI_PRM_QT, &op_TI_PRM_N, &op_TI_PRM_SCALE, &op_TI_PRM_MAP, - &op_TI_PRM_INIT + &op_TI_PRM_INIT, + + // grid + &op_G_RST, &op_G_CLR, &op_G_ROTATE, &op_G_DIM, &op_G_GRP, &op_G_GRP_EN, + &op_G_GRP_RST, &op_G_GRP_SW, &op_G_GRP_SC, &op_G_GRPI, &op_G_LED, + &op_G_LED_C, &op_G_REC, &op_G_BTN, &op_G_BTX, &op_G_BTN_EN, &op_G_BTN_V, + &op_G_BTN_L, &op_G_BTNI, &op_G_BTNV, &op_G_BTNL, &op_G_BTN_SW, &op_G_GBTN_V, + &op_G_GBTN_L, &op_G_FDR, &op_G_FDX, &op_G_FDR_EN, &op_G_FDR_V, &op_G_FDR_N, + &op_G_FDR_L, &op_G_FDRI, &op_G_FDRV, &op_G_FDRN, &op_G_FDRL, &op_G_GFDR_V, + &op_G_GFDR_N, &op_G_GFDR_L, &op_G_GFDR_RN, &op_G_XYP, &op_G_XYP_X, + &op_G_XYP_Y }; ///////////////////////////////////////////////////////////////// diff --git a/src/ops/op_enum.h b/src/ops/op_enum.h index 95f8f866..139a01c0 100644 --- a/src/ops/op_enum.h +++ b/src/ops/op_enum.h @@ -386,6 +386,47 @@ typedef enum { E_OP_TI_PRM_SCALE, E_OP_TI_PRM_MAP, E_OP_TI_PRM_INIT, + E_OP_G_RST, + E_OP_G_CLR, + E_OP_G_ROTATE, + E_OP_G_DIM, + E_OP_G_GRP, + E_OP_G_GRP_EN, + E_OP_G_GRP_RST, + E_OP_G_GRP_SW, + E_OP_G_GRP_SC, + E_OP_G_GRPI, + E_OP_G_LED, + E_OP_G_LED_C, + E_OP_G_REC, + E_OP_G_BTN, + E_OP_G_BTX, + E_OP_G_BTN_EN, + E_OP_G_BTN_V, + E_OP_G_BTN_L, + E_OP_G_BTNI, + E_OP_G_BTNV, + E_OP_G_BTNL, + E_OP_G_BTN_SW, + E_OP_G_GBTN_V, + E_OP_G_GBTN_L, + E_OP_G_FDR, + E_OP_G_FDX, + E_OP_G_FDR_EN, + E_OP_G_FDR_V, + E_OP_G_FDR_N, + E_OP_G_FDR_L, + E_OP_G_FDRI, + E_OP_G_FDRV, + E_OP_G_FDRN, + E_OP_G_FDRL, + E_OP_G_GFDR_V, + E_OP_G_GFDR_N, + E_OP_G_GFDR_L, + E_OP_G_GFDR_RN, + E_OP_G_XYP, + E_OP_G_XYP_X, + E_OP_G_XYP_Y, E_OP__LENGTH, } tele_op_idx_t; diff --git a/src/state.c b/src/state.c index b88462c7..ec9b0ddd 100644 --- a/src/state.c +++ b/src/state.c @@ -11,6 +11,7 @@ void ss_init(scene_state_t *ss) { ss->initializing = true; ss_variables_init(ss); ss_patterns_init(ss); + ss_grid_init(ss); ss->delay.count = 0; for (size_t i = 0; i < TR_COUNT; i++) { ss->tr_pulse_timer[i] = 0; } ss->stack_op.top = 0; @@ -66,6 +67,59 @@ void ss_pattern_init(scene_state_t *ss, size_t pattern_no) { for (size_t i = 0; i < PATTERN_LENGTH; i++) { p->val[i] = 0; } } +// grid + +void ss_grid_init(scene_state_t *ss) { + ss->grid.rotate = 0; + ss->grid.dim = 0; + + ss->grid.current_group = 0; + ss->grid.latest_group = 0; + ss->grid.latest_button = 0; + ss->grid.latest_fader = 0; + + for (u8 i = 0; i < GRID_MAX_DIMENSION; i++) + for (u8 j = 0; j < GRID_MAX_DIMENSION; j++) + ss->grid.leds[i][j] = LED_OFF; + + for (u8 i = 0; i < GRID_GROUP_COUNT; i++) { + ss->grid.group[i].enabled = true; + ss->grid.group[i].script = -1; + ss->grid.group[i].fader_min = 0; + ss->grid.group[i].fader_max = 16383; + } + + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { + ss_grid_common_init(&(ss->grid.button[i].common)); + ss->grid.button[i].latch = 0; + ss->grid.button[i].state = 0; + ss->grid.button[i].press_count = 0; + } + + for (u8 i = 0; i < GRID_FADER_COUNT; i++) { + ss_grid_common_init(&(ss->grid.fader[i].common)); + ss->grid.fader[i].dir = 0; + ss->grid.fader[i].value = 0; + } + + for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { + ss_grid_common_init(&(ss->grid.xypad[i].common)); + ss->grid.xypad[i].value_x = 0; + ss->grid.xypad[i].value_y = 0; + } + + ss->grid.refresh = true; +} + +void ss_grid_common_init(grid_common_t *gc) { + gc->enabled = false; + gc->group = 0; + gc->x = gc->y = 0; + gc->w = gc->h = 1; + gc->background = 5; + gc->script = -1; +} + // Hardware void ss_set_in(scene_state_t *ss, int16_t value) { diff --git a/src/state.h b/src/state.h index cb36196c..e31ea3c1 100644 --- a/src/state.h +++ b/src/state.h @@ -9,8 +9,9 @@ #include "every.h" #include "scale.h" #include "turtle.h" +#include "types.h" -#define STACK_SIZE 8 +#define STACK_SIZE 16 #define CV_COUNT 4 #define Q_LENGTH 64 #define TR_COUNT 4 @@ -24,6 +25,15 @@ #define EXEC_DEPTH 8 #define WHILE_DEPTH 10000 +#define GRID_GROUP_COUNT 8 +#define GRID_MAX_DIMENSION 16 +#define GRID_BUTTON_COUNT 256 +#define GRID_FADER_COUNT 64 +#define GRID_XYPAD_COUNT 8 +#define LED_DIM -1 +#define LED_BRI -2 +#define LED_OFF -3 + #define METRO_MIN_MS 25 #define METRO_MIN_UNSUPPORTED_MS 2 @@ -111,6 +121,59 @@ typedef struct { int16_t last_time; } scene_script_t; + typedef struct { + u8 enabled; + u8 group; + u8 x, y; + u8 w, h; + u8 background; + s8 script; +} grid_common_t; + +typedef struct { + u8 enabled; + s8 script; + s16 fader_min; + s16 fader_max; +} grid_group_t; + +typedef struct { + grid_common_t common; + u8 latch; + u8 state; + u8 press_count; +} grid_button_t; + +typedef struct { + grid_common_t common; + u8 dir; // 0 - horiz 1 - vert + u8 value; +} grid_fader_t; + +typedef struct { + grid_common_t common; + u8 value_x; + u8 value_y; +} grid_xypad_t; + +typedef struct { + u8 refresh; + u8 rotate; + u8 dim; + + u8 current_group; + u8 latest_group; + u8 latest_button; + u8 latest_fader; + + s8 leds[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION]; + grid_group_t group[GRID_GROUP_COUNT]; + + grid_button_t button[GRID_BUTTON_COUNT]; + grid_fader_t fader[GRID_FADER_COUNT]; + grid_xypad_t xypad[GRID_XYPAD_COUNT]; +} scene_grid_t; + typedef struct { bool initializing; scene_variables_t variables; @@ -121,6 +184,7 @@ typedef struct { scene_script_t scripts[SCRIPT_COUNT]; scene_turtle_t turtle; bool every_last; + scene_grid_t grid; cal_data_t cal; } scene_state_t; @@ -128,6 +192,8 @@ extern void ss_init(scene_state_t *ss); extern void ss_variables_init(scene_state_t *ss); extern void ss_patterns_init(scene_state_t *ss); extern void ss_pattern_init(scene_state_t *ss, size_t pattern_no); +extern void ss_grid_init(scene_state_t *ss); +extern void ss_grid_common_init(grid_common_t *gc); extern void ss_set_in(scene_state_t *ss, int16_t value); extern void ss_set_param(scene_state_t *ss, int16_t value); From 630e9d4058385c34f26c74924bcdf2fff11ce9b5 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sat, 14 Oct 2017 19:36:04 -0700 Subject: [PATCH 002/117] fix tests, fix ops --- simulator/Makefile | 2 +- src/ops/grid_ops.c | 19 ++++++++++--------- tests/Makefile | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/simulator/Makefile b/simulator/Makefile index dc71b114..60d6424b 100644 --- a/simulator/Makefile +++ b/simulator/Makefile @@ -10,7 +10,7 @@ OBJ = tt.o ../src/teletype.o ../src/command.o ../src/helpers.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/whitewhale.o \ - ../src/ops/init.o \ + ../src/ops/init.o ../src/ops/grid_ops.o \ ../libavr32/src/euclidean/euclidean.o ../libavr32/src/euclidean/data.o \ ../libavr32/src/util.o diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index e4269e50..15210e61 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -1,8 +1,5 @@ #include "ops/grid_ops.h" - #include "helpers.h" -#include "monome.h" -#include "teletype_io.h" #define SG ss->grid #define GB ss->grid.button[i] @@ -26,9 +23,13 @@ else if (level > 15) \ level = 15; +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + static void grid_common_init(grid_common_t *gc); static s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value); + // clang-format off static void op_G_RST_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -91,7 +92,7 @@ const tele_op_t op_G_GRP_EN = MAKE_GET_OP(G.GRP.EN, op_G_GRP_EN_get, 2, false); const tele_op_t op_G_GRP_RST = MAKE_GET_OP(G.GRP.RST, op_G_GRP_RST_get, 1, false); const tele_op_t op_G_GRP_SW = MAKE_GET_OP(G.GRP.SW, op_G_GRP_SW_get, 1, false); const tele_op_t op_G_GRP_SC = MAKE_GET_OP(G.GRP.SC, op_G_GRP_SC_get, 2, false); -const tele_op_t op_G_GRPI = MAKE_GET_OP(G.GRPI, op_G_GRPI_get, 1, true); +const tele_op_t op_G_GRPI = MAKE_GET_OP(G.GRPI, op_G_GRPI_get, 0, true); const tele_op_t op_G_LED = MAKE_GET_OP(G.LED, op_G_LED_get, 3, false); const tele_op_t op_G_LED_C = MAKE_GET_OP(G.LED.C, op_G_LED_C_get, 2, false); @@ -115,10 +116,10 @@ const tele_op_t op_G_FDR_EN = MAKE_GET_OP(G.FDR.EN, op_G_FDR_EN_get, 2, false); const tele_op_t op_G_FDR_V = MAKE_GET_SET_OP(G.FDR.V, op_G_FDR_V_get, op_G_FDR_V_set, 1, true); const tele_op_t op_G_FDR_N = MAKE_GET_SET_OP(G.FDR.N, op_G_FDR_N_get, op_G_FDR_N_set, 1, true); const tele_op_t op_G_FDR_L = MAKE_GET_OP(G.FDR.L, op_G_FDR_L_get, 2, false); -const tele_op_t op_G_FDRI = MAKE_GET_OP(G.FDRI, op_G_FDRI_get, 0, false); -const tele_op_t op_G_FDRV = MAKE_GET_OP(G.FDRV, op_G_FDRV_get, 0, false); -const tele_op_t op_G_FDRN = MAKE_GET_OP(G.FDRN, op_G_FDRN_get, 0, false); -const tele_op_t op_G_FDRL = MAKE_GET_OP(G.FDRL, op_G_FDRL_get, 1, true); +const tele_op_t op_G_FDRI = MAKE_GET_OP(G.FDRI, op_G_FDRI_get, 0, true); +const tele_op_t op_G_FDRV = MAKE_GET_OP(G.FDRV, op_G_FDRV_get, 0, true); +const tele_op_t op_G_FDRN = MAKE_GET_OP(G.FDRN, op_G_FDRN_get, 0, true); +const tele_op_t op_G_FDRL = MAKE_GET_OP(G.FDRL, op_G_FDRL_get, 1, false); const tele_op_t op_G_GFDR_V = MAKE_GET_OP(G.GFDR.V, op_G_GFDR_V_get, 2, false); const tele_op_t op_G_GFDR_N = MAKE_GET_OP(G.GFDR.N, op_G_GFDR_N_get, 2, false); const tele_op_t op_G_GFDR_L = MAKE_GET_OP(G.GFDR.L, op_G_GFDR_L_get, 3, false); @@ -715,4 +716,4 @@ void grid_common_init(grid_common_t *gc) { s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value) { if (a == b) return x; return (value - a) * (y - x) / (b - a) + x; -} \ No newline at end of file +} diff --git a/tests/Makefile b/tests/Makefile index 4839a2a7..4847f8cc 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -15,7 +15,7 @@ tests: main.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/whitewhale.c \ - ../src/ops/turtle.o ../src/ops/init.o \ + ../src/ops/turtle.o ../src/ops/init.o ../src/ops/grid_ops.o \ ../libavr32/src/euclidean/data.o ../libavr32/src/euclidean/euclidean.o \ ../libavr32/src/util.o $(CC) -o $@ $^ $(CFLAGS) From 95655449809e066c9a663b5d68862b58cd293f4d Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Wed, 18 Oct 2017 19:23:59 -0700 Subject: [PATCH 003/117] grid visualizer pt1 --- module/grid.c | 150 ++++++++++++++++++++++++++++++++++++++++----- module/grid.h | 10 +++ module/live_mode.c | 15 ++++- module/live_mode.h | 4 +- module/main.c | 6 +- src/ops/grid_ops.c | 60 +++++++++--------- src/state.c | 2 +- src/state.h | 4 +- 8 files changed, 197 insertions(+), 54 deletions(-) diff --git a/module/grid.c b/module/grid.c index bf35391c..b74b155f 100644 --- a/module/grid.c +++ b/module/grid.c @@ -1,13 +1,26 @@ #include "grid.h" +#include "globals.h" #include "state.h" #include "teletype.h" +#define SCREEN_MAX_X 16 +#define SCREEN_MAX_Y 8 + +const u8 min_y[2] = {0, 8}; +const u8 max_y[2] = {7, 15}; + +static u8 screen[SCREEN_MAX_X][SCREEN_MAX_Y]; +static u16 size_x = 16, size_y = 8; + +static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page); +static void grid_screen_refresh_led(scene_state_t *ss, u8 page); static bool grid_within_area(u8 x, u8 y, grid_common_t *gc); static void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level); +static void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page); void grid_refresh(scene_state_t *ss) { - s16 size_x = monome_size_x(); - s16 size_y = monome_size_y(); + size_x = monome_size_x(); + size_y = monome_size_y(); grid_fill_area(0, 0, size_x, size_y, 0); @@ -37,7 +50,8 @@ void grid_refresh(scene_state_t *ss) { } for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) - if (GBC.enabled && SG.group[GBC.group].enabled) grid_fill_area(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.background); + if (GBC.enabled && SG.group[GBC.group].enabled) + grid_fill_area(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.background); u16 led; for (u16 i = 0; i < size_x; i++) @@ -68,9 +82,8 @@ void grid_refresh(scene_state_t *ss) { monomeLedBuffer[total - i - 1] = temp; } } - - SG.refresh = 0; + SG.grid_dirty = 0; } void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z) { @@ -127,34 +140,137 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z) { for (u8 i = 0; i < SCRIPT_COUNT; i++) if (scripts[i]) run_script(ss, i); - SG.refresh = refresh; + SG.grid_dirty = SG.scr_dirty = refresh; +} + +void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page) { + for (int i = 0; i < 7; i++) region_fill(&line[i], 0); + switch (mode) { + case GRID_MODE_CTRL: + grid_screen_refresh_ctrl(ss, page); + break; + case GRID_MODE_LED: + grid_screen_refresh_led(ss, page); + break; + case GRID_MODE_OFF: + case GRID_MODE_LAST: + break; + } + SG.scr_dirty = 0; +} + +void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page) { } +void grid_screen_refresh_led(scene_state_t *ss, u8 page) { + grid_fill_area_scr(0, 0, SCREEN_MAX_X, SCREEN_MAX_Y, 0, 0); + + u16 x, y; + for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { + if (GXYC.enabled && SG.group[GXYC.group].enabled) { + if (GXY.value_x || GXY.value_y) { + x = GXYC.x + GXY.value_x; + y = GXYC.y + GXY.value_y; + grid_fill_area_scr(GXYC.x, y, GXYC.w, 1, GXYC.background, page); + grid_fill_area_scr(x, GXYC.y, 1, GXYC.h, GXYC.background, page); + grid_fill_area_scr(x, y, 1, 1, 15, page); + } + } + } + + for (u8 i = 0; i < GRID_FADER_COUNT; i++) { + if (GFC.enabled && SG.group[GFC.group].enabled) { + if (GF.dir) { + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.background, page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, 15, page); + } else { + grid_fill_area_scr(GFC.x, GFC.y, GF.value + 1, GFC.h, 15, page); + grid_fill_area_scr(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.background, page); + } + } + } + + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) + if (GBC.enabled && SG.group[GBC.group].enabled) + grid_fill_area_scr(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.background, page); + + for (u16 i = 0; i < SCREEN_MAX_X; i++) + for (u16 j = min_y[page]; j < max_y[page]; j++) { + if (SG.leds[i][j] >= 0) + screen[i][j] = SG.leds[i][j]; + else if (SG.leds[i][j] == LED_DIM) + screen[i][j] >>= 1; + else if (SG.leds[i][j] == LED_BRI) { + screen[i][j] <<= 1; + if (screen[i][j] > 15) screen[i][j] = 15; + else if (screen[i][j] < 1) screen[i][j] = 1; + } + } + + for (u16 x = 0; x < SCREEN_MAX_X; x++) + for (u16 y = 0; y < max_y[page]; y++) + for (u16 i = 0; i < 6; i++) + for (u16 j = 0; j < 6; j++) { + if ((j == 0 || j == 5) && (i == 0 || i == 5)) continue; + // line[0].data[0] = screen[x][y]; + } +} + + bool grid_within_area(u8 x, u8 y, grid_common_t *gc) { return x >= gc->x && x < (gc->x + gc->w) && y >= gc->y && y < (gc->y + gc->h); } void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level) { - s16 size_x = monome_size_x(); - s16 size_y = monome_size_y(); - if (level == LED_OFF) return; + u16 index; + u16 x_end = min(size_x, x + w); + u16 y_end = min(size_y, y + h); + if (level == LED_DIM) { - for (u16 _x = max(0, x); _x < min(size_x, x + w); _x++) - for (u16 _y = max(0, y); _y < min(size_y, y + h); _y++) + for (u16 _x = x; _x < x_end; _x++) + for (u16 _y = y; _y < y_end; _y++) monomeLedBuffer[_x + _y * size_x] >>= 1; } else if (level == LED_BRI) { - for (u16 _x = max(0, x); _x < min(size_x, x + w); _x++) - for (u16 _y = max(0, y); _y < min(size_y, y + h); _y++) { - monomeLedBuffer[_x + _y * size_x] <<= 1; - if (monomeLedBuffer[_x + _y * size_x] > 15) monomeLedBuffer[_x + _y * size_x] = 15; + for (u16 _x = x; _x < x_end; _x++) + for (u16 _y = y; _y < y_end; _y++) { + index = _x + _y * size_x; + monomeLedBuffer[index] <<= 1; + if (monomeLedBuffer[index] > 15) monomeLedBuffer[index] = 15; } } else { - for (u16 _x = max(0, x); _x < min(size_x, x + w); _x++) - for (u16 _y = max(0, y); _y < min(size_y, y + h); _y++) + for (u16 _x = x; _x < x_end; _x++) + for (u16 _y = y; _y < y_end; _y++) monomeLedBuffer[_x + _y * size_x] = level; } } + +void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page) { + if (level == LED_OFF) return; + + u16 x_end = min(SCREEN_MAX_X, x + w); + u16 y_start = max(min_y[page], y); + u16 y_end = min(max_y[page], y + h); + + if (level == LED_DIM) { + for (u16 _x = x; _x < x_end; _x++) { + for (u16 _y = y_start; _y < y_end; _y++) + screen[_x][_y - y_start] >>= 1; + } + + } else if (level == LED_BRI) { + for (u16 _x = x; _x < x_end; _x++) + for (u16 _y = y_start; _y < y_end; _y++) { + screen[_x][_y] <<= 1; + if (screen[_x][_y] > 15) screen[_x][_y] = 15; + } + + } else { + for (u16 _x = x; _x < x_end; _x++) + for (u16 _y = y_start; _y < y_end; _y++) + screen[_x][_y] = level; + } +} diff --git a/module/grid.h b/module/grid.h index 0350d8f4..5b984908 100644 --- a/module/grid.h +++ b/module/grid.h @@ -12,7 +12,17 @@ #define GXY ss->grid.xypad[i] #define GXYC ss->grid.xypad[i].common +typedef enum { + GRID_MODE_OFF = 0, + GRID_MODE_CTRL, + GRID_MODE_LED, + GRID_MODE_LAST +} screen_grid_mode; + + + extern void grid_refresh(scene_state_t *ss); +extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page); extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z); #endif diff --git a/module/live_mode.c b/module/live_mode.c index 9635c1a2..288031ef 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -31,11 +31,14 @@ static process_result_t output; static error_t status; static char error_msg[TELE_ERROR_MSG_LENGTH]; static bool show_welcome_message; +static screen_grid_mode grid_mode = GRID_MODE_OFF; +static uint8_t grid_page = 0; 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_VARS = 1 << 3; +static const uint8_t D_GRID = 1 << 4; static const uint8_t D_ALL = 0xFF; static uint8_t dirty; @@ -128,6 +131,11 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key) { dirty |= D_INPUT; } } + // C-g: toggle grid view + else if (match_ctrl(m, k, HID_G)) { + if (++grid_mode == GRID_MODE_LAST) grid_mode = GRID_MODE_OFF; + dirty |= D_GRID; + } // : execute command else if (match_no_mod(m, k, HID_ENTER)) { dirty |= D_MESSAGE; // something will definitely happen @@ -190,6 +198,11 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key) { uint8_t screen_refresh_live() { uint8_t screen_dirty = 0; + if ((dirty & D_GRID) || ss->grid.scr_dirty) { + grid_screen_refresh(ss, grid_mode, grid_page); + screen_dirty = true; + } + if (dirty & D_INPUT) { line_editor_draw(&le, '>', &line[7]); screen_dirty |= (1 << 7); @@ -275,7 +288,7 @@ uint8_t screen_refresh_live() { dirty &= ~D_LIST; } - if ((activity != activity_prev)) { + if ((grid_mode == GRID_MODE_OFF) && (activity != activity_prev)) { region_fill(&line[0], 0); // slew icon diff --git a/module/live_mode.h b/module/live_mode.h index 704ed12c..a3c699c0 100644 --- a/module/live_mode.h +++ b/module/live_mode.h @@ -3,13 +3,15 @@ #include "stdbool.h" #include "stdint.h" +#include "grid.h" +#include "state.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); -uint8_t screen_refresh_live(void); +uint8_t screen_refresh_live(scene_state_t *ss); void set_vars_updated(void); #endif diff --git a/module/main.c b/module/main.c index 14f3d377..9bdabcc4 100644 --- a/module/main.c +++ b/module/main.c @@ -269,7 +269,7 @@ static void monome_poll_timer_callback(void* obj) { // monome refresh callback static void monome_refresh_timer_callback(void* obj) { - if (scene_state.grid.refresh) { + if (scene_state.grid.grid_dirty) { static event_t e; e.type = kEventMonomeRefresh; event_post(&e); @@ -440,7 +440,7 @@ void handler_ScreenRefresh(int32_t data) { case M_PRESET_W: screen_dirty = screen_refresh_preset_w(); break; case M_PRESET_R: screen_dirty = screen_refresh_preset_r(); break; case M_HELP: screen_dirty = screen_refresh_help(); break; - case M_LIVE: screen_dirty = screen_refresh_live(); break; + case M_LIVE: screen_dirty = screen_refresh_live(&scene_state); break; case M_EDIT: screen_dirty = screen_refresh_edit(); break; case M_SCREENSAVER: screen_dirty = screen_refresh_screensaver(); break; } @@ -478,7 +478,7 @@ static void handler_FtdiDisconnect(s32 data) { static void handler_MonomeConnect(s32 data) { timers_set_monome(); - scene_state.grid.refresh = true; + scene_state.grid.grid_dirty = 1; } static void handler_MonomePoll(s32 data) { diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 15210e61..256ffd66 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -169,26 +169,26 @@ static void op_G_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GXY.value_y = 0; } - SG.refresh = true; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_CLR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *NOTUSED(cs)) { for (u8 i = 0; i < GRID_MAX_DIMENSION; i++) for (u8 j = 0; j < GRID_MAX_DIMENSION; j++) SG.leds[i][j] = LED_OFF; - SG.refresh = true; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_ROTATE_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 rotate = cs_pop(cs); SG.rotate = rotate; - SG.refresh = true; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_DIM_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { GET_AND_CLAMP(dim, 0, 14); SG.dim = dim; - SG.refresh = true; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GRP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -202,7 +202,7 @@ static void op_G_GRP_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_s s16 en = cs_pop(cs); if (group < 0 || group >= GRID_BUTTON_COUNT) return; SG.group[group].enabled = en; - SG.refresh = true; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GRP_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -235,7 +235,7 @@ static void op_G_GRP_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_ GXY.value_y = 0; } - SG.refresh = true; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GRP_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -245,7 +245,7 @@ static void op_G_GRP_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_s for (u8 i = 0; i < GRID_GROUP_COUNT; i++) SG.group[i].enabled = false; SG.group[group].enabled = true; - SG.refresh = true; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GRP_SC_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -271,7 +271,7 @@ static void op_G_LED_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat if (y < 0 || y >= GRID_MAX_DIMENSION) return; SG.leds[x][y] = level; - SG.refresh = true; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_LED_C_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -282,7 +282,7 @@ static void op_G_LED_C_get(const void *NOTUSED(data), scene_state_t *ss, exec_st if (y < 0 || y >= GRID_MAX_DIMENSION) return; SG.leds[x][y] = LED_OFF; - SG.refresh = true; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_REC_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -315,7 +315,7 @@ static void op_G_REC_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat for (s16 row = max(0, y); row < min(GRID_MAX_DIMENSION, y + h); row++) SG.leds[col][row] = border; - SG.refresh = true; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -342,7 +342,7 @@ static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GB.latch = latch != 0; // GB.state = 0; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -381,7 +381,7 @@ static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat // GB.state = 0; } - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTN_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -390,7 +390,7 @@ static void op_G_BTN_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_s if (i < 0 || i >= GRID_BUTTON_COUNT) return; GBC.enabled = en; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTN_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -403,7 +403,7 @@ static void op_G_BTN_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_st s16 value = cs_pop(cs); if (i < 0 || i >= GRID_BUTTON_COUNT) return; GB.state = value != 0; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -411,7 +411,7 @@ static void op_G_BTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_st GET_LEVEL(level); if (i < 0 || i >= GRID_BUTTON_COUNT) return; GBC.background = level; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTNI_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -425,7 +425,7 @@ static void op_G_BTNV_get(const void *NOTUSED(data), scene_state_t *ss, exec_sta static void op_G_BTNL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { GET_LEVEL(level); SG.button[SG.latest_button].common.background = level; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTN_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -436,7 +436,7 @@ static void op_G_BTN_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_s if (GBC.group == SG.button[id].common.group) GB.state = 0; SG.button[id].state = 1; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GBTN_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -448,7 +448,7 @@ static void op_G_GBTN_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_s for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.group == group) GB.state = value; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GBTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -464,7 +464,7 @@ static void op_G_GBTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_s GBC.background = is_odd ? odd : even; is_odd = !is_odd; } - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -491,7 +491,7 @@ static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GF.dir = dir != 0; // GF.value = 0; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -530,7 +530,7 @@ static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat // GF.value = 0; } - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDR_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -539,7 +539,7 @@ static void op_G_FDR_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_s if (i < 0 || i >= GRID_FADER_COUNT) return; GFC.enabled = en; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -564,7 +564,7 @@ static void op_G_FDR_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_st GF.value = scale(SG.group[GFC.group].fader_min, SG.group[GFC.group].fader_max, 0, GF.dir ? GFC.h - 1 : GFC.w - 1, value); - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -582,7 +582,7 @@ static void op_G_FDR_N_set(const void *NOTUSED(data), scene_state_t *ss, exec_st else if (!GF.dir && value >= GFC.w) value = GFC.w - 1; GF.value = value; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -590,7 +590,7 @@ static void op_G_FDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_st GET_LEVEL(level); if (i < 0 || i >= GRID_FADER_COUNT) return; GFC.background = level; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDRI_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -611,7 +611,7 @@ static void op_G_FDRN_get(const void *NOTUSED(data), scene_state_t *ss, exec_sta static void op_G_FDRL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { GET_LEVEL(level); SG.fader[SG.latest_fader].common.background = level; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GFDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -627,7 +627,7 @@ static void op_G_GFDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_s GF.value = scale(SG.group[group].fader_min, SG.group[group].fader_max, 0, GF.dir ? GFC.h - 1 : GFC.w - 1, value); - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GFDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -639,7 +639,7 @@ static void op_G_GFDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_s for (u16 i = 0; i < GRID_FADER_COUNT; i++) if (GFC.group == group) GF.value = min(GF.dir ? GFC.h - 1 : GFC.w - 1, value); - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GFDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -655,7 +655,7 @@ static void op_G_GFDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_s GFC.background = is_odd ? odd : even; is_odd = !is_odd; } - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GFDR_RN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -691,7 +691,7 @@ static void op_G_XYP_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GXY.value_x = 0; GXY.value_y = 0; - SG.refresh = 1; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_XYP_X_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { diff --git a/src/state.c b/src/state.c index ec9b0ddd..08ac622e 100644 --- a/src/state.c +++ b/src/state.c @@ -108,7 +108,7 @@ void ss_grid_init(scene_state_t *ss) { ss->grid.xypad[i].value_y = 0; } - ss->grid.refresh = true; + ss->grid.grid_dirty = ss->grid.scr_dirty = true; } void ss_grid_common_init(grid_common_t *gc) { diff --git a/src/state.h b/src/state.h index e31ea3c1..0a0c0e81 100644 --- a/src/state.h +++ b/src/state.h @@ -157,7 +157,9 @@ typedef struct { } grid_xypad_t; typedef struct { - u8 refresh; + u8 grid_dirty; + u8 scr_dirty; + u8 rotate; u8 dim; From ef1db3f9b1181899f3227c5808ddd2d46b9585e9 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 20 Oct 2017 12:42:37 -0700 Subject: [PATCH 004/117] grid visualizer pt2 --- module/grid.c | 43 +++++++++++------ module/grid.h | 2 +- module/live_mode.c | 118 ++++++++++++++++++++++++--------------------- 3 files changed, 94 insertions(+), 69 deletions(-) diff --git a/module/grid.c b/module/grid.c index b74b155f..4c93f486 100644 --- a/module/grid.c +++ b/module/grid.c @@ -7,13 +7,13 @@ #define SCREEN_MAX_Y 8 const u8 min_y[2] = {0, 8}; -const u8 max_y[2] = {7, 15}; +const u8 max_y[2] = {8, 16}; static u8 screen[SCREEN_MAX_X][SCREEN_MAX_Y]; static u16 size_x = 16, size_y = 8; -static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page); -static void grid_screen_refresh_led(scene_state_t *ss, u8 page); +static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 full_grid, u8 page); +static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page); static bool grid_within_area(u8 x, u8 y, grid_common_t *gc); static void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level); static void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page); @@ -143,14 +143,13 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z) { SG.grid_dirty = SG.scr_dirty = refresh; } -void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page) { - for (int i = 0; i < 7; i++) region_fill(&line[i], 0); +void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 full_grid, u8 page) { switch (mode) { case GRID_MODE_CTRL: - grid_screen_refresh_ctrl(ss, page); + grid_screen_refresh_ctrl(ss, full_grid, page); break; case GRID_MODE_LED: - grid_screen_refresh_led(ss, page); + grid_screen_refresh_led(ss, full_grid, page); break; case GRID_MODE_OFF: case GRID_MODE_LAST: @@ -159,10 +158,10 @@ void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page) { SG.scr_dirty = 0; } -void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page) { +void grid_screen_refresh_ctrl(scene_state_t *ss, u8 full_grid, u8 page) { } -void grid_screen_refresh_led(scene_state_t *ss, u8 page) { +void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page) { grid_fill_area_scr(0, 0, SCREEN_MAX_X, SCREEN_MAX_Y, 0, 0); u16 x, y; @@ -206,13 +205,29 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 page) { else if (screen[i][j] < 1) screen[i][j] = 1; } } - + + u16 _y, cell, size, left; + if (full_grid) { + cell = 8; + size = 6; + for (int i = 0; i < 8; i++) region_fill(&line[i], 0); + } else { + cell = 6; + size = 4; + for (int i = 0; i < 6; i++) region_fill(&line[i], 0); + } + left = (128 - (cell << 4)) >> 1; + for (u16 x = 0; x < SCREEN_MAX_X; x++) for (u16 y = 0; y < max_y[page]; y++) - for (u16 i = 0; i < 6; i++) - for (u16 j = 0; j < 6; j++) { - if ((j == 0 || j == 5) && (i == 0 || i == 5)) continue; - // line[0].data[0] = screen[x][y]; + for (u16 i = 0; i < size; i++) + for (u16 j = 0; j < size; j++) { + _y = y * cell + j; + if (screen[x][y] == 0) { + if (i == 0 || i == size - 1 || j == 0 || j == size - 1) + line[_y >> 3].data[left + x * cell + i + ((_y & 7) << 7)] = 1; + } else + line[_y >> 3].data[left + x * cell + i + ((_y & 7) << 7)] = screen[x][y]; } } diff --git a/module/grid.h b/module/grid.h index 5b984908..2b545a54 100644 --- a/module/grid.h +++ b/module/grid.h @@ -22,7 +22,7 @@ typedef enum { extern void grid_refresh(scene_state_t *ss); -extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page); +extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 full_grid, u8 page); extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z); #endif diff --git a/module/live_mode.c b/module/live_mode.c index 288031ef..12346b7c 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -32,7 +32,7 @@ static error_t status; static char error_msg[TELE_ERROR_MSG_LENGTH]; static bool show_welcome_message; static screen_grid_mode grid_mode = GRID_MODE_OFF; -static uint8_t grid_page = 0; +static uint8_t grid_page = 0, full_grid = 0; static const uint8_t D_INPUT = 1 << 0; static const uint8_t D_LIST = 1 << 1; @@ -136,6 +136,11 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key) { if (++grid_mode == GRID_MODE_LAST) grid_mode = GRID_MODE_OFF; dirty |= D_GRID; } + // Caps Lock: toggle full grid view + else if (match_no_mod(m, k, HID_CAPS_LOCK)) { + full_grid = !full_grid; + dirty |= D_GRID; + } // : execute command else if (match_no_mod(m, k, HID_ENTER)) { dirty |= D_MESSAGE; // something will definitely happen @@ -192,15 +197,20 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key) { bool processed = line_editor_process_keys(&le, k, m, is_held_key); if (processed) dirty |= D_INPUT; } + show_welcome_message = false; } -uint8_t screen_refresh_live() { - uint8_t screen_dirty = 0; - +bool screen_refresh_live(scene_state_t *ss) { + bool screen_dirty = 0; + bool update_activity = false; + if ((dirty & D_GRID) || ss->grid.scr_dirty) { - grid_screen_refresh(ss, grid_mode, grid_page); + grid_screen_refresh(ss, grid_mode, full_grid, grid_page); screen_dirty = true; + dirty &= ~D_GRID; + if (full_grid) return true; + update_activity = true; } if (dirty & D_INPUT) { @@ -288,73 +298,73 @@ uint8_t screen_refresh_live() { dirty &= ~D_LIST; } - if ((grid_mode == GRID_MODE_OFF) && (activity != activity_prev)) { - region_fill(&line[0], 0); + if (update_activity || activity != activity_prev) { + if (!update_activity) 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; + line[1].data[122 + 0 + 512] = slew_fg; + line[1].data[122 + 1 + 384] = slew_fg; + line[1].data[122 + 2 + 256] = slew_fg; + line[1].data[122 + 3 + 128] = slew_fg; + line[1].data[122 + 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; + line[2].data[122 + 0 + 0] = delay_fg; + line[2].data[122 + 1 + 0] = delay_fg; + line[2].data[122 + 2 + 0] = delay_fg; + line[2].data[122 + 3 + 0] = delay_fg; + line[2].data[122 + 4 + 0] = delay_fg; + line[2].data[122 + 0 + 128] = delay_fg; + line[2].data[122 + 0 + 256] = delay_fg; + line[2].data[122 + 0 + 384] = delay_fg; + line[2].data[122 + 0 + 512] = delay_fg; + line[2].data[122 + 4 + 128] = delay_fg; + line[2].data[122 + 4 + 256] = delay_fg; + line[2].data[122 + 4 + 384] = delay_fg; + line[2].data[122 + 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; + line[3].data[122 + 0 + 0] = stack_fg; + line[3].data[122 + 1 + 0] = stack_fg; + line[3].data[122 + 2 + 0] = stack_fg; + line[3].data[122 + 3 + 0] = stack_fg; + line[3].data[122 + 4 + 0] = stack_fg; + line[3].data[122 + 0 + 256] = stack_fg; + line[3].data[122 + 1 + 256] = stack_fg; + line[3].data[122 + 2 + 256] = stack_fg; + line[3].data[122 + 3 + 256] = stack_fg; + line[3].data[122 + 4 + 256] = stack_fg; + line[3].data[122 + 0 + 512] = stack_fg; + line[3].data[122 + 1 + 512] = stack_fg; + line[3].data[122 + 2 + 512] = stack_fg; + line[3].data[122 + 3 + 512] = stack_fg; + line[3].data[122 + 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; + line[4].data[122 + 0 + 0] = metro_fg; + line[4].data[122 + 0 + 128] = metro_fg; + line[4].data[122 + 0 + 256] = metro_fg; + line[4].data[122 + 0 + 384] = metro_fg; + line[4].data[122 + 0 + 512] = metro_fg; + line[4].data[122 + 1 + 128] = metro_fg; + line[4].data[122 + 2 + 256] = metro_fg; + line[4].data[122 + 3 + 128] = metro_fg; + line[4].data[122 + 4 + 0] = metro_fg; + line[4].data[122 + 4 + 128] = metro_fg; + line[4].data[122 + 4 + 256] = metro_fg; + line[4].data[122 + 4 + 384] = metro_fg; + line[4].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; + line[0].data[120 + i + stagger] = mute_fg; } activity_prev = activity; From 51b7056311116d7eddc6e0baa057595e5634a978 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sat, 28 Oct 2017 11:59:33 -0700 Subject: [PATCH 005/117] grid visualizer pt3 --- module/grid.c | 59 ++++++++++++----- module/grid.h | 8 ++- module/live_mode.c | 159 ++++++++++++++++++++++++++------------------- module/live_mode.h | 2 +- module/main.c | 22 +++++-- 5 files changed, 158 insertions(+), 92 deletions(-) diff --git a/module/grid.c b/module/grid.c index 4c93f486..45547a93 100644 --- a/module/grid.c +++ b/module/grid.c @@ -3,17 +3,14 @@ #include "state.h" #include "teletype.h" -#define SCREEN_MAX_X 16 -#define SCREEN_MAX_Y 8 - const u8 min_y[2] = {0, 8}; const u8 max_y[2] = {8, 16}; static u8 screen[SCREEN_MAX_X][SCREEN_MAX_Y]; static u16 size_x = 16, size_y = 8; -static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 full_grid, u8 page); -static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page); +static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page); +static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 sel_x, u8 sel_y); static bool grid_within_area(u8 x, u8 y, grid_common_t *gc); static void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level); static void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page); @@ -143,13 +140,16 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z) { SG.grid_dirty = SG.scr_dirty = refresh; } -void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 full_grid, u8 page) { +void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x, u8 y) { switch (mode) { - case GRID_MODE_CTRL: - grid_screen_refresh_ctrl(ss, full_grid, page); - break; case GRID_MODE_LED: - grid_screen_refresh_led(ss, full_grid, page); + grid_screen_refresh_led(ss, 0, page, x, y); + break; + //case GRID_MODE_CTRL: + // grid_screen_refresh_ctrl(ss, page); + // break; + case GRID_MODE_FULL: + grid_screen_refresh_led(ss, 1, page, x, y); break; case GRID_MODE_OFF: case GRID_MODE_LAST: @@ -158,10 +158,31 @@ void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 full_grid, SG.scr_dirty = 0; } -void grid_screen_refresh_ctrl(scene_state_t *ss, u8 full_grid, u8 page) { +void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page) { + /* + grid_fill_area_scr(0, 0, SCREEN_MAX_X, SCREEN_MAX_Y, 0, 0); + + u8 level; + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { + if (!SG.group[GBC.group].enabled) continue; + level = (GBC.enabled ? (GB.state ? 15 : 8) : 1) << 4; + if (GBC.w == 1 && GBC.h == 1) { + grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 1, page); + } else if (GBC.w == 1 && GBC.h > 1) { + grid_fill_area_scr(GBC.x, GBC.y + 1, 1, GBC.h - 2, level + 2, page); + grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 3, page); + grid_fill_area_scr(GBC.x, GBC.y + GBC.h - 1, 1, 1, level + 4, page); + } else if (GBC.w > 1 && GBC.h == 1) { + grid_fill_area_scr(GBC.x + 1, GBC.y, GBC.w - 2, 1, level + 5, page); + grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 6, page); + grid_fill_area_scr(GBC.x + GBC.w - 1, GBC.y, 1, 1, level + 7, page); + } else { + } + } + */ } -void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page) { +void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 sel_x, u8 sel_y) { grid_fill_area_scr(0, 0, SCREEN_MAX_X, SCREEN_MAX_Y, 0, 0); u16 x, y; @@ -222,13 +243,21 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page) { for (u16 y = 0; y < max_y[page]; y++) for (u16 i = 0; i < size; i++) for (u16 j = 0; j < size; j++) { - _y = y * cell + j; + _y = y * cell + j + 1; if (screen[x][y] == 0) { if (i == 0 || i == size - 1 || j == 0 || j == size - 1) - line[_y >> 3].data[left + x * cell + i + ((_y & 7) << 7)] = 1; + line[_y >> 3].data[left + x * cell + i + ((_y & 7) << 7) + 1] = 1; } else - line[_y >> 3].data[left + x * cell + i + ((_y & 7) << 7)] = screen[x][y]; + line[_y >> 3].data[left + x * cell + i + ((_y & 7) << 7) + 1] = screen[x][y]; } + + for (u16 i = 0; i < cell; i++) + for (u16 j = 0; j < cell; j++) { + if (i == 0 || i == cell - 1 || j == 0 || j == cell - 1) { + _y = sel_y * cell + j; + line[_y >> 3].data[left + sel_x * cell + i + ((_y & 7) << 7)] = 8; + } + } } diff --git a/module/grid.h b/module/grid.h index 2b545a54..b63315cf 100644 --- a/module/grid.h +++ b/module/grid.h @@ -4,6 +4,9 @@ #include "monome.h" #include "state.h" +#define SCREEN_MAX_X 16 +#define SCREEN_MAX_Y 8 + #define SG ss->grid #define GB ss->grid.button[i] #define GBC ss->grid.button[i].common @@ -14,15 +17,16 @@ typedef enum { GRID_MODE_OFF = 0, - GRID_MODE_CTRL, GRID_MODE_LED, + //GRID_MODE_CTRL, + GRID_MODE_FULL, GRID_MODE_LAST } screen_grid_mode; extern void grid_refresh(scene_state_t *ss); -extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 full_grid, u8 page); +extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x, u8 y); extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z); #endif diff --git a/module/live_mode.c b/module/live_mode.c index 12346b7c..63fe1f59 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -32,13 +32,12 @@ static error_t status; static char error_msg[TELE_ERROR_MSG_LENGTH]; static bool show_welcome_message; static screen_grid_mode grid_mode = GRID_MODE_OFF; -static uint8_t grid_page = 0, full_grid = 0; +static uint8_t grid_page = 0, grid_view_changed = 0, grid_x = 0, grid_y = 0; 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_VARS = 1 << 3; -static const uint8_t D_GRID = 1 << 4; static const uint8_t D_ALL = 0xFF; static uint8_t dirty; @@ -108,9 +107,17 @@ void set_live_mode() { history_line = -1; dirty = D_ALL; activity_prev = 0xFF; + grid_view_changed = true; } -void process_live_keys(uint8_t k, uint8_t m, bool is_held_key) { +void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, scene_state_t *ss) { + if (is_release) { + if (match_ctrl(m, k, HID_SPACEBAR)) { + grid_process_key(ss, grid_x, grid_y, 0); + } + return; + } + // or C-n: history next if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) { if (history_line > 0) { @@ -131,15 +138,35 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key) { dirty |= D_INPUT; } } - // C-g: toggle grid view + // C-G: toggle grid view else if (match_ctrl(m, k, HID_G)) { - if (++grid_mode == GRID_MODE_LAST) grid_mode = GRID_MODE_OFF; - dirty |= D_GRID; + if (++grid_mode == GRID_MODE_LAST) { + grid_mode = GRID_MODE_OFF; + set_live_mode(); + } else grid_view_changed = true; + } + // C-: move grid cursor + else if (match_ctrl(m, k, HID_UP)) { + grid_y = (grid_y + SCREEN_MAX_Y - 1) % SCREEN_MAX_Y; + grid_view_changed = true; } - // Caps Lock: toggle full grid view - else if (match_no_mod(m, k, HID_CAPS_LOCK)) { - full_grid = !full_grid; - dirty |= D_GRID; + // C-: move grid cursor + else if (match_ctrl(m, k, HID_DOWN)) { + grid_y = (grid_y + 1) % SCREEN_MAX_Y; + grid_view_changed = true; + } + // C-: move grid cursor + else if (match_ctrl(m, k, HID_LEFT)) { + grid_x = (grid_x + SCREEN_MAX_X - 1) % SCREEN_MAX_X; + grid_view_changed = true; + } + // C-: move grid cursor + else if (match_ctrl(m, k, HID_RIGHT)) { + grid_x = (grid_x + 1) % SCREEN_MAX_X; + grid_view_changed = true; + } + else if (match_ctrl(m, k, HID_SPACEBAR)) { + grid_process_key(ss, grid_x, grid_y, 1); } // : execute command else if (match_no_mod(m, k, HID_ENTER)) { @@ -202,16 +229,14 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key) { bool screen_refresh_live(scene_state_t *ss) { - bool screen_dirty = 0; - bool update_activity = false; + uint8_t screen_dirty = 0; - if ((dirty & D_GRID) || ss->grid.scr_dirty) { - grid_screen_refresh(ss, grid_mode, full_grid, grid_page); + if (grid_mode != GRID_MODE_OFF && (grid_view_changed || ss->grid.scr_dirty)) { + grid_view_changed = 0; screen_dirty = true; - dirty &= ~D_GRID; - if (full_grid) return true; - update_activity = true; + grid_screen_refresh(ss, grid_mode, grid_page, grid_x, grid_y); } + if (grid_mode == GRID_MODE_FULL) return true; if (dirty & D_INPUT) { line_editor_draw(&le, '>', &line[7]); @@ -298,73 +323,73 @@ bool screen_refresh_live(scene_state_t *ss) { dirty &= ~D_LIST; } - if (update_activity || activity != activity_prev) { - if (!update_activity) region_fill(&line[0], 0); + if (activity != activity_prev && grid_mode == GRID_MODE_OFF) { + region_fill(&line[0], 0); // slew icon uint8_t slew_fg = activity & A_SLEW ? 15 : 1; - line[1].data[122 + 0 + 512] = slew_fg; - line[1].data[122 + 1 + 384] = slew_fg; - line[1].data[122 + 2 + 256] = slew_fg; - line[1].data[122 + 3 + 128] = slew_fg; - line[1].data[122 + 4 + 0] = slew_fg; - + 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[2].data[122 + 0 + 0] = delay_fg; - line[2].data[122 + 1 + 0] = delay_fg; - line[2].data[122 + 2 + 0] = delay_fg; - line[2].data[122 + 3 + 0] = delay_fg; - line[2].data[122 + 4 + 0] = delay_fg; - line[2].data[122 + 0 + 128] = delay_fg; - line[2].data[122 + 0 + 256] = delay_fg; - line[2].data[122 + 0 + 384] = delay_fg; - line[2].data[122 + 0 + 512] = delay_fg; - line[2].data[122 + 4 + 128] = delay_fg; - line[2].data[122 + 4 + 256] = delay_fg; - line[2].data[122 + 4 + 384] = delay_fg; - line[2].data[122 + 4 + 512] = delay_fg; + 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[3].data[122 + 0 + 0] = stack_fg; - line[3].data[122 + 1 + 0] = stack_fg; - line[3].data[122 + 2 + 0] = stack_fg; - line[3].data[122 + 3 + 0] = stack_fg; - line[3].data[122 + 4 + 0] = stack_fg; - line[3].data[122 + 0 + 256] = stack_fg; - line[3].data[122 + 1 + 256] = stack_fg; - line[3].data[122 + 2 + 256] = stack_fg; - line[3].data[122 + 3 + 256] = stack_fg; - line[3].data[122 + 4 + 256] = stack_fg; - line[3].data[122 + 0 + 512] = stack_fg; - line[3].data[122 + 1 + 512] = stack_fg; - line[3].data[122 + 2 + 512] = stack_fg; - line[3].data[122 + 3 + 512] = stack_fg; - line[3].data[122 + 4 + 512] = stack_fg; + 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[4].data[122 + 0 + 0] = metro_fg; - line[4].data[122 + 0 + 128] = metro_fg; - line[4].data[122 + 0 + 256] = metro_fg; - line[4].data[122 + 0 + 384] = metro_fg; - line[4].data[122 + 0 + 512] = metro_fg; - line[4].data[122 + 1 + 128] = metro_fg; - line[4].data[122 + 2 + 256] = metro_fg; - line[4].data[122 + 3 + 128] = metro_fg; - line[4].data[122 + 4 + 0] = metro_fg; - line[4].data[122 + 4 + 128] = metro_fg; - line[4].data[122 + 4 + 256] = metro_fg; - line[4].data[122 + 4 + 384] = metro_fg; - line[4].data[122 + 4 + 512] = metro_fg; + 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[120 + i + stagger] = mute_fg; + line[0].data[87 + i + stagger] = mute_fg; } activity_prev = activity; diff --git a/module/live_mode.h b/module/live_mode.h index a3c699c0..963a367e 100644 --- a/module/live_mode.h +++ b/module/live_mode.h @@ -10,7 +10,7 @@ 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); +void process_live_keys(uint8_t key, uint8_t mod_key, bool is_held_key, bool is_release, scene_state_t *ss); uint8_t screen_refresh_live(scene_state_t *ss); void set_vars_updated(void); diff --git a/module/main.c b/module/main.c index 9bdabcc4..d40742c4 100644 --- a/module/main.c +++ b/module/main.c @@ -163,7 +163,7 @@ static void assign_msc_event_handlers(void); static void check_events(void); // key handling -static void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key); +static void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key, bool is_release); static bool process_global_keys(uint8_t key, uint8_t mod_key, bool is_held_key); // start/stop monome polling/refresh timers @@ -359,7 +359,7 @@ void handler_KeyTimer(int32_t data) { if (hold_key) { if (hold_key_count > 4) - process_keypress(hold_key, mod_key, true); + process_keypress(hold_key, mod_key, true, false); else hold_key_count++; } @@ -381,8 +381,9 @@ void handler_HidTimer(int32_t data) { if (frame[i] == 0) { mod_key = frame[0]; if (i == 2) { - hold_key = 0; hold_key_count = 0; + process_keypress(hold_key, mod_key, false, true); + hold_key = 0; } break; @@ -391,7 +392,7 @@ void handler_HidTimer(int32_t data) { if (frame_compare(frame[i]) == false) { hold_key = frame[i]; hold_key_count = 0; - process_keypress(hold_key, mod_key, false); + process_keypress(hold_key, mod_key, false, false); } } @@ -599,7 +600,7 @@ void set_last_mode() { //////////////////////////////////////////////////////////////////////////////// // key handling -void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key) { +void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key, bool is_release) { // reset inactivity counter ss_counter = 0; if (mode == M_SCREENSAVER) { @@ -608,14 +609,21 @@ void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key) { return; #endif } - + + // release is a special case for live mode + if (is_release) { + if (mode == M_LIVE) + process_live_keys(key, mod_key, is_held_key, true, &scene_state); + return; + } + // first try global keys if (process_global_keys(key, mod_key, is_held_key)) return; switch (mode) { case M_EDIT: process_edit_keys(key, mod_key, is_held_key); break; - case M_LIVE: process_live_keys(key, mod_key, is_held_key); break; + case M_LIVE: process_live_keys(key, mod_key, is_held_key, false, &scene_state); break; case M_PATTERN: process_pattern_keys(key, mod_key, is_held_key); break; case M_PRESET_W: process_preset_w_keys(key, mod_key, is_held_key); From f21529b717871a32f93a2cb1040a99e6e5770cca Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sat, 28 Oct 2017 12:31:42 -0700 Subject: [PATCH 006/117] bug fixes --- module/grid.c | 29 +++++++++++++++++------------ src/state.c | 1 - src/state.h | 1 - 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/module/grid.c b/module/grid.c index 45547a93..315022d2 100644 --- a/module/grid.c +++ b/module/grid.c @@ -54,6 +54,8 @@ void grid_refresh(scene_state_t *ss) { for (u16 i = 0; i < size_x; i++) for (u16 j = 0; j < size_y; j++) { led = j * size_x + i; + if (led >= MONOME_MAX_LED_BYTES) continue; + if (SG.leds[i][j] >= 0) monomeLedBuffer[led] = SG.leds[i][j]; else if (SG.leds[i][j] == LED_DIM) @@ -72,6 +74,7 @@ void grid_refresh(scene_state_t *ss) { if (SG.rotate) { u16 total = size_x * size_y; + if (total > MONOME_MAX_LED_BYTES) total = MONOME_MAX_LED_BYTES; u8 temp; for (u16 i = 0; i < (total >> 1); i++) { temp = monomeLedBuffer[i]; @@ -116,12 +119,8 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z) { if (GBC.enabled && SG.group[GBC.group].enabled && grid_within_area(x, y, &GBC)) { if (GB.latch) { if (z) { - if (++GB.press_count == 1) { - GB.state = !GB.state; - if (GBC.script != -1) scripts[GBC.script] = 1; - } - } else { - GB.press_count--; + GB.state = !GB.state; + if (GBC.script != -1) scripts[GBC.script] = 1; } } else { GB.state = z; @@ -274,21 +273,27 @@ void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level) { if (level == LED_DIM) { for (u16 _x = x; _x < x_end; _x++) - for (u16 _y = y; _y < y_end; _y++) - monomeLedBuffer[_x + _y * size_x] >>= 1; + for (u16 _y = y; _y < y_end; _y++) { + index = _x + _y * size_x; + if (index < MONOME_MAX_LED_BYTES) monomeLedBuffer[index] >>= 1; + } } else if (level == LED_BRI) { for (u16 _x = x; _x < x_end; _x++) for (u16 _y = y; _y < y_end; _y++) { index = _x + _y * size_x; - monomeLedBuffer[index] <<= 1; - if (monomeLedBuffer[index] > 15) monomeLedBuffer[index] = 15; + if (index < MONOME_MAX_LED_BYTES) { + monomeLedBuffer[index] <<= 1; + if (monomeLedBuffer[index] > 15) monomeLedBuffer[index] = 15; + } } } else { for (u16 _x = x; _x < x_end; _x++) - for (u16 _y = y; _y < y_end; _y++) - monomeLedBuffer[_x + _y * size_x] = level; + for (u16 _y = y; _y < y_end; _y++) { + index = _x + _y * size_x; + if (index < MONOME_MAX_LED_BYTES) monomeLedBuffer[index] = level; + } } } diff --git a/src/state.c b/src/state.c index 08ac622e..46cdc3b3 100644 --- a/src/state.c +++ b/src/state.c @@ -93,7 +93,6 @@ void ss_grid_init(scene_state_t *ss) { ss_grid_common_init(&(ss->grid.button[i].common)); ss->grid.button[i].latch = 0; ss->grid.button[i].state = 0; - ss->grid.button[i].press_count = 0; } for (u8 i = 0; i < GRID_FADER_COUNT; i++) { diff --git a/src/state.h b/src/state.h index 0a0c0e81..05e47ecd 100644 --- a/src/state.h +++ b/src/state.h @@ -141,7 +141,6 @@ typedef struct { grid_common_t common; u8 latch; u8 state; - u8 press_count; } grid_button_t; typedef struct { From 843b2d10300fff8ccdae7e554f2f2714739872ab Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 29 Oct 2017 10:50:38 -0700 Subject: [PATCH 007/117] grid visualizer pt4 --- module/grid.c | 262 ++++++++++++++++++++++++++++++++------- module/grid.h | 2 +- module/keyboard_helper.h | 5 + module/live_mode.c | 98 +++++++++++---- src/ops/grid_ops.c | 5 +- 5 files changed, 304 insertions(+), 68 deletions(-) diff --git a/module/grid.c b/module/grid.c index 315022d2..f96b7633 100644 --- a/module/grid.c +++ b/module/grid.c @@ -1,7 +1,9 @@ +#include "font.h" #include "grid.h" #include "globals.h" #include "state.h" #include "teletype.h" +#include "util.h" const u8 min_y[2] = {0, 8}; const u8 max_y[2] = {8, 16}; @@ -9,8 +11,9 @@ const u8 max_y[2] = {8, 16}; static u8 screen[SCREEN_MAX_X][SCREEN_MAX_Y]; static u16 size_x = 16, size_y = 8; -static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page); -static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 sel_x, u8 sel_y); +static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); +static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); +static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); static bool grid_within_area(u8 x, u8 y, grid_common_t *gc); static void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level); static void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page); @@ -139,16 +142,57 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z) { SG.grid_dirty = SG.scr_dirty = refresh; } -void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x, u8 y) { +bool grid_within_area(u8 x, u8 y, grid_common_t *gc) { + return x >= gc->x && x < (gc->x + gc->w) && y >= gc->y && y < (gc->y + gc->h); +} + +void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level) { + if (level == LED_OFF) return; + + u16 index; + u16 x_end = min(size_x, x + w); + u16 y_end = min(size_y, y + h); + + if (level == LED_DIM) { + for (u16 _x = x; _x < x_end; _x++) + for (u16 _y = y; _y < y_end; _y++) { + index = _x + _y * size_x; + if (index < MONOME_MAX_LED_BYTES) monomeLedBuffer[index] >>= 1; + } + + } else if (level == LED_BRI) { + for (u16 _x = x; _x < x_end; _x++) + for (u16 _y = y; _y < y_end; _y++) { + index = _x + _y * size_x; + if (index < MONOME_MAX_LED_BYTES) { + monomeLedBuffer[index] <<= 1; + if (monomeLedBuffer[index] > 15) monomeLedBuffer[index] = 15; + } + } + + } else { + for (u16 _x = x; _x < x_end; _x++) + for (u16 _y = y; _y < y_end; _y++) { + index = _x + _y * size_x; + if (index < MONOME_MAX_LED_BYTES) monomeLedBuffer[index] = level; + } + } +} + +// screen functions + +void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { switch (mode) { case GRID_MODE_LED: - grid_screen_refresh_led(ss, 0, page, x, y); + grid_screen_refresh_led(ss, 0, page, x1, y1, x2, y2); + grid_screen_refresh_info(ss, page, x1, y1, x2, y2); break; //case GRID_MODE_CTRL: // grid_screen_refresh_ctrl(ss, page); + // grid_screen_refresh_info(ss, page, x1, y1, x2, y2); // break; case GRID_MODE_FULL: - grid_screen_refresh_led(ss, 1, page, x, y); + grid_screen_refresh_led(ss, 1, page, x1, y1, x2, y2); break; case GRID_MODE_OFF: case GRID_MODE_LAST: @@ -157,7 +201,7 @@ void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x SG.scr_dirty = 0; } -void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page) { +void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { /* grid_fill_area_scr(0, 0, SCREEN_MAX_X, SCREEN_MAX_Y, 0, 0); @@ -181,7 +225,7 @@ void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page) { */ } -void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 sel_x, u8 sel_y) { +void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { grid_fill_area_scr(0, 0, SCREEN_MAX_X, SCREEN_MAX_Y, 0, 0); u16 x, y; @@ -230,13 +274,14 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 sel_x, if (full_grid) { cell = 8; size = 6; + left = 0; for (int i = 0; i < 8; i++) region_fill(&line[i], 0); } else { cell = 6; size = 4; + left = 10; for (int i = 0; i < 6; i++) region_fill(&line[i], 0); } - left = (128 - (cell << 4)) >> 1; for (u16 x = 0; x < SCREEN_MAX_X; x++) for (u16 y = 0; y < max_y[page]; y++) @@ -250,51 +295,180 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 sel_x, line[_y >> 3].data[left + x * cell + i + ((_y & 7) << 7) + 1] = screen[x][y]; } - for (u16 i = 0; i < cell; i++) - for (u16 j = 0; j < cell; j++) { - if (i == 0 || i == cell - 1 || j == 0 || j == cell - 1) { - _y = sel_y * cell + j; - line[_y >> 3].data[left + sel_x * cell + i + ((_y & 7) << 7)] = 8; + u16 area_x, area_y, area_w, area_h; + if (x1 < x2) { + area_x = x1 * cell; + area_w = (x2 + 1 - x1) * cell; + } else { + area_x = x2 * cell; + area_w = (x1 + 1 - x2) * cell; + } + if (y1 < y2) { + area_y = y1 * cell; + area_h = (y2 + 1 - y1) * cell; + } else { + area_y = y2 * cell; + area_h = (y1 + 1 - y2) * cell; + } + + for (u16 i = 0; i < area_w; i++) + for (u16 j = 0; j < area_h; j++) { + if (i == 0 || i == area_w - 1 || j == 0 || j == area_h - 1) { + _y = area_y + j; + line[_y >> 3].data[left + i + area_x + ((_y & 7) << 7)] = 8; } } } +static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { + char s[32]; + u16 area_x, area_y, area_w, area_h; -bool grid_within_area(u8 x, u8 y, grid_common_t *gc) { - return x >= gc->x && x < (gc->x + gc->w) && y >= gc->y && y < (gc->y + gc->h); -} + if (x1 < x2) { + area_x = x1; + area_w = x2 + 1 - x1; + } else { + area_x = x2; + area_w = x1 + 1 - x2; + } + if (y1 < y2) { + area_y = y1; + area_h = y2 + 1 - y1; + } else { + area_y = y2; + area_h = y1 + 1 - y2; + } -void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level) { - if (level == LED_OFF) return; + s[1] = 0; + s[0] = 'X'; + font_string_region_clip_right(&line[2], s, 127, 0, 1, 0); + s[0] = 'Y'; + font_string_region_clip_right(&line[3], s, 127, 0, 1, 0); + s[0] = 'W'; + font_string_region_clip_right(&line[4], s, 128, 0, 1, 0); + s[0] = 'H'; + font_string_region_clip_right(&line[5], s, 127, 0, 1, 0); + + itoa(area_x, s, 10); + font_string_region_clip_right(&line[2], s, 117, 0, 8, 0); + itoa(area_y, s, 10); + font_string_region_clip_right(&line[3], s, 117, 0, 8, 0); + itoa(area_w, s, 10); + font_string_region_clip_right(&line[4], s, 117, 0, 8, 0); + itoa(area_h, s, 10); + font_string_region_clip_right(&line[5], s, 117, 0, 8, 0); - u16 index; - u16 x_end = min(size_x, x + w); - u16 y_end = min(size_y, y + h); + for (u16 j = 17; j < 48; j += 2) line[j >> 3].data[119 + ((j & 7) << 7)] = 1; + + u8 l; + l = ss->grid.group[0].enabled ? 8 : 1; + line[0].data[128 + 3] = l; + line[0].data[256 + 2] = l; + line[0].data[256 + 4] = l; + line[0].data[384 + 2] = l; + line[0].data[384 + 4] = l; + line[0].data[512 + 2] = l; + line[0].data[512 + 4] = l; + line[0].data[640 + 3] = l; - if (level == LED_DIM) { - for (u16 _x = x; _x < x_end; _x++) - for (u16 _y = y; _y < y_end; _y++) { - index = _x + _y * size_x; - if (index < MONOME_MAX_LED_BYTES) monomeLedBuffer[index] >>= 1; - } + l = ss->grid.group[1].enabled ? 8 : 1; + line[0].data[896 + 4] = l; + line[1].data[ 0 + 3] = l; + line[1].data[ 0 + 4] = l; + line[1].data[128 + 4] = l; + line[1].data[256 + 4] = l; + line[1].data[384 + 4] = l; - } else if (level == LED_BRI) { - for (u16 _x = x; _x < x_end; _x++) - for (u16 _y = y; _y < y_end; _y++) { - index = _x + _y * size_x; - if (index < MONOME_MAX_LED_BYTES) { - monomeLedBuffer[index] <<= 1; - if (monomeLedBuffer[index] > 15) monomeLedBuffer[index] = 15; - } - } - - } else { - for (u16 _x = x; _x < x_end; _x++) - for (u16 _y = y; _y < y_end; _y++) { - index = _x + _y * size_x; - if (index < MONOME_MAX_LED_BYTES) monomeLedBuffer[index] = level; - } - } + l = ss->grid.group[2].enabled ? 8 : 1; + line[1].data[640 + 2] = l; + line[1].data[640 + 3] = l; + line[1].data[768 + 4] = l; + line[1].data[896 + 3] = l; + line[2].data[ 0 + 2] = l; + line[2].data[128 + 2] = l; + line[2].data[128 + 3] = l; + line[2].data[128 + 4] = l; + + l = ss->grid.group[3].enabled ? 8 : 1; + line[2].data[384 + 2] = l; + line[2].data[384 + 3] = l; + line[2].data[384 + 4] = l; + line[2].data[512 + 4] = l; + line[2].data[640 + 3] = l; + line[2].data[768 + 4] = l; + line[2].data[896 + 2] = l; + line[2].data[896 + 3] = l; + + l = ss->grid.group[4].enabled ? 8 : 1; + line[3].data[128 + 2] = l; + line[3].data[128 + 4] = l; + line[3].data[256 + 2] = l; + line[3].data[256 + 4] = l; + line[3].data[384 + 2] = l; + line[3].data[384 + 3] = l; + line[3].data[384 + 4] = l; + line[3].data[512 + 4] = l; + line[3].data[640 + 4] = l; + + l = ss->grid.group[5].enabled ? 8 : 1; + line[3].data[896 + 2] = l; + line[3].data[896 + 3] = l; + line[3].data[896 + 4] = l; + line[4].data[ 0 + 2] = l; + line[4].data[128 + 2] = l; + line[4].data[128 + 3] = l; + line[4].data[256 + 4] = l; + line[4].data[384 + 2] = l; + line[4].data[384 + 3] = l; + + l = ss->grid.group[6].enabled ? 8 : 1; + line[4].data[640 + 3] = l; + line[4].data[640 + 4] = l; + line[4].data[768 + 2] = l; + line[4].data[896 + 2] = l; + line[4].data[896 + 3] = l; + line[5].data[ 0 + 2] = l; + line[5].data[ 0 + 4] = l; + line[5].data[128 + 3] = l; + + l = ss->grid.group[7].enabled ? 8 : 1; + line[5].data[384 + 2] = l; + line[5].data[384 + 3] = l; + line[5].data[384 + 4] = l; + line[5].data[512 + 4] = l; + line[5].data[640 + 3] = l; + line[5].data[768 + 3] = l; + line[5].data[896 + 3] = l; + + for (u16 j = ss->grid.current_group * 6 + 1; j < ss->grid.current_group * 6 + 6; j++) + line[j >> 3].data[(j & 7) << 7] = 2; + + l = page == 0 ? 8 : 2; + for (u16 i = 122; i < 128; i++) line[0].data[i + 128] = l; + line[0].data[122 + 256] = l; + line[0].data[127 + 256] = l; + line[0].data[122 + 384] = l; + line[0].data[127 + 384] = l; + + l = page == 1 ? 8 : 2; + line[0].data[122 + 512] = l; + line[0].data[127 + 512] = l; + line[0].data[122 + 640] = l; + line[0].data[127 + 640] = l; + for (u16 i = 122; i < 128; i++) line[0].data[i + 768] = l; + + l = ss->grid.rotate ? 8 : 2; + line[1].data[128 + 123] = l; + line[1].data[128 + 124] = l; + line[1].data[128 + 125] = l; + line[1].data[256 + 122] = l; + line[1].data[256 + 126] = l; + line[1].data[384 + 122] = l; + line[1].data[384 + 126] = l; + line[1].data[512 + 125] = l; + line[1].data[512 + 126] = l; + line[1].data[512 + 127] = l; + line[1].data[640 + 126] = l; } void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page) { diff --git a/module/grid.h b/module/grid.h index b63315cf..eb4c4c7b 100644 --- a/module/grid.h +++ b/module/grid.h @@ -26,7 +26,7 @@ typedef enum { extern void grid_refresh(scene_state_t *ss); -extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x, u8 y); +extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z); #endif diff --git a/module/keyboard_helper.h b/module/keyboard_helper.h index 183f64c1..637ff404 100644 --- a/module/keyboard_helper.h +++ b/module/keyboard_helper.h @@ -76,6 +76,11 @@ static inline bool match_shift_alt(uint8_t mod, uint8_t key, return mod_only_shift_alt(mod) && key == required_key; } +static inline bool match_shift_ctrl(uint8_t mod, uint8_t key, + uint8_t required_key) { + return mod_only_shift_ctrl(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; } diff --git a/module/live_mode.c b/module/live_mode.c index 63fe1f59..6d69cfaf 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -32,7 +32,8 @@ static error_t status; static char error_msg[TELE_ERROR_MSG_LENGTH]; static bool show_welcome_message; static screen_grid_mode grid_mode = GRID_MODE_OFF; -static uint8_t grid_page = 0, grid_view_changed = 0, grid_x = 0, grid_y = 0; +static uint8_t grid_page = 0, grid_view_changed = 0; +static uint8_t grid_x1 = 0, grid_y1 = 0, grid_x2 = 0, grid_y2 = 0; static const uint8_t D_INPUT = 1 << 0; static const uint8_t D_LIST = 1 << 1; @@ -112,14 +113,16 @@ void set_live_mode() { void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, scene_state_t *ss) { if (is_release) { - if (match_ctrl(m, k, HID_SPACEBAR)) { - grid_process_key(ss, grid_x, grid_y, 0); + if (match_ctrl(m, k, HID_SPACEBAR) || + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SPACEBAR))) { + grid_process_key(ss, grid_x1, grid_y1, 0); } return; } // or C-n: history next - if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) { + if ((match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) + && grid_mode != GRID_MODE_FULL) { if (history_line > 0) { history_line--; line_editor_set_command(&le, &history[history_line]); @@ -131,7 +134,8 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, dirty |= D_INPUT; } // or C-p: history previous - else if (match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) { + else if ((match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) + && grid_mode != GRID_MODE_FULL) { if (history_line < history_top) { history_line++; line_editor_set_command(&le, &history[history_line]); @@ -139,37 +143,87 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, } } // C-G: toggle grid view - else if (match_ctrl(m, k, HID_G)) { + else if (match_ctrl(m, k, HID_G) || + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_G))) { if (++grid_mode == GRID_MODE_LAST) { grid_mode = GRID_MODE_OFF; set_live_mode(); } else grid_view_changed = true; } // C-: move grid cursor - else if (match_ctrl(m, k, HID_UP)) { - grid_y = (grid_y + SCREEN_MAX_Y - 1) % SCREEN_MAX_Y; + else if (match_ctrl(m, k, HID_UP) || + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_UP))) { + grid_y1 = (grid_y1 + SCREEN_MAX_Y - 1) % SCREEN_MAX_Y; + grid_x2 = grid_x1; + grid_y2 = grid_y1; grid_view_changed = true; } // C-: move grid cursor - else if (match_ctrl(m, k, HID_DOWN)) { - grid_y = (grid_y + 1) % SCREEN_MAX_Y; + else if (match_ctrl(m, k, HID_DOWN) || + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_DOWN))) { + grid_y1 = (grid_y1 + 1) % SCREEN_MAX_Y; + grid_x2 = grid_x1; + grid_y2 = grid_y1; grid_view_changed = true; } // C-: move grid cursor - else if (match_ctrl(m, k, HID_LEFT)) { - grid_x = (grid_x + SCREEN_MAX_X - 1) % SCREEN_MAX_X; + else if (match_ctrl(m, k, HID_LEFT) || + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_LEFT))) { + grid_x1 = (grid_x1 + SCREEN_MAX_X - 1) % SCREEN_MAX_X; + grid_x2 = grid_x1; + grid_y2 = grid_y1; grid_view_changed = true; } // C-: move grid cursor - else if (match_ctrl(m, k, HID_RIGHT)) { - grid_x = (grid_x + 1) % SCREEN_MAX_X; + else if (match_ctrl(m, k, HID_RIGHT) || + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_RIGHT))) { + grid_x1 = (grid_x1 + 1) % SCREEN_MAX_X; + grid_x2 = grid_x1; + grid_y2 = grid_y1; grid_view_changed = true; } - else if (match_ctrl(m, k, HID_SPACEBAR)) { - grid_process_key(ss, grid_x, grid_y, 1); + // C-S-: expand grid area up + else if (match_shift_ctrl(m, k, HID_UP) || + (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_UP))) { + if (grid_y2 > 0) { + grid_y2--; + grid_view_changed = true; + } + } + // C-S-: expand grid area down + else if (match_shift_ctrl(m, k, HID_DOWN) || + (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_DOWN))) { + if (grid_y2 < SCREEN_MAX_Y - 1) { + grid_y2++; + grid_view_changed = true; + } + } + // C-S-: expand grid area left + else if (match_shift_ctrl(m, k, HID_LEFT) || + (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_LEFT))) { + if (grid_x2 > 0) { + grid_x2--; + grid_view_changed = true; + } + } + // C-S-: expand grid area right + else if (match_shift_ctrl(m, k, HID_RIGHT) || + (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_RIGHT))) { + if (grid_x2 < SCREEN_MAX_X - 1) { + grid_x2++; + grid_view_changed = true; + } + } + // C-: emulate grid press + else if (!is_held_key && (match_ctrl(m, k, HID_SPACEBAR) || + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SPACEBAR)))) { + grid_x2 = grid_x1; + grid_y2 = grid_y1; + grid_view_changed = true; + grid_process_key(ss, grid_x1, grid_y1, 1); } // : execute command - else if (match_no_mod(m, k, HID_ENTER)) { + else if (match_no_mod(m, k, HID_ENTER) && grid_mode != GRID_MODE_FULL) { dirty |= D_MESSAGE; // something will definitely happen dirty |= D_INPUT; @@ -220,7 +274,8 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, if (show_vars) dirty |= D_VARS; // combined with this... dirty |= D_LIST; // cheap flag to indicate mode just switched } - else { // pass the key though to the line editor + // pass the key though to the line editor + else if (grid_mode != GRID_MODE_FULL) { bool processed = line_editor_process_keys(&le, k, m, is_held_key); if (processed) dirty |= D_INPUT; } @@ -234,7 +289,7 @@ bool screen_refresh_live(scene_state_t *ss) { if (grid_mode != GRID_MODE_OFF && (grid_view_changed || ss->grid.scr_dirty)) { grid_view_changed = 0; screen_dirty = true; - grid_screen_refresh(ss, grid_mode, grid_page, grid_x, grid_y); + grid_screen_refresh(ss, grid_mode, grid_page, grid_x1, grid_y1, grid_x2, grid_y2); } if (grid_mode == GRID_MODE_FULL) return true; @@ -276,7 +331,8 @@ bool screen_refresh_live(scene_state_t *ss) { dirty &= ~D_MESSAGE; } - if (show_vars && ((dirty & D_VARS) || (dirty & D_LIST))) { + if (show_vars && ((dirty & D_VARS) || (dirty & D_LIST)) && + grid_mode == GRID_MODE_OFF) { int16_t* vp = &scene_state.variables .a; // 8 int16_t all in a row, point at the first one @@ -316,7 +372,7 @@ bool screen_refresh_live(scene_state_t *ss) { dirty &= ~D_LIST; } - if (dirty & D_LIST) { + if (dirty & D_LIST && grid_mode == GRID_MODE_OFF) { for (int i = 1; i < 6; i++) region_fill(&line[i], 0); screen_dirty |= 0x3E; diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 256ffd66..5fe77f30 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -195,6 +195,7 @@ static void op_G_GRP_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 group = cs_pop(cs); if (group < 0 || group >= GRID_BUTTON_COUNT) return; SG.current_group = group; + SG.scr_dirty = 1; } static void op_G_GRP_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -340,7 +341,7 @@ static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GBC.background = level; GBC.script = script; GB.latch = latch != 0; - // GB.state = 0; + if (!GB.latch) GB.state = 0; SG.scr_dirty = SG.grid_dirty = 1; } @@ -378,7 +379,7 @@ static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GBC.background = level; GBC.script = script; GB.latch = latch != 0; - // GB.state = 0; + if (!GB.latch) GB.state = 0; } SG.scr_dirty = SG.grid_dirty = 1; From 1b81ea8680551a9db90efd0454bf04fab08bab77 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 29 Oct 2017 15:06:51 -0700 Subject: [PATCH 008/117] fix boundary checking --- module/flash.c | 13 ++- module/grid.c | 14 +++- src/ops/grid_ops.c | 195 ++++++++++++++++++++++++++------------------- 3 files changed, 131 insertions(+), 91 deletions(-) diff --git a/module/flash.c b/module/flash.c index 67c82c1a..e3337a72 100644 --- a/module/flash.c +++ b/module/flash.c @@ -10,10 +10,12 @@ #include "teletype.h" #define FIRSTRUN_KEY 0x22 +#define BUTTON_STATE_SIZE (GRID_BUTTON_COUNT >> 3) +#define FADER_STATE_SIZE (GRID_FADER_COUNT >> 1) typedef struct { - uint8_t button_states[GRID_BUTTON_COUNT >> 3]; - uint8_t fader_states[GRID_FADER_COUNT >> 1]; + uint8_t button_states[BUTTON_STATE_SIZE]; + uint8_t fader_states[FADER_STATE_SIZE]; } grid_data_t; static grid_data_t grid_data; @@ -114,12 +116,15 @@ static void pack_grid(scene_state_t *scene) { for (uint16_t i = 0; i < GRID_BUTTON_COUNT; i++) { byte |= (scene->grid.button[i].state != 0) << (i & 7); if ((i & 7) == 7) { - grid_data.button_states[byte_count++] = byte; + if (++byte_count >= BUTTON_STATE_SIZE) break; + grid_data.button_states[byte_count] = byte; byte = 0; } } for (uint16_t i = 0; i < GRID_FADER_COUNT; i += 2) { - grid_data.fader_states[i >> 1] = (scene->grid.fader[i].value << 4) + + byte = i >> 1; + if (byte >= FADER_STATE_SIZE) break; + grid_data.fader_states[byte] = (scene->grid.fader[i].value << 4) + scene->grid.fader[i+1].value; } } diff --git a/module/grid.c b/module/grid.c index f96b7633..fa35a2ad 100644 --- a/module/grid.c +++ b/module/grid.c @@ -283,16 +283,21 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 for (int i = 0; i < 6; i++) region_fill(&line[i], 0); } + u8 _line; + u16 _data; for (u16 x = 0; x < SCREEN_MAX_X; x++) for (u16 y = 0; y < max_y[page]; y++) for (u16 i = 0; i < size; i++) for (u16 j = 0; j < size; j++) { _y = y * cell + j + 1; + _line = _y >> 3; + _data = left + x * cell + i + ((_y & 7) << 7) + 1; + if (_line > 7 || _data > 1023) continue; if (screen[x][y] == 0) { if (i == 0 || i == size - 1 || j == 0 || j == size - 1) - line[_y >> 3].data[left + x * cell + i + ((_y & 7) << 7) + 1] = 1; + line[_line].data[_data] = 1; } else - line[_y >> 3].data[left + x * cell + i + ((_y & 7) << 7) + 1] = screen[x][y]; + line[_line].data[_data] = screen[x][y]; } u16 area_x, area_y, area_w, area_h; @@ -315,7 +320,10 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 for (u16 j = 0; j < area_h; j++) { if (i == 0 || i == area_w - 1 || j == 0 || j == area_h - 1) { _y = area_y + j; - line[_y >> 3].data[left + i + area_x + ((_y & 7) << 7)] = 8; + _line = _y >> 3; + _data = left + i + area_x + ((_y & 7) << 7); + if (_line > 7 || _data > 1023) continue; + line[_line].data[_data] = 8; } } } diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 5fe77f30..144f1ff8 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -11,20 +11,32 @@ #define GET_AND_CLAMP(value, min, max) \ s16 value = cs_pop(cs); \ - if (value < (min)) \ + if (value < (s16)(min)) \ value = (min); \ - else if (value > (max)) \ + else if (value > (s16)(max)) \ value = (max); -#define GET_LEVEL(level) \ - s16 level = cs_pop(cs); \ - if (level < LED_OFF) \ - level = LED_OFF; \ - else if (level > 15) \ +#define GET_LEVEL(level) \ + s16 level = cs_pop(cs); \ + if (level < (s16)LED_OFF) \ + level = LED_OFF; \ + else if (level > (s16)15) \ level = 15; -#define min(a, b) ((a) < (b) ? (a) : (b)) -#define max(a, b) ((a) > (b) ? (a) : (b)) +#define CLAMP_X_Y_W_H(op) \ + if (x < (s16)0) { \ + w += x; \ + x = 0; \ + } else if (x >= (s16)GRID_MAX_DIMENSION) op; \ + if (w + x > (s16)GRID_MAX_DIMENSION) w = GRID_MAX_DIMENSION - x; \ + if (y < (s16)0) { \ + h += y; \ + y = 0; \ + } else if (y >= (s16)GRID_MAX_DIMENSION) op; \ + if (h + y > (s16)GRID_MAX_DIMENSION) h = GRID_MAX_DIMENSION - y; + +#define min(a, b) ((s32)(a) < (s32)(b) ? (s32)(a) : (s32)(b)) +#define max(a, b) ((s32)(a) > (s32)(b) ? (s32)(a) : (s32)(b)) static void grid_common_init(grid_common_t *gc); static s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value); @@ -181,7 +193,7 @@ static void op_G_CLR_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat static void op_G_ROTATE_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 rotate = cs_pop(cs); - SG.rotate = rotate; + SG.rotate = rotate != 0; SG.scr_dirty = SG.grid_dirty = 1; } @@ -193,7 +205,7 @@ static void op_G_DIM_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat static void op_G_GRP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); - if (group < 0 || group >= GRID_BUTTON_COUNT) return; + if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; SG.current_group = group; SG.scr_dirty = 1; } @@ -201,14 +213,14 @@ static void op_G_GRP_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat static void op_G_GRP_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 en = cs_pop(cs); - if (group < 0 || group >= GRID_BUTTON_COUNT) return; - SG.group[group].enabled = en; + if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; + SG.group[group].enabled = en != 0; SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GRP_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); - if (group < 0 || group >= GRID_BUTTON_COUNT) return; + if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; SG.group[group].enabled = true; SG.group[group].script = -1; @@ -241,7 +253,7 @@ static void op_G_GRP_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_ static void op_G_GRP_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); - if (group < 0 || group >= GRID_BUTTON_COUNT) return; + if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; for (u8 i = 0; i < GRID_GROUP_COUNT; i++) SG.group[i].enabled = false; SG.group[group].enabled = true; @@ -253,7 +265,7 @@ static void op_G_GRP_SC_get(const void *NOTUSED(data), scene_state_t *ss, exec_s s16 group = cs_pop(cs); s16 script = cs_pop(cs) - 1; - if (group < 0 || group >= GRID_BUTTON_COUNT) return; + if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; if (script < 0 || script > INIT_SCRIPT) script = -1; SG.group[group].script = script; @@ -268,8 +280,8 @@ static void op_G_LED_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 y = cs_pop(cs); GET_LEVEL(level); - if (x < 0 || x >= GRID_MAX_DIMENSION) return; - if (y < 0 || y >= GRID_MAX_DIMENSION) return; + if (x < (s16)0 || x >= (s16)GRID_MAX_DIMENSION) return; + if (y < (s16)0 || y >= (s16)GRID_MAX_DIMENSION) return; SG.leds[x][y] = level; SG.scr_dirty = SG.grid_dirty = 1; @@ -279,8 +291,8 @@ static void op_G_LED_C_get(const void *NOTUSED(data), scene_state_t *ss, exec_st s16 x = cs_pop(cs); s16 y = cs_pop(cs); - if (x < 0 || x >= GRID_MAX_DIMENSION) return; - if (y < 0 || y >= GRID_MAX_DIMENSION) return; + if (x < (s16)0 || x >= (s16)GRID_MAX_DIMENSION) return; + if (y < (s16)0 || y >= (s16)GRID_MAX_DIMENSION) return; SG.leds[x][y] = LED_OFF; SG.scr_dirty = SG.grid_dirty = 1; @@ -294,26 +306,26 @@ static void op_G_REC_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GET_LEVEL(fill); GET_LEVEL(border); - for (s16 col = max(0, x + 1); col < min(GRID_MAX_DIMENSION, x + w - 1); col++) - for (s16 row = max(0, y + 1); row < min(GRID_MAX_DIMENSION, y + h - 1); row++) + for (u16 col = max(0, x + (s32)1); col < min(GRID_MAX_DIMENSION, x + w - (s32)1); col++) + for (u16 row = max(0, y + (s32)1); row < min(GRID_MAX_DIMENSION, y + h - (s32)1); row++) SG.leds[col][row] = fill; - if (y >= 0 && y < GRID_MAX_DIMENSION) - for (s16 col = max(0, x); col < min(GRID_MAX_DIMENSION, x + w); col++) + if (y >= (s16)0 && y < (s16)GRID_MAX_DIMENSION) + for (u16 col = max(0, x); col < min(GRID_MAX_DIMENSION, (s32)x + w); col++) SG.leds[col][y] = border; - s16 row = y + h - 1; - if (row >= 0 && row < GRID_MAX_DIMENSION) - for (s16 col = max(0, x); col < min(GRID_MAX_DIMENSION, x + w); col++) + s16 row = y + h - (s16)1; + if (row >= (s16)0 && row < (s16)GRID_MAX_DIMENSION) + for (u16 col = max(0, x); col < min(GRID_MAX_DIMENSION, (s32)x + w); col++) SG.leds[col][row] = border; - if (x >= 0 && x < GRID_MAX_DIMENSION) - for (s16 row = max(0, y); row < min(GRID_MAX_DIMENSION, y + h); row++) + if (x >= (s16)0 && x < (s16)GRID_MAX_DIMENSION) + for (u16 row = max(0, y); row < min(GRID_MAX_DIMENSION, (s32)y + h); row++) SG.leds[x][row] = border; s16 col = x + w - 1; - if (col >= 0 && col < GRID_MAX_DIMENSION) - for (s16 row = max(0, y); row < min(GRID_MAX_DIMENSION, y + h); row++) + if (col >= (s16)0 && col < (s16)GRID_MAX_DIMENSION) + for (u16 row = max(0, y); row < min(GRID_MAX_DIMENSION, (s32)y + h); row++) SG.leds[col][row] = border; SG.scr_dirty = SG.grid_dirty = 1; @@ -329,8 +341,9 @@ static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GET_LEVEL(level); s16 script = cs_pop(cs) - 1; - if (i < 0 || i >= GRID_BUTTON_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; if (script < 0 || script > INIT_SCRIPT) script = -1; + CLAMP_X_Y_W_H(return); GBC.enabled = true; GBC.group = SG.current_group; @@ -348,32 +361,38 @@ static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 id = cs_pop(cs); - s16 x = cs_pop(cs); - s16 y = cs_pop(cs); - s16 w = cs_pop(cs); - s16 h = cs_pop(cs); + s16 _x = cs_pop(cs); + s16 _y = cs_pop(cs); + s16 _w = cs_pop(cs); + s16 _h = cs_pop(cs); s16 latch = cs_pop(cs); GET_LEVEL(level); s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); - if (id < 0 || id >= GRID_BUTTON_COUNT) return; + if (id < (s16)0 || id >= (s16)GRID_BUTTON_COUNT) return; if (script < 0 || script > INIT_SCRIPT) script = -1; - if (count_x <= 0) return; - if (count_x > 16) count_x = 16; - if (count_y <= 0) return; - if (count_y > 16) count_y = 16; + if (count_x <= (s16)0) return; + if (count_x > (s16)16) count_x = 16; + if (count_y <= (s16)0) return; + if (count_y > (s16)16) count_y = 16; u16 i; - for (u16 cy = 0; cy < count_y; cy++) - for (u16 cx = 0; cx < count_x; cx++) { + s16 x, y, w, h; + for (s16 cy = 0; cy < count_y; cy++) + for (s16 cx = 0; cx < count_x; cx++) { i = id + cy * count_x + cx; if (i >= GRID_BUTTON_COUNT) break; GBC.enabled = true; GBC.group = SG.current_group; - GBC.x = x + w * cx; - GBC.y = y + h * cy; + x = _x + _w * cx; + w = _w; + y = _y + _h * cy; + h = _h; + CLAMP_X_Y_W_H(continue); + GBC.x = x; + GBC.y = y; GBC.w = w; GBC.h = h; GBC.background = level; @@ -389,20 +408,20 @@ static void op_G_BTN_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_s s16 i = cs_pop(cs); s16 en = cs_pop(cs); - if (i < 0 || i >= GRID_BUTTON_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; GBC.enabled = en; SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTN_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - cs_push(cs, i < 0 || i >= GRID_BUTTON_COUNT ? 0 : GB.state); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GB.state); } static void op_G_BTN_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 value = cs_pop(cs); - if (i < 0 || i >= GRID_BUTTON_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; GB.state = value != 0; SG.scr_dirty = SG.grid_dirty = 1; } @@ -410,7 +429,7 @@ static void op_G_BTN_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_st static void op_G_BTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); GET_LEVEL(level); - if (i < 0 || i >= GRID_BUTTON_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; GBC.background = level; SG.scr_dirty = SG.grid_dirty = 1; } @@ -431,7 +450,7 @@ static void op_G_BTNL_get(const void *NOTUSED(data), scene_state_t *ss, exec_sta static void op_G_BTN_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 id = cs_pop(cs); - if (id < 0 || id >= GRID_BUTTON_COUNT) return; + if (id < (s16)0 || id >= (s16)GRID_BUTTON_COUNT) return; for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.group == SG.button[id].common.group) GB.state = 0; @@ -444,7 +463,7 @@ static void op_G_GBTN_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_s s16 group = cs_pop(cs); s16 value = cs_pop(cs); - if (group < 0 || group > GRID_GROUP_COUNT) return; + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; value = value != 0; for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) @@ -457,7 +476,7 @@ static void op_G_GBTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_s GET_LEVEL(odd); GET_LEVEL(even); - if (group < 0 || group > GRID_GROUP_COUNT) return; + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; u8 is_odd = 1; for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) @@ -478,9 +497,10 @@ static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GET_LEVEL(level); s16 script = cs_pop(cs) - 1; - if (i < 0 || i >= GRID_FADER_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; if (script < 0 || script > INIT_SCRIPT) script = -1; - + CLAMP_X_Y_W_H(return); + GFC.enabled = true; GFC.group = SG.current_group; GFC.x = x; @@ -497,32 +517,38 @@ static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 id = cs_pop(cs); - s16 x = cs_pop(cs); - s16 y = cs_pop(cs); - s16 w = cs_pop(cs); - s16 h = cs_pop(cs); + s16 _x = cs_pop(cs); + s16 _y = cs_pop(cs); + s16 _w = cs_pop(cs); + s16 _h = cs_pop(cs); s16 dir = cs_pop(cs); GET_LEVEL(level); s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); - if (id < 0 || id >= GRID_FADER_COUNT) return; + if (id < (s16)0 || id >= (s16)GRID_FADER_COUNT) return; if (script < 0 || script > INIT_SCRIPT) script = -1; - if (count_x <= 0) return; - if (count_x > 16) count_x = 16; - if (count_y <= 0) return; - if (count_y > 16) count_y = 16; + if (count_x <= (s16)0) return; + if (count_x > (s16)16) count_x = 16; + if (count_y <= (s16)0) return; + if (count_y > (s16)16) count_y = 16; u16 i; + s16 x, y, w, h; for (u16 cy = 0; cy < count_y; cy++) for (u16 cx = 0; cx < count_x; cx++) { i = id + cy * count_x + cx; - if (i >= GRID_FADER_COUNT) break; + if (i >= (s16)GRID_FADER_COUNT) break; GFC.enabled = true; GFC.group = SG.current_group; - GFC.x = x + w * cx; - GFC.y = y + h * cy; + x = _x + _w * cx; + w = _w; + y = _y + _h * cy; + h = _h; + CLAMP_X_Y_W_H(continue); + GFC.x = x; + GFC.y = y; GFC.w = w; GFC.h = h; GFC.background = level; @@ -538,14 +564,14 @@ static void op_G_FDR_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_s s16 i = cs_pop(cs); s16 en = cs_pop(cs); - if (i < 0 || i >= GRID_FADER_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; GFC.enabled = en; SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - if (i < 0 || i >= GRID_FADER_COUNT) { + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) { cs_push(cs, 0); return; } @@ -559,7 +585,7 @@ static void op_G_FDR_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_st s16 i = cs_pop(cs); s16 value = cs_pop(cs); - if (i < 0 || i >= GRID_FADER_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; if (value < SG.group[GFC.group].fader_min) value = SG.group[GFC.group].fader_min; else if (value > SG.group[GFC.group].fader_max) value = SG.group[GFC.group].fader_max; @@ -570,17 +596,17 @@ static void op_G_FDR_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_st static void op_G_FDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - cs_push(cs, i < 0 || i >= GRID_FADER_COUNT ? 1 : GF.value + 1); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 1 : GF.value + 1); } static void op_G_FDR_N_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 value = cs_pop(cs) - 1; - if (i < 0 || i >= GRID_FADER_COUNT) return; - if (value < 0) value = 0; - else if (GF.dir && value >= GFC.h) value = GFC.h - 1; - else if (!GF.dir && value >= GFC.w) value = GFC.w - 1; + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; + if (value < (s16)0) value = 0; + else if (GF.dir && value >= (s16)GFC.h) value = GFC.h - 1; + else if (!GF.dir && value >= (s16)GFC.w) value = GFC.w - 1; GF.value = value; SG.scr_dirty = SG.grid_dirty = 1; @@ -589,7 +615,7 @@ static void op_G_FDR_N_set(const void *NOTUSED(data), scene_state_t *ss, exec_st static void op_G_FDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); GET_LEVEL(level); - if (i < 0 || i >= GRID_FADER_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; GFC.background = level; SG.scr_dirty = SG.grid_dirty = 1; } @@ -619,7 +645,7 @@ static void op_G_GFDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_s s16 group = cs_pop(cs); s16 value = cs_pop(cs); - if (group < 0 || group > GRID_GROUP_COUNT) return; + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; if (value < SG.group[group].fader_min) value = SG.group[group].fader_min; else if (value > SG.group[group].fader_max) value = SG.group[group].fader_max; @@ -635,8 +661,8 @@ static void op_G_GFDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_s s16 group = cs_pop(cs); s16 value = cs_pop(cs) - 1; - if (group < 0 || group > GRID_GROUP_COUNT) return; - if (value < 0) value = 0; + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; + if (value < (s16)0) value = 0; for (u16 i = 0; i < GRID_FADER_COUNT; i++) if (GFC.group == group) GF.value = min(GF.dir ? GFC.h - 1 : GFC.w - 1, value); @@ -648,7 +674,7 @@ static void op_G_GFDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_s GET_LEVEL(odd); GET_LEVEL(even); - if (group < 0 || group > GRID_GROUP_COUNT) return; + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; u8 is_odd = 1; for (u16 i = 0; i < GRID_FADER_COUNT; i++) @@ -664,7 +690,7 @@ static void op_G_GFDR_RN_get(const void *NOTUSED(data), scene_state_t *ss, exec_ s16 min = cs_pop(cs); s16 max = cs_pop(cs); - if (group < 0 || group > GRID_GROUP_COUNT) return; + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; SG.group[group].fader_min = min; SG.group[group].fader_max = max; } @@ -678,9 +704,10 @@ static void op_G_XYP_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GET_LEVEL(level); s16 script = cs_pop(cs) - 1; - if (i < 0 || i >= GRID_XYPAD_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_XYPAD_COUNT) return; if (script < 0 || script > INIT_SCRIPT) script = -1; - + CLAMP_X_Y_W_H(return); + GXYC.enabled = true; GXYC.group = SG.current_group; GXYC.x = x; @@ -697,12 +724,12 @@ static void op_G_XYP_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat static void op_G_XYP_X_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - cs_push(cs, i < 0 || i >= GRID_XYPAD_COUNT ? 0 : GXY.value_x); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_XYPAD_COUNT ? 0 : GXY.value_x); } static void op_G_XYP_Y_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - cs_push(cs, i < 0 || i >= GRID_XYPAD_COUNT ? 0 : GXY.value_y); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_XYPAD_COUNT ? 0 : GXY.value_y); } void grid_common_init(grid_common_t *gc) { From 359866e16320debf0b5f79c49cbb7a7b5a8f0052 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 29 Oct 2017 17:17:34 -0700 Subject: [PATCH 009/117] grid visualizer pt5 --- module/grid.c | 70 ++++++++++++++++++++++++++-------------------- module/grid.h | 5 ---- module/live_mode.c | 66 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 100 insertions(+), 41 deletions(-) diff --git a/module/grid.c b/module/grid.c index fa35a2ad..fec6609c 100644 --- a/module/grid.c +++ b/module/grid.c @@ -5,11 +5,8 @@ #include "teletype.h" #include "util.h" -const u8 min_y[2] = {0, 8}; -const u8 max_y[2] = {8, 16}; - -static u8 screen[SCREEN_MAX_X][SCREEN_MAX_Y]; static u16 size_x = 16, size_y = 8; +static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION]; static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); @@ -179,7 +176,7 @@ void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level) { } } -// screen functions +///////////////////////////////////////// screen functions void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { switch (mode) { @@ -226,7 +223,7 @@ void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u } void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { - grid_fill_area_scr(0, 0, SCREEN_MAX_X, SCREEN_MAX_Y, 0, 0); + grid_fill_area_scr(0, 0, GRID_MAX_DIMENSION, GRID_MAX_DIMENSION, 0, 0); u16 x, y; for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { @@ -257,8 +254,8 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 if (GBC.enabled && SG.group[GBC.group].enabled) grid_fill_area_scr(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.background, page); - for (u16 i = 0; i < SCREEN_MAX_X; i++) - for (u16 j = min_y[page]; j < max_y[page]; j++) { + for (u16 i = 0; i < GRID_MAX_DIMENSION; i++) + for (u16 j = 0; j < GRID_MAX_DIMENSION; j++) { if (SG.leds[i][j] >= 0) screen[i][j] = SG.leds[i][j]; else if (SG.leds[i][j] == LED_DIM) @@ -273,7 +270,7 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 u16 _y, cell, size, left; if (full_grid) { cell = 8; - size = 6; + size = 5; left = 0; for (int i = 0; i < 8; i++) region_fill(&line[i], 0); } else { @@ -285,12 +282,16 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 u8 _line; u16 _data; - for (u16 x = 0; x < SCREEN_MAX_X; x++) - for (u16 y = 0; y < max_y[page]; y++) - for (u16 i = 0; i < size; i++) - for (u16 j = 0; j < size; j++) { - _y = y * cell + j + 1; - _line = _y >> 3; + for (u16 x = 0; x < GRID_MAX_DIMENSION; x++) + for (u16 y = 0; y < GRID_MAX_DIMENSION; y++) + for (u16 j = 0; j < size; j++) { + _y = y * cell + j + 1; + if (page) { + if (_y < cell << 3) continue; + _y -= cell << 3; + } + _line = _y >> 3; + for (u16 i = 0; i < size; i++) { _data = left + x * cell + i + ((_y & 7) << 7) + 1; if (_line > 7 || _data > 1023) continue; if (screen[x][y] == 0) { @@ -299,6 +300,7 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 } else line[_line].data[_data] = screen[x][y]; } + } u16 area_x, area_y, area_w, area_h; if (x1 < x2) { @@ -315,22 +317,31 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 area_y = y2 * cell; area_h = (y1 + 1 - y2) * cell; } + if (full_grid) { + area_w--; + area_h--; + } - for (u16 i = 0; i < area_w; i++) - for (u16 j = 0; j < area_h; j++) { + for (u16 j = 0; j < area_h; j++) { + _y = area_y + j; + if (page) { + if (_y < (cell << 3)) continue; + _y -= cell << 3 ; + } + _line = _y >> 3; + for (u16 i = 0; i < area_w; i++) { if (i == 0 || i == area_w - 1 || j == 0 || j == area_h - 1) { - _y = area_y + j; - _line = _y >> 3; _data = left + i + area_x + ((_y & 7) << 7); if (_line > 7 || _data > 1023) continue; line[_line].data[_data] = 8; } } + } } static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { char s[32]; - u16 area_x, area_y, area_w, area_h; + u8 area_x, area_y, area_w, area_h; if (x1 < x2) { area_x = x1; @@ -451,21 +462,21 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u for (u16 j = ss->grid.current_group * 6 + 1; j < ss->grid.current_group * 6 + 6; j++) line[j >> 3].data[(j & 7) << 7] = 2; - l = page == 0 ? 8 : 2; + l = page == 0 ? 10 : 2; for (u16 i = 122; i < 128; i++) line[0].data[i + 128] = l; line[0].data[122 + 256] = l; line[0].data[127 + 256] = l; line[0].data[122 + 384] = l; line[0].data[127 + 384] = l; - l = page == 1 ? 8 : 2; + l = page == 1 ? 10 : 2; line[0].data[122 + 512] = l; line[0].data[127 + 512] = l; line[0].data[122 + 640] = l; line[0].data[127 + 640] = l; for (u16 i = 122; i < 128; i++) line[0].data[i + 768] = l; - l = ss->grid.rotate ? 8 : 2; + l = ss->grid.rotate ? 10 : 2; line[1].data[128 + 123] = l; line[1].data[128 + 124] = l; line[1].data[128 + 125] = l; @@ -482,26 +493,25 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page) { if (level == LED_OFF) return; - u16 x_end = min(SCREEN_MAX_X, x + w); - u16 y_start = max(min_y[page], y); - u16 y_end = min(max_y[page], y + h); + u16 x_end = min(GRID_MAX_DIMENSION, x + w); + u16 y_end = min(GRID_MAX_DIMENSION, y + h); if (level == LED_DIM) { for (u16 _x = x; _x < x_end; _x++) { - for (u16 _y = y_start; _y < y_end; _y++) - screen[_x][_y - y_start] >>= 1; + for (u16 _y = y; _y < y_end; _y++) + screen[_x][_y] >>= 1; } } else if (level == LED_BRI) { for (u16 _x = x; _x < x_end; _x++) - for (u16 _y = y_start; _y < y_end; _y++) { + for (u16 _y = y; _y < y_end; _y++) { screen[_x][_y] <<= 1; if (screen[_x][_y] > 15) screen[_x][_y] = 15; } } else { for (u16 _x = x; _x < x_end; _x++) - for (u16 _y = y_start; _y < y_end; _y++) + for (u16 _y = y; _y < y_end; _y++) screen[_x][_y] = level; } } diff --git a/module/grid.h b/module/grid.h index eb4c4c7b..8cedfb13 100644 --- a/module/grid.h +++ b/module/grid.h @@ -4,9 +4,6 @@ #include "monome.h" #include "state.h" -#define SCREEN_MAX_X 16 -#define SCREEN_MAX_Y 8 - #define SG ss->grid #define GB ss->grid.button[i] #define GBC ss->grid.button[i].common @@ -23,8 +20,6 @@ typedef enum { GRID_MODE_LAST } screen_grid_mode; - - extern void grid_refresh(scene_state_t *ss); extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z); diff --git a/module/live_mode.c b/module/live_mode.c index 6d69cfaf..4a0f0399 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -153,7 +153,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // C-: move grid cursor else if (match_ctrl(m, k, HID_UP) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_UP))) { - grid_y1 = (grid_y1 + SCREEN_MAX_Y - 1) % SCREEN_MAX_Y; + grid_y1 = (grid_y1 + GRID_MAX_DIMENSION - 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; grid_view_changed = true; @@ -161,7 +161,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // C-: move grid cursor else if (match_ctrl(m, k, HID_DOWN) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_DOWN))) { - grid_y1 = (grid_y1 + 1) % SCREEN_MAX_Y; + grid_y1 = (grid_y1 + 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; grid_view_changed = true; @@ -169,7 +169,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // C-: move grid cursor else if (match_ctrl(m, k, HID_LEFT) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_LEFT))) { - grid_x1 = (grid_x1 + SCREEN_MAX_X - 1) % SCREEN_MAX_X; + grid_x1 = (grid_x1 + GRID_MAX_DIMENSION - 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; grid_view_changed = true; @@ -177,7 +177,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // C-: move grid cursor else if (match_ctrl(m, k, HID_RIGHT) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_RIGHT))) { - grid_x1 = (grid_x1 + 1) % SCREEN_MAX_X; + grid_x1 = (grid_x1 + 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; grid_view_changed = true; @@ -193,7 +193,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // C-S-: expand grid area down else if (match_shift_ctrl(m, k, HID_DOWN) || (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_DOWN))) { - if (grid_y2 < SCREEN_MAX_Y - 1) { + if (grid_y2 < GRID_MAX_DIMENSION - 1) { grid_y2++; grid_view_changed = true; } @@ -209,7 +209,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // C-S-: expand grid area right else if (match_shift_ctrl(m, k, HID_RIGHT) || (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_RIGHT))) { - if (grid_x2 < SCREEN_MAX_X - 1) { + if (grid_x2 < GRID_MAX_DIMENSION - 1) { grid_x2++; grid_view_changed = true; } @@ -222,6 +222,60 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, grid_view_changed = true; grid_process_key(ss, grid_x1, grid_y1, 1); } + // C-: insert coordinates / size + else if (!is_held_key && match_ctrl(m, k, HID_PRINTSCREEN) && + grid_mode != GRID_MODE_FULL) { + u8 area_x, area_y, area_w, area_h; + if (grid_x1 < grid_x2) { + area_x = grid_x1; + area_w = grid_x2 + 1 - grid_x1; + } else { + area_x = grid_x2; + area_w = grid_x1 + 1 - grid_x2; + } + if (grid_y1 < grid_y2) { + area_y = grid_y1; + area_h = grid_y2 + 1 - grid_y1; + } else { + area_y = grid_y2; + area_h = grid_y1 + 1 - grid_y2; + } + if (area_x > 9) { + line_editor_process_keys(&le, HID_1, HID_MODIFIER_NONE, false); + area_x -= 10; + } + line_editor_process_keys(&le, + area_x ? HID_1 + area_x - 1 : HID_0, HID_MODIFIER_NONE, false); + line_editor_process_keys(&le, HID_SPACEBAR, HID_MODIFIER_NONE, false); + if (area_y > 9) { + line_editor_process_keys(&le, HID_1, HID_MODIFIER_NONE, false); + area_y -= 10; + } + line_editor_process_keys(&le, + area_y ? HID_1 + area_y - 1 : HID_0, HID_MODIFIER_NONE, false); + line_editor_process_keys(&le, HID_SPACEBAR, HID_MODIFIER_NONE, false); + if (area_w > 9) { + line_editor_process_keys(&le, HID_1, HID_MODIFIER_NONE, false); + area_w -= 10; + } + line_editor_process_keys(&le, + area_w ? HID_1 + area_w - 1 : HID_0, HID_MODIFIER_NONE, false); + line_editor_process_keys(&le, HID_SPACEBAR, HID_MODIFIER_NONE, false); + if (area_h > 9) { + line_editor_process_keys(&le, HID_1, HID_MODIFIER_NONE, false); + area_h -= 10; + } + line_editor_process_keys(&le, + area_h ? HID_1 + area_h - 1 : HID_0, HID_MODIFIER_NONE, false); + line_editor_process_keys(&le, HID_SPACEBAR, HID_MODIFIER_NONE, false); + dirty |= D_INPUT; + } + // C-: toggle grid page + else if (match_ctrl(m, k, HID_SLASH) || + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SLASH))) { + if (++grid_page > 1) grid_page = 0; + grid_view_changed = true; + } // : execute command else if (match_no_mod(m, k, HID_ENTER) && grid_mode != GRID_MODE_FULL) { dirty |= D_MESSAGE; // something will definitely happen From 0a27d4d17cac527c2f827dd8602f6cb783a6eb5b Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 13 Nov 2017 12:47:26 -0800 Subject: [PATCH 010/117] grid visualizer pt6 --- module/grid.c | 83 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 10 deletions(-) diff --git a/module/grid.c b/module/grid.c index fec6609c..04ee722a 100644 --- a/module/grid.c +++ b/module/grid.c @@ -5,8 +5,36 @@ #include "teletype.h" #include "util.h" +static const u8 font[][] = { + { + 0b000000, + 0b011110, + 0b000000, + 0b000000, + 0b000000, + 0b000000 + }, + { + 0b000000, + 0b000000, + 0b000000, + 0b000000, + 0b000000, + 0b000000 + }, + { + 0b000000, + 0b000000, + 0b000000, + 0b000000, + 0b000000, + 0b000000 + } +}; + static u16 size_x = 16, size_y = 8; static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION]; +static u8 layout[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION]; static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); @@ -199,27 +227,62 @@ void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x } void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { - /* - grid_fill_area_scr(0, 0, SCREEN_MAX_X, SCREEN_MAX_Y, 0, 0); + grid_fill_area_scr(0, 0, GRID_MAX_DIMENSION, GRID_MAX_DIMENSION, 0, 0); - u8 level; + u8 level, last_x, last_y; for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { if (!SG.group[GBC.group].enabled) continue; level = (GBC.enabled ? (GB.state ? 15 : 8) : 1) << 4; + last_x = GBC.x + GBC.w - 1; + last_y = GBC.y + GBC.h - 1; if (GBC.w == 1 && GBC.h == 1) { grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 1, page); } else if (GBC.w == 1 && GBC.h > 1) { - grid_fill_area_scr(GBC.x, GBC.y + 1, 1, GBC.h - 2, level + 2, page); - grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 3, page); - grid_fill_area_scr(GBC.x, GBC.y + GBC.h - 1, 1, 1, level + 4, page); + grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 2, page); + grid_fill_area_scr(GBC.x, GBC.y + 1, 1, GBC.h - 2, level + 3, page); + grid_fill_area_scr(GBC.x, last_y, 1, 1, level + 4, page); } else if (GBC.w > 1 && GBC.h == 1) { - grid_fill_area_scr(GBC.x + 1, GBC.y, GBC.w - 2, 1, level + 5, page); - grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 6, page); - grid_fill_area_scr(GBC.x + GBC.w - 1, GBC.y, 1, 1, level + 7, page); + grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 5, page); + grid_fill_area_scr(GBC.x + 1, GBC.y, GBC.w - 2, 1, level + 6, page); + grid_fill_area_scr(last_x, GBC.y, 1, 1, level + 7, page); } else { + grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 8, page); + grid_fill_area_scr(GBC.x + 1, GBC.y, GBC.w - 2, 1, level + 9, page); + grid_fill_area_scr(last_x, GBC.y, 1, 1, level + 10, page); + grid_fill_area_scr(GBC.x, GBC.y + 1, 1, GBC.h - 2, level + 11, page); + grid_fill_area_scr(last_x, GBC.y + 1, 1, GBC.h - 2, level + 12, page); + grid_fill_area_scr(GBC.x, last_y, 1, 1, level + 13, page); + grid_fill_area_scr(GBC.x + 1, last_y, GBC.w - 2, 1, level + 14, page); + grid_fill_area_scr(last_x, last_y, 1, 1, level + 15, page); } } - */ + + u8 _line; + u16 _data; + u8 type; + for (u16 x = 0; x < GRID_MAX_DIMENSION; x++) + for (u16 y = 0; y < GRID_MAX_DIMENSION; y++) + type = screen[x][y] && ; + + for (u16 j = 0; j < 6; j++) { + _y = y * 6 + j + 1; + if (page) { + if (_y < cell << 3) continue; + _y -= cell << 3; + } + _line = _y >> 3; + for (u16 i = 0; i < size; i++) { + _data = left + x * cell + i + ((_y & 7) << 7) + 1; + if (_line > 7 || _data > 1023) continue; + if (screen[x][y] == 0) { + if (i == 0 || i == size - 1 || j == 0 || j == size - 1) + line[_line].data[_data] = 1; + } else + line[_line].data[_data] = screen[x][y]; + } + } + + } void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { From 8e3acf9c19814955b596713e325ccdb26528a7f6 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 13 Nov 2017 16:02:41 -0800 Subject: [PATCH 011/117] visualizer wip --- module/grid.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/module/grid.c b/module/grid.c index 04ee722a..ada99b5d 100644 --- a/module/grid.c +++ b/module/grid.c @@ -5,6 +5,7 @@ #include "teletype.h" #include "util.h" +/* static const u8 font[][] = { { 0b000000, @@ -31,6 +32,7 @@ static const u8 font[][] = { 0b000000 } }; +*/ static u16 size_x = 16, size_y = 8; static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION]; @@ -229,6 +231,7 @@ void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { grid_fill_area_scr(0, 0, GRID_MAX_DIMENSION, GRID_MAX_DIMENSION, 0, 0); + /* u8 level, last_x, last_y; for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { if (!SG.group[GBC.group].enabled) continue; @@ -282,7 +285,7 @@ void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u } } - + */ } void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { From d9a42f4c6b2b9d0d3cde8d5cbd917a07b80281db Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 14 Nov 2017 19:18:59 -0800 Subject: [PATCH 012/117] update libavr32 --- libavr32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavr32 b/libavr32 index c30e406a..cb0da4ef 160000 --- a/libavr32 +++ b/libavr32 @@ -1 +1 @@ -Subproject commit c30e406ae5e1c1fb1f7752e8b91326d41c788393 +Subproject commit cb0da4ef5ffdf4f7e9e7370267f623c0ee6845f8 From 384806d345afeaa38d6e7fa776c329438cdc4ead Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 14 Nov 2017 19:50:39 -0800 Subject: [PATCH 013/117] increase groups to 64 --- module/grid.c | 132 ++++++++++----------------------------------- module/live_mode.c | 2 + src/state.h | 2 +- 3 files changed, 30 insertions(+), 106 deletions(-) diff --git a/module/grid.c b/module/grid.c index ada99b5d..7a2dd994 100644 --- a/module/grid.c +++ b/module/grid.c @@ -342,7 +342,7 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 } else { cell = 6; size = 4; - left = 10; + left = 5; for (int i = 0; i < 6; i++) region_fill(&line[i], 0); } @@ -425,6 +425,8 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u } s[1] = 0; + s[0] = 'G'; + font_string_region_clip_right(&line[1], s, 127, 0, 1, 0); s[0] = 'X'; font_string_region_clip_right(&line[2], s, 127, 0, 1, 0); s[0] = 'Y'; @@ -434,6 +436,8 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u s[0] = 'H'; font_string_region_clip_right(&line[5], s, 127, 0, 1, 0); + itoa(ss->grid.current_group, s, 10); + font_string_region_clip_right(&line[1], s, 117, 0, 8, 0); itoa(area_x, s, 10); font_string_region_clip_right(&line[2], s, 117, 0, 8, 0); itoa(area_y, s, 10); @@ -443,117 +447,35 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u itoa(area_h, s, 10); font_string_region_clip_right(&line[5], s, 117, 0, 8, 0); - for (u16 j = 17; j < 48; j += 2) line[j >> 3].data[119 + ((j & 7) << 7)] = 1; + for (u16 j = 9; j < 48; j += 2) line[j >> 3].data[119 + ((j & 7) << 7)] = 1; u8 l; - l = ss->grid.group[0].enabled ? 8 : 1; - line[0].data[128 + 3] = l; - line[0].data[256 + 2] = l; - line[0].data[256 + 4] = l; - line[0].data[384 + 2] = l; - line[0].data[384 + 4] = l; - line[0].data[512 + 2] = l; - line[0].data[512 + 4] = l; - line[0].data[640 + 3] = l; - - l = ss->grid.group[1].enabled ? 8 : 1; - line[0].data[896 + 4] = l; - line[1].data[ 0 + 3] = l; - line[1].data[ 0 + 4] = l; - line[1].data[128 + 4] = l; - line[1].data[256 + 4] = l; - line[1].data[384 + 4] = l; - - l = ss->grid.group[2].enabled ? 8 : 1; - line[1].data[640 + 2] = l; - line[1].data[640 + 3] = l; - line[1].data[768 + 4] = l; - line[1].data[896 + 3] = l; - line[2].data[ 0 + 2] = l; - line[2].data[128 + 2] = l; - line[2].data[128 + 3] = l; - line[2].data[128 + 4] = l; - - l = ss->grid.group[3].enabled ? 8 : 1; - line[2].data[384 + 2] = l; - line[2].data[384 + 3] = l; - line[2].data[384 + 4] = l; - line[2].data[512 + 4] = l; - line[2].data[640 + 3] = l; - line[2].data[768 + 4] = l; - line[2].data[896 + 2] = l; - line[2].data[896 + 3] = l; - - l = ss->grid.group[4].enabled ? 8 : 1; - line[3].data[128 + 2] = l; - line[3].data[128 + 4] = l; - line[3].data[256 + 2] = l; - line[3].data[256 + 4] = l; - line[3].data[384 + 2] = l; - line[3].data[384 + 3] = l; - line[3].data[384 + 4] = l; - line[3].data[512 + 4] = l; - line[3].data[640 + 4] = l; - - l = ss->grid.group[5].enabled ? 8 : 1; - line[3].data[896 + 2] = l; - line[3].data[896 + 3] = l; - line[3].data[896 + 4] = l; - line[4].data[ 0 + 2] = l; - line[4].data[128 + 2] = l; - line[4].data[128 + 3] = l; - line[4].data[256 + 4] = l; - line[4].data[384 + 2] = l; - line[4].data[384 + 3] = l; - - l = ss->grid.group[6].enabled ? 8 : 1; - line[4].data[640 + 3] = l; - line[4].data[640 + 4] = l; - line[4].data[768 + 2] = l; - line[4].data[896 + 2] = l; - line[4].data[896 + 3] = l; - line[5].data[ 0 + 2] = l; - line[5].data[ 0 + 4] = l; - line[5].data[128 + 3] = l; - - l = ss->grid.group[7].enabled ? 8 : 1; - line[5].data[384 + 2] = l; - line[5].data[384 + 3] = l; - line[5].data[384 + 4] = l; - line[5].data[512 + 4] = l; - line[5].data[640 + 3] = l; - line[5].data[768 + 3] = l; - line[5].data[896 + 3] = l; - - for (u16 j = ss->grid.current_group * 6 + 1; j < ss->grid.current_group * 6 + 6; j++) - line[j >> 3].data[(j & 7) << 7] = 2; - l = page == 0 ? 10 : 2; - for (u16 i = 122; i < 128; i++) line[0].data[i + 128] = l; - line[0].data[122 + 256] = l; - line[0].data[127 + 256] = l; - line[0].data[122 + 384] = l; - line[0].data[127 + 384] = l; + for (u16 i = 110; i < 116; i++) line[0].data[i + 128] = l; + line[0].data[110 + 256] = l; + line[0].data[115 + 256] = l; + line[0].data[110 + 384] = l; + line[0].data[115 + 384] = l; l = page == 1 ? 10 : 2; - line[0].data[122 + 512] = l; - line[0].data[127 + 512] = l; - line[0].data[122 + 640] = l; - line[0].data[127 + 640] = l; - for (u16 i = 122; i < 128; i++) line[0].data[i + 768] = l; + line[0].data[110 + 512] = l; + line[0].data[115 + 512] = l; + line[0].data[110 + 640] = l; + line[0].data[115 + 640] = l; + for (u16 i = 110; i < 116; i++) line[0].data[i + 768] = l; l = ss->grid.rotate ? 10 : 2; - line[1].data[128 + 123] = l; - line[1].data[128 + 124] = l; - line[1].data[128 + 125] = l; - line[1].data[256 + 122] = l; - line[1].data[256 + 126] = l; - line[1].data[384 + 122] = l; - line[1].data[384 + 126] = l; - line[1].data[512 + 125] = l; - line[1].data[512 + 126] = l; - line[1].data[512 + 127] = l; - line[1].data[640 + 126] = l; + line[0].data[128 + 123] = l; + line[0].data[128 + 124] = l; + line[0].data[128 + 125] = l; + line[0].data[256 + 122] = l; + line[0].data[256 + 126] = l; + line[0].data[384 + 122] = l; + line[0].data[384 + 126] = l; + line[0].data[512 + 125] = l; + line[0].data[512 + 126] = l; + line[0].data[512 + 127] = l; + line[0].data[640 + 126] = l; } void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page) { diff --git a/module/live_mode.c b/module/live_mode.c index 4a0f0399..b4513ac9 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -109,6 +109,8 @@ void set_live_mode() { dirty = D_ALL; activity_prev = 0xFF; grid_view_changed = true; + if (grid_mode == GRID_MODE_FULL) + grid_mode = GRID_MODE_LED; } void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, scene_state_t *ss) { diff --git a/src/state.h b/src/state.h index 05e47ecd..034b8112 100644 --- a/src/state.h +++ b/src/state.h @@ -25,7 +25,7 @@ #define EXEC_DEPTH 8 #define WHILE_DEPTH 10000 -#define GRID_GROUP_COUNT 8 +#define GRID_GROUP_COUNT 64 #define GRID_MAX_DIMENSION 16 #define GRID_BUTTON_COUNT 256 #define GRID_FADER_COUNT 64 From 6d2bb87d461b2cacf029536bffc6c76d4fd644cd Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 14 Nov 2017 20:31:20 -0800 Subject: [PATCH 014/117] added some getters --- src/ops/grid_ops.c | 69 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 144f1ff8..7ece615f 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -50,22 +50,28 @@ static void op_G_DIM_get (const void *data, scene_state_t *ss, exec_state_t * static void op_G_CLR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GRP_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GRP_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GRP_EN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_G_GRP_RST_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GRP_EN_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GRP_RST_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GRP_SW_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GRP_SC_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GRP_SC_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GRPI_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_LED_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_LED_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_LED_C_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_REC_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTX_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_EN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTN_EN_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_V_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_V_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_L_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTN_L_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTNI_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTNV_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTNL_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -76,11 +82,13 @@ static void op_G_GBTN_L_get (const void *data, scene_state_t *ss, exec_state_t * static void op_G_FDR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDX_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_EN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_EN_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_V_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_V_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_N_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_N_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_L_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_L_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDRI_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDRV_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDRN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -99,22 +107,22 @@ const tele_op_t op_G_ROTATE = MAKE_GET_OP(G.ROTATE, op_G_ROTATE_get, 1, false); const tele_op_t op_G_DIM = MAKE_GET_OP(G.DIM, op_G_DIM_get, 1, false); const tele_op_t op_G_CLR = MAKE_GET_OP(G.CLR, op_G_CLR_get, 0, false); -const tele_op_t op_G_GRP = MAKE_GET_OP(G.GRP, op_G_GRP_get, 1, false); -const tele_op_t op_G_GRP_EN = MAKE_GET_OP(G.GRP.EN, op_G_GRP_EN_get, 2, false); +const tele_op_t op_G_GRP = MAKE_GET_SET_OP(G.GRP, op_G_GRP_get, op_G_GRP_set, 0, true); +const tele_op_t op_G_GRP_EN = MAKE_GET_SET_OP(G.GRP.EN, op_G_GRP_EN_get, op_G_GRP_EN_set, 1, true); const tele_op_t op_G_GRP_RST = MAKE_GET_OP(G.GRP.RST, op_G_GRP_RST_get, 1, false); const tele_op_t op_G_GRP_SW = MAKE_GET_OP(G.GRP.SW, op_G_GRP_SW_get, 1, false); -const tele_op_t op_G_GRP_SC = MAKE_GET_OP(G.GRP.SC, op_G_GRP_SC_get, 2, false); +const tele_op_t op_G_GRP_SC = MAKE_GET_SET_OP(G.GRP.SC, op_G_GRP_SC_get, op_G_GRP_SC_set, 1, true); const tele_op_t op_G_GRPI = MAKE_GET_OP(G.GRPI, op_G_GRPI_get, 0, true); -const tele_op_t op_G_LED = MAKE_GET_OP(G.LED, op_G_LED_get, 3, false); +const tele_op_t op_G_LED = MAKE_GET_SET_OP(G.LED, op_G_LED_get, op_G_LED_set, 2, true); const tele_op_t op_G_LED_C = MAKE_GET_OP(G.LED.C, op_G_LED_C_get, 2, false); const tele_op_t op_G_REC = MAKE_GET_OP(G.REC, op_G_REC_get, 6, false); const tele_op_t op_G_BTN = MAKE_GET_OP(G.BTN, op_G_BTN_get, 8, false); const tele_op_t op_G_BTX = MAKE_GET_OP(G.BTX, op_G_BTX_get, 10, false); -const tele_op_t op_G_BTN_EN = MAKE_GET_OP(G.BTN.EN, op_G_BTN_EN_get, 2, false); +const tele_op_t op_G_BTN_EN = MAKE_GET_SET_OP(G.BTN.EN, op_G_BTN_EN_get, op_G_BTN_EN_set, 1, true); const tele_op_t op_G_BTN_V = MAKE_GET_SET_OP(G.BTN.V, op_G_BTN_V_get, op_G_BTN_V_set, 1, true); -const tele_op_t op_G_BTN_L = MAKE_GET_OP(G.BTN.L, op_G_BTN_L_get, 2, false); +const tele_op_t op_G_BTN_L = MAKE_GET_SET_OP(G.BTN.L, op_G_BTN_L_get, op_G_BTN_L_set, 1, true); const tele_op_t op_G_BTNI = MAKE_GET_OP(G.BTNI, op_G_BTNI_get, 0, true); const tele_op_t op_G_BTNV = MAKE_GET_OP(G.BTNV, op_G_BTNV_get, 0, true); const tele_op_t op_G_BTNL = MAKE_GET_OP(G.BTNL, op_G_BTNL_get, 1, false); @@ -124,10 +132,10 @@ const tele_op_t op_G_GBTN_L = MAKE_GET_OP(G.GBTN.L, op_G_GBTN_L_get, 3, false); const tele_op_t op_G_FDR = MAKE_GET_OP(G.FDR, op_G_FDR_get, 8, false); const tele_op_t op_G_FDX = MAKE_GET_OP(G.FDX, op_G_FDX_get, 10, false); -const tele_op_t op_G_FDR_EN = MAKE_GET_OP(G.FDR.EN, op_G_FDR_EN_get, 2, false); +const tele_op_t op_G_FDR_EN = MAKE_GET_SET_OP(G.FDR.EN, op_G_FDR_EN_get, op_G_FDR_EN_set, 1, true); const tele_op_t op_G_FDR_V = MAKE_GET_SET_OP(G.FDR.V, op_G_FDR_V_get, op_G_FDR_V_set, 1, true); const tele_op_t op_G_FDR_N = MAKE_GET_SET_OP(G.FDR.N, op_G_FDR_N_get, op_G_FDR_N_set, 1, true); -const tele_op_t op_G_FDR_L = MAKE_GET_OP(G.FDR.L, op_G_FDR_L_get, 2, false); +const tele_op_t op_G_FDR_L = MAKE_GET_SET_OP(G.FDR.L, op_G_FDR_L_get, op_G_FDR_L_set, 1, true); const tele_op_t op_G_FDRI = MAKE_GET_OP(G.FDRI, op_G_FDRI_get, 0, true); const tele_op_t op_G_FDRV = MAKE_GET_OP(G.FDRV, op_G_FDRV_get, 0, true); const tele_op_t op_G_FDRN = MAKE_GET_OP(G.FDRN, op_G_FDRN_get, 0, true); @@ -204,6 +212,10 @@ static void op_G_DIM_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat } static void op_G_GRP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, SG.current_group); +} + +static void op_G_GRP_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; SG.current_group = group; @@ -211,6 +223,11 @@ static void op_G_GRP_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat } static void op_G_GRP_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + cs_push(cs, group < (s16)0 || group >= (s16)GRID_GROUP_COUNT ? 0 : SG.group[group].enabled); +} + +static void op_G_GRP_EN_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 en = cs_pop(cs); if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; @@ -262,6 +279,11 @@ static void op_G_GRP_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_s } static void op_G_GRP_SC_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + cs_push(cs, group < (s16)0 || group >= (s16)GRID_GROUP_COUNT ? -1 : SG.group[group].script); +} + +static void op_G_GRP_SC_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 script = cs_pop(cs) - 1; @@ -278,6 +300,15 @@ static void op_G_GRPI_get(const void *NOTUSED(data), scene_state_t *ss, exec_sta static void op_G_LED_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 x = cs_pop(cs); s16 y = cs_pop(cs); + + if (x < (s16)0 || x >= (s16)GRID_MAX_DIMENSION) cs_push(cs, LED_OFF); + else if (y < (s16)0 || y >= (s16)GRID_MAX_DIMENSION) cs_push(cs, LED_OFF); + else cs_push(cs, SG.leds[x][y]); +} + +static void op_G_LED_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); GET_LEVEL(level); if (x < (s16)0 || x >= (s16)GRID_MAX_DIMENSION) return; @@ -405,6 +436,11 @@ static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat } static void op_G_BTN_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GBC.enabled); +} + +static void op_G_BTN_EN_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 en = cs_pop(cs); @@ -427,6 +463,11 @@ static void op_G_BTN_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_st } static void op_G_BTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GBC.background); +} + +static void op_G_BTN_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); GET_LEVEL(level); if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; @@ -561,6 +602,11 @@ static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat } static void op_G_FDR_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GFC.enabled); +} + +static void op_G_FDR_EN_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 en = cs_pop(cs); @@ -613,6 +659,11 @@ static void op_G_FDR_N_set(const void *NOTUSED(data), scene_state_t *ss, exec_st } static void op_G_FDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GFC.background); +} + +static void op_G_FDR_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); GET_LEVEL(level); if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; From 5addfc9097bbc1182a1b4311e53e423142c64c2f Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 14 Nov 2017 21:10:25 -0800 Subject: [PATCH 015/117] updated visualizer for groups --- module/grid.c | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/module/grid.c b/module/grid.c index 7a2dd994..fc3dd3d0 100644 --- a/module/grid.c +++ b/module/grid.c @@ -342,7 +342,7 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 } else { cell = 6; size = 4; - left = 5; + left = 10; for (int i = 0; i < 6; i++) region_fill(&line[i], 0); } @@ -426,7 +426,7 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u s[1] = 0; s[0] = 'G'; - font_string_region_clip_right(&line[1], s, 127, 0, 1, 0); + font_string_region_clip_right(&line[0], s, 127, 0, 1, 0); s[0] = 'X'; font_string_region_clip_right(&line[2], s, 127, 0, 1, 0); s[0] = 'Y'; @@ -437,7 +437,7 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u font_string_region_clip_right(&line[5], s, 127, 0, 1, 0); itoa(ss->grid.current_group, s, 10); - font_string_region_clip_right(&line[1], s, 117, 0, 8, 0); + font_string_region_clip_right(&line[0], s, 117, 0, 8, 0); itoa(area_x, s, 10); font_string_region_clip_right(&line[2], s, 117, 0, 8, 0); itoa(area_y, s, 10); @@ -447,35 +447,36 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u itoa(area_h, s, 10); font_string_region_clip_right(&line[5], s, 117, 0, 8, 0); - for (u16 j = 9; j < 48; j += 2) line[j >> 3].data[119 + ((j & 7) << 7)] = 1; + for (u16 j = 0; j < 9; j += 2) line[j >> 3].data[119 + ((j & 7) << 7)] = 1; + for (u16 j = 17; j < 48; j += 2) line[j >> 3].data[119 + ((j & 7) << 7)] = 1; u8 l; l = page == 0 ? 10 : 2; - for (u16 i = 110; i < 116; i++) line[0].data[i + 128] = l; - line[0].data[110 + 256] = l; - line[0].data[115 + 256] = l; - line[0].data[110 + 384] = l; - line[0].data[115 + 384] = l; + for (u16 i = 0; i < 6; i++) line[0].data[i] = l; + line[0].data[0 + 128] = l; + line[0].data[5 + 128] = l; + line[0].data[0 + 256] = l; + line[0].data[5 + 256] = l; l = page == 1 ? 10 : 2; - line[0].data[110 + 512] = l; - line[0].data[115 + 512] = l; - line[0].data[110 + 640] = l; - line[0].data[115 + 640] = l; - for (u16 i = 110; i < 116; i++) line[0].data[i + 768] = l; + line[0].data[0 + 384] = l; + line[0].data[5 + 384] = l; + line[0].data[0 + 512] = l; + line[0].data[5 + 512] = l; + for (u16 i = 0; i < 6; i++) line[0].data[i + 640] = l; l = ss->grid.rotate ? 10 : 2; - line[0].data[128 + 123] = l; - line[0].data[128 + 124] = l; - line[0].data[128 + 125] = l; - line[0].data[256 + 122] = l; - line[0].data[256 + 126] = l; - line[0].data[384 + 122] = l; - line[0].data[384 + 126] = l; - line[0].data[512 + 125] = l; - line[0].data[512 + 126] = l; - line[0].data[512 + 127] = l; - line[0].data[640 + 126] = l; + line[1].data[0 + 1] = l; + line[1].data[0 + 2] = l; + line[1].data[0 + 3] = l; + line[1].data[128 + 0] = l; + line[1].data[128 + 4] = l; + line[1].data[256 + 0] = l; + line[1].data[256 + 4] = l; + line[1].data[384 + 3] = l; + line[1].data[384 + 4] = l; + line[1].data[384 + 5] = l; + line[1].data[512 + 4] = l; } void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page) { From 35e2aa55c699236eb514011c519b9992233b0ef6 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Wed, 15 Nov 2017 21:41:34 -0800 Subject: [PATCH 016/117] starting new ops --- src/match_token.rl | 16 +++ src/ops/grid_ops.c | 244 +++++++++++++++++++++++++++++++++++++++++++-- src/ops/grid_ops.h | 16 +++ src/ops/op.c | 17 ++-- src/ops/op_enum.h | 16 +++ 5 files changed, 296 insertions(+), 13 deletions(-) diff --git a/src/match_token.rl b/src/match_token.rl index 092fd8e2..cb70dbd9 100644 --- a/src/match_token.rl +++ b/src/match_token.rl @@ -451,6 +451,7 @@ "G.CLR" => { MATCH_OP(E_OP_G_CLR); }; "G.ROTATE" => { MATCH_OP(E_OP_G_ROTATE); }; "G.DIM" => { MATCH_OP(E_OP_G_DIM); }; + "G.KEY" => { MATCH_OP(E_OP_G_KEY); }; "G.GRP" => { MATCH_OP(E_OP_G_GRP); }; "G.GRP.EN" => { MATCH_OP(E_OP_G_GRP_EN); }; @@ -462,29 +463,44 @@ "G.LED" => { MATCH_OP(E_OP_G_LED); }; "G.LED.C" => { MATCH_OP(E_OP_G_LED_C); }; "G.REC" => { MATCH_OP(E_OP_G_REC); }; + "G.RCT" => { MATCH_OP(E_OP_G_RCT); }; "G.BTN" => { MATCH_OP(E_OP_G_BTN); }; "G.BTX" => { MATCH_OP(E_OP_G_BTX); }; + "G.GBT" => { MATCH_OP(E_OP_G_GBT); }; + "G.GBX" => { MATCH_OP(E_OP_G_GBX); }; "G.BTN.EN" => { MATCH_OP(E_OP_G_BTN_EN); }; "G.BTN.V" => { MATCH_OP(E_OP_G_BTN_V); }; "G.BTN.L" => { MATCH_OP(E_OP_G_BTN_L); }; + "G.BTN.X" => { MATCH_OP(E_OP_G_BTN_X); }; + "G.BTN.Y" => { MATCH_OP(E_OP_G_BTN_Y); }; "G.BTNI" => { MATCH_OP(E_OP_G_BTNI); }; "G.BTNV" => { MATCH_OP(E_OP_G_BTNV); }; "G.BTNL" => { MATCH_OP(E_OP_G_BTNL); }; + "G.BTNX" => { MATCH_OP(E_OP_G_BTNX); }; + "G.BTNY" => { MATCH_OP(E_OP_G_BTNY); }; + "G.BTN.PR" => { MATCH_OP(E_OP_G_BTN_PR); }; "G.BTN.SW" => { MATCH_OP(E_OP_G_BTN_SW); }; "G.GBTN.V" => { MATCH_OP(E_OP_G_GBTN_V); }; "G.GBTN.L" => { MATCH_OP(E_OP_G_GBTN_L); }; "G.FDR" => { MATCH_OP(E_OP_G_FDR); }; "G.FDX" => { MATCH_OP(E_OP_G_FDX); }; + "G.GFD" => { MATCH_OP(E_OP_G_GFD); }; + "G.GFX" => { MATCH_OP(E_OP_G_GFX); }; "G.FDR.EN" => { MATCH_OP(E_OP_G_FDR_EN); }; "G.FDR.V" => { MATCH_OP(E_OP_G_FDR_V); }; "G.FDR.N" => { MATCH_OP(E_OP_G_FDR_N); }; "G.FDR.L" => { MATCH_OP(E_OP_G_FDR_L); }; + "G.FDR.X" => { MATCH_OP(E_OP_G_FDR_X); }; + "G.FDR.Y" => { MATCH_OP(E_OP_G_FDR_Y); }; "G.FDRI" => { MATCH_OP(E_OP_G_FDRI); }; "G.FDRV" => { MATCH_OP(E_OP_G_FDRV); }; "G.FDRN" => { MATCH_OP(E_OP_G_FDRN); }; "G.FDRL" => { MATCH_OP(E_OP_G_FDRL); }; + "G.FDRX" => { MATCH_OP(E_OP_G_FDRX); }; + "G.FDRY" => { MATCH_OP(E_OP_G_FDRY); }; + "G.FDR.PR" => { MATCH_OP(E_OP_G_FDR_PR); }; "G.GFDR.V" => { MATCH_OP(E_OP_G_GFDR_V); }; "G.GFDR.N" => { MATCH_OP(E_OP_G_GFDR_N); }; "G.GFDR.L" => { MATCH_OP(E_OP_G_GFDR_L); }; diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 7ece615f..fec90f12 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -45,9 +45,10 @@ static s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value); // clang-format off static void op_G_RST_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_CLR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_ROTATE_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_DIM_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_G_CLR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_KEY_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GRP_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GRP_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -63,24 +64,40 @@ static void op_G_LED_get (const void *data, scene_state_t *ss, exec_state_t * static void op_G_LED_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_LED_C_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_REC_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_RCT_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTX_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GBT_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GBX_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_EN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_EN_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_V_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_V_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_L_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_L_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTN_X_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTN_X_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTN_Y_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTN_Y_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTNI_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTNV_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTNV_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTNL_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTNL_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTNX_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTNX_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTNY_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTNY_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_BTN_SW_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_BTN_PR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GBTN_V_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GBTN_L_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDX_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GFD_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GFX_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_EN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_EN_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_V_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -89,10 +106,22 @@ static void op_G_FDR_N_get (const void *data, scene_state_t *ss, exec_state_t * static void op_G_FDR_N_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_L_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_L_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_X_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_X_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_Y_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_Y_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDRI_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDRV_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDRV_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDRN_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDRN_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDRL_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDRL_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDRX_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDRX_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDRY_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDRY_set (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_FDR_PR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GFDR_V_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GFDR_N_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GFDR_L_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -106,6 +135,7 @@ const tele_op_t op_G_RST = MAKE_GET_OP(G.RST, op_G_RST_get, 0, false); const tele_op_t op_G_ROTATE = MAKE_GET_OP(G.ROTATE, op_G_ROTATE_get, 1, false); const tele_op_t op_G_DIM = MAKE_GET_OP(G.DIM, op_G_DIM_get, 1, false); const tele_op_t op_G_CLR = MAKE_GET_OP(G.CLR, op_G_CLR_get, 0, false); +const tele_op_t op_G_KEY = MAKE_GET_OP(G.KEY, op_G_KEY_get, 3, false); const tele_op_t op_G_GRP = MAKE_GET_SET_OP(G.GRP, op_G_GRP_get, op_G_GRP_set, 0, true); const tele_op_t op_G_GRP_EN = MAKE_GET_SET_OP(G.GRP.EN, op_G_GRP_EN_get, op_G_GRP_EN_set, 1, true); @@ -117,29 +147,44 @@ const tele_op_t op_G_GRPI = MAKE_GET_OP(G.GRPI, op_G_GRPI_get, 0, true); const tele_op_t op_G_LED = MAKE_GET_SET_OP(G.LED, op_G_LED_get, op_G_LED_set, 2, true); const tele_op_t op_G_LED_C = MAKE_GET_OP(G.LED.C, op_G_LED_C_get, 2, false); const tele_op_t op_G_REC = MAKE_GET_OP(G.REC, op_G_REC_get, 6, false); +const tele_op_t op_G_RCT = MAKE_GET_OP(G.RCT, op_G_RCT_get, 6, false); const tele_op_t op_G_BTN = MAKE_GET_OP(G.BTN, op_G_BTN_get, 8, false); const tele_op_t op_G_BTX = MAKE_GET_OP(G.BTX, op_G_BTX_get, 10, false); +const tele_op_t op_G_GBT = MAKE_GET_OP(G.GBT, op_G_GBT_get, 9, false); +const tele_op_t op_G_GBX = MAKE_GET_OP(G.GBX, op_G_GBX_get, 11, false); const tele_op_t op_G_BTN_EN = MAKE_GET_SET_OP(G.BTN.EN, op_G_BTN_EN_get, op_G_BTN_EN_set, 1, true); const tele_op_t op_G_BTN_V = MAKE_GET_SET_OP(G.BTN.V, op_G_BTN_V_get, op_G_BTN_V_set, 1, true); const tele_op_t op_G_BTN_L = MAKE_GET_SET_OP(G.BTN.L, op_G_BTN_L_get, op_G_BTN_L_set, 1, true); +const tele_op_t op_G_BTN_X = MAKE_GET_SET_OP(G.BTN.X, op_G_BTN_X_get, op_G_BTN_X_set, 1, true); +const tele_op_t op_G_BTN_Y = MAKE_GET_SET_OP(G.BTN.Y, op_G_BTN_Y_get, op_G_BTN_Y_set, 1, true); const tele_op_t op_G_BTNI = MAKE_GET_OP(G.BTNI, op_G_BTNI_get, 0, true); -const tele_op_t op_G_BTNV = MAKE_GET_OP(G.BTNV, op_G_BTNV_get, 0, true); -const tele_op_t op_G_BTNL = MAKE_GET_OP(G.BTNL, op_G_BTNL_get, 1, false); +const tele_op_t op_G_BTNV = MAKE_GET_SET_OP(G.BTNV, op_G_BTNV_get, op_G_BTNV_set, 0, true); +const tele_op_t op_G_BTNL = MAKE_GET_SET_OP(G.BTNL, op_G_BTNL_get, op_G_BTNL_set, 0, true); +const tele_op_t op_G_BTNX = MAKE_GET_SET_OP(G.BTNX, op_G_BTNX_get, op_G_BTNX_set, 0, true); +const tele_op_t op_G_BTNY = MAKE_GET_SET_OP(G.BTNY, op_G_BTNY_get, op_G_BTNY_set, 0, true); const tele_op_t op_G_BTN_SW = MAKE_GET_OP(G.BTN.SW, op_G_BTN_SW_get, 1, false); +const tele_op_t op_G_BTN_PR = MAKE_GET_OP(G.BTN.PR, op_G_BTN_PR_get, 2, false); const tele_op_t op_G_GBTN_V = MAKE_GET_OP(G.GBTN.V, op_G_GBTN_V_get, 2, false); const tele_op_t op_G_GBTN_L = MAKE_GET_OP(G.GBTN.L, op_G_GBTN_L_get, 3, false); const tele_op_t op_G_FDR = MAKE_GET_OP(G.FDR, op_G_FDR_get, 8, false); const tele_op_t op_G_FDX = MAKE_GET_OP(G.FDX, op_G_FDX_get, 10, false); +const tele_op_t op_G_GFD = MAKE_GET_OP(G.GFD, op_G_GFD_get, 9, false); +const tele_op_t op_G_GFX = MAKE_GET_OP(G.GFX, op_G_GFX_get, 11, false); const tele_op_t op_G_FDR_EN = MAKE_GET_SET_OP(G.FDR.EN, op_G_FDR_EN_get, op_G_FDR_EN_set, 1, true); const tele_op_t op_G_FDR_V = MAKE_GET_SET_OP(G.FDR.V, op_G_FDR_V_get, op_G_FDR_V_set, 1, true); const tele_op_t op_G_FDR_N = MAKE_GET_SET_OP(G.FDR.N, op_G_FDR_N_get, op_G_FDR_N_set, 1, true); const tele_op_t op_G_FDR_L = MAKE_GET_SET_OP(G.FDR.L, op_G_FDR_L_get, op_G_FDR_L_set, 1, true); +const tele_op_t op_G_FDR_X = MAKE_GET_SET_OP(G.FDR.X, op_G_FDR_X_get, op_G_FDR_X_set, 1, true); +const tele_op_t op_G_FDR_Y = MAKE_GET_SET_OP(G.FDR.Y, op_G_FDR_Y_get, op_G_FDR_Y_set, 1, true); const tele_op_t op_G_FDRI = MAKE_GET_OP(G.FDRI, op_G_FDRI_get, 0, true); -const tele_op_t op_G_FDRV = MAKE_GET_OP(G.FDRV, op_G_FDRV_get, 0, true); -const tele_op_t op_G_FDRN = MAKE_GET_OP(G.FDRN, op_G_FDRN_get, 0, true); -const tele_op_t op_G_FDRL = MAKE_GET_OP(G.FDRL, op_G_FDRL_get, 1, false); +const tele_op_t op_G_FDRV = MAKE_GET_SET_OP(G.FDRV, op_G_FDRV_get, op_G_FDRV_set, 0, true); +const tele_op_t op_G_FDRN = MAKE_GET_SET_OP(G.FDRN, op_G_FDRN_get, op_G_FDRN_set, 0, true); +const tele_op_t op_G_FDRL = MAKE_GET_SET_OP(G.FDRL, op_G_FDRL_get, op_G_FDRL_set, 0, true); +const tele_op_t op_G_FDRX = MAKE_GET_SET_OP(G.FDRX, op_G_FDRX_get, op_G_FDRX_set, 0, true); +const tele_op_t op_G_FDRY = MAKE_GET_SET_OP(G.FDRY, op_G_FDRY_get, op_G_FDRY_set, 0, true); +const tele_op_t op_G_FDR_PR = MAKE_GET_OP(G.FDR.PR, op_G_FDR_PR_get, 2, false); const tele_op_t op_G_GFDR_V = MAKE_GET_OP(G.GFDR.V, op_G_GFDR_V_get, 2, false); const tele_op_t op_G_GFDR_N = MAKE_GET_OP(G.GFDR.N, op_G_GFDR_N_get, 2, false); const tele_op_t op_G_GFDR_L = MAKE_GET_OP(G.GFDR.L, op_G_GFDR_L_get, 3, false); @@ -211,6 +256,12 @@ static void op_G_DIM_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat SG.scr_dirty = SG.grid_dirty = 1; } +static void op_G_KEY_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs) { + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + s16 action = cs_pop(cs); +} + static void op_G_GRP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.current_group); } @@ -362,6 +413,15 @@ static void op_G_REC_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat SG.scr_dirty = SG.grid_dirty = 1; } +static void op_G_RCT_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 x1 = cs_pop(cs); + s16 y1 = cs_pop(cs); + s16 x2 = cs_pop(cs); + s16 y2 = cs_pop(cs); + GET_LEVEL(fill); + GET_LEVEL(border); +} + static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 x = cs_pop(cs); @@ -390,6 +450,18 @@ static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat SG.scr_dirty = SG.grid_dirty = 1; } +static void op_G_GBT_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + s16 i = cs_pop(cs); + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + s16 w = cs_pop(cs); + s16 h = cs_pop(cs); + s16 latch = cs_pop(cs); + GET_LEVEL(level); + s16 script = cs_pop(cs) - 1; +} + static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 id = cs_pop(cs); s16 _x = cs_pop(cs); @@ -435,6 +507,20 @@ static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat SG.scr_dirty = SG.grid_dirty = 1; } +static void op_G_GBX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + s16 id = cs_pop(cs); + s16 _x = cs_pop(cs); + s16 _y = cs_pop(cs); + s16 _w = cs_pop(cs); + s16 _h = cs_pop(cs); + s16 latch = cs_pop(cs); + GET_LEVEL(level); + s16 script = cs_pop(cs) - 1; + s16 count_x = cs_pop(cs); + s16 count_y = cs_pop(cs); +} + static void op_G_BTN_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GBC.enabled); @@ -475,6 +561,26 @@ static void op_G_BTN_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_st SG.scr_dirty = SG.grid_dirty = 1; } +static void op_G_BTN_X_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + cs_push(cs, 0); +} + +static void op_G_BTN_X_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + s16 x = cs_pop(cs); +} + +static void op_G_BTN_Y_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + cs_push(cs, 0); +} + +static void op_G_BTN_Y_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + s16 y = cs_pop(cs); +} + static void op_G_BTNI_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.latest_button); } @@ -483,12 +589,38 @@ static void op_G_BTNV_get(const void *NOTUSED(data), scene_state_t *ss, exec_sta cs_push(cs, SG.button[SG.latest_button].state); } +static void op_G_BTNV_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 value = cs_pop(cs); + SG.button[SG.latest_button].state = value != 0; + SG.scr_dirty = SG.grid_dirty = 1; +} + static void op_G_BTNL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, SG.button[SG.latest_button].common.background); +} + +static void op_G_BTNL_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { GET_LEVEL(level); SG.button[SG.latest_button].common.background = level; SG.scr_dirty = SG.grid_dirty = 1; } +static void op_G_BTNX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, 0); +} + +static void op_G_BTNX_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 x = cs_pop(cs); +} + +static void op_G_BTNY_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, 0); +} + +static void op_G_BTNY_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 y = cs_pop(cs); +} + static void op_G_BTN_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 id = cs_pop(cs); if (id < (s16)0 || id >= (s16)GRID_BUTTON_COUNT) return; @@ -500,6 +632,11 @@ static void op_G_BTN_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_s SG.scr_dirty = SG.grid_dirty = 1; } +static void op_G_BTN_PR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 id = cs_pop(cs); + s16 action = cs_pop(cs); +} + static void op_G_GBTN_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 value = cs_pop(cs); @@ -556,6 +693,18 @@ static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat SG.scr_dirty = SG.grid_dirty = 1; } +static void op_G_GFD_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + s16 i = cs_pop(cs); + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + s16 w = cs_pop(cs); + s16 h = cs_pop(cs); + s16 dir = cs_pop(cs); + GET_LEVEL(level); + s16 script = cs_pop(cs) - 1; +} + static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 id = cs_pop(cs); s16 _x = cs_pop(cs); @@ -601,6 +750,20 @@ static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat SG.scr_dirty = SG.grid_dirty = 1; } +static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + s16 id = cs_pop(cs); + s16 _x = cs_pop(cs); + s16 _y = cs_pop(cs); + s16 _w = cs_pop(cs); + s16 _h = cs_pop(cs); + s16 dir = cs_pop(cs); + GET_LEVEL(level); + s16 script = cs_pop(cs) - 1; + s16 count_x = cs_pop(cs); + s16 count_y = cs_pop(cs); +} + static void op_G_FDR_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GFC.enabled); @@ -671,6 +834,26 @@ static void op_G_FDR_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_st SG.scr_dirty = SG.grid_dirty = 1; } +static void op_G_FDR_X_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + cs_push(cs, 0); +} + +static void op_G_FDR_X_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + s16 x = cs_pop(cs); +} + +static void op_G_FDR_Y_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + cs_push(cs, 0); +} + +static void op_G_FDR_Y_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs); + s16 y = cs_pop(cs); +} + static void op_G_FDRI_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.latest_fader); } @@ -682,16 +865,65 @@ static void op_G_FDRV_get(const void *NOTUSED(data), scene_state_t *ss, exec_sta cs_push(cs, value); } +static void op_G_FDRV_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 value = cs_pop(cs); + s16 i = SG.latest_fader; + + if (value < SG.group[GFC.group].fader_min) value = SG.group[GFC.group].fader_min; + else if (value > SG.group[GFC.group].fader_max) value = SG.group[GFC.group].fader_max; + + GF.value = scale(SG.group[GFC.group].fader_min, + SG.group[GFC.group].fader_max, 0, GF.dir ? GFC.h - 1 : GFC.w - 1, value); + SG.scr_dirty = SG.grid_dirty = 1; +} + static void op_G_FDRN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.fader[SG.latest_fader].value); } +static void op_G_FDRN_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 value = cs_pop(cs) - 1; + s16 i = SG.latest_fader; + + if (value < (s16)0) value = 0; + else if (GF.dir && value >= (s16)GFC.h) value = GFC.h - 1; + else if (!GF.dir && value >= (s16)GFC.w) value = GFC.w - 1; + + GF.value = value; + SG.scr_dirty = SG.grid_dirty = 1; +} + static void op_G_FDRL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, SG.fader[SG.latest_fader].common.background); +} + +static void op_G_FDRL_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { GET_LEVEL(level); SG.fader[SG.latest_fader].common.background = level; SG.scr_dirty = SG.grid_dirty = 1; } +static void op_G_FDRX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, 0); +} + +static void op_G_FDRX_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 x = cs_pop(cs); +} + +static void op_G_FDRY_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, 0); +} + +static void op_G_FDRY_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 y = cs_pop(cs); +} + +static void op_G_FDR_PR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 id = cs_pop(cs); + s16 value = cs_pop(cs); +} + static void op_G_GFDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 value = cs_pop(cs); diff --git a/src/ops/grid_ops.h b/src/ops/grid_ops.h index e2b2dc81..a92d95f1 100644 --- a/src/ops/grid_ops.h +++ b/src/ops/grid_ops.h @@ -7,6 +7,7 @@ extern const tele_op_t op_G_RST; extern const tele_op_t op_G_CLR; extern const tele_op_t op_G_ROTATE; extern const tele_op_t op_G_DIM; +extern const tele_op_t op_G_KEY; extern const tele_op_t op_G_GRP; extern const tele_op_t op_G_GRP_EN; @@ -18,33 +19,48 @@ extern const tele_op_t op_G_GRPI; extern const tele_op_t op_G_LED; extern const tele_op_t op_G_LED_C; extern const tele_op_t op_G_REC; +extern const tele_op_t op_G_RCT; extern const tele_op_t op_G_BTN; extern const tele_op_t op_G_BTX; +extern const tele_op_t op_G_GBT; +extern const tele_op_t op_G_GBX; extern const tele_op_t op_G_BTN_EN; extern const tele_op_t op_G_BTN_V; extern const tele_op_t op_G_BTN_L; +extern const tele_op_t op_G_BTN_X; +extern const tele_op_t op_G_BTN_Y; extern const tele_op_t op_G_BTNI; extern const tele_op_t op_G_BTNV; extern const tele_op_t op_G_BTNL; +extern const tele_op_t op_G_BTNX; +extern const tele_op_t op_G_BTNY; extern const tele_op_t op_G_BTN_SW; +extern const tele_op_t op_G_BTN_PR; extern const tele_op_t op_G_GBTN_V; extern const tele_op_t op_G_GBTN_L; extern const tele_op_t op_G_FDR; extern const tele_op_t op_G_FDX; +extern const tele_op_t op_G_GFD; +extern const tele_op_t op_G_GFX; extern const tele_op_t op_G_FDR_EN; extern const tele_op_t op_G_FDR_V; extern const tele_op_t op_G_FDR_N; extern const tele_op_t op_G_FDR_L; +extern const tele_op_t op_G_FDR_X; +extern const tele_op_t op_G_FDR_Y; extern const tele_op_t op_G_FDRI; extern const tele_op_t op_G_FDRV; extern const tele_op_t op_G_FDRN; extern const tele_op_t op_G_FDRL; +extern const tele_op_t op_G_FDRX; +extern const tele_op_t op_G_FDRY; extern const tele_op_t op_G_GFDR_V; extern const tele_op_t op_G_GFDR_N; extern const tele_op_t op_G_GFDR_L; extern const tele_op_t op_G_GFDR_RN; +extern const tele_op_t op_G_FDR_PR; extern const tele_op_t op_G_XYP; extern const tele_op_t op_G_XYP_X; diff --git a/src/ops/op.c b/src/ops/op.c index aa44f29a..33b83283 100644 --- a/src/ops/op.c +++ b/src/ops/op.c @@ -163,13 +163,16 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_TI_PRM_INIT, // grid - &op_G_RST, &op_G_CLR, &op_G_ROTATE, &op_G_DIM, &op_G_GRP, &op_G_GRP_EN, - &op_G_GRP_RST, &op_G_GRP_SW, &op_G_GRP_SC, &op_G_GRPI, &op_G_LED, - &op_G_LED_C, &op_G_REC, &op_G_BTN, &op_G_BTX, &op_G_BTN_EN, &op_G_BTN_V, - &op_G_BTN_L, &op_G_BTNI, &op_G_BTNV, &op_G_BTNL, &op_G_BTN_SW, &op_G_GBTN_V, - &op_G_GBTN_L, &op_G_FDR, &op_G_FDX, &op_G_FDR_EN, &op_G_FDR_V, &op_G_FDR_N, - &op_G_FDR_L, &op_G_FDRI, &op_G_FDRV, &op_G_FDRN, &op_G_FDRL, &op_G_GFDR_V, - &op_G_GFDR_N, &op_G_GFDR_L, &op_G_GFDR_RN, &op_G_XYP, &op_G_XYP_X, + &op_G_RST, &op_G_CLR, &op_G_ROTATE, &op_G_DIM, &op_G_KEY, &op_G_GRP, + &op_G_GRP_EN, &op_G_GRP_RST, &op_G_GRP_SW, &op_G_GRP_SC, &op_G_GRPI, + &op_G_LED, &op_G_LED_C, &op_G_REC, &op_G_RCT, &op_G_BTN, &op_G_BTX, + &op_G_GBT, &op_G_GBX, &op_G_BTN_EN, &op_G_BTN_V, &op_G_BTN_L, &op_G_BTN_X, + &op_G_BTN_Y, &op_G_BTNI, &op_G_BTNV, &op_G_BTNL, &op_G_BTNX, &op_G_BTNY, + &op_G_BTN_SW, &op_G_BTN_PR, &op_G_GBTN_V, &op_G_GBTN_L, &op_G_FDR, + &op_G_FDX, &op_G_GFD, &op_G_GFX, &op_G_FDR_EN, &op_G_FDR_V, &op_G_FDR_N, + &op_G_FDR_L, &op_G_FDR_X, &op_G_FDR_Y, &op_G_FDRI, &op_G_FDRV, &op_G_FDRN, + &op_G_FDRL, &op_G_FDRX, &op_G_FDRY, &op_G_FDR_PR, &op_G_GFDR_V, + &op_G_GFDR_N, &op_G_GFDR_L, &op_G_GFDR_RN, &op_G_XYP, &op_G_XYP_X, &op_G_XYP_Y }; diff --git a/src/ops/op_enum.h b/src/ops/op_enum.h index 139a01c0..b79912b7 100644 --- a/src/ops/op_enum.h +++ b/src/ops/op_enum.h @@ -390,6 +390,7 @@ typedef enum { E_OP_G_CLR, E_OP_G_ROTATE, E_OP_G_DIM, + E_OP_G_KEY, E_OP_G_GRP, E_OP_G_GRP_EN, E_OP_G_GRP_RST, @@ -399,27 +400,42 @@ typedef enum { E_OP_G_LED, E_OP_G_LED_C, E_OP_G_REC, + E_OP_G_RCT, E_OP_G_BTN, E_OP_G_BTX, + E_OP_G_GBT, + E_OP_G_GBX, E_OP_G_BTN_EN, E_OP_G_BTN_V, E_OP_G_BTN_L, + E_OP_G_BTN_X, + E_OP_G_BTN_Y, E_OP_G_BTNI, E_OP_G_BTNV, E_OP_G_BTNL, + E_OP_G_BTNX, + E_OP_G_BTNY, E_OP_G_BTN_SW, + E_OP_G_BTN_PR, E_OP_G_GBTN_V, E_OP_G_GBTN_L, E_OP_G_FDR, E_OP_G_FDX, + E_OP_G_GFD, + E_OP_G_GFX, E_OP_G_FDR_EN, E_OP_G_FDR_V, E_OP_G_FDR_N, E_OP_G_FDR_L, + E_OP_G_FDR_X, + E_OP_G_FDR_Y, E_OP_G_FDRI, E_OP_G_FDRV, E_OP_G_FDRN, E_OP_G_FDRL, + E_OP_G_FDRX, + E_OP_G_FDRY, + E_OP_G_FDR_PR, E_OP_G_GFDR_V, E_OP_G_GFDR_N, E_OP_G_GFDR_L, From 8885204b899fdead8bbbdaa71af150b75d1e25b1 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 19 Nov 2017 12:45:24 -0800 Subject: [PATCH 017/117] updated icons --- module/grid.c | 61 ++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/module/grid.c b/module/grid.c index fc3dd3d0..da3eca11 100644 --- a/module/grid.c +++ b/module/grid.c @@ -450,33 +450,40 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u for (u16 j = 0; j < 9; j += 2) line[j >> 3].data[119 + ((j & 7) << 7)] = 1; for (u16 j = 17; j < 48; j += 2) line[j >> 3].data[119 + ((j & 7) << 7)] = 1; - u8 l; - l = page == 0 ? 10 : 2; - for (u16 i = 0; i < 6; i++) line[0].data[i] = l; - line[0].data[0 + 128] = l; - line[0].data[5 + 128] = l; - line[0].data[0 + 256] = l; - line[0].data[5 + 256] = l; - - l = page == 1 ? 10 : 2; - line[0].data[0 + 384] = l; - line[0].data[5 + 384] = l; - line[0].data[0 + 512] = l; - line[0].data[5 + 512] = l; - for (u16 i = 0; i < 6; i++) line[0].data[i + 640] = l; - - l = ss->grid.rotate ? 10 : 2; - line[1].data[0 + 1] = l; - line[1].data[0 + 2] = l; - line[1].data[0 + 3] = l; - line[1].data[128 + 0] = l; - line[1].data[128 + 4] = l; - line[1].data[256 + 0] = l; - line[1].data[256 + 4] = l; - line[1].data[384 + 3] = l; - line[1].data[384 + 4] = l; - line[1].data[384 + 5] = l; - line[1].data[512 + 4] = l; + for (u16 i = 0; i < 6; i++) line[0].data[i] = 8; + line[0].data[0 + 128] = 8; + line[0].data[5 + 128] = 8; + line[0].data[0 + 256] = 8; + line[0].data[5 + 256] = 8; + line[0].data[0 + 384] = 8; + line[0].data[5 + 384] = 8; + line[0].data[0 + 512] = 8; + line[0].data[5 + 512] = 8; + for (u16 i = 0; i < 6; i++) line[0].data[i + 640] = 8; + if (page == 0) { + for (u16 i = 1; i < 5; i++) + for (u16 j = 1; j < 3; j++) + line[0].data[i + (j << 7)] = 15; + } else { + for (u16 i = 1; i < 5; i++) + for (u16 j = 3; j < 5; j++) + line[0].data[i + (j << 7)] = 15; + } + + u8 l = ss->grid.rotate ? 10 : 2; + line[1].data[0 + 0] = l; + line[1].data[1 + 0] = l; + line[1].data[2 + 0] = l; + line[1].data[3 + 0] = l; + line[1].data[3 + 128] = l; + line[1].data[3 + 256] = l; + line[1].data[1 + 384] = l; + line[1].data[3 + 384] = l; + line[1].data[5 + 384] = l; + line[1].data[2 + 512] = l; + line[1].data[3 + 512] = l; + line[1].data[4 + 512] = l; + line[1].data[3 + 640] = l; } void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page) { From 0c3ec73324c2ebb4a12f814f0603f49c336ff46f Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 23 Nov 2017 17:10:51 -0800 Subject: [PATCH 018/117] new ops implemented --- module/main.c | 5 + simulator/tt.c | 5 + src/ops/grid_ops.c | 329 +++++++++++++++++++++++++++++++++++++++------ src/teletype_io.h | 3 + tests/main.c | 3 + 5 files changed, 306 insertions(+), 39 deletions(-) diff --git a/module/main.c b/module/main.c index d40742c4..a330c1ae 100644 --- a/module/main.c +++ b/module/main.c @@ -856,6 +856,11 @@ void tele_save_calibration() { flash_update_cal(&scene_state.cal); } +void grid_key_press(uint8_t x, int8_t y, int8_t z) { + grid_process_key(&scene_state, x, y, z); +} + + //////////////////////////////////////////////////////////////////////////////// // main diff --git a/simulator/tt.c b/simulator/tt.c index 5c7a49b0..73329124 100644 --- a/simulator/tt.c +++ b/simulator/tt.c @@ -102,6 +102,11 @@ void tele_save_calibration() {} void tele_profile_script(size_t s) {} void tele_profile_delay(uint8_t d) {} +void grid_key_press(uint8_t x, int8_t y, int8_t z) { + printf("GRID KEY PRESS x:%" PRIu8 " y:%" PRIu8 " z:%" PRIu8, x, y, z); + printf("\n"); +} + int main() { char *in; time_t t; diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index fec90f12..00d8c5e6 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -1,5 +1,7 @@ #include "ops/grid_ops.h" #include "helpers.h" +#include "teletype.h" +#include "teletype_io.h" #define SG ss->grid #define GB ss->grid.button[i] @@ -40,6 +42,7 @@ static void grid_common_init(grid_common_t *gc); static s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value); +static void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fill, u8 border); // clang-format off @@ -260,6 +263,8 @@ static void op_G_KEY_get(const void *data, scene_state_t *ss, exec_state_t *es, s16 x = cs_pop(cs); s16 y = cs_pop(cs); s16 action = cs_pop(cs); + if (x < 0 || y < 0 || x >= GRID_MAX_DIMENSION || y >= GRID_MAX_DIMENSION) return; + grid_key_press(x, y, action != 0); } static void op_G_GRP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -331,7 +336,7 @@ static void op_G_GRP_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_s static void op_G_GRP_SC_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); - cs_push(cs, group < (s16)0 || group >= (s16)GRID_GROUP_COUNT ? -1 : SG.group[group].script); + cs_push(cs, group < (s16)0 || group >= (s16)GRID_GROUP_COUNT ? -1 : SG.group[group].script + 1); } static void op_G_GRP_SC_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -387,30 +392,7 @@ static void op_G_REC_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 h = cs_pop(cs); GET_LEVEL(fill); GET_LEVEL(border); - - for (u16 col = max(0, x + (s32)1); col < min(GRID_MAX_DIMENSION, x + w - (s32)1); col++) - for (u16 row = max(0, y + (s32)1); row < min(GRID_MAX_DIMENSION, y + h - (s32)1); row++) - SG.leds[col][row] = fill; - - if (y >= (s16)0 && y < (s16)GRID_MAX_DIMENSION) - for (u16 col = max(0, x); col < min(GRID_MAX_DIMENSION, (s32)x + w); col++) - SG.leds[col][y] = border; - - s16 row = y + h - (s16)1; - if (row >= (s16)0 && row < (s16)GRID_MAX_DIMENSION) - for (u16 col = max(0, x); col < min(GRID_MAX_DIMENSION, (s32)x + w); col++) - SG.leds[col][row] = border; - - if (x >= (s16)0 && x < (s16)GRID_MAX_DIMENSION) - for (u16 row = max(0, y); row < min(GRID_MAX_DIMENSION, (s32)y + h); row++) - SG.leds[x][row] = border; - - s16 col = x + w - 1; - if (col >= (s16)0 && col < (s16)GRID_MAX_DIMENSION) - for (u16 row = max(0, y); row < min(GRID_MAX_DIMENSION, (s32)y + h); row++) - SG.leds[col][row] = border; - - SG.scr_dirty = SG.grid_dirty = 1; + grid_rectangle(ss, x, y, w, h, fill, border); } static void op_G_RCT_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -420,6 +402,7 @@ static void op_G_RCT_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 y2 = cs_pop(cs); GET_LEVEL(fill); GET_LEVEL(border); + grid_rectangle(ss, x1, y1, x2 - x1 + 1, y2 - y1 + 1, fill, border); } static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -460,6 +443,24 @@ static void op_G_GBT_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 latch = cs_pop(cs); GET_LEVEL(level); s16 script = cs_pop(cs) - 1; + + if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; + if (script < 0 || script > INIT_SCRIPT) script = -1; + CLAMP_X_Y_W_H(return); + + GBC.enabled = true; + GBC.group = group; + GBC.x = x; + GBC.y = y; + GBC.w = w; + GBC.h = h; + GBC.background = level; + GBC.script = script; + GB.latch = latch != 0; + if (!GB.latch) GB.state = 0; + + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -519,6 +520,39 @@ static void op_G_GBX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); + + if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; + if (id < (s16)0 || id >= (s16)GRID_BUTTON_COUNT) return; + if (script < 0 || script > INIT_SCRIPT) script = -1; + if (count_x <= (s16)0) return; + if (count_x > (s16)16) count_x = 16; + if (count_y <= (s16)0) return; + if (count_y > (s16)16) count_y = 16; + + u16 i; + s16 x, y, w, h; + for (s16 cy = 0; cy < count_y; cy++) + for (s16 cx = 0; cx < count_x; cx++) { + i = id + cy * count_x + cx; + if (i >= GRID_BUTTON_COUNT) break; + GBC.enabled = true; + GBC.group = group; + x = _x + _w * cx; + w = _w; + y = _y + _h * cy; + h = _h; + CLAMP_X_Y_W_H(continue); + GBC.x = x; + GBC.y = y; + GBC.w = w; + GBC.h = h; + GBC.background = level; + GBC.script = script; + GB.latch = latch != 0; + if (!GB.latch) GB.state = 0; + } + + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTN_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -563,22 +597,46 @@ static void op_G_BTN_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_st static void op_G_BTN_X_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - cs_push(cs, 0); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GBC.x); } static void op_G_BTN_X_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 x = cs_pop(cs); + + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; + s16 y = GBC.y; + s16 w = GBC.w; + s16 h = GBC.h; + CLAMP_X_Y_W_H(return); + + GBC.x = x; + GBC.y = y; + GBC.w = w; + GBC.h = h; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTN_Y_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - cs_push(cs, 0); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GBC.y); } static void op_G_BTN_Y_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 y = cs_pop(cs); + + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; + s16 x = GBC.x; + s16 w = GBC.w; + s16 h = GBC.h; + CLAMP_X_Y_W_H(return); + + GBC.x = x; + GBC.y = y; + GBC.w = w; + GBC.h = h; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTNI_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -606,19 +664,43 @@ static void op_G_BTNL_set(const void *NOTUSED(data), scene_state_t *ss, exec_sta } static void op_G_BTNX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, 0); + cs_push(cs, SG.button[SG.latest_button].common.x); } static void op_G_BTNX_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 x = cs_pop(cs); + u16 i = SG.latest_button; + + s16 y = GBC.y; + s16 w = GBC.w; + s16 h = GBC.h; + CLAMP_X_Y_W_H(return); + + GBC.x = x; + GBC.y = y; + GBC.w = w; + GBC.h = h; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTNY_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, 0); + cs_push(cs, SG.button[SG.latest_button].common.y); } static void op_G_BTNY_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 y = cs_pop(cs); + u16 i = SG.latest_button; + + s16 x = GBC.x; + s16 w = GBC.w; + s16 h = GBC.h; + CLAMP_X_Y_W_H(return); + + GBC.x = x; + GBC.y = y; + GBC.w = w; + GBC.h = h; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_BTN_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -632,9 +714,30 @@ static void op_G_BTN_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_s SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTN_PR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - s16 id = cs_pop(cs); +static void op_G_BTN_PR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *es, command_state_t *cs) { + s16 i = cs_pop(cs); s16 action = cs_pop(cs); + + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; + if (!GBC.enabled || !SG.group[GBC.group].enabled) return; + + GB.state = GB.latch ? !GB.state : action != 0; + SG.latest_button = i; + SG.latest_group = GBC.group; + + if (GBC.script != -1) { + es_push(es); + if (!es->overflow) run_script_with_exec_state(ss, es, GBC.script); + es_pop(es); + } + + if (SG.group[GBC.group].script != -1) { + es_push(es); + if (!es->overflow) run_script_with_exec_state(ss, es, SG.group[GBC.group].script); + es_pop(es); + } + + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GBTN_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -703,6 +806,23 @@ static void op_G_GFD_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 dir = cs_pop(cs); GET_LEVEL(level); s16 script = cs_pop(cs) - 1; + + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; + if (script < 0 || script > INIT_SCRIPT) script = -1; + CLAMP_X_Y_W_H(return); + + GFC.enabled = true; + GFC.group = group; + GFC.x = x; + GFC.y = y; + GFC.w = w; + GFC.h = h; + GFC.background = level; + GFC.script = script; + GF.dir = dir != 0; + + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -762,6 +882,38 @@ static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); + + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; + if (id < (s16)0 || id >= (s16)GRID_FADER_COUNT) return; + if (script < 0 || script > INIT_SCRIPT) script = -1; + if (count_x <= (s16)0) return; + if (count_x > (s16)16) count_x = 16; + if (count_y <= (s16)0) return; + if (count_y > (s16)16) count_y = 16; + + u16 i; + s16 x, y, w, h; + for (u16 cy = 0; cy < count_y; cy++) + for (u16 cx = 0; cx < count_x; cx++) { + i = id + cy * count_x + cx; + if (i >= (s16)GRID_FADER_COUNT) break; + GFC.enabled = true; + GFC.group = group; + x = _x + _w * cx; + w = _w; + y = _y + _h * cy; + h = _h; + CLAMP_X_Y_W_H(continue); + GFC.x = x; + GFC.y = y; + GFC.w = w; + GFC.h = h; + GFC.background = level; + GFC.script = script; + GF.dir = dir != 0; + } + + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDR_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -836,22 +988,46 @@ static void op_G_FDR_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_st static void op_G_FDR_X_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - cs_push(cs, 0); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GFC.x); } static void op_G_FDR_X_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 x = cs_pop(cs); + + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; + s16 y = GFC.y; + s16 w = GFC.w; + s16 h = GFC.h; + CLAMP_X_Y_W_H(return); + + GFC.x = x; + GFC.y = y; + GFC.w = w; + GFC.h = h; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDR_Y_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - cs_push(cs, 0); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GFC.y); } static void op_G_FDR_Y_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 y = cs_pop(cs); + + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; + s16 x = GFC.x; + s16 w = GFC.w; + s16 h = GFC.h; + CLAMP_X_Y_W_H(return); + + GFC.x = x; + GFC.y = y; + GFC.w = w; + GFC.h = h; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDRI_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -878,7 +1054,7 @@ static void op_G_FDRV_set(const void *NOTUSED(data), scene_state_t *ss, exec_sta } static void op_G_FDRN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, SG.fader[SG.latest_fader].value); + cs_push(cs, SG.fader[SG.latest_fader].value + 1); } static void op_G_FDRN_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -904,24 +1080,73 @@ static void op_G_FDRL_set(const void *NOTUSED(data), scene_state_t *ss, exec_sta } static void op_G_FDRX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, 0); + cs_push(cs, SG.fader[SG.latest_fader].common.x); } static void op_G_FDRX_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 x = cs_pop(cs); + s16 i = SG.latest_fader; + + s16 y = GFC.y; + s16 w = GFC.w; + s16 h = GFC.h; + CLAMP_X_Y_W_H(return); + + GFC.x = x; + GFC.y = y; + GFC.w = w; + GFC.h = h; + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDRY_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, 0); + cs_push(cs, SG.fader[SG.latest_fader].common.y); } static void op_G_FDRY_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 y = cs_pop(cs); + s16 i = SG.latest_fader; + + s16 x = GFC.x; + s16 w = GFC.w; + s16 h = GFC.h; + CLAMP_X_Y_W_H(return); + + GFC.x = x; + GFC.y = y; + GFC.w = w; + GFC.h = h; + SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDR_PR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - s16 id = cs_pop(cs); - s16 value = cs_pop(cs); +static void op_G_FDR_PR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *es, command_state_t *cs) { + s16 i = cs_pop(cs); + s16 value = cs_pop(cs) - 1; + + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; + if (!GFC.enabled || !SG.group[GFC.group].enabled) return; + + if (value < (s16)0) value = 0; + else if (GF.dir && value >= (s16)GFC.h) value = GFC.h - 1; + else if (!GF.dir && value >= (s16)GFC.w) value = GFC.w - 1; + + GF.value = value; + SG.latest_fader = i; + SG.latest_group = GFC.group; + + if (GFC.script != -1) { + es_push(es); + if (!es->overflow) run_script_with_exec_state(ss, es, GFC.script); + es_pop(es); + } + + if (SG.group[GFC.group].script != -1) { + es_push(es); + if (!es->overflow) run_script_with_exec_state(ss, es, SG.group[GFC.group].script); + es_pop(es); + } + + SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GFDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { @@ -1028,3 +1253,29 @@ s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value) { if (a == b) return x; return (value - a) * (y - x) / (b - a) + x; } + +void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fill, u8 border) { + for (u16 col = max(0, x + (s32)1); col < min(GRID_MAX_DIMENSION, x + w - (s32)1); col++) + for (u16 row = max(0, y + (s32)1); row < min(GRID_MAX_DIMENSION, y + h - (s32)1); row++) + SG.leds[col][row] = fill; + + if (y >= (s16)0 && y < (s16)GRID_MAX_DIMENSION) + for (u16 col = max(0, x); col < min(GRID_MAX_DIMENSION, (s32)x + w); col++) + SG.leds[col][y] = border; + + s16 row = y + h - (s16)1; + if (row >= (s16)0 && row < (s16)GRID_MAX_DIMENSION) + for (u16 col = max(0, x); col < min(GRID_MAX_DIMENSION, (s32)x + w); col++) + SG.leds[col][row] = border; + + if (x >= (s16)0 && x < (s16)GRID_MAX_DIMENSION) + for (u16 row = max(0, y); row < min(GRID_MAX_DIMENSION, (s32)y + h); row++) + SG.leds[x][row] = border; + + s16 col = x + w - 1; + if (col >= (s16)0 && col < (s16)GRID_MAX_DIMENSION) + for (u16 row = max(0, y); row < min(GRID_MAX_DIMENSION, (s32)y + h); row++) + SG.leds[col][row] = border; + + SG.scr_dirty = SG.grid_dirty = 1; +} diff --git a/src/teletype_io.h b/src/teletype_io.h index 1eef8295..a228c08d 100644 --- a/src/teletype_io.h +++ b/src/teletype_io.h @@ -46,4 +46,7 @@ void tele_profile_script(size_t); void tele_profile_delay(uint8_t); #endif +// emulate grid key press +extern void grid_key_press(uint8_t x, int8_t y, int8_t z); + #endif diff --git a/tests/main.c b/tests/main.c index dc9c82cf..9c0cc6b7 100644 --- a/tests/main.c +++ b/tests/main.c @@ -32,8 +32,11 @@ void tele_profile_delay(uint8_t d) {} bool tele_get_input_state(uint8_t n) { return false; } + void tele_save_calibration() {} +void grid_key_press(uint8_t x, int8_t y, int8_t z) {} + GREATEST_MAIN_DEFS(); int main(int argc, char **argv) { From 0ae051e48c16240ecbe25c9c66ea8069c2a29de5 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 23 Nov 2017 18:41:31 -0800 Subject: [PATCH 019/117] refactor --- src/ops/grid_ops.c | 128 ++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 88 deletions(-) diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 00d8c5e6..1d7171c3 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -40,12 +40,13 @@ #define min(a, b) ((s32)(a) < (s32)(b) ? (s32)(a) : (s32)(b)) #define max(a, b) ((s32)(a) > (s32)(b) ? (s32)(a) : (s32)(b)) +// clang-format off + static void grid_common_init(grid_common_t *gc); static s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value); static void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fill, u8 border); - - -// clang-format off +static void grid_init_button(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 latch, u8 level, u8 script); +static void grid_init_fader(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 dir, u8 level, u8 script); static void op_G_RST_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_CLR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -419,17 +420,7 @@ static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat if (script < 0 || script > INIT_SCRIPT) script = -1; CLAMP_X_Y_W_H(return); - GBC.enabled = true; - GBC.group = SG.current_group; - GBC.x = x; - GBC.y = y; - GBC.w = w; - GBC.h = h; - GBC.background = level; - GBC.script = script; - GB.latch = latch != 0; - if (!GB.latch) GB.state = 0; - + grid_init_button(ss, SG.current_group, i, x, y, w, h, latch != 0, level, script); SG.scr_dirty = SG.grid_dirty = 1; } @@ -449,17 +440,7 @@ static void op_G_GBT_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat if (script < 0 || script > INIT_SCRIPT) script = -1; CLAMP_X_Y_W_H(return); - GBC.enabled = true; - GBC.group = group; - GBC.x = x; - GBC.y = y; - GBC.w = w; - GBC.h = h; - GBC.background = level; - GBC.script = script; - GB.latch = latch != 0; - if (!GB.latch) GB.state = 0; - + grid_init_button(ss, group, i, x, y, w, h, latch != 0, level, script); SG.scr_dirty = SG.grid_dirty = 1; } @@ -469,7 +450,7 @@ static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 _y = cs_pop(cs); s16 _w = cs_pop(cs); s16 _h = cs_pop(cs); - s16 latch = cs_pop(cs); + s16 latch = cs_pop(cs) != 0; GET_LEVEL(level); s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); @@ -488,21 +469,12 @@ static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat for (s16 cx = 0; cx < count_x; cx++) { i = id + cy * count_x + cx; if (i >= GRID_BUTTON_COUNT) break; - GBC.enabled = true; - GBC.group = SG.current_group; x = _x + _w * cx; w = _w; y = _y + _h * cy; h = _h; CLAMP_X_Y_W_H(continue); - GBC.x = x; - GBC.y = y; - GBC.w = w; - GBC.h = h; - GBC.background = level; - GBC.script = script; - GB.latch = latch != 0; - if (!GB.latch) GB.state = 0; + grid_init_button(ss, SG.current_group, i, x, y, w, h, latch, level, script); } SG.scr_dirty = SG.grid_dirty = 1; @@ -515,7 +487,7 @@ static void op_G_GBX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 _y = cs_pop(cs); s16 _w = cs_pop(cs); s16 _h = cs_pop(cs); - s16 latch = cs_pop(cs); + s16 latch = cs_pop(cs) != 0; GET_LEVEL(level); s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); @@ -535,21 +507,12 @@ static void op_G_GBX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat for (s16 cx = 0; cx < count_x; cx++) { i = id + cy * count_x + cx; if (i >= GRID_BUTTON_COUNT) break; - GBC.enabled = true; - GBC.group = group; x = _x + _w * cx; w = _w; y = _y + _h * cy; h = _h; CLAMP_X_Y_W_H(continue); - GBC.x = x; - GBC.y = y; - GBC.w = w; - GBC.h = h; - GBC.background = level; - GBC.script = script; - GB.latch = latch != 0; - if (!GB.latch) GB.state = 0; + grid_init_button(ss, group, i, x, y, w, h, latch, level, script); } SG.scr_dirty = SG.grid_dirty = 1; @@ -782,17 +745,7 @@ static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat if (script < 0 || script > INIT_SCRIPT) script = -1; CLAMP_X_Y_W_H(return); - GFC.enabled = true; - GFC.group = SG.current_group; - GFC.x = x; - GFC.y = y; - GFC.w = w; - GFC.h = h; - GFC.background = level; - GFC.script = script; - GF.dir = dir != 0; - // GF.value = 0; - + grid_init_fader(ss, SG.current_group, i, x, y, w, h, dir != 0, level, script); SG.scr_dirty = SG.grid_dirty = 1; } @@ -812,16 +765,7 @@ static void op_G_GFD_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat if (script < 0 || script > INIT_SCRIPT) script = -1; CLAMP_X_Y_W_H(return); - GFC.enabled = true; - GFC.group = group; - GFC.x = x; - GFC.y = y; - GFC.w = w; - GFC.h = h; - GFC.background = level; - GFC.script = script; - GF.dir = dir != 0; - + grid_init_fader(ss, group, i, x, y, w, h, dir != 0, level, script); SG.scr_dirty = SG.grid_dirty = 1; } @@ -831,7 +775,7 @@ static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 _y = cs_pop(cs); s16 _w = cs_pop(cs); s16 _h = cs_pop(cs); - s16 dir = cs_pop(cs); + s16 dir = cs_pop(cs) != 0; GET_LEVEL(level); s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); @@ -850,21 +794,12 @@ static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat for (u16 cx = 0; cx < count_x; cx++) { i = id + cy * count_x + cx; if (i >= (s16)GRID_FADER_COUNT) break; - GFC.enabled = true; - GFC.group = SG.current_group; x = _x + _w * cx; w = _w; y = _y + _h * cy; h = _h; CLAMP_X_Y_W_H(continue); - GFC.x = x; - GFC.y = y; - GFC.w = w; - GFC.h = h; - GFC.background = level; - GFC.script = script; - GF.dir = dir != 0; - // GF.value = 0; + grid_init_fader(ss, SG.current_group, i, x, y, w, h, dir, level, script); } SG.scr_dirty = SG.grid_dirty = 1; @@ -897,20 +832,12 @@ static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat for (u16 cx = 0; cx < count_x; cx++) { i = id + cy * count_x + cx; if (i >= (s16)GRID_FADER_COUNT) break; - GFC.enabled = true; - GFC.group = group; x = _x + _w * cx; w = _w; y = _y + _h * cy; h = _h; CLAMP_X_Y_W_H(continue); - GFC.x = x; - GFC.y = y; - GFC.w = w; - GFC.h = h; - GFC.background = level; - GFC.script = script; - GF.dir = dir != 0; + grid_init_fader(ss, group, i, x, y, w, h, dir, level, script); } SG.scr_dirty = SG.grid_dirty = 1; @@ -1279,3 +1206,28 @@ void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fill, u8 b SG.scr_dirty = SG.grid_dirty = 1; } + +static void grid_init_button(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 latch, u8 level, u8 script) { + GBC.enabled = true; + GBC.group = group; + GBC.x = x; + GBC.y = y; + GBC.w = w; + GBC.h = h; + GBC.background = level; + GBC.script = script; + GB.latch = latch != 0; + if (!GB.latch) GB.state = 0; +} + +static void grid_init_fader(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 dir, u8 level, u8 script) { + GFC.enabled = true; + GFC.group = group; + GFC.x = x; + GFC.y = y; + GFC.w = w; + GFC.h = h; + GFC.background = level; + GFC.script = script; + GF.dir = dir != 0; +} From 58a7d5bc86f0624c6689747277a1bc34fd11aaca Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 19 Dec 2017 16:49:33 -0800 Subject: [PATCH 020/117] grid visualizer complete --- module/grid.c | 390 +++++++++++++++++++++++++++++++-------------- module/grid.h | 9 +- module/live_mode.c | 41 +++-- module/main.c | 6 +- simulator/tt.c | 2 +- src/teletype_io.h | 2 +- tests/main.c | 2 +- 7 files changed, 302 insertions(+), 150 deletions(-) diff --git a/module/grid.c b/module/grid.c index da3eca11..dc8fc5a7 100644 --- a/module/grid.c +++ b/module/grid.c @@ -5,19 +5,82 @@ #include "teletype.h" #include "util.h" -/* -static const u8 font[][] = { +static const u8 glyph[16][6] = { { 0b000000, + 0b000000, + 0b000000, + 0b000000, + 0b000000, + 0b000000 + }, + { + 0b000000, + 0b011110, + 0b010010, + 0b010010, 0b011110, + 0b000000 + }, + { 0b000000, + 0b011110, + 0b010010, + 0b010010, + 0b010010, + 0b010010 + }, + { + 0b010010, + 0b010010, + 0b010010, + 0b010010, + 0b010010, + 0b010010 + }, + { + 0b010010, + 0b010010, + 0b010010, + 0b010010, + 0b011110, + 0b000000 + }, + { + 0b000000, + 0b011111, + 0b010000, + 0b010000, + 0b011111, + 0b000000 + }, + { + 0b000000, + 0b111111, 0b000000, 0b000000, + 0b111111, 0b000000 }, { 0b000000, + 0b111110, + 0b000010, + 0b000010, + 0b111110, + 0b000000 + }, + { 0b000000, + 0b011111, + 0b010000, + 0b010000, + 0b010000, + 0b010000 + }, + { + 0b000000, + 0b111111, 0b000000, 0b000000, 0b000000, @@ -25,18 +88,56 @@ static const u8 font[][] = { }, { 0b000000, + 0b111110, + 0b000010, + 0b000010, + 0b000010, + 0b000010 + }, + { + 0b010000, + 0b010000, + 0b010000, + 0b010000, + 0b010000, + 0b010000 + }, + { + 0b000010, + 0b000010, + 0b000010, + 0b000010, + 0b000010, + 0b000010 + }, + { + 0b010000, + 0b010000, + 0b010000, + 0b010000, + 0b011111, + 0b000000 + }, + { 0b000000, 0b000000, 0b000000, 0b000000, + 0b111111, + 0b000000 + }, + { + 0b000010, + 0b000010, + 0b000010, + 0b000010, + 0b111110, 0b000000 } }; -*/ static u16 size_x = 16, size_y = 8; -static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION]; -static u8 layout[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION]; +static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION/2]; static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); @@ -116,9 +217,9 @@ void grid_refresh(scene_state_t *ss) { SG.grid_dirty = 0; } -void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z) { - u8 x = SG.rotate ? monome_size_x() - _x - 1 : _x; - u8 y = SG.rotate ? monome_size_y() - _y - 1 : _y; +void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { + u8 x = SG.rotate && !ignore_rotate ? monome_size_x() - _x - 1 : _x; + u8 y = SG.rotate && !ignore_rotate ? monome_size_y() - _y - 1 : _y; u8 refresh = 0; u8 scripts[SCRIPT_COUNT]; for (u8 i = 0; i < SCRIPT_COUNT; i++) scripts[i] = 0; @@ -208,16 +309,13 @@ void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level) { ///////////////////////////////////////// screen functions -void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { +void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 ctrl, u8 x1, u8 y1, u8 x2, u8 y2) { switch (mode) { - case GRID_MODE_LED: + case GRID_MODE_EDIT: grid_screen_refresh_led(ss, 0, page, x1, y1, x2, y2); + if (ctrl) grid_screen_refresh_ctrl(ss, page, x1, y1, x2, y2); grid_screen_refresh_info(ss, page, x1, y1, x2, y2); break; - //case GRID_MODE_CTRL: - // grid_screen_refresh_ctrl(ss, page); - // grid_screen_refresh_info(ss, page, x1, y1, x2, y2); - // break; case GRID_MODE_FULL: grid_screen_refresh_led(ss, 1, page, x1, y1, x2, y2); break; @@ -231,61 +329,72 @@ void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { grid_fill_area_scr(0, 0, GRID_MAX_DIMENSION, GRID_MAX_DIMENSION, 0, 0); - /* - u8 level, last_x, last_y; + u8 last_x, last_y; + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { - if (!SG.group[GBC.group].enabled) continue; - level = (GBC.enabled ? (GB.state ? 15 : 8) : 1) << 4; + if (!SG.group[GBC.group].enabled || !GBC.enabled) continue; last_x = GBC.x + GBC.w - 1; last_y = GBC.y + GBC.h - 1; if (GBC.w == 1 && GBC.h == 1) { - grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 1, page); + grid_fill_area_scr(GBC.x, GBC.y, 1, 1, 1, page); } else if (GBC.w == 1 && GBC.h > 1) { - grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 2, page); - grid_fill_area_scr(GBC.x, GBC.y + 1, 1, GBC.h - 2, level + 3, page); - grid_fill_area_scr(GBC.x, last_y, 1, 1, level + 4, page); + grid_fill_area_scr(GBC.x, GBC.y, 1, 1, 2, page); + grid_fill_area_scr(GBC.x, GBC.y + 1, 1, GBC.h - 2, 3, page); + grid_fill_area_scr(GBC.x, last_y, 1, 1, 4, page); } else if (GBC.w > 1 && GBC.h == 1) { - grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 5, page); - grid_fill_area_scr(GBC.x + 1, GBC.y, GBC.w - 2, 1, level + 6, page); - grid_fill_area_scr(last_x, GBC.y, 1, 1, level + 7, page); + grid_fill_area_scr(GBC.x, GBC.y, 1, 1, 5, page); + grid_fill_area_scr(GBC.x + 1, GBC.y, GBC.w - 2, 1, 6, page); + grid_fill_area_scr(last_x, GBC.y, 1, 1, 7, page); } else { - grid_fill_area_scr(GBC.x, GBC.y, 1, 1, level + 8, page); - grid_fill_area_scr(GBC.x + 1, GBC.y, GBC.w - 2, 1, level + 9, page); - grid_fill_area_scr(last_x, GBC.y, 1, 1, level + 10, page); - grid_fill_area_scr(GBC.x, GBC.y + 1, 1, GBC.h - 2, level + 11, page); - grid_fill_area_scr(last_x, GBC.y + 1, 1, GBC.h - 2, level + 12, page); - grid_fill_area_scr(GBC.x, last_y, 1, 1, level + 13, page); - grid_fill_area_scr(GBC.x + 1, last_y, GBC.w - 2, 1, level + 14, page); - grid_fill_area_scr(last_x, last_y, 1, 1, level + 15, page); + grid_fill_area_scr(GBC.x, GBC.y, 1, 1, 8, page); + grid_fill_area_scr(GBC.x + 1, GBC.y, GBC.w - 2, 1, 9, page); + grid_fill_area_scr(last_x, GBC.y, 1, 1, 10, page); + grid_fill_area_scr(GBC.x, GBC.y + 1, 1, GBC.h - 2, 11, page); + grid_fill_area_scr(last_x, GBC.y + 1, 1, GBC.h - 2, 12, page); + grid_fill_area_scr(GBC.x, last_y, 1, 1, 13, page); + grid_fill_area_scr(GBC.x + 1, last_y, GBC.w - 2, 1, 14, page); + grid_fill_area_scr(last_x, last_y, 1, 1, 15, page); } } - - u8 _line; - u16 _data; - u8 type; - for (u16 x = 0; x < GRID_MAX_DIMENSION; x++) - for (u16 y = 0; y < GRID_MAX_DIMENSION; y++) - type = screen[x][y] && ; - - for (u16 j = 0; j < 6; j++) { - _y = y * 6 + j + 1; - if (page) { - if (_y < cell << 3) continue; - _y -= cell << 3; - } - _line = _y >> 3; - for (u16 i = 0; i < size; i++) { - _data = left + x * cell + i + ((_y & 7) << 7) + 1; - if (_line > 7 || _data > 1023) continue; - if (screen[x][y] == 0) { - if (i == 0 || i == size - 1 || j == 0 || j == size - 1) - line[_line].data[_data] = 1; - } else - line[_line].data[_data] = screen[x][y]; - } - } - */ + for (u16 i = 0; i < GRID_FADER_COUNT; i++) { + if (!SG.group[GFC.group].enabled || !GFC.enabled) continue; + last_x = GFC.x + GFC.w - 1; + last_y = GFC.y + GFC.h - 1; + if (GFC.w == 1 && GFC.h == 1) { + grid_fill_area_scr(GFC.x, GFC.y, 1, 1, 1, page); + } else if (GFC.w == 1 && GFC.h > 1) { + grid_fill_area_scr(GFC.x, GFC.y, 1, 1, 2, page); + grid_fill_area_scr(GFC.x, GFC.y + 1, 1, GFC.h - 2, 3, page); + grid_fill_area_scr(GFC.x, last_y, 1, 1, 4, page); + } else if (GFC.w > 1 && GFC.h == 1) { + grid_fill_area_scr(GFC.x, GFC.y, 1, 1, 5, page); + grid_fill_area_scr(GFC.x + 1, GFC.y, GFC.w - 2, 1, 6, page); + grid_fill_area_scr(last_x, GFC.y, 1, 1, 7, page); + } else { + grid_fill_area_scr(GFC.x, GFC.y, 1, 1, 8, page); + grid_fill_area_scr(GFC.x + 1, GFC.y, GFC.w - 2, 1, 9, page); + grid_fill_area_scr(last_x, GFC.y, 1, 1, 10, page); + grid_fill_area_scr(GFC.x, GFC.y + 1, 1, GFC.h - 2, 11, page); + grid_fill_area_scr(last_x, GFC.y + 1, 1, GFC.h - 2, 12, page); + grid_fill_area_scr(GFC.x, last_y, 1, 1, 13, page); + grid_fill_area_scr(GFC.x + 1, last_y, GFC.w - 2, 1, 14, page); + grid_fill_area_scr(last_x, last_y, 1, 1, 15, page); + } + } + + u8 l, _y, __y; + u16 d; + for (u16 y = 0; y < 48; y++) { + l = y >> 3; + d = 10 + ((y & 7) << 7); + _y = y / 6; + __y = y % 6; + for (u16 x = 0; x < 96; x++) + if ((1 << (5 - (x%6))) & glyph[screen[x/6][_y]][__y]) line[l].data[x + d] = 10; + } + + return; } void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { @@ -320,13 +429,16 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 if (GBC.enabled && SG.group[GBC.group].enabled) grid_fill_area_scr(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.background, page); + u16 pd = page ? 8 : 0; + s8 l; for (u16 i = 0; i < GRID_MAX_DIMENSION; i++) - for (u16 j = 0; j < GRID_MAX_DIMENSION; j++) { - if (SG.leds[i][j] >= 0) - screen[i][j] = SG.leds[i][j]; - else if (SG.leds[i][j] == LED_DIM) + for (u16 j = 0; j < GRID_MAX_DIMENSION/2; j++) { + l = SG.leds[i][j + pd]; + if (l >= 0) + screen[i][j] = l; + else if (l == LED_DIM) screen[i][j] >>= 1; - else if (SG.leds[i][j] == LED_BRI) { + else if (l == LED_BRI) { screen[i][j] <<= 1; if (screen[i][j] > 15) screen[i][j] = 15; else if (screen[i][j] < 1) screen[i][j] = 1; @@ -349,13 +461,9 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 u8 _line; u16 _data; for (u16 x = 0; x < GRID_MAX_DIMENSION; x++) - for (u16 y = 0; y < GRID_MAX_DIMENSION; y++) + for (u16 y = 0; y < GRID_MAX_DIMENSION/2; y++) for (u16 j = 0; j < size; j++) { _y = y * cell + j + 1; - if (page) { - if (_y < cell << 3) continue; - _y -= cell << 3; - } _line = _y >> 3; for (u16 i = 0; i < size; i++) { _data = left + x * cell + i + ((_y & 7) << 7) + 1; @@ -368,41 +476,67 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 } } - u16 area_x, area_y, area_w, area_h; - if (x1 < x2) { - area_x = x1 * cell; - area_w = (x2 + 1 - x1) * cell; + // draw selected area + + u8 _x1, _x2; + u16 _y1, _y2; + _x1 = min(x1, x2) * cell; + _y1 = min(y1, y2) * cell; + if (full_grid) { + _x2 = _x1 + size + 1; + _y2 = _y1 + size + 1; } else { - area_x = x2 * cell; - area_w = (x1 + 1 - x2) * cell; + _x2 = (max(x1, x2) + 1) * cell - 1; + _y2 = (max(y1, y2) + 1) * cell - 1; } - if (y1 < y2) { - area_y = y1 * cell; - area_h = (y2 + 1 - y1) * cell; + + u8 show_y1, show_y2; + show_y1 = show_y2 = true; + + u16 p = cell << 3; + if (page) { + if (_y2 < p) return; + if (_y1 < p) { + show_y1 = false; + _y1 = p; + }; + _y1 -= p; + _y2 -= p; } else { - area_y = y2 * cell; - area_h = (y1 + 1 - y2) * cell; + if (_y1 >= p) return; + if (_y2 >= p) { + show_y2 = false; + _y2 = p - 1; + } } - if (full_grid) { - area_w--; - area_h--; + + if (show_y1) { + _line = _y1 >> 3; + _data = left + ((_y1 & 7) << 7); + for (u16 x = _x1; x <= _x2; x++) + line[_line].data[_data + x] = x & 1 ? 4 : 15; + } + if (show_y2) { + _line = _y2 >> 3; + _data = left + ((_y2 & 7) << 7); + if (full_grid) + for (u16 x = _x1 + 1; x <= _x2; x++) + line[_line].data[_data + x] = x & 1 ? 4 : 15; + else + for (u16 x = _x1 + 1; x <= _x2; x++) + line[_line].data[_data + x] = x & 1 ? 15 : 4; } - for (u16 j = 0; j < area_h; j++) { - _y = area_y + j; - if (page) { - if (_y < (cell << 3)) continue; - _y -= cell << 3 ; + if (full_grid) + for (u16 y = _y1; y <= _y2; y++) { + line[y >> 3].data[left + ((y & 7) << 7) + _x1] = + line[y >> 3].data[left + ((y & 7) << 7) + _x2] = y & 1 ? 4 : 15; } - _line = _y >> 3; - for (u16 i = 0; i < area_w; i++) { - if (i == 0 || i == area_w - 1 || j == 0 || j == area_h - 1) { - _data = left + i + area_x + ((_y & 7) << 7); - if (_line > 7 || _data > 1023) continue; - line[_line].data[_data] = 8; - } + else + for (u16 y = _y1; y <= _y2; y++) { + line[y >> 3].data[left + ((y & 7) << 7) + _x1] = y & 1 ? 4 : 15; + line[y >> 3].data[left + ((y & 7) << 7) + _x2] = y & 1 ? 15 : 4; } - } } static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { @@ -450,64 +584,72 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u for (u16 j = 0; j < 9; j += 2) line[j >> 3].data[119 + ((j & 7) << 7)] = 1; for (u16 j = 17; j < 48; j += 2) line[j >> 3].data[119 + ((j & 7) << 7)] = 1; - for (u16 i = 0; i < 6; i++) line[0].data[i] = 8; - line[0].data[0 + 128] = 8; - line[0].data[5 + 128] = 8; - line[0].data[0 + 256] = 8; - line[0].data[5 + 256] = 8; - line[0].data[0 + 384] = 8; - line[0].data[5 + 384] = 8; - line[0].data[0 + 512] = 8; - line[0].data[5 + 512] = 8; - for (u16 i = 0; i < 6; i++) line[0].data[i + 640] = 8; + // icons + if (page == 0) { - for (u16 i = 1; i < 5; i++) - for (u16 j = 1; j < 3; j++) - line[0].data[i + (j << 7)] = 15; + for (u16 i = 0; i < 5; i++) line[0].data[i] = line[0].data[i + 128] = 10; + line[0].data[0 + 256] = 1; + line[0].data[4 + 256] = 1; + line[0].data[0 + 384] = 1; + line[0].data[4 + 384] = 1; + for (u16 i = 512; i < 517; i++) line[0].data[i] = 1; } else { - for (u16 i = 1; i < 5; i++) - for (u16 j = 3; j < 5; j++) - line[0].data[i + (j << 7)] = 15; + for (u16 i = 0; i < 5; i++) line[0].data[i] = 1; + line[0].data[0 + 128] = 1; + line[0].data[4 + 128] = 1; + line[0].data[0 + 256] = 1; + line[0].data[4 + 256] = 1; + for (u16 i = 384; i < 389; i++) line[0].data[i] = line[0].data[i + 128] = 10; } - u8 l = ss->grid.rotate ? 10 : 2; + u8 l = ss->grid.rotate ? 10 : 1; line[1].data[0 + 0] = l; line[1].data[1 + 0] = l; line[1].data[2 + 0] = l; - line[1].data[3 + 0] = l; - line[1].data[3 + 128] = l; - line[1].data[3 + 256] = l; + line[1].data[2 + 128] = l; + line[1].data[0 + 256] = l; + line[1].data[2 + 256] = l; + line[1].data[4 + 256] = l; line[1].data[1 + 384] = l; + line[1].data[2 + 384] = l; line[1].data[3 + 384] = l; - line[1].data[5 + 384] = l; line[1].data[2 + 512] = l; - line[1].data[3 + 512] = l; - line[1].data[4 + 512] = l; - line[1].data[3 + 640] = l; } void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page) { if (level == LED_OFF) return; u16 x_end = min(GRID_MAX_DIMENSION, x + w); - u16 y_end = min(GRID_MAX_DIMENSION, y + h); + u16 y1, y2; + y1 = y; + y2 = min(GRID_MAX_DIMENSION, y + h) - 1; + + if (page) { + if (y2 < 8) return; + if (y1 < 8) y1 = 8; + y1 -= 8; + y2 -= 8; + } else { + if (y1 >= 8) return; + if (y2 >= 8) y2 = 7; + } if (level == LED_DIM) { for (u16 _x = x; _x < x_end; _x++) { - for (u16 _y = y; _y < y_end; _y++) + for (u16 _y = y1; _y <= y2; _y++) screen[_x][_y] >>= 1; } } else if (level == LED_BRI) { for (u16 _x = x; _x < x_end; _x++) - for (u16 _y = y; _y < y_end; _y++) { + for (u16 _y = y1; _y <= y2; _y++) { screen[_x][_y] <<= 1; if (screen[_x][_y] > 15) screen[_x][_y] = 15; } } else { for (u16 _x = x; _x < x_end; _x++) - for (u16 _y = y; _y < y_end; _y++) + for (u16 _y = y1; _y <= y2; _y++) screen[_x][_y] = level; } } diff --git a/module/grid.h b/module/grid.h index 8cedfb13..ace1e2d7 100644 --- a/module/grid.h +++ b/module/grid.h @@ -14,14 +14,15 @@ typedef enum { GRID_MODE_OFF = 0, - GRID_MODE_LED, - //GRID_MODE_CTRL, + GRID_MODE_EDIT, GRID_MODE_FULL, GRID_MODE_LAST } screen_grid_mode; extern void grid_refresh(scene_state_t *ss); -extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); -extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z); +extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, + u8 page, u8 ctrl, u8 x1, u8 y1, u8 x2, u8 y2); +extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, + u8 ignore_rotate); #endif diff --git a/module/live_mode.c b/module/live_mode.c index b4513ac9..e5decd41 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -32,7 +32,7 @@ static error_t status; static char error_msg[TELE_ERROR_MSG_LENGTH]; static bool show_welcome_message; static screen_grid_mode grid_mode = GRID_MODE_OFF; -static uint8_t grid_page = 0, grid_view_changed = 0; +static uint8_t grid_page = 0, grid_ctrl = 0, grid_view_changed = 0; static uint8_t grid_x1 = 0, grid_y1 = 0, grid_x2 = 0, grid_y2 = 0; static const uint8_t D_INPUT = 1 << 0; @@ -110,14 +110,14 @@ void set_live_mode() { activity_prev = 0xFF; grid_view_changed = true; if (grid_mode == GRID_MODE_FULL) - grid_mode = GRID_MODE_LED; + grid_mode = GRID_MODE_EDIT; } void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, scene_state_t *ss) { if (is_release) { if (match_ctrl(m, k, HID_SPACEBAR) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SPACEBAR))) { - grid_process_key(ss, grid_x1, grid_y1, 0); + grid_process_key(ss, grid_x1, grid_y1, 0, 1); } return; } @@ -150,7 +150,13 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, if (++grid_mode == GRID_MODE_LAST) { grid_mode = GRID_MODE_OFF; set_live_mode(); - } else grid_view_changed = true; + } else { + if (grid_mode == GRID_MODE_FULL) { + grid_x2 = grid_x1; + grid_y2 = grid_y1; + } + grid_view_changed = true; + } } // C-: move grid cursor else if (match_ctrl(m, k, HID_UP) || @@ -185,32 +191,28 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, grid_view_changed = true; } // C-S-: expand grid area up - else if (match_shift_ctrl(m, k, HID_UP) || - (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_UP))) { + else if (match_shift_ctrl(m, k, HID_UP) && grid_mode != GRID_MODE_FULL) { if (grid_y2 > 0) { grid_y2--; grid_view_changed = true; } } // C-S-: expand grid area down - else if (match_shift_ctrl(m, k, HID_DOWN) || - (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_DOWN))) { + else if (match_shift_ctrl(m, k, HID_DOWN) && grid_mode != GRID_MODE_FULL) { if (grid_y2 < GRID_MAX_DIMENSION - 1) { grid_y2++; grid_view_changed = true; } } // C-S-: expand grid area left - else if (match_shift_ctrl(m, k, HID_LEFT) || - (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_LEFT))) { + else if (match_shift_ctrl(m, k, HID_LEFT) && grid_mode != GRID_MODE_FULL) { if (grid_x2 > 0) { grid_x2--; grid_view_changed = true; } } // C-S-: expand grid area right - else if (match_shift_ctrl(m, k, HID_RIGHT) || - (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_RIGHT))) { + else if (match_shift_ctrl(m, k, HID_RIGHT) && grid_mode != GRID_MODE_FULL) { if (grid_x2 < GRID_MAX_DIMENSION - 1) { grid_x2++; grid_view_changed = true; @@ -222,11 +224,11 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, grid_x2 = grid_x1; grid_y2 = grid_y1; grid_view_changed = true; - grid_process_key(ss, grid_x1, grid_y1, 1); + grid_process_key(ss, grid_x1, grid_y1, 1, 1); } // C-: insert coordinates / size else if (!is_held_key && match_ctrl(m, k, HID_PRINTSCREEN) && - grid_mode != GRID_MODE_FULL) { + grid_mode == GRID_MODE_EDIT) { u8 area_x, area_y, area_w, area_h; if (grid_x1 < grid_x2) { area_x = grid_x1; @@ -272,12 +274,18 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, line_editor_process_keys(&le, HID_SPACEBAR, HID_MODIFIER_NONE, false); dirty |= D_INPUT; } - // C-: toggle grid page + // C-: toggle grid page else if (match_ctrl(m, k, HID_SLASH) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SLASH))) { if (++grid_page > 1) grid_page = 0; grid_view_changed = true; } + // C-<\>: toggle control view + else if (match_ctrl(m, k, HID_BACKSLASH) || + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_BACKSLASH))) { + grid_ctrl = !grid_ctrl; + grid_view_changed = true; + } // : execute command else if (match_no_mod(m, k, HID_ENTER) && grid_mode != GRID_MODE_FULL) { dirty |= D_MESSAGE; // something will definitely happen @@ -345,7 +353,8 @@ bool screen_refresh_live(scene_state_t *ss) { if (grid_mode != GRID_MODE_OFF && (grid_view_changed || ss->grid.scr_dirty)) { grid_view_changed = 0; screen_dirty = true; - grid_screen_refresh(ss, grid_mode, grid_page, grid_x1, grid_y1, grid_x2, grid_y2); + grid_screen_refresh(ss, grid_mode, + grid_page, grid_ctrl, grid_x1, grid_y1, grid_x2, grid_y2); } if (grid_mode == GRID_MODE_FULL) return true; diff --git a/module/main.c b/module/main.c index a330c1ae..79c09cb9 100644 --- a/module/main.c +++ b/module/main.c @@ -494,7 +494,7 @@ static void handler_MonomeRefresh(s32 data) { static void handler_MonomeGridKey(s32 data) { u8 x, y, z; monome_grid_key_parse_event_data(data, &x, &y, &z); - grid_process_key(&scene_state, x, y, z); + grid_process_key(&scene_state, x, y, z, 0); } @@ -856,8 +856,8 @@ void tele_save_calibration() { flash_update_cal(&scene_state.cal); } -void grid_key_press(uint8_t x, int8_t y, int8_t z) { - grid_process_key(&scene_state, x, y, z); +void grid_key_press(uint8_t x, uint8_t y, uint8_t z) { + grid_process_key(&scene_state, x, y, z, 1); } diff --git a/simulator/tt.c b/simulator/tt.c index 73329124..faea5718 100644 --- a/simulator/tt.c +++ b/simulator/tt.c @@ -102,7 +102,7 @@ void tele_save_calibration() {} void tele_profile_script(size_t s) {} void tele_profile_delay(uint8_t d) {} -void grid_key_press(uint8_t x, int8_t y, int8_t z) { +void grid_key_press(uint8_t x, uint8_t y, uint8_t z) { printf("GRID KEY PRESS x:%" PRIu8 " y:%" PRIu8 " z:%" PRIu8, x, y, z); printf("\n"); } diff --git a/src/teletype_io.h b/src/teletype_io.h index a228c08d..a5d7f8ac 100644 --- a/src/teletype_io.h +++ b/src/teletype_io.h @@ -47,6 +47,6 @@ void tele_profile_delay(uint8_t); #endif // emulate grid key press -extern void grid_key_press(uint8_t x, int8_t y, int8_t z); +extern void grid_key_press(uint8_t x, uint8_t y, uint8_t z); #endif diff --git a/tests/main.c b/tests/main.c index 9c0cc6b7..49d8e4ef 100644 --- a/tests/main.c +++ b/tests/main.c @@ -35,7 +35,7 @@ bool tele_get_input_state(uint8_t n) { void tele_save_calibration() {} -void grid_key_press(uint8_t x, int8_t y, int8_t z) {} +void grid_key_press(uint8_t x, uint8_t y, uint8_t z) {} GREATEST_MAIN_DEFS(); From a0ee4b5d6df36e616762e153c73d91af7d8568a7 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 21 Dec 2017 11:35:41 -0800 Subject: [PATCH 021/117] added dot and gradient faders --- module/grid.c | 130 ++++++++++++++++++----- src/ops/grid_ops.c | 259 ++++++++++++++++++++++++++++++++++----------- src/state.c | 4 +- src/state.h | 10 +- 4 files changed, 314 insertions(+), 89 deletions(-) diff --git a/module/grid.c b/module/grid.c index dc8fc5a7..7fd1a16d 100644 --- a/module/grid.c +++ b/module/grid.c @@ -158,28 +158,52 @@ void grid_refresh(scene_state_t *ss) { if (GXY.value_x || GXY.value_y) { x = GXYC.x + GXY.value_x; y = GXYC.y + GXY.value_y; - grid_fill_area(GXYC.x, y, GXYC.w, 1, GXYC.background); - grid_fill_area(x, GXYC.y, 1, GXYC.h, GXYC.background); + grid_fill_area(GXYC.x, y, GXYC.w, 1, GXYC.level); + grid_fill_area(x, GXYC.y, 1, GXYC.h, GXYC.level); grid_fill_area(x, y, 1, 1, 15); } } } + u16 fv, ff, fp; for (u8 i = 0; i < GRID_FADER_COUNT; i++) { if (GFC.enabled && SG.group[GFC.group].enabled) { - if (GF.dir) { - grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.background); - grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, 15); - } else { - grid_fill_area(GFC.x, GFC.y, GF.value + 1, GFC.h, 15); - grid_fill_area(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.background); + switch (GF.type) { + case FADER_H_BAR: + grid_fill_area(GFC.x, GFC.y, GF.value + 1, GFC.h, 15); + grid_fill_area(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.level); + break; + case FADER_V_BAR: + grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.level); + grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, 15); + break; + case FADER_H_DOT: + grid_fill_area(GFC.x + GF.value, GFC.y, 1, GFC.h, 15); + break; + case FADER_V_DOT: + grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, 15); + break; + case FADER_H_FINE: + fv = ((GFC.w << 4) * GF.value) / (GFC.level + 1); + ff = fv >> 4; + fp = fv & 15; + grid_fill_area(GFC.x, GFC.y, ff, GFC.h, 15); + if (fp) grid_fill_area(GFC.x + ff, GFC.y, 1, GFC.h, fp); + break; + case FADER_V_FINE: + fv = ((GFC.h << 4) * GF.value) / (GFC.level + 1); + ff = fv >> 4; + fp = fv & 15; + grid_fill_area(GFC.x, GFC.y + GFC.h - ff, GFC.w, ff, 15); + if (fp) grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff, fp); + break; } } } for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.enabled && SG.group[GBC.group].enabled) - grid_fill_area(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.background); + grid_fill_area(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.level); u16 led; for (u16 i = 0; i < size_x; i++) @@ -235,14 +259,44 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { } } - for (u8 i = 0; i < GRID_FADER_COUNT; i++) { - if (GFC.enabled && SG.group[GFC.group].enabled && grid_within_area(x, y, &GFC)) { - GF.value = GF.dir ? GFC.h + GFC.y - y - 1 : x - GFC.x; - if (GFC.script != -1) scripts[GFC.script] = 1; - SG.latest_fader = i; - SG.latest_group = GFC.group; - if (SG.group[GFC.group].script != -1) scripts[SG.group[GFC.group].script] = 1; - refresh = 1; + if (z) { + for (u8 i = 0; i < GRID_FADER_COUNT; i++) { + if (GFC.enabled && SG.group[GFC.group].enabled && grid_within_area(x, y, &GFC)) { + switch (GF.type) { + case FADER_H_BAR: + case FADER_H_DOT: + GF.value = x - GFC.x; + break; + case FADER_V_BAR: + case FADER_V_DOT: + GF.value = GFC.h + GFC.y - y - 1; + break; + case FADER_H_FINE: + if (x == GFC.x) { + if (GF.value) GF.value--; + } else if (x == GFC.x + GFC.w - 1) { + if (GF.value < GFC.level) GF.value++; + } else { + GF.value = ((((x - GFC.x) << 4) + 8) * (GFC.level + 1)) / (GFC.w << 4); + } + break; + case FADER_V_FINE: + if (y == GFC.y) { + if (GF.value < GFC.level) GF.value++; + } else if (y == GFC.y + GFC.h - 1) { + if (GF.value) GF.value--; + } else { + GF.value = ((((y - GFC.y) << 4) + 8) * (GFC.level + 1)) / (GFC.h << 4); + } + break; + } + + if (GFC.script != -1) scripts[GFC.script] = 1; + SG.latest_fader = i; + SG.latest_group = GFC.group; + if (SG.group[GFC.group].script != -1) scripts[SG.group[GFC.group].script] = 1; + refresh = 1; + } } } @@ -406,28 +460,52 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 if (GXY.value_x || GXY.value_y) { x = GXYC.x + GXY.value_x; y = GXYC.y + GXY.value_y; - grid_fill_area_scr(GXYC.x, y, GXYC.w, 1, GXYC.background, page); - grid_fill_area_scr(x, GXYC.y, 1, GXYC.h, GXYC.background, page); + grid_fill_area_scr(GXYC.x, y, GXYC.w, 1, GXYC.level, page); + grid_fill_area_scr(x, GXYC.y, 1, GXYC.h, GXYC.level, page); grid_fill_area_scr(x, y, 1, 1, 15, page); } } } + u16 fv, ff, fp; for (u8 i = 0; i < GRID_FADER_COUNT; i++) { if (GFC.enabled && SG.group[GFC.group].enabled) { - if (GF.dir) { - grid_fill_area_scr(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.background, page); - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, 15, page); - } else { - grid_fill_area_scr(GFC.x, GFC.y, GF.value + 1, GFC.h, 15, page); - grid_fill_area_scr(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.background, page); + switch (GF.type) { + case FADER_H_BAR: + grid_fill_area_scr(GFC.x, GFC.y, GF.value + 1, GFC.h, 15, page); + grid_fill_area_scr(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.level, page); + break; + case FADER_V_BAR: + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.level, page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, 15, page); + break; + case FADER_H_DOT: + grid_fill_area_scr(GFC.x + GF.value, GFC.y, 1, GFC.h, 15, page); + break; + case FADER_V_DOT: + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, 15, page); + break; + case FADER_H_FINE: + fv = ((GFC.w << 4) * GF.value) / (GFC.level + 1); + ff = fv >> 4; + fp = fv & 15; + grid_fill_area_scr(GFC.x, GFC.y, ff, GFC.h, 15, page); + if (fp) grid_fill_area_scr(GFC.x + ff, GFC.y, 1, GFC.h, fp, page); + break; + case FADER_V_FINE: + fv = ((GFC.h << 4) * GF.value) / (GFC.level + 1); + ff = fv >> 4; + fp = fv & 15; + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff, GFC.w, ff, 15, page); + if (fp) grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff, fp, page); + break; } } } for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.enabled && SG.group[GBC.group].enabled) - grid_fill_area_scr(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.background, page); + grid_fill_area_scr(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.level, page); u16 pd = page ? 8 : 0; s8 l; diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 1d7171c3..dc5f7705 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -46,7 +46,8 @@ static void grid_common_init(grid_common_t *gc); static s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value); static void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fill, u8 border); static void grid_init_button(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 latch, u8 level, u8 script); -static void grid_init_fader(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 dir, u8 level, u8 script); +static void grid_init_fader(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 type, u8 level, u8 script); +static s16 grid_fader_max_value(scene_state_t *ss, u16 i); static void op_G_RST_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_CLR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -228,7 +229,7 @@ static void op_G_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat for (u8 i = 0; i < GRID_FADER_COUNT; i++) { grid_common_init(&(GFC)); - GF.dir = 0; + GF.type = FADER_H_BAR; GF.value = 0; } @@ -311,7 +312,7 @@ static void op_G_GRP_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_ for (u8 i = 0; i < GRID_FADER_COUNT; i++) if (GFC.group == group) { grid_common_init(&(GFC)); - GF.dir = 0; + GF.type = FADER_H_BAR; GF.value = 0; } @@ -547,14 +548,14 @@ static void op_G_BTN_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_st static void op_G_BTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GBC.background); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GBC.level); } static void op_G_BTN_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); GET_LEVEL(level); if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; - GBC.background = level; + GBC.level = level; SG.scr_dirty = SG.grid_dirty = 1; } @@ -617,12 +618,12 @@ static void op_G_BTNV_set(const void *NOTUSED(data), scene_state_t *ss, exec_sta } static void op_G_BTNL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, SG.button[SG.latest_button].common.background); + cs_push(cs, SG.button[SG.latest_button].common.level); } static void op_G_BTNL_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { GET_LEVEL(level); - SG.button[SG.latest_button].common.background = level; + SG.button[SG.latest_button].common.level = level; SG.scr_dirty = SG.grid_dirty = 1; } @@ -722,10 +723,10 @@ static void op_G_GBTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_s if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; - u8 is_odd = 1; + u8 is_odd = 0; for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.group == group) { - GBC.background = is_odd ? odd : even; + GBC.level = is_odd ? odd : even; is_odd = !is_odd; } SG.scr_dirty = SG.grid_dirty = 1; @@ -737,15 +738,28 @@ static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 y = cs_pop(cs); s16 w = cs_pop(cs); s16 h = cs_pop(cs); - s16 dir = cs_pop(cs); - GET_LEVEL(level); + s16 type = cs_pop(cs); + s16 level = cs_pop(cs); s16 script = cs_pop(cs) - 1; if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; if (script < 0 || script > INIT_SCRIPT) script = -1; CLAMP_X_Y_W_H(return); + if (type > FADER_V_FINE) type = FADER_H_BAR; + if (type == FADER_H_FINE || type == FADER_V_FINE) { + s16 maxlevel = ((type == FADER_H_FINE ? w : h) << 4) - 1; + if (level < 0) + level = 0; + else if (level > maxlevel) + level = maxlevel; + } else { + if (level < (s16)LED_OFF) + level = LED_OFF; + else if (level > (s16)15) + level = 15; + } - grid_init_fader(ss, SG.current_group, i, x, y, w, h, dir != 0, level, script); + grid_init_fader(ss, SG.current_group, i, x, y, w, h, type, level, script); SG.scr_dirty = SG.grid_dirty = 1; } @@ -756,16 +770,29 @@ static void op_G_GFD_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 y = cs_pop(cs); s16 w = cs_pop(cs); s16 h = cs_pop(cs); - s16 dir = cs_pop(cs); - GET_LEVEL(level); + s16 type = cs_pop(cs); + s16 level = cs_pop(cs); s16 script = cs_pop(cs) - 1; if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; if (script < 0 || script > INIT_SCRIPT) script = -1; CLAMP_X_Y_W_H(return); + if (type > FADER_V_FINE) type = FADER_H_BAR; + if (type == FADER_H_FINE || type == FADER_V_FINE) { + s16 maxlevel = ((type == FADER_H_FINE ? w : h) << 4) - 1; + if (level < 0) + level = 0; + else if (level > maxlevel) + level = maxlevel; + } else { + if (level < (s16)LED_OFF) + level = LED_OFF; + else if (level > (s16)15) + level = 15; + } - grid_init_fader(ss, group, i, x, y, w, h, dir != 0, level, script); + grid_init_fader(ss, group, i, x, y, w, h, type, level, script); SG.scr_dirty = SG.grid_dirty = 1; } @@ -775,8 +802,8 @@ static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 _y = cs_pop(cs); s16 _w = cs_pop(cs); s16 _h = cs_pop(cs); - s16 dir = cs_pop(cs) != 0; - GET_LEVEL(level); + s16 type = cs_pop(cs); + s16 level = cs_pop(cs); s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); @@ -787,6 +814,19 @@ static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat if (count_x > (s16)16) count_x = 16; if (count_y <= (s16)0) return; if (count_y > (s16)16) count_y = 16; + if (type > FADER_V_FINE) type = FADER_H_BAR; + if (type == FADER_H_FINE || type == FADER_V_FINE) { + s16 maxlevel = ((type == FADER_H_FINE ? _w : _h) << 4) - 1; + if (level < 0) + level = 0; + else if (level > maxlevel) + level = maxlevel; + } else { + if (level < (s16)LED_OFF) + level = LED_OFF; + else if (level > (s16)15) + level = 15; + } u16 i; s16 x, y, w, h; @@ -799,7 +839,7 @@ static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat y = _y + _h * cy; h = _h; CLAMP_X_Y_W_H(continue); - grid_init_fader(ss, SG.current_group, i, x, y, w, h, dir, level, script); + grid_init_fader(ss, SG.current_group, i, x, y, w, h, type, level, script); } SG.scr_dirty = SG.grid_dirty = 1; @@ -812,8 +852,8 @@ static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 _y = cs_pop(cs); s16 _w = cs_pop(cs); s16 _h = cs_pop(cs); - s16 dir = cs_pop(cs); - GET_LEVEL(level); + s16 type = cs_pop(cs); + s16 level = cs_pop(cs); s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); @@ -825,6 +865,19 @@ static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat if (count_x > (s16)16) count_x = 16; if (count_y <= (s16)0) return; if (count_y > (s16)16) count_y = 16; + if (type > FADER_V_FINE) type = FADER_H_BAR; + if (type == FADER_H_FINE || type == FADER_V_FINE) { + s16 maxlevel = ((type == FADER_H_FINE ? _w : _h) << 4) - 1; + if (level < 0) + level = 0; + else if (level > maxlevel) + level = maxlevel; + } else { + if (level < (s16)LED_OFF) + level = LED_OFF; + else if (level > (s16)15) + level = 15; + } u16 i; s16 x, y, w, h; @@ -837,7 +890,7 @@ static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat y = _y + _h * cy; h = _h; CLAMP_X_Y_W_H(continue); - grid_init_fader(ss, group, i, x, y, w, h, dir, level, script); + grid_init_fader(ss, group, i, x, y, w, h, type, level, script); } SG.scr_dirty = SG.grid_dirty = 1; @@ -864,8 +917,8 @@ static void op_G_FDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_st return; } - s16 value = scale(0, GF.dir ? GFC.h - 1 : GFC.w - 1, SG.group[GFC.group].fader_min, - SG.group[GFC.group].fader_max, GF.value); + s16 value = scale(0, grid_fader_max_value(ss, i), + SG.group[GFC.group].fader_min, SG.group[GFC.group].fader_max, GF.value); cs_push(cs, value); } @@ -877,24 +930,25 @@ static void op_G_FDR_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_st if (value < SG.group[GFC.group].fader_min) value = SG.group[GFC.group].fader_min; else if (value > SG.group[GFC.group].fader_max) value = SG.group[GFC.group].fader_max; - GF.value = scale(SG.group[GFC.group].fader_min, - SG.group[GFC.group].fader_max, 0, GF.dir ? GFC.h - 1 : GFC.w - 1, value); + GF.value = scale(SG.group[GFC.group].fader_min, + SG.group[GFC.group].fader_max, 0, grid_fader_max_value(ss, i), value); SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 1 : GF.value + 1); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GF.value); } static void op_G_FDR_N_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - s16 value = cs_pop(cs) - 1; + s16 value = cs_pop(cs); if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; + + s16 maxvalue = grid_fader_max_value(ss, i); if (value < (s16)0) value = 0; - else if (GF.dir && value >= (s16)GFC.h) value = GFC.h - 1; - else if (!GF.dir && value >= (s16)GFC.w) value = GFC.w - 1; + else if (value > maxvalue) value = maxvalue; GF.value = value; SG.scr_dirty = SG.grid_dirty = 1; @@ -902,14 +956,28 @@ static void op_G_FDR_N_set(const void *NOTUSED(data), scene_state_t *ss, exec_st static void op_G_FDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GFC.background); + cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GFC.level); } static void op_G_FDR_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); - GET_LEVEL(level); + s16 level = cs_pop(cs); if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; - GFC.background = level; + + if (GF.type == FADER_H_FINE || GF.type == FADER_V_FINE) { + s16 maxlevel = ((GF.type == FADER_H_FINE ? GFC.w : GFC.h) << 4) - 1; + if (level < 0) + level = 0; + else if (level > maxlevel) + level = maxlevel; + } else { + if (level < (s16)LED_OFF) + level = LED_OFF; + else if (level > (s16)15) + level = 15; + } + + GFC.level = level; SG.scr_dirty = SG.grid_dirty = 1; } @@ -963,8 +1031,8 @@ static void op_G_FDRI_get(const void *NOTUSED(data), scene_state_t *ss, exec_sta static void op_G_FDRV_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { u8 i = SG.latest_fader; - s16 value = scale(0, GF.dir ? GFC.h - 1 : GFC.w - 1, SG.group[GFC.group].fader_min, - SG.group[GFC.group].fader_max, GF.value); + s16 value = scale(0, grid_fader_max_value(ss, i), + SG.group[GFC.group].fader_min, SG.group[GFC.group].fader_max, GF.value); cs_push(cs, value); } @@ -976,33 +1044,48 @@ static void op_G_FDRV_set(const void *NOTUSED(data), scene_state_t *ss, exec_sta else if (value > SG.group[GFC.group].fader_max) value = SG.group[GFC.group].fader_max; GF.value = scale(SG.group[GFC.group].fader_min, - SG.group[GFC.group].fader_max, 0, GF.dir ? GFC.h - 1 : GFC.w - 1, value); + SG.group[GFC.group].fader_max, 0, grid_fader_max_value(ss, i), value); SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDRN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, SG.fader[SG.latest_fader].value + 1); + cs_push(cs, SG.fader[SG.latest_fader].value); } static void op_G_FDRN_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - s16 value = cs_pop(cs) - 1; + s16 value = cs_pop(cs); s16 i = SG.latest_fader; + s16 maxvalue = grid_fader_max_value(ss, i); if (value < (s16)0) value = 0; - else if (GF.dir && value >= (s16)GFC.h) value = GFC.h - 1; - else if (!GF.dir && value >= (s16)GFC.w) value = GFC.w - 1; + else if (value > maxvalue) value = maxvalue; GF.value = value; SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_FDRL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - cs_push(cs, SG.fader[SG.latest_fader].common.background); + cs_push(cs, SG.fader[SG.latest_fader].common.level); } static void op_G_FDRL_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - GET_LEVEL(level); - SG.fader[SG.latest_fader].common.background = level; + s16 level = cs_pop(cs); + u16 i = SG.latest_fader; + + if (GF.type == FADER_H_FINE || GF.type == FADER_V_FINE) { + s16 maxlevel = ((GF.type == FADER_H_FINE ? GFC.w : GFC.h) << 4) - 1; + if (level < 0) + level = 0; + else if (level > maxlevel) + level = maxlevel; + } else { + if (level < (s16)LED_OFF) + level = LED_OFF; + else if (level > (s16)15) + level = 15; + } + + GFC.level = level; SG.scr_dirty = SG.grid_dirty = 1; } @@ -1054,10 +1137,38 @@ static void op_G_FDR_PR_get(const void *NOTUSED(data), scene_state_t *ss, exec_s if (!GFC.enabled || !SG.group[GFC.group].enabled) return; if (value < (s16)0) value = 0; - else if (GF.dir && value >= (s16)GFC.h) value = GFC.h - 1; - else if (!GF.dir && value >= (s16)GFC.w) value = GFC.w - 1; + else if (GF.type && value >= (s16)GFC.h) value = GFC.h - 1; + else if (!GF.type && value >= (s16)GFC.w) value = GFC.w - 1; + + switch (GF.type) { + case FADER_H_BAR: + case FADER_H_DOT: + case FADER_V_BAR: + case FADER_V_DOT: + GF.value = value; + break; + case FADER_H_FINE: + if (value == 0) { + if (GF.value) GF.value--; + } else if (value == GFC.w - 1) { + if (GF.value < GFC.level) GF.value++; + } else { + GF.value = (((value << 4) + 8) * (GFC.level + 1)) / + (GFC.w << 4); + } + break; + case FADER_V_FINE: + if (value == 0) { + if (GF.value) GF.value--; + } else if (value == GFC.h - 1) { + if (GF.value < GFC.level) GF.value++; + } else { + GF.value = (((value << 4) + 8) * (GFC.level + 1)) / + (GFC.h << 4); + } + break; + } - GF.value = value; SG.latest_fader = i; SG.latest_group = GFC.group; @@ -1087,34 +1198,49 @@ static void op_G_GFDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_s for (u16 i = 0; i < GRID_FADER_COUNT; i++) if (GFC.group == group) GF.value = scale(SG.group[group].fader_min, - SG.group[group].fader_max, 0, GF.dir ? GFC.h - 1 : GFC.w - 1, value); + SG.group[group].fader_max, 0, grid_fader_max_value(ss, i), value); SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GFDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); - s16 value = cs_pop(cs) - 1; + s16 value = cs_pop(cs); if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; if (value < (s16)0) value = 0; for (u16 i = 0; i < GRID_FADER_COUNT; i++) - if (GFC.group == group) GF.value = min(GF.dir ? GFC.h - 1 : GFC.w - 1, value); + if (GFC.group == group) + GF.value = min(grid_fader_max_value(ss, i), value); SG.scr_dirty = SG.grid_dirty = 1; } static void op_G_GFDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); - GET_LEVEL(odd); - GET_LEVEL(even); + s16 odd = cs_pop(cs); + s16 even = cs_pop(cs); if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; - u8 is_odd = 1; + s16 level; + u8 is_odd = 0; for (u16 i = 0; i < GRID_FADER_COUNT; i++) if (GFC.group == group) { - GFC.background = is_odd ? odd : even; + level = is_odd ? odd : even; + if (GF.type == FADER_H_FINE || GF.type == FADER_V_FINE) { + s16 maxlevel = ((GF.type == FADER_H_FINE ? GFC.w : GFC.h) << 4) - 1; + if (level < 0) + level = 0; + else if (level > maxlevel) + level = maxlevel; + } else { + if (level < (s16)LED_OFF) + level = LED_OFF; + else if (level > (s16)15) + level = 15; + } + GFC.level = level; is_odd = !is_odd; } SG.scr_dirty = SG.grid_dirty = 1; @@ -1149,7 +1275,7 @@ static void op_G_XYP_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GXYC.y = y; GXYC.w = w; GXYC.h = h; - GXYC.background = level; + GXYC.level = level; GXYC.script = script; GXY.value_x = 0; GXY.value_y = 0; @@ -1172,7 +1298,7 @@ void grid_common_init(grid_common_t *gc) { gc->group = 0; gc->x = gc->y = 0; gc->w = gc->h = 1; - gc->background = 5; + gc->level = 5; gc->script = -1; } @@ -1214,20 +1340,35 @@ static void grid_init_button(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 GBC.y = y; GBC.w = w; GBC.h = h; - GBC.background = level; + GBC.level = level; GBC.script = script; GB.latch = latch != 0; if (!GB.latch) GB.state = 0; } -static void grid_init_fader(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 dir, u8 level, u8 script) { +static void grid_init_fader(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 type, u8 level, u8 script) { GFC.enabled = true; GFC.group = group; GFC.x = x; GFC.y = y; GFC.w = w; GFC.h = h; - GFC.background = level; + GFC.level = level; GFC.script = script; - GF.dir = dir != 0; -} + GF.type = type; +} + +static s16 grid_fader_max_value(scene_state_t *ss, u16 i) { + switch (GF.type) { + case FADER_H_BAR: + case FADER_H_DOT: + return GFC.w - 1; + case FADER_V_BAR: + case FADER_V_DOT: + return GFC.h - 1; + case FADER_H_FINE: + case FADER_V_FINE: + return GFC.level; + } + return 0; +} \ No newline at end of file diff --git a/src/state.c b/src/state.c index 46cdc3b3..eceed55f 100644 --- a/src/state.c +++ b/src/state.c @@ -97,7 +97,7 @@ void ss_grid_init(scene_state_t *ss) { for (u8 i = 0; i < GRID_FADER_COUNT; i++) { ss_grid_common_init(&(ss->grid.fader[i].common)); - ss->grid.fader[i].dir = 0; + ss->grid.fader[i].type = FADER_H_BAR; ss->grid.fader[i].value = 0; } @@ -115,7 +115,7 @@ void ss_grid_common_init(grid_common_t *gc) { gc->group = 0; gc->x = gc->y = 0; gc->w = gc->h = 1; - gc->background = 5; + gc->level = 5; gc->script = -1; } diff --git a/src/state.h b/src/state.h index 034b8112..30826046 100644 --- a/src/state.h +++ b/src/state.h @@ -33,6 +33,12 @@ #define LED_DIM -1 #define LED_BRI -2 #define LED_OFF -3 +#define FADER_H_BAR 0 +#define FADER_V_BAR 1 +#define FADER_H_DOT 2 +#define FADER_V_DOT 3 +#define FADER_H_FINE 4 +#define FADER_V_FINE 5 #define METRO_MIN_MS 25 #define METRO_MIN_UNSUPPORTED_MS 2 @@ -126,7 +132,7 @@ typedef struct { u8 group; u8 x, y; u8 w, h; - u8 background; + u8 level; s8 script; } grid_common_t; @@ -145,7 +151,7 @@ typedef struct { typedef struct { grid_common_t common; - u8 dir; // 0 - horiz 1 - vert + u8 type; u8 value; } grid_fader_t; From c51779b141c6d34623921e8d7b01acd8ebfacc58 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Wed, 27 Dec 2017 13:53:30 -0800 Subject: [PATCH 022/117] grid key hold/repeat --- module/grid.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++ module/grid.h | 1 + module/main.c | 6 +++ 3 files changed, 112 insertions(+) diff --git a/module/grid.c b/module/grid.c index 7fd1a16d..e25f2848 100644 --- a/module/grid.c +++ b/module/grid.c @@ -3,8 +3,13 @@ #include "globals.h" #include "state.h" #include "teletype.h" +#include "timers.h" #include "util.h" +#define GRID_MAX_KEY_PRESSED 5 +#define GRID_KEY_HOLD_DELAY 700 +#define GRID_KEY_REPEAT_RATE 40 + static const u8 glyph[16][6] = { { 0b000000, @@ -136,9 +141,23 @@ static const u8 glyph[16][6] = { } }; +typedef struct { + u8 used; + u8 key; + u8 x; + u8 y; + u8 ignore_rotate; + scene_state_t *ss; + softTimer_t timer; +} hold_repeat_timer; + static u16 size_x = 16, size_y = 8; static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION/2]; +static hold_repeat_timer hold_repeat_timers[GRID_MAX_KEY_PRESSED]; +static u8 timers_uninitialized = 1; +static void hold_repeat_timer_callback(void* o); +static void grid_process_key_hold_repeat(scene_state_t *ss, u8 _x, u8 _y, u8 ignore_rotate, u8 is_hold); static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); @@ -242,6 +261,34 @@ void grid_refresh(scene_state_t *ss) { } void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { + if (timers_uninitialized) { + timers_uninitialized = 0; + for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) + hold_repeat_timers[i].used = 0; + } + + u8 key = (_y << 4) | _x; + if (z) { + for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) + if (!hold_repeat_timers[i].used || hold_repeat_timers[i].key == key) { + hold_repeat_timers[i].used = 1; + hold_repeat_timers[i].key = key; + hold_repeat_timers[i].x = _x; + hold_repeat_timers[i].y = _y; + hold_repeat_timers[i].ignore_rotate = ignore_rotate; + hold_repeat_timers[i].ss = ss; + timer_add(&hold_repeat_timers[i].timer, GRID_KEY_HOLD_DELAY, + &hold_repeat_timer_callback, (void *)&hold_repeat_timers[i]); + break; + } + } else { + for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) + if (hold_repeat_timers[i].key == key) { + timer_remove(&hold_repeat_timers[i].timer); + hold_repeat_timers[i].used = 0; + } + } + u8 x = SG.rotate && !ignore_rotate ? monome_size_x() - _x - 1 : _x; u8 y = SG.rotate && !ignore_rotate ? monome_size_y() - _y - 1 : _y; u8 refresh = 0; @@ -324,6 +371,64 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { SG.grid_dirty = SG.scr_dirty = refresh; } +void grid_process_key_hold_repeat(scene_state_t *ss, u8 _x, u8 _y, u8 ignore_rotate, u8 is_hold) { + u8 x = SG.rotate && !ignore_rotate ? monome_size_x() - _x - 1 : _x; + u8 y = SG.rotate && !ignore_rotate ? monome_size_y() - _y - 1 : _y; + u8 refresh = 0; + u8 scripts[SCRIPT_COUNT]; + for (u8 i = 0; i < SCRIPT_COUNT; i++) scripts[i] = 0; + + u8 update = 0; + for (u8 i = 0; i < GRID_FADER_COUNT; i++) { + if (GFC.enabled && SG.group[GFC.group].enabled && grid_within_area(x, y, &GFC)) { + update = 0; + if (GF.type == FADER_H_FINE) { + if (x == GFC.x) { + if (GF.value) GF.value--; + update = 1; + } else if (x == GFC.x + GFC.w - 1) { + if (GF.value < GFC.level) GF.value++; + update = 1; + } + } else if (GF.type == FADER_V_FINE) { + if (y == GFC.y) { + if (GF.value < GFC.level) GF.value++; + update = 1; + } else if (y == GFC.y + GFC.h - 1) { + if (GF.value) GF.value--; + update = 1; + } + } + + if (update) { + if (GFC.script != -1) scripts[GFC.script] = 1; + SG.latest_fader = i; + SG.latest_group = GFC.group; + if (SG.group[GFC.group].script != -1) scripts[SG.group[GFC.group].script] = 1; + refresh = 1; + } + } + } + + for (u8 i = 0; i < SCRIPT_COUNT; i++) + if (scripts[i]) run_script(ss, i); + + SG.grid_dirty = SG.scr_dirty = refresh; +} + +void hold_repeat_timer_callback(void* o) { + hold_repeat_timer* timer = o; + u8 is_hold = timer->used == 1; + if (is_hold) { + timer_set(&timer->timer, GRID_KEY_REPEAT_RATE); + timer->used = 2; + } + grid_process_key_hold_repeat(timer->ss, timer->x, timer->y, timer->ignore_rotate, is_hold); +} + +void grid_process_fader_slew(scene_state_t *ss) { +} + bool grid_within_area(u8 x, u8 y, grid_common_t *gc) { return x >= gc->x && x < (gc->x + gc->w) && y >= gc->y && y < (gc->y + gc->h); } diff --git a/module/grid.h b/module/grid.h index ace1e2d7..04ad7af1 100644 --- a/module/grid.h +++ b/module/grid.h @@ -24,5 +24,6 @@ extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 ctrl, u8 x1, u8 y1, u8 x2, u8 y2); extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 ignore_rotate); +extern void grid_process_fader_slew(scene_state_t *ss); #endif diff --git a/module/main.c b/module/main.c index 79c09cb9..ed7e47ce 100644 --- a/module/main.c +++ b/module/main.c @@ -126,6 +126,7 @@ static softTimer_t hidTimer = { .next = NULL, .prev = NULL }; static softTimer_t metroTimer = { .next = NULL, .prev = NULL }; static softTimer_t monomePollTimer = {.next = NULL, .prev = NULL }; static softTimer_t monomeRefreshTimer = {.next = NULL, .prev = NULL }; +static softTimer_t gridFaderTimer = { .next = NULL, .prev = NULL }; //////////////////////////////////////////////////////////////////////////////// @@ -141,6 +142,7 @@ static void hidTimer_callback(void* o); static void metroTimer_callback(void* o); static void monome_poll_timer_callback(void* obj); static void monome_refresh_timer_callback(void* obj); +static void grid_fader_timer_callback(void* obj); // event handler prototypes static void handler_None(int32_t data); @@ -288,6 +290,9 @@ void timers_unset_monome(void) { timer_remove(&monomeRefreshTimer); } +void grid_fader_timer_callback(void* o) { + grid_process_fader_slew(&scene_state); +} //////////////////////////////////////////////////////////////////////////////// // event handlers @@ -917,6 +922,7 @@ int main(void) { timer_add(&keyTimer, 71, &keyTimer_callback, NULL); timer_add(&adcTimer, 61, &adcTimer_callback, NULL); timer_add(&refreshTimer, 63, &refreshTimer_callback, NULL); + timer_add(&gridFaderTimer, 25, &grid_fader_timer_callback, NULL); // manually call tele_metro_updated to sync metro to scene_state metro_timer_enabled = false; From 032b279a599dd6cd597dd06dd876b2cb2102b935 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Wed, 27 Dec 2017 16:27:16 -0800 Subject: [PATCH 023/117] refactoring --- module/grid.c | 190 ++++++++++++++++++++++---------------------- src/ops/grid_ops.c | 194 +++++++++++++++++++-------------------------- 2 files changed, 177 insertions(+), 207 deletions(-) diff --git a/module/grid.c b/module/grid.c index e25f2848..14f54086 100644 --- a/module/grid.c +++ b/module/grid.c @@ -165,101 +165,6 @@ static bool grid_within_area(u8 x, u8 y, grid_common_t *gc); static void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level); static void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page); -void grid_refresh(scene_state_t *ss) { - size_x = monome_size_x(); - size_y = monome_size_y(); - - grid_fill_area(0, 0, size_x, size_y, 0); - - u16 x, y; - for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { - if (GXYC.enabled && SG.group[GXYC.group].enabled) { - if (GXY.value_x || GXY.value_y) { - x = GXYC.x + GXY.value_x; - y = GXYC.y + GXY.value_y; - grid_fill_area(GXYC.x, y, GXYC.w, 1, GXYC.level); - grid_fill_area(x, GXYC.y, 1, GXYC.h, GXYC.level); - grid_fill_area(x, y, 1, 1, 15); - } - } - } - - u16 fv, ff, fp; - for (u8 i = 0; i < GRID_FADER_COUNT; i++) { - if (GFC.enabled && SG.group[GFC.group].enabled) { - switch (GF.type) { - case FADER_H_BAR: - grid_fill_area(GFC.x, GFC.y, GF.value + 1, GFC.h, 15); - grid_fill_area(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.level); - break; - case FADER_V_BAR: - grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.level); - grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, 15); - break; - case FADER_H_DOT: - grid_fill_area(GFC.x + GF.value, GFC.y, 1, GFC.h, 15); - break; - case FADER_V_DOT: - grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, 15); - break; - case FADER_H_FINE: - fv = ((GFC.w << 4) * GF.value) / (GFC.level + 1); - ff = fv >> 4; - fp = fv & 15; - grid_fill_area(GFC.x, GFC.y, ff, GFC.h, 15); - if (fp) grid_fill_area(GFC.x + ff, GFC.y, 1, GFC.h, fp); - break; - case FADER_V_FINE: - fv = ((GFC.h << 4) * GF.value) / (GFC.level + 1); - ff = fv >> 4; - fp = fv & 15; - grid_fill_area(GFC.x, GFC.y + GFC.h - ff, GFC.w, ff, 15); - if (fp) grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff, fp); - break; - } - } - } - - for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) - if (GBC.enabled && SG.group[GBC.group].enabled) - grid_fill_area(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.level); - - u16 led; - for (u16 i = 0; i < size_x; i++) - for (u16 j = 0; j < size_y; j++) { - led = j * size_x + i; - if (led >= MONOME_MAX_LED_BYTES) continue; - - if (SG.leds[i][j] >= 0) - monomeLedBuffer[led] = SG.leds[i][j]; - else if (SG.leds[i][j] == LED_DIM) - monomeLedBuffer[led] >>= 1; - else if (SG.leds[i][j] == LED_BRI) { - monomeLedBuffer[led] <<= 1; - if (monomeLedBuffer[led] > 15) monomeLedBuffer[led] = 15; - else if (monomeLedBuffer[led] < 1) monomeLedBuffer[led] = 1; - } - - if (monomeLedBuffer[led] < SG.dim) - monomeLedBuffer[led] = 0; - else - monomeLedBuffer[led] -= SG.dim; - } - - if (SG.rotate) { - u16 total = size_x * size_y; - if (total > MONOME_MAX_LED_BYTES) total = MONOME_MAX_LED_BYTES; - u8 temp; - for (u16 i = 0; i < (total >> 1); i++) { - temp = monomeLedBuffer[i]; - monomeLedBuffer[i] = monomeLedBuffer[total - i - 1]; - monomeLedBuffer[total - i - 1] = temp; - } - } - - SG.grid_dirty = 0; -} - void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { if (timers_uninitialized) { timers_uninitialized = 0; @@ -433,6 +338,101 @@ bool grid_within_area(u8 x, u8 y, grid_common_t *gc) { return x >= gc->x && x < (gc->x + gc->w) && y >= gc->y && y < (gc->y + gc->h); } +void grid_refresh(scene_state_t *ss) { + size_x = monome_size_x(); + size_y = monome_size_y(); + + grid_fill_area(0, 0, size_x, size_y, 0); + + u16 x, y; + for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { + if (GXYC.enabled && SG.group[GXYC.group].enabled) { + if (GXY.value_x || GXY.value_y) { + x = GXYC.x + GXY.value_x; + y = GXYC.y + GXY.value_y; + grid_fill_area(GXYC.x, y, GXYC.w, 1, GXYC.level); + grid_fill_area(x, GXYC.y, 1, GXYC.h, GXYC.level); + grid_fill_area(x, y, 1, 1, 15); + } + } + } + + u16 fv, ff, fp; + for (u8 i = 0; i < GRID_FADER_COUNT; i++) { + if (GFC.enabled && SG.group[GFC.group].enabled) { + switch (GF.type) { + case FADER_H_BAR: + grid_fill_area(GFC.x, GFC.y, GF.value + 1, GFC.h, 15); + grid_fill_area(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.level); + break; + case FADER_V_BAR: + grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.level); + grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, 15); + break; + case FADER_H_DOT: + grid_fill_area(GFC.x + GF.value, GFC.y, 1, GFC.h, 15); + break; + case FADER_V_DOT: + grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, 15); + break; + case FADER_H_FINE: + fv = ((GFC.w << 4) * GF.value) / (GFC.level + 1); + ff = fv >> 4; + fp = fv & 15; + grid_fill_area(GFC.x, GFC.y, ff, GFC.h, 15); + if (fp) grid_fill_area(GFC.x + ff, GFC.y, 1, GFC.h, fp); + break; + case FADER_V_FINE: + fv = ((GFC.h << 4) * GF.value) / (GFC.level + 1); + ff = fv >> 4; + fp = fv & 15; + grid_fill_area(GFC.x, GFC.y + GFC.h - ff, GFC.w, ff, 15); + if (fp) grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff, fp); + break; + } + } + } + + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) + if (GBC.enabled && SG.group[GBC.group].enabled) + grid_fill_area(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.level); + + u16 led; + for (u16 i = 0; i < size_x; i++) + for (u16 j = 0; j < size_y; j++) { + led = j * size_x + i; + if (led >= MONOME_MAX_LED_BYTES) continue; + + if (SG.leds[i][j] >= 0) + monomeLedBuffer[led] = SG.leds[i][j]; + else if (SG.leds[i][j] == LED_DIM) + monomeLedBuffer[led] >>= 1; + else if (SG.leds[i][j] == LED_BRI) { + monomeLedBuffer[led] <<= 1; + if (monomeLedBuffer[led] > 15) monomeLedBuffer[led] = 15; + else if (monomeLedBuffer[led] < 1) monomeLedBuffer[led] = 1; + } + + if (monomeLedBuffer[led] < SG.dim) + monomeLedBuffer[led] = 0; + else + monomeLedBuffer[led] -= SG.dim; + } + + if (SG.rotate) { + u16 total = size_x * size_y; + if (total > MONOME_MAX_LED_BYTES) total = MONOME_MAX_LED_BYTES; + u8 temp; + for (u16 i = 0; i < (total >> 1); i++) { + temp = monomeLedBuffer[i]; + monomeLedBuffer[i] = monomeLedBuffer[total - i - 1]; + monomeLedBuffer[total - i - 1] = temp; + } + } + + SG.grid_dirty = 0; +} + void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level) { if (level == LED_OFF) return; diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index dc5f7705..b981771d 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -45,8 +45,8 @@ static void grid_common_init(grid_common_t *gc); static s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value); static void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fill, u8 border); -static void grid_init_button(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 latch, u8 level, u8 script); -static void grid_init_fader(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 type, u8 level, u8 script); +static void grid_init_button(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, s16 w, s16 h, s16 latch, s16 level, s16 script); +static void grid_init_fader(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, s16 w, s16 h, s16 type, s16 level, s16 script); static s16 grid_fader_max_value(scene_state_t *ss, u16 i); static void op_G_RST_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -414,14 +414,9 @@ static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 w = cs_pop(cs); s16 h = cs_pop(cs); s16 latch = cs_pop(cs); - GET_LEVEL(level); + s16 level = cs_pop(cs); s16 script = cs_pop(cs) - 1; - - if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; - if (script < 0 || script > INIT_SCRIPT) script = -1; - CLAMP_X_Y_W_H(return); - - grid_init_button(ss, SG.current_group, i, x, y, w, h, latch != 0, level, script); + grid_init_button(ss, SG.current_group, i, x, y, w, h, latch, level, script); SG.scr_dirty = SG.grid_dirty = 1; } @@ -433,15 +428,9 @@ static void op_G_GBT_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 w = cs_pop(cs); s16 h = cs_pop(cs); s16 latch = cs_pop(cs); - GET_LEVEL(level); + s16 level = cs_pop(cs); s16 script = cs_pop(cs) - 1; - - if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; - if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; - if (script < 0 || script > INIT_SCRIPT) script = -1; - CLAMP_X_Y_W_H(return); - - grid_init_button(ss, group, i, x, y, w, h, latch != 0, level, script); + grid_init_button(ss, group, i, x, y, w, h, latch, level, script); SG.scr_dirty = SG.grid_dirty = 1; } @@ -451,30 +440,26 @@ static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 _y = cs_pop(cs); s16 _w = cs_pop(cs); s16 _h = cs_pop(cs); - s16 latch = cs_pop(cs) != 0; - GET_LEVEL(level); + s16 latch = cs_pop(cs); + s16 level = cs_pop(cs); s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); - if (id < (s16)0 || id >= (s16)GRID_BUTTON_COUNT) return; - if (script < 0 || script > INIT_SCRIPT) script = -1; if (count_x <= (s16)0) return; - if (count_x > (s16)16) count_x = 16; + if (count_x > (s16)GRID_MAX_DIMENSION) count_x = GRID_MAX_DIMENSION; if (count_y <= (s16)0) return; - if (count_y > (s16)16) count_y = 16; + if (count_y > (s16)GRID_MAX_DIMENSION) count_y = GRID_MAX_DIMENSION; u16 i; s16 x, y, w, h; for (s16 cy = 0; cy < count_y; cy++) for (s16 cx = 0; cx < count_x; cx++) { i = id + cy * count_x + cx; - if (i >= GRID_BUTTON_COUNT) break; x = _x + _w * cx; w = _w; y = _y + _h * cy; h = _h; - CLAMP_X_Y_W_H(continue); grid_init_button(ss, SG.current_group, i, x, y, w, h, latch, level, script); } @@ -488,31 +473,26 @@ static void op_G_GBX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 _y = cs_pop(cs); s16 _w = cs_pop(cs); s16 _h = cs_pop(cs); - s16 latch = cs_pop(cs) != 0; - GET_LEVEL(level); + s16 latch = cs_pop(cs); + s16 level = cs_pop(cs); s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); - if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; - if (id < (s16)0 || id >= (s16)GRID_BUTTON_COUNT) return; - if (script < 0 || script > INIT_SCRIPT) script = -1; if (count_x <= (s16)0) return; - if (count_x > (s16)16) count_x = 16; + if (count_x > (s16)GRID_MAX_DIMENSION) count_x = GRID_MAX_DIMENSION; if (count_y <= (s16)0) return; - if (count_y > (s16)16) count_y = 16; + if (count_y > (s16)GRID_MAX_DIMENSION) count_y = GRID_MAX_DIMENSION; u16 i; s16 x, y, w, h; for (s16 cy = 0; cy < count_y; cy++) for (s16 cx = 0; cx < count_x; cx++) { i = id + cy * count_x + cx; - if (i >= GRID_BUTTON_COUNT) break; x = _x + _w * cx; w = _w; y = _y + _h * cy; h = _h; - CLAMP_X_Y_W_H(continue); grid_init_button(ss, group, i, x, y, w, h, latch, level, script); } @@ -741,24 +721,6 @@ static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 type = cs_pop(cs); s16 level = cs_pop(cs); s16 script = cs_pop(cs) - 1; - - if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; - if (script < 0 || script > INIT_SCRIPT) script = -1; - CLAMP_X_Y_W_H(return); - if (type > FADER_V_FINE) type = FADER_H_BAR; - if (type == FADER_H_FINE || type == FADER_V_FINE) { - s16 maxlevel = ((type == FADER_H_FINE ? w : h) << 4) - 1; - if (level < 0) - level = 0; - else if (level > maxlevel) - level = maxlevel; - } else { - if (level < (s16)LED_OFF) - level = LED_OFF; - else if (level > (s16)15) - level = 15; - } - grid_init_fader(ss, SG.current_group, i, x, y, w, h, type, level, script); SG.scr_dirty = SG.grid_dirty = 1; } @@ -773,25 +735,6 @@ static void op_G_GFD_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 type = cs_pop(cs); s16 level = cs_pop(cs); s16 script = cs_pop(cs) - 1; - - if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; - if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; - if (script < 0 || script > INIT_SCRIPT) script = -1; - CLAMP_X_Y_W_H(return); - if (type > FADER_V_FINE) type = FADER_H_BAR; - if (type == FADER_H_FINE || type == FADER_V_FINE) { - s16 maxlevel = ((type == FADER_H_FINE ? w : h) << 4) - 1; - if (level < 0) - level = 0; - else if (level > maxlevel) - level = maxlevel; - } else { - if (level < (s16)LED_OFF) - level = LED_OFF; - else if (level > (s16)15) - level = 15; - } - grid_init_fader(ss, group, i, x, y, w, h, type, level, script); SG.scr_dirty = SG.grid_dirty = 1; } @@ -808,37 +751,20 @@ static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); - if (id < (s16)0 || id >= (s16)GRID_FADER_COUNT) return; - if (script < 0 || script > INIT_SCRIPT) script = -1; if (count_x <= (s16)0) return; - if (count_x > (s16)16) count_x = 16; + if (count_x > (s16)GRID_MAX_DIMENSION) count_x = GRID_MAX_DIMENSION; if (count_y <= (s16)0) return; - if (count_y > (s16)16) count_y = 16; - if (type > FADER_V_FINE) type = FADER_H_BAR; - if (type == FADER_H_FINE || type == FADER_V_FINE) { - s16 maxlevel = ((type == FADER_H_FINE ? _w : _h) << 4) - 1; - if (level < 0) - level = 0; - else if (level > maxlevel) - level = maxlevel; - } else { - if (level < (s16)LED_OFF) - level = LED_OFF; - else if (level > (s16)15) - level = 15; - } + if (count_y > (s16)GRID_MAX_DIMENSION) count_y = GRID_MAX_DIMENSION; u16 i; s16 x, y, w, h; for (u16 cy = 0; cy < count_y; cy++) for (u16 cx = 0; cx < count_x; cx++) { i = id + cy * count_x + cx; - if (i >= (s16)GRID_FADER_COUNT) break; x = _x + _w * cx; w = _w; y = _y + _h * cy; h = _h; - CLAMP_X_Y_W_H(continue); grid_init_fader(ss, SG.current_group, i, x, y, w, h, type, level, script); } @@ -858,38 +784,20 @@ static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); - if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; - if (id < (s16)0 || id >= (s16)GRID_FADER_COUNT) return; - if (script < 0 || script > INIT_SCRIPT) script = -1; if (count_x <= (s16)0) return; - if (count_x > (s16)16) count_x = 16; + if (count_x > (s16)GRID_MAX_DIMENSION) count_x = GRID_MAX_DIMENSION; if (count_y <= (s16)0) return; - if (count_y > (s16)16) count_y = 16; - if (type > FADER_V_FINE) type = FADER_H_BAR; - if (type == FADER_H_FINE || type == FADER_V_FINE) { - s16 maxlevel = ((type == FADER_H_FINE ? _w : _h) << 4) - 1; - if (level < 0) - level = 0; - else if (level > maxlevel) - level = maxlevel; - } else { - if (level < (s16)LED_OFF) - level = LED_OFF; - else if (level > (s16)15) - level = 15; - } + if (count_y > (s16)GRID_MAX_DIMENSION) count_y = GRID_MAX_DIMENSION; u16 i; s16 x, y, w, h; for (u16 cy = 0; cy < count_y; cy++) for (u16 cx = 0; cx < count_x; cx++) { i = id + cy * count_x + cx; - if (i >= (s16)GRID_FADER_COUNT) break; x = _x + _w * cx; w = _w; y = _y + _h * cy; h = _h; - CLAMP_X_Y_W_H(continue); grid_init_fader(ss, group, i, x, y, w, h, type, level, script); } @@ -1333,12 +1241,38 @@ void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fill, u8 b SG.scr_dirty = SG.grid_dirty = 1; } -static void grid_init_button(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 latch, u8 level, u8 script) { +static void grid_init_button(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, + s16 w, s16 h, s16 latch, s16 level, s16 script) { + + if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; + + if (x >= (s16)GRID_MAX_DIMENSION || y >= (s16)GRID_MAX_DIMENSION) return; + if (x < (s16)0) { + w += x; + x = 0; + } + if (w + x > (s16)GRID_MAX_DIMENSION) w = GRID_MAX_DIMENSION - x; + if (y < (s16)0) { + h += y; + y = 0; + } + if (h + y > (s16)GRID_MAX_DIMENSION) h = GRID_MAX_DIMENSION - y; + if (w == 0 || h == 0) return; + + if (level < (s16)LED_OFF) + level = LED_OFF; + else if (level > (s16)15) + level = 15; + + if (script < 0 || script > INIT_SCRIPT) script = -1; + GBC.enabled = true; GBC.group = group; GBC.x = x; GBC.y = y; GBC.w = w; + GBC.h = h; GBC.level = level; GBC.script = script; @@ -1346,7 +1280,43 @@ static void grid_init_button(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 if (!GB.latch) GB.state = 0; } -static void grid_init_fader(scene_state_t *ss, u8 group, u16 i, u8 x, u8 y, u8 w, u8 h, u8 type, u8 level, u8 script) { +static void grid_init_fader(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, + s16 w, s16 h, s16 type, s16 level, s16 script) { + + if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; + + if (x >= (s16)GRID_MAX_DIMENSION || y >= (s16)GRID_MAX_DIMENSION) return; + if (x < (s16)0) { + w += x; + x = 0; + } + if (w + x > (s16)GRID_MAX_DIMENSION) w = GRID_MAX_DIMENSION - x; + if (y < (s16)0) { + h += y; + y = 0; + } + if (h + y > (s16)GRID_MAX_DIMENSION) h = GRID_MAX_DIMENSION - y; + if (w == 0 || h == 0) return; + + if (type > FADER_V_FINE) type = FADER_H_BAR; + + if (type == FADER_H_FINE || type == FADER_V_FINE) { + u8 size = type == FADER_H_FINE ? w : h; + s16 maxlevel = ((size - 2) << 4) - 1; + if (level < 0 || size < 3) + level = 0; + else if (level > maxlevel) + level = maxlevel; + } else { + if (level < (s16)LED_OFF) + level = LED_OFF; + else if (level > (s16)15) + level = 15; + } + + if (script < 0 || script > INIT_SCRIPT) script = -1; + GFC.enabled = true; GFC.group = group; GFC.x = x; From cbf8ec88e4fa192e17bb090c1add9ab43977bd7c Mon Sep 17 00:00:00 2001 From: Brendon Cassidy Date: Sun, 31 Dec 2017 18:52:06 -0800 Subject: [PATCH 024/117] new TELEX ops, ER-301 support, 16n support, and two new operators for patterns (MIN and MAX) --- docs/ops/er301.md | 3 + docs/ops/er301.toml | 36 ++++ docs/ops/fader.md | 3 + docs/ops/fader.toml | 4 + docs/ops/patterns.toml | 22 ++ docs/ops/telex_o.toml | 31 +++ libavr32 | 2 +- module/config.mk | 2 + module/flash.c | 13 +- module/grid.c | 85 ++++---- module/keyboard_helper.h | 2 +- module/live_mode.c | 58 +++--- module/live_mode.h | 4 +- module/main.c | 53 ++--- module/usb_disk_mode.c | 31 +-- src/match_token.rl | 28 ++- src/ops/er301.c | 107 ++++++++++ src/ops/er301.h | 42 ++++ src/ops/fader.c | 29 +++ src/ops/fader.h | 11 + src/ops/grid_ops.c | 425 ++++++++++++++++++++++++--------------- src/ops/maths.c | 2 +- src/ops/op.c | 17 +- src/ops/op_enum.h | 19 ++ src/ops/patterns.c | 82 ++++++++ src/ops/patterns.h | 4 + src/ops/telex.c | 73 +++++-- src/ops/telex.h | 15 +- src/state.c | 10 +- src/state.h | 12 +- src/teletype.c | 4 +- src/turtle.c | 16 +- tests/Makefile | 4 +- tests/op_mod_tests.c | 8 +- tests/process_tests.c | 2 +- tests/turtle_tests.c | 4 +- 36 files changed, 931 insertions(+), 332 deletions(-) create mode 100644 docs/ops/er301.md create mode 100644 docs/ops/er301.toml create mode 100644 docs/ops/fader.md create mode 100644 docs/ops/fader.toml create mode 100644 src/ops/er301.c create mode 100644 src/ops/er301.h create mode 100644 src/ops/fader.c create mode 100644 src/ops/fader.h diff --git a/docs/ops/er301.md b/docs/ops/er301.md new file mode 100644 index 00000000..bb66d21f --- /dev/null +++ b/docs/ops/er301.md @@ -0,0 +1,3 @@ +## Orthogonal Devices ER-301 Sound Computer + +The ER-301 is a voltage-controllable canvas for digital signal processing algorithms available from Orthogonal Devices. It can communicate with the Teletype to send up to 100 triggers and 100 CV values per device. Up to three devices are software-selectable and correlate to outputs up to 300. \ No newline at end of file diff --git a/docs/ops/er301.toml b/docs/ops/er301.toml new file mode 100644 index 00000000..12d27885 --- /dev/null +++ b/docs/ops/er301.toml @@ -0,0 +1,36 @@ +["SC.TR"] +prototype = "SC.TR x y" +short = "Set trigger output for the ER-301 virtual output x to y (0-1)" + +["SC.TR.POL"] +prototype = "SC.TR.POL x y" +short = "Set polarity of trigger for the ER-301 virtual output x to y (0-1)" + +["SC.TR.TIME"] +prototype = "SC.TR.TIME x y" +short = "Set the pulse time for the ER-301 virtual trigger `x` to `y` in ms" + +["SC.TR.TOG"] +prototype = "SC.TR.TOG x" +short = "Flip the state for the ER-301 virtual trigger output `x`" + +["SC.TR.PULSE"] +prototype = "SC.TR.PULSE x" +aliases = ["SC.TR.P"] +short = "Pulse the ER-301 virtual trigger output `x`" + +["SC.CV"] +prototype = "SC.CV x y" +short = "CV target value for the ER-301 virtual output `x` to value `y`" + +["SC.CV.OFF"] +prototype = "SC.CV.OFF x y" +short = "CV offset added to the ER-301 virtual output `x`" + +["SC.CV.SET"] +prototype = "SC.CV.SET x" +short = "Set CV value for the ER-301 virtual output `x`" + +["SC.CV.SLEW"] +prototype = "SC.CV.SLEW x y" +short = "Set the CV slew time for the ER-301 virtual output `x` in ms" \ No newline at end of file diff --git a/docs/ops/fader.md b/docs/ops/fader.md new file mode 100644 index 00000000..b07fb237 --- /dev/null +++ b/docs/ops/fader.md @@ -0,0 +1,3 @@ +## 16n Faderbank + +The 16n Faderbank is an open-source controller that can be polled by the Teletype to read the positions of its 16 sliders. \ No newline at end of file diff --git a/docs/ops/fader.toml b/docs/ops/fader.toml new file mode 100644 index 00000000..5899732d --- /dev/null +++ b/docs/ops/fader.toml @@ -0,0 +1,4 @@ +["FADER"] +prototype = "FADER x" +aliases = ["FB"] +short = "reads the value of the `FADER` slider `x`; default return range is from 0 to 16383" \ No newline at end of file diff --git a/docs/ops/patterns.toml b/docs/ops/patterns.toml index cf86308b..828b57c4 100644 --- a/docs/ops/patterns.toml +++ b/docs/ops/patterns.toml @@ -184,3 +184,25 @@ short = "return and remove the value from the end of the working pattern (like a ["PN.POP"] prototype = "PN.POP x" short = "return and remove the value from the end of pattern `x` (like a stack), destructive to loop length" + + +["P.MIN"] +prototype = "P.MIN" +short = "find the first minimum value in the pattern between the START and END for the working pattern and return its index" + +["PN.MIN"] +prototype = "PN.MIN x" +short = "find the first minimum value in the pattern between the START and END for pattern `x` and return its index" + + +["P.MAX"] +prototype = "P.MAX" +short = "find the first maximum value in the pattern between the START and END for the working pattern and return its index" + +["PN.MAX"] +prototype = "PN.MAX x" +short = "find the first maximum value in the pattern between the START and END for pattern `x` and return its index" + + + + diff --git a/docs/ops/telex_o.toml b/docs/ops/telex_o.toml index c61a4277..e537da0f 100644 --- a/docs/ops/telex_o.toml +++ b/docs/ops/telex_o.toml @@ -247,6 +247,33 @@ If a curve is too small for the range being covered, values above the range will """ +["TO.CV.CALIB"] +prototype = "TO.CV.CALIB x" +short = "Locks the current offset (`CV.OFF`) as a calibration offset and saves it to persist between power cycles for output `x`." +description = """ + +To calibrate your TXo outputs, follow these steps. Before you start, let your expander warm up for a few minutes. It won't take long - but you want to make sure that it is calibrated at a more representative temperature. + +Then, first adjust your offset (CV.OFF) until the output is at zero volts (0). For example: + +``` +CV.OFF 1 8 +``` + +Once that output measures at zero volts, you want to lock it in as the calibration by calling the following operator: + +``` +CV.CALIB 1 +``` + +You will find that the offset is now zero, but the output is at the value that you targeted during your prior adjustment. To reset to normal (and forget this calibration offset), use the `TO.CV.RESET` command. + +""" + +["TO.CV.RESET"] +prototype = "TO.CV.RESET x" +short = "Clears the calibration offset for output `x`." + ["TO.OSC"] prototype = "TO.OSC x y" short = "targets oscillation for CV output `x` to `y` with the portamento rate determined by the `TO.OSC.SLEW` value; `y` is 1v/oct translated from the standard range (1-16384); a value of `0` disables oscillation; `CV` amplitude is used as the peak for oscillation and needs to be `> 0` for it to be perceivable" @@ -440,6 +467,10 @@ This will initialize the `CV 1` output to have an envelope that will ramp to `+8 To return your `CV` output to normal function, either deactivate the envelope (`TO.ENV.ACT 1 0`) or reinitialize the output (`TO.CV.INIT 1`). """ +["TO.ENV"] +prototype = "TO.ENV x y" +short = "This parameter essentially allows output `x` to act as a gate between the 0 and 1 state. Changing this value from 0 to 1 causes the envelope to trigger the attack phase and hold at the peak CV value; changing this value from 1 to 0 causes the decay stage of the envelope to be triggered." + ["TO.ENV.TRIG"] prototype = "TO.ENV.TRIG x" short = "triggers the envelope at `CV` output `x` to cycle; `CV` amplitude is used as the peak for the envelope and needs to be `> 0` for the envelope to be perceivable" diff --git a/libavr32 b/libavr32 index cb0da4ef..3264a8e1 160000 --- a/libavr32 +++ b/libavr32 @@ -1 +1 @@ -Subproject commit cb0da4ef5ffdf4f7e9e7370267f623c0ee6845f8 +Subproject commit 3264a8e1ec7d971108a5aa7585392a95b3b60dda diff --git a/module/config.mk b/module/config.mk index b6668c7e..c5f6c8a5 100644 --- a/module/config.mk +++ b/module/config.mk @@ -89,6 +89,8 @@ CSRCS = \ ../src/ops/controlflow.c \ ../src/ops/delay.c \ ../src/ops/earthsea.c \ + ../src/ops/er301.c \ + ../src/ops/fader.c \ ../src/ops/grid_ops.c \ ../src/ops/hardware.c \ ../src/ops/init.c \ diff --git a/module/flash.c b/module/flash.c index e3337a72..95031227 100644 --- a/module/flash.c +++ b/module/flash.c @@ -85,7 +85,7 @@ void flash_read(uint8_t preset_no, scene_state_t *scene, memcpy(ss_patterns_ptr(scene), &f.scenes[preset_no].patterns, ss_patterns_size()); memcpy(&grid_data, &f.scenes[preset_no].grid_data, sizeof(grid_data_t)); - unpack_grid(scene); + unpack_grid(scene); memcpy(text, &f.scenes[preset_no].text, SCENE_TEXT_LINES * SCENE_TEXT_CHARS); } @@ -124,18 +124,19 @@ static void pack_grid(scene_state_t *scene) { for (uint16_t i = 0; i < GRID_FADER_COUNT; i += 2) { byte = i >> 1; if (byte >= FADER_STATE_SIZE) break; - grid_data.fader_states[byte] = (scene->grid.fader[i].value << 4) + - scene->grid.fader[i+1].value; + grid_data.fader_states[byte] = + (scene->grid.fader[i].value << 4) + scene->grid.fader[i + 1].value; } } static void unpack_grid(scene_state_t *scene) { for (uint16_t i = 0; i < GRID_BUTTON_COUNT; i++) { - scene->grid.button[i].state = + scene->grid.button[i].state = 0 != (grid_data.button_states[i >> 3] & (1 << (i & 7))); } for (uint16_t i = 0; i < GRID_FADER_COUNT; i += 2) { scene->grid.fader[i].value = grid_data.fader_states[i >> 1] >> 4; - scene->grid.fader[i+1].value = grid_data.fader_states[i >> 1] & 0b1111; + scene->grid.fader[i + 1].value = + grid_data.fader_states[i >> 1] & 0b1111; } -} +} diff --git a/module/grid.c b/module/grid.c index 14f54086..fafcdbec 100644 --- a/module/grid.c +++ b/module/grid.c @@ -1,5 +1,5 @@ -#include "font.h" #include "grid.h" +#include "font.h" #include "globals.h" #include "state.h" #include "teletype.h" @@ -402,23 +402,25 @@ void grid_refresh(scene_state_t *ss) { for (u16 j = 0; j < size_y; j++) { led = j * size_x + i; if (led >= MONOME_MAX_LED_BYTES) continue; - + if (SG.leds[i][j] >= 0) monomeLedBuffer[led] = SG.leds[i][j]; else if (SG.leds[i][j] == LED_DIM) monomeLedBuffer[led] >>= 1; else if (SG.leds[i][j] == LED_BRI) { monomeLedBuffer[led] <<= 1; - if (monomeLedBuffer[led] > 15) monomeLedBuffer[led] = 15; - else if (monomeLedBuffer[led] < 1) monomeLedBuffer[led] = 1; + if (monomeLedBuffer[led] > 15) + monomeLedBuffer[led] = 15; + else if (monomeLedBuffer[led] < 1) + monomeLedBuffer[led] = 1; } - + if (monomeLedBuffer[led] < SG.dim) monomeLedBuffer[led] = 0; else monomeLedBuffer[led] -= SG.dim; } - + if (SG.rotate) { u16 total = size_x * size_y; if (total > MONOME_MAX_LED_BYTES) total = MONOME_MAX_LED_BYTES; @@ -429,39 +431,41 @@ void grid_refresh(scene_state_t *ss) { monomeLedBuffer[total - i - 1] = temp; } } - + SG.grid_dirty = 0; } void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level) { if (level == LED_OFF) return; - + u16 index; u16 x_end = min(size_x, x + w); u16 y_end = min(size_y, y + h); - + if (level == LED_DIM) { for (u16 _x = x; _x < x_end; _x++) for (u16 _y = y; _y < y_end; _y++) { index = _x + _y * size_x; if (index < MONOME_MAX_LED_BYTES) monomeLedBuffer[index] >>= 1; } - - } else if (level == LED_BRI) { + } + else if (level == LED_BRI) { for (u16 _x = x; _x < x_end; _x++) for (u16 _y = y; _y < y_end; _y++) { index = _x + _y * size_x; if (index < MONOME_MAX_LED_BYTES) { - monomeLedBuffer[index] <<= 1; - if (monomeLedBuffer[index] > 15) monomeLedBuffer[index] = 15; + monomeLedBuffer[index] <<= 1; + if (monomeLedBuffer[index] > 15) + monomeLedBuffer[index] = 15; } } - - } else { + } + else { for (u16 _x = x; _x < x_end; _x++) for (u16 _y = y; _y < y_end; _y++) { index = _x + _y * size_x; - if (index < MONOME_MAX_LED_BYTES) monomeLedBuffer[index] = level; + if (index < MONOME_MAX_LED_BYTES) + monomeLedBuffer[index] = level; } } } @@ -479,13 +483,13 @@ void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 c grid_screen_refresh_led(ss, 1, page, x1, y1, x2, y2); break; case GRID_MODE_OFF: - case GRID_MODE_LAST: - break; + case GRID_MODE_LAST: break; } SG.scr_dirty = 0; } -void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { +void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, + u8 y2) { grid_fill_area_scr(0, 0, GRID_MAX_DIMENSION, GRID_MAX_DIMENSION, 0, 0); u8 last_x, last_y; @@ -556,9 +560,10 @@ void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u return; } -void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { +void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, + u8 y1, u8 x2, u8 y2) { grid_fill_area_scr(0, 0, GRID_MAX_DIMENSION, GRID_MAX_DIMENSION, 0, 0); - + u16 x, y; for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { if (GXYC.enabled && SG.group[GXYC.group].enabled) { @@ -623,24 +628,27 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 screen[i][j] >>= 1; else if (l == LED_BRI) { screen[i][j] <<= 1; - if (screen[i][j] > 15) screen[i][j] = 15; - else if (screen[i][j] < 1) screen[i][j] = 1; + if (screen[i][j] > 15) + screen[i][j] = 15; + else if (screen[i][j] < 1) + screen[i][j] = 1; } } - + u16 _y, cell, size, left; if (full_grid) { cell = 8; size = 5; left = 0; for (int i = 0; i < 8; i++) region_fill(&line[i], 0); - } else { + } + else { cell = 6; size = 4; left = 10; for (int i = 0; i < 6; i++) region_fill(&line[i], 0); } - + u8 _line; u16 _data; for (u16 x = 0; x < GRID_MAX_DIMENSION; x++) @@ -654,7 +662,8 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 if (screen[x][y] == 0) { if (i == 0 || i == size - 1 || j == 0 || j == size - 1) line[_line].data[_data] = 1; - } else + } + else line[_line].data[_data] = screen[x][y]; } } @@ -722,21 +731,24 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 } } -static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { +static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, + u8 x2, u8 y2) { char s[32]; u8 area_x, area_y, area_w, area_h; if (x1 < x2) { area_x = x1; area_w = x2 + 1 - x1; - } else { + } + else { area_x = x2; area_w = x1 + 1 - x2; } if (y1 < y2) { area_y = y1; area_h = y2 + 1 - y1; - } else { + } + else { area_y = y2; area_h = y1 + 1 - y2; } @@ -763,9 +775,10 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u font_string_region_clip_right(&line[4], s, 117, 0, 8, 0); itoa(area_h, s, 10); font_string_region_clip_right(&line[5], s, 117, 0, 8, 0); - + for (u16 j = 0; j < 9; j += 2) line[j >> 3].data[119 + ((j & 7) << 7)] = 1; - for (u16 j = 17; j < 48; j += 2) line[j >> 3].data[119 + ((j & 7) << 7)] = 1; + for (u16 j = 17; j < 48; j += 2) + line[j >> 3].data[119 + ((j & 7) << 7)] = 1; // icons @@ -822,15 +835,15 @@ void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page) { for (u16 _y = y1; _y <= y2; _y++) screen[_x][_y] >>= 1; } - - } else if (level == LED_BRI) { + } + else if (level == LED_BRI) { for (u16 _x = x; _x < x_end; _x++) for (u16 _y = y1; _y <= y2; _y++) { screen[_x][_y] <<= 1; if (screen[_x][_y] > 15) screen[_x][_y] = 15; } - - } else { + } + else { for (u16 _x = x; _x < x_end; _x++) for (u16 _y = y1; _y <= y2; _y++) screen[_x][_y] = level; diff --git a/module/keyboard_helper.h b/module/keyboard_helper.h index 637ff404..35c4d688 100644 --- a/module/keyboard_helper.h +++ b/module/keyboard_helper.h @@ -77,7 +77,7 @@ static inline bool match_shift_alt(uint8_t mod, uint8_t key, } static inline bool match_shift_ctrl(uint8_t mod, uint8_t key, - uint8_t required_key) { + uint8_t required_key) { return mod_only_shift_ctrl(mod) && key == required_key; } diff --git a/module/live_mode.c b/module/live_mode.c index e5decd41..da3fccea 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -113,18 +113,19 @@ void set_live_mode() { grid_mode = GRID_MODE_EDIT; } -void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, scene_state_t *ss) { +void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, + scene_state_t *ss) { if (is_release) { - if (match_ctrl(m, k, HID_SPACEBAR) || + if (match_ctrl(m, k, HID_SPACEBAR) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SPACEBAR))) { grid_process_key(ss, grid_x1, grid_y1, 0, 1); } return; } - + // or C-n: history next - if ((match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) - && grid_mode != GRID_MODE_FULL) { + if ((match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) && + grid_mode != GRID_MODE_FULL) { if (history_line > 0) { history_line--; line_editor_set_command(&le, &history[history_line]); @@ -136,8 +137,8 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, dirty |= D_INPUT; } // or C-p: history previous - else if ((match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) - && grid_mode != GRID_MODE_FULL) { + else if ((match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) && + grid_mode != GRID_MODE_FULL) { if (history_line < history_top) { history_line++; line_editor_set_command(&le, &history[history_line]); @@ -145,8 +146,8 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, } } // C-G: toggle grid view - else if (match_ctrl(m, k, HID_G) || - (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_G))) { + else if (match_ctrl(m, k, HID_G) || + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_G))) { if (++grid_mode == GRID_MODE_LAST) { grid_mode = GRID_MODE_OFF; set_live_mode(); @@ -160,7 +161,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, } // C-: move grid cursor else if (match_ctrl(m, k, HID_UP) || - (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_UP))) { + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_UP))) { grid_y1 = (grid_y1 + GRID_MAX_DIMENSION - 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; @@ -168,7 +169,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, } // C-: move grid cursor else if (match_ctrl(m, k, HID_DOWN) || - (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_DOWN))) { + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_DOWN))) { grid_y1 = (grid_y1 + 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; @@ -176,7 +177,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, } // C-: move grid cursor else if (match_ctrl(m, k, HID_LEFT) || - (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_LEFT))) { + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_LEFT))) { grid_x1 = (grid_x1 + GRID_MAX_DIMENSION - 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; @@ -184,7 +185,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, } // C-: move grid cursor else if (match_ctrl(m, k, HID_RIGHT) || - (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_RIGHT))) { + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_RIGHT))) { grid_x1 = (grid_x1 + 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; @@ -220,7 +221,8 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, } // C-: emulate grid press else if (!is_held_key && (match_ctrl(m, k, HID_SPACEBAR) || - (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SPACEBAR)))) { + (grid_mode == GRID_MODE_FULL && + match_no_mod(m, k, HID_SPACEBAR)))) { grid_x2 = grid_x1; grid_y2 = grid_y1; grid_view_changed = true; @@ -233,14 +235,16 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, if (grid_x1 < grid_x2) { area_x = grid_x1; area_w = grid_x2 + 1 - grid_x1; - } else { + } + else { area_x = grid_x2; area_w = grid_x1 + 1 - grid_x2; } if (grid_y1 < grid_y2) { area_y = grid_y1; area_h = grid_y2 + 1 - grid_y1; - } else { + } + else { area_y = grid_y2; area_h = grid_y1 + 1 - grid_y2; } @@ -248,35 +252,35 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, line_editor_process_keys(&le, HID_1, HID_MODIFIER_NONE, false); area_x -= 10; } - line_editor_process_keys(&le, - area_x ? HID_1 + area_x - 1 : HID_0, HID_MODIFIER_NONE, false); + line_editor_process_keys(&le, area_x ? HID_1 + area_x - 1 : HID_0, + HID_MODIFIER_NONE, false); line_editor_process_keys(&le, HID_SPACEBAR, HID_MODIFIER_NONE, false); if (area_y > 9) { line_editor_process_keys(&le, HID_1, HID_MODIFIER_NONE, false); area_y -= 10; } - line_editor_process_keys(&le, - area_y ? HID_1 + area_y - 1 : HID_0, HID_MODIFIER_NONE, false); + line_editor_process_keys(&le, area_y ? HID_1 + area_y - 1 : HID_0, + HID_MODIFIER_NONE, false); line_editor_process_keys(&le, HID_SPACEBAR, HID_MODIFIER_NONE, false); if (area_w > 9) { line_editor_process_keys(&le, HID_1, HID_MODIFIER_NONE, false); area_w -= 10; } - line_editor_process_keys(&le, - area_w ? HID_1 + area_w - 1 : HID_0, HID_MODIFIER_NONE, false); + line_editor_process_keys(&le, area_w ? HID_1 + area_w - 1 : HID_0, + HID_MODIFIER_NONE, false); line_editor_process_keys(&le, HID_SPACEBAR, HID_MODIFIER_NONE, false); if (area_h > 9) { line_editor_process_keys(&le, HID_1, HID_MODIFIER_NONE, false); area_h -= 10; } - line_editor_process_keys(&le, - area_h ? HID_1 + area_h - 1 : HID_0, HID_MODIFIER_NONE, false); + line_editor_process_keys(&le, area_h ? HID_1 + area_h - 1 : HID_0, + HID_MODIFIER_NONE, false); line_editor_process_keys(&le, HID_SPACEBAR, HID_MODIFIER_NONE, false); dirty |= D_INPUT; } // C-: toggle grid page else if (match_ctrl(m, k, HID_SLASH) || - (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SLASH))) { + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SLASH))) { if (++grid_page > 1) grid_page = 0; grid_view_changed = true; } @@ -357,7 +361,7 @@ bool screen_refresh_live(scene_state_t *ss) { grid_page, grid_ctrl, grid_x1, grid_y1, grid_x2, grid_y2); } if (grid_mode == GRID_MODE_FULL) return true; - + if (dirty & D_INPUT) { line_editor_draw(&le, '>', &line[7]); screen_dirty |= (1 << 7); @@ -454,7 +458,7 @@ bool screen_refresh_live(scene_state_t *ss) { 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; diff --git a/module/live_mode.h b/module/live_mode.h index 963a367e..4b6ea010 100644 --- a/module/live_mode.h +++ b/module/live_mode.h @@ -1,10 +1,10 @@ #ifndef _LIVE_MODE_H_ #define _LIVE_MODE_H_ -#include "stdbool.h" -#include "stdint.h" #include "grid.h" #include "state.h" +#include "stdbool.h" +#include "stdint.h" void set_slew_icon(bool display); void set_metro_icon(bool display); diff --git a/module/main.c b/module/main.c index ed7e47ce..9c9eaee2 100644 --- a/module/main.c +++ b/module/main.c @@ -81,14 +81,12 @@ void tele_profile_delay(uint8_t d) { scene_state_t scene_state; char scene_text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; uint8_t preset_select; -region line[8] = { { .w = 128, .h = 8, .x = 0, .y = 0 }, - { .w = 128, .h = 8, .x = 0, .y = 8 }, - { .w = 128, .h = 8, .x = 0, .y = 16 }, - { .w = 128, .h = 8, .x = 0, .y = 24 }, - { .w = 128, .h = 8, .x = 0, .y = 32 }, - { .w = 128, .h = 8, .x = 0, .y = 40 }, - { .w = 128, .h = 8, .x = 0, .y = 48 }, - { .w = 128, .h = 8, .x = 0, .y = 56 } }; +region line[8] = { + {.w = 128, .h = 8, .x = 0, .y = 0 }, {.w = 128, .h = 8, .x = 0, .y = 8 }, + {.w = 128, .h = 8, .x = 0, .y = 16 }, {.w = 128, .h = 8, .x = 0, .y = 24 }, + {.w = 128, .h = 8, .x = 0, .y = 32 }, {.w = 128, .h = 8, .x = 0, .y = 40 }, + {.w = 128, .h = 8, .x = 0, .y = 48 }, {.w = 128, .h = 8, .x = 0, .y = 56 } +}; //////////////////////////////////////////////////////////////////////////////// @@ -117,13 +115,13 @@ static uint8_t mod_key = 0, hold_key, hold_key_count = 0; static uint64_t last_in_tick = 0; // timers -static softTimer_t clockTimer = { .next = NULL, .prev = NULL }; -static softTimer_t refreshTimer = { .next = NULL, .prev = NULL }; -static softTimer_t keyTimer = { .next = NULL, .prev = NULL }; -static softTimer_t cvTimer = { .next = NULL, .prev = NULL }; -static softTimer_t adcTimer = { .next = NULL, .prev = NULL }; -static softTimer_t hidTimer = { .next = NULL, .prev = NULL }; -static softTimer_t metroTimer = { .next = NULL, .prev = NULL }; +static softTimer_t clockTimer = {.next = NULL, .prev = NULL }; +static softTimer_t refreshTimer = {.next = NULL, .prev = NULL }; +static softTimer_t keyTimer = {.next = NULL, .prev = NULL }; +static softTimer_t cvTimer = {.next = NULL, .prev = NULL }; +static softTimer_t adcTimer = {.next = NULL, .prev = NULL }; +static softTimer_t hidTimer = {.next = NULL, .prev = NULL }; +static softTimer_t metroTimer = {.next = NULL, .prev = NULL }; static softTimer_t monomePollTimer = {.next = NULL, .prev = NULL }; static softTimer_t monomeRefreshTimer = {.next = NULL, .prev = NULL }; static softTimer_t gridFaderTimer = { .next = NULL, .prev = NULL }; @@ -165,7 +163,8 @@ static void assign_msc_event_handlers(void); static void check_events(void); // key handling -static void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key, bool is_release); +static void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key, + bool is_release); static bool process_global_keys(uint8_t key, uint8_t mod_key, bool is_held_key); // start/stop monome polling/refresh timers @@ -233,32 +232,32 @@ void cvTimer_callback(void* o) { } void clockTimer_callback(void* o) { - event_t e = { .type = kEventTimer, .data = 0 }; + event_t e = {.type = kEventTimer, .data = 0 }; event_post(&e); } void refreshTimer_callback(void* o) { - event_t e = { .type = kEventScreenRefresh, .data = 0 }; + event_t e = {.type = kEventScreenRefresh, .data = 0 }; event_post(&e); } void keyTimer_callback(void* o) { - event_t e = { .type = kEventKeyTimer, .data = 0 }; + event_t e = {.type = kEventKeyTimer, .data = 0 }; event_post(&e); } void adcTimer_callback(void* o) { - event_t e = { .type = kEventPollADC, .data = 0 }; + event_t e = {.type = kEventPollADC, .data = 0 }; event_post(&e); } void hidTimer_callback(void* o) { - event_t e = { .type = kEventHidTimer, .data = 0 }; + event_t e = {.type = kEventHidTimer, .data = 0 }; event_post(&e); } void metroTimer_callback(void* o) { - event_t e = { .type = kEventAppCustom, .data = 0 }; + event_t e = {.type = kEventAppCustom, .data = 0 }; event_post(&e); } @@ -532,7 +531,7 @@ void assign_main_event_handlers() { app_event_handlers[kEventMonomeDisconnect] = &handler_None; app_event_handlers[kEventMonomePoll] = &handler_MonomePoll; app_event_handlers[kEventMonomeRefresh] = &handler_MonomeRefresh; - app_event_handlers[kEventMonomeGridKey] = &handler_MonomeGridKey; + app_event_handlers[kEventMonomeGridKey] = &handler_MonomeGridKey; } static void assign_msc_event_handlers(void) { @@ -617,18 +616,20 @@ void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key, bool is_re // release is a special case for live mode if (is_release) { - if (mode == M_LIVE) + if (mode == M_LIVE) process_live_keys(key, mod_key, is_held_key, true, &scene_state); return; } - + // first try global keys if (process_global_keys(key, mod_key, is_held_key)) return; switch (mode) { case M_EDIT: process_edit_keys(key, mod_key, is_held_key); break; - case M_LIVE: process_live_keys(key, mod_key, is_held_key, false, &scene_state); break; + case M_LIVE: + process_live_keys(key, mod_key, is_held_key, false, &scene_state); + break; case M_PATTERN: process_pattern_keys(key, mod_key, is_held_key); break; case M_PRESET_W: process_preset_w_keys(key, mod_key, is_held_key); diff --git a/module/usb_disk_mode.c b/module/usb_disk_mode.c index d00a8e83..d642fe86 100644 --- a/module/usb_disk_mode.c +++ b/module/usb_disk_mode.c @@ -110,7 +110,7 @@ void tele_usb_disk() { char blank = 0; for (int l = 0; l < SCENE_TEXT_LINES; l++) { if (strlen(text[l])) { - file_write_buf((uint8_t*)text[l], strlen(text[l])); + file_write_buf((uint8_t *)text[l], strlen(text[l])); file_putc('\n'); blank = 0; } @@ -135,7 +135,7 @@ void tele_usb_disk() { for (int l = 0; l < ss_get_script_len(&scene, s); l++) { file_putc('\n'); print_command(ss_get_script_command(&scene, s, l), input); - file_write_buf((uint8_t*)input, strlen(input)); + file_write_buf((uint8_t *)input, strlen(input)); } } @@ -147,7 +147,7 @@ void tele_usb_disk() { for (int b = 0; b < 4; b++) { itoa(ss_get_pattern_len(&scene, b), input, 10); - file_write_buf((uint8_t*)input, strlen(input)); + file_write_buf((uint8_t *)input, strlen(input)); if (b == 3) file_putc('\n'); else @@ -156,7 +156,7 @@ void tele_usb_disk() { for (int b = 0; b < 4; b++) { itoa(ss_get_pattern_wrap(&scene, b), input, 10); - file_write_buf((uint8_t*)input, strlen(input)); + file_write_buf((uint8_t *)input, strlen(input)); if (b == 3) file_putc('\n'); else @@ -165,7 +165,7 @@ void tele_usb_disk() { for (int b = 0; b < 4; b++) { itoa(ss_get_pattern_start(&scene, b), input, 10); - file_write_buf((uint8_t*)input, strlen(input)); + file_write_buf((uint8_t *)input, strlen(input)); if (b == 3) file_putc('\n'); else @@ -174,7 +174,7 @@ void tele_usb_disk() { for (int b = 0; b < 4; b++) { itoa(ss_get_pattern_end(&scene, b), input, 10); - file_write_buf((uint8_t*)input, strlen(input)); + file_write_buf((uint8_t *)input, strlen(input)); if (b == 3) file_putc('\n'); else @@ -186,7 +186,7 @@ void tele_usb_disk() { for (int l = 0; l < 64; l++) { for (int b = 0; b < 4; b++) { itoa(ss_get_pattern_val(&scene, b, l), input, 10); - file_write_buf((uint8_t*)input, strlen(input)); + file_write_buf((uint8_t *)input, strlen(input)); if (b == 3) file_putc('\n'); else @@ -195,7 +195,7 @@ void tele_usb_disk() { } grid_usb_write(&scene); - + file_close(); lun_state |= (1 << lun); // LUN test is done. @@ -266,7 +266,8 @@ void tele_usb_disk() { else if (c == 'G') { grid_state = grid_num = grid_count = 0; s = 11; - } else { + } + else { s = c - 49; if (s < 0 || s > 7) s = -1; } @@ -392,7 +393,7 @@ void tele_usb_disk() { // GRID else if (s == 11) { grid_usb_read(&scene, c); - } + } } @@ -441,13 +442,13 @@ static void grid_usb_read(scene_state_t *scene, char c) { grid_count = 0; grid_state = 1; if (!file_eof()) file_getc(); - if (!file_eof()) file_getc(); // eat \n\n + if (!file_eof()) file_getc(); // eat \n\n } } - } else if (grid_state == 1) { - if (c >= '0' && c <= '9') { - grid_num = grid_num * 10 + c - '0'; - } else if (c == '\t' || c == '\n') { + } + else if (grid_state == 1) { + if (c >= '0' && c <= '9') { grid_num = grid_num * 10 + c - '0'; } + else if (c == '\t' || c == '\n') { if (grid_count < GRID_FADER_COUNT) { scene->grid.fader[grid_count].value = grid_num; grid_num = 0; diff --git a/src/match_token.rl b/src/match_token.rl index cb70dbd9..f10a1fed 100644 --- a/src/match_token.rl +++ b/src/match_token.rl @@ -109,6 +109,10 @@ "PN.PUSH" => { MATCH_OP(E_OP_PN_PUSH); }; "P.POP" => { MATCH_OP(E_OP_P_POP); }; "PN.POP" => { MATCH_OP(E_OP_PN_POP); }; + "P.MIN" => { MATCH_OP(E_OP_P_MIN); }; + "PN.MIN" => { MATCH_OP(E_OP_PN_MIN); }; + "P.MAX" => { MATCH_OP(E_OP_P_MAX); }; + "PN.MAX" => { MATCH_OP(E_OP_PN_MAX); }; # queue "Q" => { MATCH_OP(E_OP_Q); }; @@ -418,7 +422,11 @@ "TO.ENV.EOR" => { MATCH_OP(E_OP_TO_ENV_EOR); }; "TO.ENV.EOC" => { MATCH_OP(E_OP_TO_ENV_EOC); }; - "TO.ENV.LOOP" => { MATCH_OP(E_OP_TO_ENV_LOOP); }; + "TO.ENV.LOOP" => { MATCH_OP(E_OP_TO_ENV_LOOP); }; + + "TO.ENV" => { MATCH_OP(E_OP_TO_ENV); }; + "TO.CV.CALIB" => { MATCH_OP(E_OP_TO_CV_CALIB); }; + "TO.CV.RESET" => { MATCH_OP(E_OP_TO_CV_RESET); }; "TI.PARAM" => { MATCH_OP(E_OP_TI_PARAM); }; "TI.PARAM.QT" => { MATCH_OP(E_OP_TI_PARAM_QT); }; @@ -446,6 +454,24 @@ "TI.PRM.MAP" => { MATCH_OP(E_OP_TI_PRM_MAP); }; "TI.PRM.INIT" => { MATCH_OP(E_OP_TI_PRM_INIT); }; + # fader + "FADER" => { MATCH_OP(E_OP_FADER); }; + "FB" => { MATCH_OP(E_OP_FB); }; + + # ER301 + "SC.TR" => { MATCH_OP(E_OP_SC_TR); }; + "SC.TR.TOG" => { MATCH_OP(E_OP_SC_TR_TOG); }; + "SC.TR.PULSE" => { MATCH_OP(E_OP_SC_TR_PULSE); }; + "SC.TR.TIME" => { MATCH_OP(E_OP_SC_TR_TIME); }; + "SC.TR.POL" => { MATCH_OP(E_OP_SC_TR_POL); }; + + "SC.TR.P" => { MATCH_OP(E_OP_SC_TR_P); }; + + "SC.CV" => { MATCH_OP(E_OP_SC_CV); }; + "SC.CV.SLEW" => { MATCH_OP(E_OP_SC_CV_SLEW); }; + "SC.CV.SET" => { MATCH_OP(E_OP_SC_CV_SET); }; + "SC.CV.OFF" => { MATCH_OP(E_OP_SC_CV_OFF); }; + # grid "G.RST" => { MATCH_OP(E_OP_G_RST); }; "G.CLR" => { MATCH_OP(E_OP_G_CLR); }; diff --git a/src/ops/er301.c b/src/ops/er301.c new file mode 100644 index 00000000..7249ec9f --- /dev/null +++ b/src/ops/er301.c @@ -0,0 +1,107 @@ +#include "ops/er301.h" + +#include "helpers.h" +#include "ii.h" +#include "teletype.h" +#include "teletype_io.h" +#include "telex.h" + +static void op_SC_TR_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_SC_TR_TOG_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_SC_TR_PULSE_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_SC_TR_TIME_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_SC_TR_POL_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); + +static void op_SC_CV_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_SC_CV_SLEW_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_SC_CV_SET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_SC_CV_OFF_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); + +const tele_op_t op_SC_TR = MAKE_GET_OP(SC.TR, op_SC_TR_get, 2, false); +const tele_op_t op_SC_TR_TOG = + MAKE_GET_OP(SC.TR.TOG, op_SC_TR_TOG_get, 1, false); +const tele_op_t op_SC_TR_PULSE = + MAKE_GET_OP(SC.TR.PULSE, op_SC_TR_PULSE_get, 1, false); +const tele_op_t op_SC_TR_TIME = + MAKE_GET_OP(SC.TR.TIME, op_SC_TR_TIME_get, 2, false); +const tele_op_t op_SC_TR_POL = + MAKE_GET_OP(SC.TR.POL, op_SC_TR_POL_get, 2, false); + +const tele_op_t op_SC_TR_P = + MAKE_ALIAS_OP(SC.TR.P, op_SC_TR_PULSE_get, NULL, 1, false); + +const tele_op_t op_SC_CV = MAKE_GET_OP(SC.CV, op_SC_CV_get, 2, false); +const tele_op_t op_SC_CV_SLEW = + MAKE_GET_OP(SC.CV.SLEW, op_SC_CV_SLEW_get, 2, false); +const tele_op_t op_SC_CV_SET = + MAKE_GET_OP(SC.CV.SET, op_SC_CV_SET_get, 2, false); +const tele_op_t op_SC_CV_OFF = + MAKE_GET_OP(SC.CV.OFF, op_SC_CV_OFF_get, 2, false); + + +void ERSend(uint8_t command, uint16_t output, int16_t value, bool set) { + // zero-index the output + output -= 1; + // convert the output to the device and the port + uint8_t port = output % 100; + uint8_t device = output / 100; + uint8_t address = ER301 + device; + // put the package in the i2c mail + SendIt(address, command, port, value, set); +} +void ERSet(uint8_t command, command_state_t *cs) { + uint16_t output = cs_pop(cs); + int16_t value = cs_pop(cs); + ERSend(command, output, value, true); +} +void ERCommand(uint8_t command, uint16_t output) { + ERSend(command, output, 0, false); +} + + +static void op_SC_TR_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + ERSet(TO_TR, cs); +} +static void op_SC_TR_TOG_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + ERCommand(TO_TR_TOG, cs_pop(cs)); +} +static void op_SC_TR_PULSE_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + ERCommand(TO_TR_PULSE, cs_pop(cs)); +} +static void op_SC_TR_TIME_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + ERSet(TO_TR_TIME, cs); +} +static void op_SC_TR_POL_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + ERSet(TO_TR_POL, cs); +} + +static void op_SC_CV_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + ERSet(TO_CV, cs); +} +static void op_SC_CV_SLEW_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + ERSet(TO_CV_SLEW, cs); +} +static void op_SC_CV_SET_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + ERSet(TO_CV_SET, cs); +} +static void op_SC_CV_OFF_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + ERSet(TO_CV_OFF, cs); +} \ No newline at end of file diff --git a/src/ops/er301.h b/src/ops/er301.h new file mode 100644 index 00000000..14c1cc09 --- /dev/null +++ b/src/ops/er301.h @@ -0,0 +1,42 @@ +#ifndef _OPS_ER301_H_ +#define _OPS_ER301_H_ + +#include "ops/op.h" + +extern const tele_op_t op_SC_TR; +extern const tele_op_t op_SC_TR_TOG; +extern const tele_op_t op_SC_TR_PULSE; +extern const tele_op_t op_SC_TR_TIME; +extern const tele_op_t op_SC_TR_POL; + +extern const tele_op_t op_SC_TR_P; + +extern const tele_op_t op_SC_CV; +extern const tele_op_t op_SC_CV_SLEW; +extern const tele_op_t op_SC_CV_SET; +extern const tele_op_t op_SC_CV_OFF; + +#define ER301 0xB0 + +void ERSend(uint8_t command, uint16_t output, int16_t value, bool set); +void ERSet(uint8_t command, command_state_t *cs); +void ERCommand(uint8_t command, uint16_t output); + +// not using these defines +// using the ones from the telex to make +// testing super-easy + +/* +#define SC_TR 0x00 +#define SC_TR_TOG 0x01 +#define SC_TR_TIME 0x02 +#define SC_TR_PULSE 0x05 +#define SC_TR_POL 0x06 + +#define SC_CV 0x10 +#define SC_CV_SET 0x11 +#define SC_CV_SLEW 0x12 +#define SC_CV_OFF 0x15 +*/ + +#endif \ No newline at end of file diff --git a/src/ops/fader.c b/src/ops/fader.c new file mode 100644 index 00000000..1deb71f7 --- /dev/null +++ b/src/ops/fader.c @@ -0,0 +1,29 @@ +#include "ops/fader.h" + +#include "helpers.h" +#include "ii.h" +#include "teletype.h" +#include "teletype_io.h" +#include "telex.h" + + +static void op_FADER_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); + + +const tele_op_t op_FADER = MAKE_GET_OP(FADER, op_FADER_get, 1, true); + +const tele_op_t op_FB = MAKE_ALIAS_OP(FB, op_FADER_get, NULL, 1, true); + + +static void op_FADER_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + uint16_t input = cs_pop(cs); + // zero-index the input + input -= 1; + // convert the input to the device and the port + uint8_t port = input % 16; + uint8_t device = input / 16; + uint8_t address = FADER + device; + ReceiveIt(address, port, cs); +} \ No newline at end of file diff --git a/src/ops/fader.h b/src/ops/fader.h new file mode 100644 index 00000000..7a02871c --- /dev/null +++ b/src/ops/fader.h @@ -0,0 +1,11 @@ +#ifndef _OPS_FADER_H_ +#define _OPS_FADER_H_ + +#include "ops/op.h" + +extern const tele_op_t op_FADER; +extern const tele_op_t op_FB; + +#define FADER 0x80 + +#endif \ No newline at end of file diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index b981771d..3c8f420b 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -29,14 +29,18 @@ if (x < (s16)0) { \ w += x; \ x = 0; \ - } else if (x >= (s16)GRID_MAX_DIMENSION) op; \ + } \ + else if (x >= (s16)GRID_MAX_DIMENSION) \ + op; \ if (w + x > (s16)GRID_MAX_DIMENSION) w = GRID_MAX_DIMENSION - x; \ if (y < (s16)0) { \ h += y; \ y = 0; \ - } else if (y >= (s16)GRID_MAX_DIMENSION) op; \ + } \ + else if (y >= (s16)GRID_MAX_DIMENSION) \ + op; \ if (h + y > (s16)GRID_MAX_DIMENSION) h = GRID_MAX_DIMENSION - y; - + #define min(a, b) ((s32)(a) < (s32)(b) ? (s32)(a) : (s32)(b)) #define max(a, b) ((s32)(a) > (s32)(b) ? (s32)(a) : (s32)(b)) @@ -201,18 +205,19 @@ const tele_op_t op_G_XYP_Y = MAKE_GET_OP(G.XYP.Y, op_G_XYP_Y_get, 1, true); // clang-format on -static void op_G_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *NOTUSED(cs)) { +static void op_G_RST_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), + command_state_t *NOTUSED(cs)) { SG.rotate = 0; SG.dim = 0; - + SG.current_group = 0; SG.latest_group = 0; SG.latest_button = 0; SG.latest_fader = 0; - + for (u8 i = 0; i < GRID_MAX_DIMENSION; i++) - for (u8 j = 0; j < GRID_MAX_DIMENSION; j++) - SG.leds[i][j] = LED_OFF; + for (u8 j = 0; j < GRID_MAX_DIMENSION; j++) SG.leds[i][j] = LED_OFF; for (u8 i = 0; i < GRID_GROUP_COUNT; i++) { SG.group[i].enabled = true; @@ -220,7 +225,7 @@ static void op_G_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat SG.group[i].fader_min = 0; SG.group[i].fader_max = 16383; } - + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { grid_common_init(&(GBC)); GB.latch = 0; @@ -232,60 +237,71 @@ static void op_G_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GF.type = FADER_H_BAR; GF.value = 0; } - + for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { grid_common_init(&(GXYC)); GXY.value_x = 0; GXY.value_y = 0; } - + SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_CLR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *NOTUSED(cs)) { +static void op_G_CLR_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), + command_state_t *NOTUSED(cs)) { for (u8 i = 0; i < GRID_MAX_DIMENSION; i++) - for (u8 j = 0; j < GRID_MAX_DIMENSION; j++) - SG.leds[i][j] = LED_OFF; + for (u8 j = 0; j < GRID_MAX_DIMENSION; j++) SG.leds[i][j] = LED_OFF; SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_ROTATE_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_ROTATE_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 rotate = cs_pop(cs); SG.rotate = rotate != 0; SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_DIM_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_DIM_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { GET_AND_CLAMP(dim, 0, 14); SG.dim = dim; SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_KEY_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs) { +static void op_G_KEY_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs) { s16 x = cs_pop(cs); s16 y = cs_pop(cs); s16 action = cs_pop(cs); - if (x < 0 || y < 0 || x >= GRID_MAX_DIMENSION || y >= GRID_MAX_DIMENSION) return; + if (x < 0 || y < 0 || x >= GRID_MAX_DIMENSION || y >= GRID_MAX_DIMENSION) + return; grid_key_press(x, y, action != 0); } -static void op_G_GRP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GRP_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.current_group); } -static void op_G_GRP_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GRP_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; SG.current_group = group; SG.scr_dirty = 1; } -static void op_G_GRP_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GRP_EN_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); - cs_push(cs, group < (s16)0 || group >= (s16)GRID_GROUP_COUNT ? 0 : SG.group[group].enabled); + cs_push(cs, group < (s16)0 || group >= (s16)GRID_GROUP_COUNT + ? 0 + : SG.group[group].enabled); } -static void op_G_GRP_EN_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GRP_EN_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 en = cs_pop(cs); if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; @@ -293,15 +309,16 @@ static void op_G_GRP_EN_set(const void *NOTUSED(data), scene_state_t *ss, exec_s SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GRP_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GRP_RST_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; - + SG.group[group].enabled = true; SG.group[group].script = -1; SG.group[group].fader_min = 0; SG.group[group].fader_max = 0; - + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.group == group) { grid_common_init(&(GBC)); @@ -315,79 +332,92 @@ static void op_G_GRP_RST_get(const void *NOTUSED(data), scene_state_t *ss, exec_ GF.type = FADER_H_BAR; GF.value = 0; } - + for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) if (GXYC.group == group) { grid_common_init(&(GXYC)); GXY.value_x = 0; GXY.value_y = 0; } - + SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GRP_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GRP_SW_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; - + for (u8 i = 0; i < GRID_GROUP_COUNT; i++) SG.group[i].enabled = false; SG.group[group].enabled = true; - + SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GRP_SC_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GRP_SC_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); - cs_push(cs, group < (s16)0 || group >= (s16)GRID_GROUP_COUNT ? -1 : SG.group[group].script + 1); + cs_push(cs, group < (s16)0 || group >= (s16)GRID_GROUP_COUNT + ? -1 + : SG.group[group].script + 1); } -static void op_G_GRP_SC_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GRP_SC_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 script = cs_pop(cs) - 1; - + if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; if (script < 0 || script > INIT_SCRIPT) script = -1; - + SG.group[group].script = script; } -static void op_G_GRPI_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GRPI_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.latest_group); } -static void op_G_LED_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_LED_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 x = cs_pop(cs); s16 y = cs_pop(cs); - if (x < (s16)0 || x >= (s16)GRID_MAX_DIMENSION) cs_push(cs, LED_OFF); - else if (y < (s16)0 || y >= (s16)GRID_MAX_DIMENSION) cs_push(cs, LED_OFF); - else cs_push(cs, SG.leds[x][y]); + if (x < (s16)0 || x >= (s16)GRID_MAX_DIMENSION) + cs_push(cs, LED_OFF); + else if (y < (s16)0 || y >= (s16)GRID_MAX_DIMENSION) + cs_push(cs, LED_OFF); + else + cs_push(cs, SG.leds[x][y]); } -static void op_G_LED_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_LED_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 x = cs_pop(cs); s16 y = cs_pop(cs); GET_LEVEL(level); if (x < (s16)0 || x >= (s16)GRID_MAX_DIMENSION) return; if (y < (s16)0 || y >= (s16)GRID_MAX_DIMENSION) return; - + SG.leds[x][y] = level; SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_LED_C_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_LED_C_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 x = cs_pop(cs); s16 y = cs_pop(cs); if (x < (s16)0 || x >= (s16)GRID_MAX_DIMENSION) return; if (y < (s16)0 || y >= (s16)GRID_MAX_DIMENSION) return; - + SG.leds[x][y] = LED_OFF; SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_REC_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_REC_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 x = cs_pop(cs); s16 y = cs_pop(cs); s16 w = cs_pop(cs); @@ -397,7 +427,8 @@ static void op_G_REC_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat grid_rectangle(ss, x, y, w, h, fill, border); } -static void op_G_RCT_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_RCT_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 x1 = cs_pop(cs); s16 y1 = cs_pop(cs); s16 x2 = cs_pop(cs); @@ -407,7 +438,8 @@ static void op_G_RCT_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat grid_rectangle(ss, x1, y1, x2 - x1 + 1, y2 - y1 + 1, fill, border); } -static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 x = cs_pop(cs); s16 y = cs_pop(cs); @@ -420,7 +452,8 @@ static void op_G_BTN_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GBT_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GBT_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 i = cs_pop(cs); s16 x = cs_pop(cs); @@ -434,7 +467,8 @@ static void op_G_GBT_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 id = cs_pop(cs); s16 _x = cs_pop(cs); s16 _y = cs_pop(cs); @@ -462,11 +496,12 @@ static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat h = _h; grid_init_button(ss, SG.current_group, i, x, y, w, h, latch, level, script); } - + SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GBX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GBX_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 id = cs_pop(cs); s16 _x = cs_pop(cs); @@ -495,30 +530,34 @@ static void op_G_GBX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat h = _h; grid_init_button(ss, group, i, x, y, w, h, latch, level, script); } - + SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTN_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTN_EN_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GBC.enabled); } -static void op_G_BTN_EN_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTN_EN_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 en = cs_pop(cs); - + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; GBC.enabled = en; SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTN_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTN_V_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GB.state); } -static void op_G_BTN_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTN_V_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 value = cs_pop(cs); if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; @@ -526,12 +565,14 @@ static void op_G_BTN_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_st SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTN_L_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GBC.level); } -static void op_G_BTN_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTN_L_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); GET_LEVEL(level); if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; @@ -539,21 +580,23 @@ static void op_G_BTN_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_st SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTN_X_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTN_X_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GBC.x); } -static void op_G_BTN_X_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTN_X_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 x = cs_pop(cs); - + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; s16 y = GBC.y; s16 w = GBC.w; s16 h = GBC.h; - CLAMP_X_Y_W_H(return); - + CLAMP_X_Y_W_H(return ); + GBC.x = x; GBC.y = y; GBC.w = w; @@ -561,21 +604,23 @@ static void op_G_BTN_X_set(const void *NOTUSED(data), scene_state_t *ss, exec_st SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTN_Y_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTN_Y_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT ? 0 : GBC.y); } -static void op_G_BTN_Y_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTN_Y_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 y = cs_pop(cs); - + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; s16 x = GBC.x; s16 w = GBC.w; s16 h = GBC.h; - CLAMP_X_Y_W_H(return); - + CLAMP_X_Y_W_H(return ); + GBC.x = x; GBC.y = y; GBC.w = w; @@ -583,15 +628,18 @@ static void op_G_BTN_Y_set(const void *NOTUSED(data), scene_state_t *ss, exec_st SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTNI_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTNI_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.latest_button); } -static void op_G_BTNV_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTNV_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.button[SG.latest_button].state); } -static void op_G_BTNV_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTNV_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 value = cs_pop(cs); SG.button[SG.latest_button].state = value != 0; SG.scr_dirty = SG.grid_dirty = 1; @@ -601,25 +649,28 @@ static void op_G_BTNL_get(const void *NOTUSED(data), scene_state_t *ss, exec_sta cs_push(cs, SG.button[SG.latest_button].common.level); } -static void op_G_BTNL_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTNL_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { GET_LEVEL(level); SG.button[SG.latest_button].common.level = level; SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTNX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTNX_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.button[SG.latest_button].common.x); } -static void op_G_BTNX_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTNX_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 x = cs_pop(cs); u16 i = SG.latest_button; - + s16 y = GBC.y; s16 w = GBC.w; s16 h = GBC.h; - CLAMP_X_Y_W_H(return); - + CLAMP_X_Y_W_H(return ); + GBC.x = x; GBC.y = y; GBC.w = w; @@ -627,19 +678,21 @@ static void op_G_BTNX_set(const void *NOTUSED(data), scene_state_t *ss, exec_sta SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTNY_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTNY_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.button[SG.latest_button].common.y); } -static void op_G_BTNY_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTNY_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 y = cs_pop(cs); u16 i = SG.latest_button; - + s16 x = GBC.x; s16 w = GBC.w; s16 h = GBC.h; - CLAMP_X_Y_W_H(return); - + CLAMP_X_Y_W_H(return ); + GBC.x = x; GBC.y = y; GBC.w = w; @@ -647,47 +700,51 @@ static void op_G_BTNY_set(const void *NOTUSED(data), scene_state_t *ss, exec_sta SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTN_SW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTN_SW_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 id = cs_pop(cs); if (id < (s16)0 || id >= (s16)GRID_BUTTON_COUNT) return; - + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.group == SG.button[id].common.group) GB.state = 0; - + SG.button[id].state = 1; SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTN_PR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *es, command_state_t *cs) { +static void op_G_BTN_PR_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *es, command_state_t *cs) { s16 i = cs_pop(cs); s16 action = cs_pop(cs); - + if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; if (!GBC.enabled || !SG.group[GBC.group].enabled) return; - + GB.state = GB.latch ? !GB.state : action != 0; SG.latest_button = i; SG.latest_group = GBC.group; - + if (GBC.script != -1) { es_push(es); if (!es->overflow) run_script_with_exec_state(ss, es, GBC.script); es_pop(es); } - + if (SG.group[GBC.group].script != -1) { es_push(es); - if (!es->overflow) run_script_with_exec_state(ss, es, SG.group[GBC.group].script); + if (!es->overflow) + run_script_with_exec_state(ss, es, SG.group[GBC.group].script); es_pop(es); } SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GBTN_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GBTN_V_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 value = cs_pop(cs); - + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; value = value != 0; @@ -696,11 +753,12 @@ static void op_G_GBTN_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_s SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GBTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GBTN_L_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); GET_LEVEL(odd); GET_LEVEL(even); - + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; u8 is_odd = 0; @@ -712,7 +770,8 @@ static void op_G_GBTN_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_s SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 x = cs_pop(cs); s16 y = cs_pop(cs); @@ -725,7 +784,8 @@ static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GFD_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GFD_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 i = cs_pop(cs); s16 x = cs_pop(cs); @@ -739,7 +799,8 @@ static void op_G_GFD_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 id = cs_pop(cs); s16 _x = cs_pop(cs); s16 _y = cs_pop(cs); @@ -767,11 +828,12 @@ static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat h = _h; grid_init_fader(ss, SG.current_group, i, x, y, w, h, type, level, script); } - + SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 id = cs_pop(cs); s16 _x = cs_pop(cs); @@ -800,25 +862,28 @@ static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat h = _h; grid_init_fader(ss, group, i, x, y, w, h, type, level, script); } - + SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDR_EN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_EN_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GFC.enabled); } -static void op_G_FDR_EN_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_EN_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 en = cs_pop(cs); - + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; GFC.enabled = en; SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_V_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) { cs_push(cs, 0); @@ -830,10 +895,11 @@ static void op_G_FDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_st cs_push(cs, value); } -static void op_G_FDR_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_V_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 value = cs_pop(cs); - + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; if (value < SG.group[GFC.group].fader_min) value = SG.group[GFC.group].fader_min; else if (value > SG.group[GFC.group].fader_max) value = SG.group[GFC.group].fader_max; @@ -843,12 +909,14 @@ static void op_G_FDR_V_set(const void *NOTUSED(data), scene_state_t *ss, exec_st SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_N_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GF.value); } -static void op_G_FDR_N_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_N_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 value = cs_pop(cs); @@ -862,12 +930,14 @@ static void op_G_FDR_N_set(const void *NOTUSED(data), scene_state_t *ss, exec_st SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_L_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GFC.level); } -static void op_G_FDR_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_L_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 level = cs_pop(cs); if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; @@ -889,21 +959,23 @@ static void op_G_FDR_L_set(const void *NOTUSED(data), scene_state_t *ss, exec_st SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDR_X_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_X_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GFC.x); } -static void op_G_FDR_X_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_X_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 x = cs_pop(cs); - + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; s16 y = GFC.y; s16 w = GFC.w; s16 h = GFC.h; - CLAMP_X_Y_W_H(return); - + CLAMP_X_Y_W_H(return ); + GFC.x = x; GFC.y = y; GFC.w = w; @@ -911,21 +983,23 @@ static void op_G_FDR_X_set(const void *NOTUSED(data), scene_state_t *ss, exec_st SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDR_Y_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_Y_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_FADER_COUNT ? 0 : GFC.y); } -static void op_G_FDR_Y_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDR_Y_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 y = cs_pop(cs); - + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; s16 x = GFC.x; s16 w = GFC.w; s16 h = GFC.h; - CLAMP_X_Y_W_H(return); - + CLAMP_X_Y_W_H(return ); + GFC.x = x; GFC.y = y; GFC.w = w; @@ -933,18 +1007,21 @@ static void op_G_FDR_Y_set(const void *NOTUSED(data), scene_state_t *ss, exec_st SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDRI_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDRI_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.latest_fader); } -static void op_G_FDRV_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDRV_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { u8 i = SG.latest_fader; s16 value = scale(0, grid_fader_max_value(ss, i), SG.group[GFC.group].fader_min, SG.group[GFC.group].fader_max, GF.value); cs_push(cs, value); } -static void op_G_FDRV_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDRV_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 value = cs_pop(cs); s16 i = SG.latest_fader; @@ -997,19 +1074,21 @@ static void op_G_FDRL_set(const void *NOTUSED(data), scene_state_t *ss, exec_sta SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDRX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDRX_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.fader[SG.latest_fader].common.x); } -static void op_G_FDRX_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDRX_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 x = cs_pop(cs); s16 i = SG.latest_fader; - + s16 y = GFC.y; s16 w = GFC.w; s16 h = GFC.h; - CLAMP_X_Y_W_H(return); - + CLAMP_X_Y_W_H(return ); + GFC.x = x; GFC.y = y; GFC.w = w; @@ -1017,19 +1096,21 @@ static void op_G_FDRX_set(const void *NOTUSED(data), scene_state_t *ss, exec_sta SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDRY_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDRY_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.fader[SG.latest_fader].common.y); } -static void op_G_FDRY_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDRY_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 y = cs_pop(cs); s16 i = SG.latest_fader; - + s16 x = GFC.x; s16 w = GFC.w; s16 h = GFC.h; - CLAMP_X_Y_W_H(return); - + CLAMP_X_Y_W_H(return ); + GFC.x = x; GFC.y = y; GFC.w = w; @@ -1037,10 +1118,11 @@ static void op_G_FDRY_set(const void *NOTUSED(data), scene_state_t *ss, exec_sta SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDR_PR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *es, command_state_t *cs) { +static void op_G_FDR_PR_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *es, command_state_t *cs) { s16 i = cs_pop(cs); s16 value = cs_pop(cs) - 1; - + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; if (!GFC.enabled || !SG.group[GFC.group].enabled) return; @@ -1079,29 +1161,33 @@ static void op_G_FDR_PR_get(const void *NOTUSED(data), scene_state_t *ss, exec_s SG.latest_fader = i; SG.latest_group = GFC.group; - + if (GFC.script != -1) { es_push(es); if (!es->overflow) run_script_with_exec_state(ss, es, GFC.script); es_pop(es); } - + if (SG.group[GFC.group].script != -1) { es_push(es); - if (!es->overflow) run_script_with_exec_state(ss, es, SG.group[GFC.group].script); + if (!es->overflow) + run_script_with_exec_state(ss, es, SG.group[GFC.group].script); es_pop(es); } SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GFDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GFDR_V_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 value = cs_pop(cs); - + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; - if (value < SG.group[group].fader_min) value = SG.group[group].fader_min; - else if (value > SG.group[group].fader_max) value = SG.group[group].fader_max; + if (value < SG.group[group].fader_min) + value = SG.group[group].fader_min; + else if (value > SG.group[group].fader_max) + value = SG.group[group].fader_max; for (u16 i = 0; i < GRID_FADER_COUNT; i++) if (GFC.group == group) @@ -1111,7 +1197,8 @@ static void op_G_GFDR_V_get(const void *NOTUSED(data), scene_state_t *ss, exec_s SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GFDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GFDR_N_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 value = cs_pop(cs); @@ -1124,7 +1211,8 @@ static void op_G_GFDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_s SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GFDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GFDR_L_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 odd = cs_pop(cs); s16 even = cs_pop(cs); @@ -1154,17 +1242,19 @@ static void op_G_GFDR_L_get(const void *NOTUSED(data), scene_state_t *ss, exec_s SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_GFDR_RN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_GFDR_RN_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 min = cs_pop(cs); s16 max = cs_pop(cs); - + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; SG.group[group].fader_min = min; SG.group[group].fader_max = max; } -static void op_G_XYP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_XYP_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 x = cs_pop(cs); s16 y = cs_pop(cs); @@ -1172,10 +1262,10 @@ static void op_G_XYP_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat s16 h = cs_pop(cs); GET_LEVEL(level); s16 script = cs_pop(cs) - 1; - + if (i < (s16)0 || i >= (s16)GRID_XYPAD_COUNT) return; if (script < 0 || script > INIT_SCRIPT) script = -1; - CLAMP_X_Y_W_H(return); + CLAMP_X_Y_W_H(return ); GXYC.enabled = true; GXYC.group = SG.current_group; @@ -1187,16 +1277,18 @@ static void op_G_XYP_get(const void *NOTUSED(data), scene_state_t *ss, exec_stat GXYC.script = script; GXY.value_x = 0; GXY.value_y = 0; - + SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_XYP_X_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_XYP_X_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_XYPAD_COUNT ? 0 : GXY.value_x); } -static void op_G_XYP_Y_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_XYP_Y_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); cs_push(cs, i < (s16)0 || i >= (s16)GRID_XYPAD_COUNT ? 0 : GXY.value_y); } @@ -1215,27 +1307,34 @@ s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value) { return (value - a) * (y - x) / (b - a) + x; } -void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fill, u8 border) { - for (u16 col = max(0, x + (s32)1); col < min(GRID_MAX_DIMENSION, x + w - (s32)1); col++) - for (u16 row = max(0, y + (s32)1); row < min(GRID_MAX_DIMENSION, y + h - (s32)1); row++) +void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fill, + u8 border) { + for (u16 col = max(0, x + (s32)1); + col < min(GRID_MAX_DIMENSION, x + w - (s32)1); col++) + for (u16 row = max(0, y + (s32)1); + row < min(GRID_MAX_DIMENSION, y + h - (s32)1); row++) SG.leds[col][row] = fill; if (y >= (s16)0 && y < (s16)GRID_MAX_DIMENSION) - for (u16 col = max(0, x); col < min(GRID_MAX_DIMENSION, (s32)x + w); col++) + for (u16 col = max(0, x); col < min(GRID_MAX_DIMENSION, (s32)x + w); + col++) SG.leds[col][y] = border; - + s16 row = y + h - (s16)1; if (row >= (s16)0 && row < (s16)GRID_MAX_DIMENSION) - for (u16 col = max(0, x); col < min(GRID_MAX_DIMENSION, (s32)x + w); col++) + for (u16 col = max(0, x); col < min(GRID_MAX_DIMENSION, (s32)x + w); + col++) SG.leds[col][row] = border; if (x >= (s16)0 && x < (s16)GRID_MAX_DIMENSION) - for (u16 row = max(0, y); row < min(GRID_MAX_DIMENSION, (s32)y + h); row++) + for (u16 row = max(0, y); row < min(GRID_MAX_DIMENSION, (s32)y + h); + row++) SG.leds[x][row] = border; s16 col = x + w - 1; if (col >= (s16)0 && col < (s16)GRID_MAX_DIMENSION) - for (u16 row = max(0, y); row < min(GRID_MAX_DIMENSION, (s32)y + h); row++) + for (u16 row = max(0, y); row < min(GRID_MAX_DIMENSION, (s32)y + h); + row++) SG.leds[col][row] = border; SG.scr_dirty = SG.grid_dirty = 1; diff --git a/src/ops/maths.c b/src/ops/maths.c index b9f5d5c0..dc697611 100644 --- a/src/ops/maths.c +++ b/src/ops/maths.c @@ -509,7 +509,7 @@ static void op_JI_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), quotient = d / prime[p]; } } - result = ( result + 8 ) >> 4; // round & scale + result = (result + 8) >> 4; // round & scale while (result >= 1638) { result -= 1638; } // normalize `V 0` to `V 1` while (result < 0) { result += 1638; } cs_push(cs, result); diff --git a/src/ops/op.c b/src/ops/op.c index 33b83283..0b7c3fc2 100644 --- a/src/ops/op.c +++ b/src/ops/op.c @@ -9,6 +9,8 @@ #include "ops/controlflow.h" #include "ops/delay.h" #include "ops/earthsea.h" +#include "ops/er301.h" +#include "ops/fader.h" #include "ops/grid_ops.h" #include "ops/hardware.h" #include "ops/init.h" @@ -56,7 +58,7 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_P_START, &op_PN_START, &op_P_END, &op_PN_END, &op_P_I, &op_PN_I, &op_P_HERE, &op_PN_HERE, &op_P_NEXT, &op_PN_NEXT, &op_P_PREV, &op_PN_PREV, &op_P_INS, &op_PN_INS, &op_P_RM, &op_PN_RM, &op_P_PUSH, &op_PN_PUSH, - &op_P_POP, &op_PN_POP, + &op_P_POP, &op_PN_POP, &op_P_MIN, &op_PN_MIN, &op_P_MAX, &op_PN_MAX, // queue &op_Q, &op_Q_AVG, &op_Q_N, @@ -152,6 +154,8 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_TO_ENV_DEC, &op_TO_ENV_DEC_S, &op_TO_ENV_DEC_M, &op_TO_ENV_TRIG, &op_TO_ENV_EOR, &op_TO_ENV_EOC, &op_TO_ENV_LOOP, + &op_TO_ENV, &op_TO_CV_CALIB, &op_TO_CV_RESET, + &op_TI_PARAM, &op_TI_PARAM_QT, &op_TI_PARAM_N, &op_TI_PARAM_SCALE, &op_TI_PARAM_MAP, &op_TI_IN, &op_TI_IN_QT, &op_TI_IN_N, &op_TI_IN_SCALE, &op_TI_IN_MAP, &op_TI_PARAM_CALIB, &op_TI_IN_CALIB, &op_TI_STORE, @@ -161,7 +165,14 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_TI_PRM, &op_TI_PRM_QT, &op_TI_PRM_N, &op_TI_PRM_SCALE, &op_TI_PRM_MAP, &op_TI_PRM_INIT, - + + // fader + &op_FADER, &op_FB, + + // ER301 + &op_SC_TR, &op_SC_TR_TOG, &op_SC_TR_PULSE, &op_SC_TR_TIME, &op_SC_TR_POL, + &op_SC_CV, &op_SC_CV_SLEW, &op_SC_CV_SET, &op_SC_CV_OFF, &op_SC_TR_P, + // grid &op_G_RST, &op_G_CLR, &op_G_ROTATE, &op_G_DIM, &op_G_KEY, &op_G_GRP, &op_G_GRP_EN, &op_G_GRP_RST, &op_G_GRP_SW, &op_G_GRP_SC, &op_G_GRPI, @@ -171,7 +182,7 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_G_BTN_SW, &op_G_BTN_PR, &op_G_GBTN_V, &op_G_GBTN_L, &op_G_FDR, &op_G_FDX, &op_G_GFD, &op_G_GFX, &op_G_FDR_EN, &op_G_FDR_V, &op_G_FDR_N, &op_G_FDR_L, &op_G_FDR_X, &op_G_FDR_Y, &op_G_FDRI, &op_G_FDRV, &op_G_FDRN, - &op_G_FDRL, &op_G_FDRX, &op_G_FDRY, &op_G_FDR_PR, &op_G_GFDR_V, + &op_G_FDRL, &op_G_FDRX, &op_G_FDRY, &op_G_FDR_PR, &op_G_GFDR_V, &op_G_GFDR_N, &op_G_GFDR_L, &op_G_GFDR_RN, &op_G_XYP, &op_G_XYP_X, &op_G_XYP_Y }; diff --git a/src/ops/op_enum.h b/src/ops/op_enum.h index b79912b7..c565df2d 100644 --- a/src/ops/op_enum.h +++ b/src/ops/op_enum.h @@ -88,6 +88,10 @@ typedef enum { E_OP_PN_PUSH, E_OP_P_POP, E_OP_PN_POP, + E_OP_P_MIN, + E_OP_PN_MIN, + E_OP_P_MAX, + E_OP_PN_MAX, E_OP_Q, E_OP_Q_AVG, E_OP_Q_N, @@ -363,6 +367,9 @@ typedef enum { E_OP_TO_ENV_EOR, E_OP_TO_ENV_EOC, E_OP_TO_ENV_LOOP, + E_OP_TO_ENV, + E_OP_TO_CV_CALIB, + E_OP_TO_CV_RESET, E_OP_TI_PARAM, E_OP_TI_PARAM_QT, E_OP_TI_PARAM_N, @@ -386,6 +393,18 @@ typedef enum { E_OP_TI_PRM_SCALE, E_OP_TI_PRM_MAP, E_OP_TI_PRM_INIT, + E_OP_FADER, + E_OP_FB, + E_OP_SC_TR, + E_OP_SC_TR_TOG, + E_OP_SC_TR_PULSE, + E_OP_SC_TR_TIME, + E_OP_SC_TR_POL, + E_OP_SC_CV, + E_OP_SC_CV_SLEW, + E_OP_SC_CV_SET, + E_OP_SC_CV_OFF, + E_OP_SC_TR_P, E_OP_G_RST, E_OP_G_CLR, E_OP_G_ROTATE, diff --git a/src/ops/patterns.c b/src/ops/patterns.c index 0f7adf26..8237aa19 100644 --- a/src/ops/patterns.c +++ b/src/ops/patterns.c @@ -658,3 +658,85 @@ static void op_PN_POP_get(const void *NOTUSED(data), scene_state_t *ss, // Make ops const tele_op_t op_P_POP = MAKE_GET_OP(P.POP, op_P_POP_get, 0, true); const tele_op_t op_PN_POP = MAKE_GET_OP(PN.POP, op_PN_POP_get, 1, true); + + +//////////////////////////////////////////////////////////////////////////////// +// P.MIN /////////////////////////////////////////////////////////////////////// + +// Get +static int16_t p_min_get(scene_state_t *ss, int16_t pn) { + pn = normalise_pn(pn); + + int16_t start = ss_get_pattern_start(ss, pn); + int16_t end = ss_get_pattern_end(ss, pn); + + int16_t pos = start; + int16_t val = ss_get_pattern_val(ss, pn, pos); + int16_t temp = 0; + + for (int16_t i = start + 1; i <= end; i++) { + temp = ss_get_pattern_val(ss, pn, i); + if (temp < val) { + pos = i; + val = temp; + } + } + + return pos; +} + +static void op_P_MIN_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, p_min_get(ss, ss->variables.p_n)); +} + +static void op_PN_MIN_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + cs_push(cs, p_min_get(ss, pn)); +} + +// Make ops +const tele_op_t op_P_MIN = MAKE_GET_OP(P.MIN, op_P_MIN_get, 0, true); +const tele_op_t op_PN_MIN = MAKE_GET_OP(PN.MIN, op_PN_MIN_get, 1, true); + + +//////////////////////////////////////////////////////////////////////////////// +// P.MAX /////////////////////////////////////////////////////////////////////// + +// Get +static int16_t p_max_get(scene_state_t *ss, int16_t pn) { + pn = normalise_pn(pn); + + int16_t start = ss_get_pattern_start(ss, pn); + int16_t end = ss_get_pattern_end(ss, pn); + + int16_t pos = start; + int16_t val = ss_get_pattern_val(ss, pn, pos); + int16_t temp = 0; + + for (int16_t i = start + 1; i <= end; i++) { + temp = ss_get_pattern_val(ss, pn, i); + if (temp > val) { + pos = i; + val = temp; + } + } + + return pos; +} + +static void op_P_MAX_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, p_max_get(ss, ss->variables.p_n)); +} + +static void op_PN_MAX_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + cs_push(cs, p_max_get(ss, pn)); +} + +// Make ops +const tele_op_t op_P_MAX = MAKE_GET_OP(P.MAX, op_P_MAX_get, 0, true); +const tele_op_t op_PN_MAX = MAKE_GET_OP(PN.MAX, op_PN_MAX_get, 1, true); diff --git a/src/ops/patterns.h b/src/ops/patterns.h index 87748884..bbebf99f 100644 --- a/src/ops/patterns.h +++ b/src/ops/patterns.h @@ -31,5 +31,9 @@ extern const tele_op_t op_P_PUSH; extern const tele_op_t op_PN_PUSH; extern const tele_op_t op_P_POP; extern const tele_op_t op_PN_POP; +extern const tele_op_t op_P_MIN; +extern const tele_op_t op_PN_MIN; +extern const tele_op_t op_P_MAX; +extern const tele_op_t op_PN_MAX; #endif diff --git a/src/ops/telex.c b/src/ops/telex.c index 1447e014..39b74a5f 100644 --- a/src/ops/telex.c +++ b/src/ops/telex.c @@ -173,6 +173,14 @@ static void op_TO_TR_INIT_get(const void *data, scene_state_t *ss, static void op_TO_INIT_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_TO_ENV_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); + +static void op_TO_CV_CALIB_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_TO_CV_RESET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); + // TXi Methods static void op_TI_PARAM_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -303,6 +311,11 @@ const tele_op_t op_TO_CV_INIT = MAKE_GET_OP(TO.CV.INIT , op_TO_ const tele_op_t op_TO_TR_INIT = MAKE_GET_OP(TO.TR.INIT , op_TO_TR_INIT_get , 1, false); const tele_op_t op_TO_INIT = MAKE_GET_OP(TO.INIT , op_TO_INIT_get , 1, false); +const tele_op_t op_TO_ENV = MAKE_GET_OP(TO.ENV , op_TO_ENV_get , 2, false); + +const tele_op_t op_TO_CV_CALIB = MAKE_GET_OP(TO.CV.CALIB , op_TO_CV_CALIB_get , 1, false); +const tele_op_t op_TO_CV_RESET = MAKE_GET_OP(TO.CV.RESET , op_TO_CV_RESET_get , 1, false); + // TXo Ailiases const tele_op_t op_TO_TR_P = MAKE_ALIAS_OP(TO.TR.P , op_TO_TR_PULSE_get , NULL, 1, false); const tele_op_t op_TO_TR_P_DIV = MAKE_ALIAS_OP(TO.TR.P.DIV , op_TO_TR_PULSE_DIV_get , NULL, 2, false); @@ -341,15 +354,9 @@ const tele_op_t op_TI_PRM_INIT = MAKE_ALIAS_OP(TI.PRM.INIT , op_TI_ // clang-format on // telex helpers -void TXSend(uint8_t model, uint8_t command, uint8_t output, int16_t value, +void SendIt(uint8_t address, uint8_t command, uint8_t port, int16_t value, bool set) { - // zero-index the output - output -= 1; - // convert the output to the device and the port - uint8_t port = output & 3; - uint8_t device = output >> 2; - uint8_t address = model + device; - // init and fill the buffer (make the buffer smaller if we are not sending a + // init and fill the buffer (make the buffer smaller if we are not sending a // payload) uint8_t buffer[set ? 4 : 2]; buffer[0] = command; @@ -361,6 +368,18 @@ void TXSend(uint8_t model, uint8_t command, uint8_t output, int16_t value, } tele_ii_tx(address, buffer, set ? 4 : 2); } + +void TXSend(uint8_t model, uint8_t command, uint8_t output, int16_t value, + bool set) { + // zero-index the output + output -= 1; + // convert the output to the device and the port + uint8_t port = output & 3; + uint8_t device = output >> 2; + uint8_t address = model + device; + // put the package in the i2c mail + SendIt(address, command, port, value, set); +} void TXCmd(uint8_t model, uint8_t command, uint8_t output) { TXSend(model, command, output, 0, false); } @@ -374,16 +393,7 @@ void TXDeviceSet(uint8_t model, uint8_t command, command_state_t *cs) { int16_t value = cs_pop(cs); TXSend(model, command, output, value, true); } -void TXReceive(uint8_t model, command_state_t *cs, uint8_t mode, bool shift) { - // zero-index the output - uint8_t input = cs_pop(cs) - 1; - // send the port, device and address - uint8_t port = input & 3; - uint8_t device = input >> 2; - uint8_t address = model + device; - // inputs are numbered 0-7 for each device - shift is for the second half - // mode pushes it up so it can read quantized values and note numbers - port += (shift ? 4 : 0) + (mode << 3); +void ReceiveIt(uint8_t address, uint8_t port, command_state_t *cs) { // tell the device what value you are going to query uint8_t buffer[2]; buffer[0] = port; @@ -395,6 +405,19 @@ void TXReceive(uint8_t model, command_state_t *cs, uint8_t mode, bool shift) { int16_t value = (buffer[0] << 8) + buffer[1]; cs_push(cs, value); } +void TXReceive(uint8_t model, command_state_t *cs, uint8_t mode, bool shift) { + // zero-index the output + uint8_t input = cs_pop(cs) - 1; + // send the port, device and address + uint8_t port = input & 3; + uint8_t device = input >> 2; + uint8_t address = model + device; + // inputs are numbered 0-7 for each device - shift is for the second half + // mode pushes it up so it can read quantized values and note numbers + port += (shift ? 4 : 0) + (mode << 3); + // summon the package from the i2c mail + ReceiveIt(address, port, cs); +} uint8_t DeviceToOutput(int16_t device) { return ((device - 1) * 4) + 1; } @@ -757,6 +780,20 @@ static void op_TO_INIT_get(const void *NOTUSED(data), scene_state_t *ss, TXCmd(TO, TO_INIT, DeviceToOutput(cs_pop(cs))); } + +static void op_TO_ENV_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + TXSet(TO, TO_ENV, cs); +} +static void op_TO_CV_CALIB_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + TXCmd(TO, TO_CV_CALIB, cs_pop(cs)); +} +static void op_TO_CV_RESET_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + TXCmd(TO, TO_CV_RESET, cs_pop(cs)); +} + // TXi static void op_TI_PARAM_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { diff --git a/src/ops/telex.h b/src/ops/telex.h index 85664963..5f82a8ec 100644 --- a/src/ops/telex.h +++ b/src/ops/telex.h @@ -99,6 +99,11 @@ extern const tele_op_t op_TO_TR_P_DIV; extern const tele_op_t op_TO_TR_P_MUTE; extern const tele_op_t op_TO_TR_P_MUL; +extern const tele_op_t op_TO_ENV; + +extern const tele_op_t op_TO_CV_CALIB; +extern const tele_op_t op_TO_CV_RESET; + // TXi Operators extern const tele_op_t op_TI_PARAM; @@ -130,10 +135,13 @@ extern const tele_op_t op_TI_PRM_MAP; extern const tele_op_t op_TI_PRM_INIT; // helpers +void SendIt(uint8_t address, uint8_t command, uint8_t port, int16_t value, + bool set); void TXSend(uint8_t model, uint8_t command, uint8_t output, int16_t value, bool set); void TXCmd(uint8_t model, uint8_t command, uint8_t output); void TXSet(uint8_t model, uint8_t command, command_state_t *cs); +void ReceiveIt(uint8_t address, uint8_t port, command_state_t *cs); void TXDeviceSet(uint8_t model, uint8_t command, command_state_t *cs); void TXReceive(uint8_t model, command_state_t *cs, uint8_t mode, bool shift); uint8_t DeviceToOutput(int16_t device); @@ -194,7 +202,7 @@ void PRMInit(uint8_t input); #define TO_M_COUNT 0x1E #define TO_KILL 0x20 -#define TO_RESET 0x21 +// #define TO_RESET 0x21 #define TO_TR_INIT 0x22 #define TO_CV_INIT 0x23 #define TO_INIT 0x24 @@ -250,6 +258,11 @@ void PRMInit(uint8_t input); #define TO_ENV_EOC 0x6B #define TO_ENV_LOOP 0x6C +#define TO_ENV 0x6D + +#define TO_CV_CALIB 0x6E +#define TO_CV_RESET 0x6F + // TELEXi #define TI 0x68 diff --git a/src/state.c b/src/state.c index eceed55f..2e268e4d 100644 --- a/src/state.c +++ b/src/state.c @@ -72,12 +72,12 @@ void ss_pattern_init(scene_state_t *ss, size_t pattern_no) { void ss_grid_init(scene_state_t *ss) { ss->grid.rotate = 0; ss->grid.dim = 0; - + ss->grid.current_group = 0; ss->grid.latest_group = 0; ss->grid.latest_button = 0; ss->grid.latest_fader = 0; - + for (u8 i = 0; i < GRID_MAX_DIMENSION; i++) for (u8 j = 0; j < GRID_MAX_DIMENSION; j++) ss->grid.leds[i][j] = LED_OFF; @@ -88,7 +88,7 @@ void ss_grid_init(scene_state_t *ss) { ss->grid.group[i].fader_min = 0; ss->grid.group[i].fader_max = 16383; } - + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { ss_grid_common_init(&(ss->grid.button[i].common)); ss->grid.button[i].latch = 0; @@ -100,13 +100,13 @@ void ss_grid_init(scene_state_t *ss) { ss->grid.fader[i].type = FADER_H_BAR; ss->grid.fader[i].value = 0; } - + for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { ss_grid_common_init(&(ss->grid.xypad[i].common)); ss->grid.xypad[i].value_x = 0; ss->grid.xypad[i].value_y = 0; } - + ss->grid.grid_dirty = ss->grid.scr_dirty = true; } diff --git a/src/state.h b/src/state.h index 30826046..b3732e5e 100644 --- a/src/state.h +++ b/src/state.h @@ -127,7 +127,7 @@ typedef struct { int16_t last_time; } scene_script_t; - typedef struct { +typedef struct { u8 enabled; u8 group; u8 x, y; @@ -164,7 +164,7 @@ typedef struct { typedef struct { u8 grid_dirty; u8 scr_dirty; - + u8 rotate; u8 dim; @@ -172,10 +172,10 @@ typedef struct { u8 latest_group; u8 latest_button; u8 latest_fader; - + s8 leds[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION]; grid_group_t group[GRID_GROUP_COUNT]; - + grid_button_t button[GRID_BUTTON_COUNT]; grid_fader_t fader[GRID_FADER_COUNT]; grid_xypad_t xypad[GRID_XYPAD_COUNT]; @@ -316,9 +316,7 @@ typedef struct { int16_t top; } command_state_stack_t; -typedef struct { - command_state_stack_t stack; -} command_state_t; +typedef struct { command_state_stack_t stack; } command_state_t; extern void cs_init(command_state_t *cs); extern int16_t cs_stack_size(command_state_t *cs); diff --git a/src/teletype.c b/src/teletype.c index 9af16f8a..e155b401 100644 --- a/src/teletype.c +++ b/src/teletype.c @@ -284,11 +284,11 @@ process_result_t process_command(scene_state_t *ss, exec_state_t *es, // --------- // sometimes we have single value left of the stack, if so return it if (cs_stack_size(&cs)) { - process_result_t o = { .has_value = true, .value = cs_pop(&cs) }; + process_result_t o = {.has_value = true, .value = cs_pop(&cs) }; return o; } else { - process_result_t o = { .has_value = false, .value = 0 }; + process_result_t o = {.has_value = false, .value = 0 }; return o; } } diff --git a/src/turtle.c b/src/turtle.c index 30c3a972..28c35d57 100644 --- a/src/turtle.c +++ b/src/turtle.c @@ -4,21 +4,19 @@ #define max(X, Y) ((X) > (Y) ? (X) : (Y)) void turtle_init(scene_turtle_t *st) { - scene_turtle_t t = { .fence = { .x1 = 0, .y1 = 0, .x2 = 3, .y2 = 63 }, - .mode = TURTLE_BUMP, - .heading = 180, - .speed = 100, - .stepped = false, - .script_number = TEMP_SCRIPT }; + scene_turtle_t t = {.fence = {.x1 = 0, .y1 = 0, .x2 = 3, .y2 = 63 }, + .mode = TURTLE_BUMP, + .heading = 180, + .speed = 100, + .stepped = false, + .script_number = TEMP_SCRIPT }; memcpy(st, &t, sizeof(t)); turtle_set_x(st, 0); turtle_set_y(st, 0); st->last = st->position; } -typedef struct { - QT x1, y1, x2, y2; -} Q_fence_t; +typedef struct { QT x1, y1, x2, y2; } Q_fence_t; static inline Q_fence_t normalize_fence(turtle_fence_t in, turtle_mode_t mode) { Q_fence_t out; diff --git a/tests/Makefile b/tests/Makefile index 4847f8cc..7e7204e0 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -10,7 +10,9 @@ tests: main.o \ ../src/every.o ../src/match_token.o ../src/scanner.o \ ../src/state.o ../src/table.o ../src/turtle.o ../src/chaos.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/delay.o ../src/ops/earthsea.o \ + ../src/ops/er301.o ../src/ops/fader.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 \ diff --git a/tests/op_mod_tests.c b/tests/op_mod_tests.c index 0f402f55..37234013 100644 --- a/tests/op_mod_tests.c +++ b/tests/op_mod_tests.c @@ -107,10 +107,10 @@ TEST mod_stack_size() { for (int j = 0; j < mod->params + stack_extra; j++) cs_push(&cs, 0); // execute func - const tele_command_t sub_command = { .length = 1, - .separator = 0, - .data = { { .tag = OP, - .value = E_OP_A } } }; + const tele_command_t sub_command = {.length = 1, + .separator = 0, + .data = { {.tag = OP, + .value = E_OP_A } } }; mod->func(&ss, &es, &cs, &sub_command); // check that the stack has the correct number of items in it diff --git a/tests/process_tests.c b/tests/process_tests.c index 3125aa8d..5f86210a 100644 --- a/tests/process_tests.c +++ b/tests/process_tests.c @@ -11,7 +11,7 @@ // correct (allows contiuation of state) TEST process_helper_state(scene_state_t* ss, size_t n, char* lines[], int16_t answer) { - process_result_t result = { .has_value = false, .value = 0 }; + process_result_t result = {.has_value = false, .value = 0 }; exec_state_t es; es_init(&es); es_push(&es); diff --git a/tests/turtle_tests.c b/tests/turtle_tests.c index cba7a621..088b0461 100644 --- a/tests/turtle_tests.c +++ b/tests/turtle_tests.c @@ -34,7 +34,7 @@ static const char *error_message(error_t e) { TEST process_helper_state(scene_state_t *ss, size_t n, char *lines[], int16_t answer) { count++; - process_result_t result = { .has_value = false, .value = 0 }; + process_result_t result = {.has_value = false, .value = 0 }; exec_state_t es; memset(&es, 0, sizeof(es)); es_init(&es); @@ -216,7 +216,7 @@ TEST test_turtle_bounce() { char *test10b[4] = { "@BOUNCE 1", "@F 0 0 1 1", "@STEP", "@DIR" }; CHECK_CALL(process_helper(4, test10b, 180)); - // The following tests reveal the charade that is the length between fences +// The following tests reveal the charade that is the length between fences #if 0 char *test10c[4] = { "@BOUNCE 1", "@F 0 0 1 1", "L 1 2: @STEP", "@DIR" }; CHECK_CALL(process_helper(4, test10c, 0)); From d5e320fa281f635c4fa17ecc570e976ca3ca6efe Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sat, 6 Jan 2018 15:28:05 -0800 Subject: [PATCH 025/117] faders - fixes, fine dot added --- module/grid.c | 125 ++++++++++++++++++++++--------- src/ops/grid_ops.c | 178 ++++++++++++++------------------------------- src/state.c | 2 +- src/state.h | 17 +++-- 4 files changed, 156 insertions(+), 166 deletions(-) diff --git a/module/grid.c b/module/grid.c index fafcdbec..048af7af 100644 --- a/module/grid.c +++ b/module/grid.c @@ -211,34 +211,39 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { } } + u16 value; if (z) { for (u8 i = 0; i < GRID_FADER_COUNT; i++) { if (GFC.enabled && SG.group[GFC.group].enabled && grid_within_area(x, y, &GFC)) { switch (GF.type) { - case FADER_H_BAR: - case FADER_H_DOT: + case FADER_CH_BAR: + case FADER_CH_DOT: GF.value = x - GFC.x; break; - case FADER_V_BAR: - case FADER_V_DOT: + case FADER_CV_BAR: + case FADER_CV_DOT: GF.value = GFC.h + GFC.y - y - 1; break; - case FADER_H_FINE: + case FADER_FH_BAR: + case FADER_FH_DOT: if (x == GFC.x) { if (GF.value) GF.value--; } else if (x == GFC.x + GFC.w - 1) { if (GF.value < GFC.level) GF.value++; } else { - GF.value = ((((x - GFC.x) << 4) + 8) * (GFC.level + 1)) / (GFC.w << 4); + value = ((((x - GFC.x - 1) << 1) + 1) * GFC.level) / (GFC.w - 2); + GF.value = (value >> 1) + (value & 1); } break; - case FADER_V_FINE: + case FADER_FV_BAR: + case FADER_FV_DOT: if (y == GFC.y) { if (GF.value < GFC.level) GF.value++; } else if (y == GFC.y + GFC.h - 1) { if (GF.value) GF.value--; } else { - GF.value = ((((y - GFC.y) << 4) + 8) * (GFC.level + 1)) / (GFC.h << 4); + value = ((((GFC.h + GFC.y - y - 2) << 1) + 1) * GFC.level) / (GFC.h - 2); + GF.value = (value >> 1) + (value & 1); } break; } @@ -273,7 +278,7 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { for (u8 i = 0; i < SCRIPT_COUNT; i++) if (scripts[i]) run_script(ss, i); - SG.grid_dirty = SG.scr_dirty = refresh; + if (refresh) SG.grid_dirty = SG.scr_dirty = 1; } void grid_process_key_hold_repeat(scene_state_t *ss, u8 _x, u8 _y, u8 ignore_rotate, u8 is_hold) { @@ -287,7 +292,7 @@ void grid_process_key_hold_repeat(scene_state_t *ss, u8 _x, u8 _y, u8 ignore_rot for (u8 i = 0; i < GRID_FADER_COUNT; i++) { if (GFC.enabled && SG.group[GFC.group].enabled && grid_within_area(x, y, &GFC)) { update = 0; - if (GF.type == FADER_H_FINE) { + if (GF.type == FADER_FH_BAR || GF.type == FADER_FH_DOT) { if (x == GFC.x) { if (GF.value) GF.value--; update = 1; @@ -295,7 +300,7 @@ void grid_process_key_hold_repeat(scene_state_t *ss, u8 _x, u8 _y, u8 ignore_rot if (GF.value < GFC.level) GF.value++; update = 1; } - } else if (GF.type == FADER_V_FINE) { + } else if (GF.type == FADER_FV_BAR || GF.type == FADER_FV_DOT) { if (y == GFC.y) { if (GF.value < GFC.level) GF.value++; update = 1; @@ -318,7 +323,7 @@ void grid_process_key_hold_repeat(scene_state_t *ss, u8 _x, u8 _y, u8 ignore_rot for (u8 i = 0; i < SCRIPT_COUNT; i++) if (scripts[i]) run_script(ss, i); - SG.grid_dirty = SG.scr_dirty = refresh; + if (refresh) SG.grid_dirty = SG.scr_dirty = 1; } void hold_repeat_timer_callback(void* o) { @@ -361,33 +366,57 @@ void grid_refresh(scene_state_t *ss) { for (u8 i = 0; i < GRID_FADER_COUNT; i++) { if (GFC.enabled && SG.group[GFC.group].enabled) { switch (GF.type) { - case FADER_H_BAR: + case FADER_CH_BAR: grid_fill_area(GFC.x, GFC.y, GF.value + 1, GFC.h, 15); grid_fill_area(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.level); break; - case FADER_V_BAR: + case FADER_CV_BAR: grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.level); grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, 15); break; - case FADER_H_DOT: + case FADER_CH_DOT: grid_fill_area(GFC.x + GF.value, GFC.y, 1, GFC.h, 15); break; - case FADER_V_DOT: + case FADER_CV_DOT: grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, 15); break; - case FADER_H_FINE: - fv = ((GFC.w << 4) * GF.value) / (GFC.level + 1); + case FADER_FH_BAR: + fv = (((GFC.w - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; - grid_fill_area(GFC.x, GFC.y, ff, GFC.h, 15); - if (fp) grid_fill_area(GFC.x + ff, GFC.y, 1, GFC.h, fp); + grid_fill_area(GFC.x, GFC.y, ff + 1, GFC.h, 15); + if (fp) grid_fill_area(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp); + grid_fill_area(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, 15); break; - case FADER_V_FINE: - fv = ((GFC.h << 4) * GF.value) / (GFC.level + 1); + case FADER_FV_BAR: + fv = (((GFC.h - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; - grid_fill_area(GFC.x, GFC.y + GFC.h - ff, GFC.w, ff, 15); - if (fp) grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff, fp); + grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff + 1, 15); + if (fp) grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, fp); + grid_fill_area(GFC.x, GFC.y, GFC.w, 1, 15); + break; + case FADER_FH_DOT: + grid_fill_area(GFC.x, GFC.y, 1, GFC.h, 15); + grid_fill_area(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, 15); + fv = (((GFC.w - 2) << 4) * GF.value) / GFC.level; + ff = fv >> 4; + fp = fv & 15; + if (fp) + grid_fill_area(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp); + else if (ff) + grid_fill_area(GFC.x + ff, GFC.y, 1, GFC.h, 15); + break; + case FADER_FV_DOT: + grid_fill_area(GFC.x, GFC.y + GFC.h - 1, GFC.w, 1, 15); + grid_fill_area(GFC.x, GFC.y, GFC.w, 1, 15); + fv = (((GFC.h - 2) << 4) * GF.value) / GFC.level; + ff = fv >> 4; + fp = fv & 15; + if (fp) + grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, fp); + else if (ff) + grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, 1, 15); break; } } @@ -581,33 +610,57 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, for (u8 i = 0; i < GRID_FADER_COUNT; i++) { if (GFC.enabled && SG.group[GFC.group].enabled) { switch (GF.type) { - case FADER_H_BAR: + case FADER_CH_BAR: grid_fill_area_scr(GFC.x, GFC.y, GF.value + 1, GFC.h, 15, page); grid_fill_area_scr(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.level, page); break; - case FADER_V_BAR: + case FADER_CV_BAR: grid_fill_area_scr(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.level, page); grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, 15, page); break; - case FADER_H_DOT: + case FADER_CH_DOT: grid_fill_area_scr(GFC.x + GF.value, GFC.y, 1, GFC.h, 15, page); break; - case FADER_V_DOT: + case FADER_CV_DOT: grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, 15, page); break; - case FADER_H_FINE: - fv = ((GFC.w << 4) * GF.value) / (GFC.level + 1); + case FADER_FH_BAR: + fv = (((GFC.w - 2) << 4) * GF.value) / GFC.level; + ff = fv >> 4; + fp = fv & 15; + grid_fill_area_scr(GFC.x, GFC.y, ff + 1, GFC.h, 15, page); + if (fp) grid_fill_area_scr(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp, page); + grid_fill_area_scr(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, 15, page); + break; + case FADER_FV_BAR: + fv = (((GFC.h - 2) << 4) * GF.value) / GFC.level; + ff = fv >> 4; + fp = fv & 15; + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff + 1, 15, page); + if (fp) grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, fp, page); + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, 1, 15, page); + break; + case FADER_FH_DOT: + grid_fill_area_scr(GFC.x, GFC.y, 1, GFC.h, 15, page); + grid_fill_area_scr(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, 15, page); + fv = (((GFC.w - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; - grid_fill_area_scr(GFC.x, GFC.y, ff, GFC.h, 15, page); - if (fp) grid_fill_area_scr(GFC.x + ff, GFC.y, 1, GFC.h, fp, page); + if (fp) + grid_fill_area_scr(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp, page); + else if (ff) + grid_fill_area_scr(GFC.x + ff, GFC.y, 1, GFC.h, 15, page); break; - case FADER_V_FINE: - fv = ((GFC.h << 4) * GF.value) / (GFC.level + 1); + case FADER_FV_DOT: + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - 1, GFC.w, 1, 15, page); + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, 1, 15, page); + fv = (((GFC.h - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff, GFC.w, ff, 15, page); - if (fp) grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff, fp, page); + if (fp) + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, fp, page); + else if (ff) + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, 1, 15, page); break; } } diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 3c8f420b..f76fad8d 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -52,6 +52,7 @@ static void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fil static void grid_init_button(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, s16 w, s16 h, s16 latch, s16 level, s16 script); static void grid_init_fader(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, s16 w, s16 h, s16 type, s16 level, s16 script); static s16 grid_fader_max_value(scene_state_t *ss, u16 i); +static s16 grid_fader_clamp_level(s16 level, s16 type, s16 w, s16 h); static void op_G_RST_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_CLR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -234,7 +235,7 @@ static void op_G_RST_get(const void *NOTUSED(data), scene_state_t *ss, for (u8 i = 0; i < GRID_FADER_COUNT; i++) { grid_common_init(&(GFC)); - GF.type = FADER_H_BAR; + GF.type = FADER_CH_BAR; GF.value = 0; } @@ -329,7 +330,7 @@ static void op_G_GRP_RST_get(const void *NOTUSED(data), scene_state_t *ss, for (u8 i = 0; i < GRID_FADER_COUNT; i++) if (GFC.group == group) { grid_common_init(&(GFC)); - GF.type = FADER_H_BAR; + GF.type = FADER_CH_BAR; GF.value = 0; } @@ -802,10 +803,10 @@ static void op_G_GFD_get(const void *NOTUSED(data), scene_state_t *ss, static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 id = cs_pop(cs); - s16 _x = cs_pop(cs); - s16 _y = cs_pop(cs); - s16 _w = cs_pop(cs); - s16 _h = cs_pop(cs); + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + s16 w = cs_pop(cs); + s16 h = cs_pop(cs); s16 type = cs_pop(cs); s16 level = cs_pop(cs); s16 script = cs_pop(cs) - 1; @@ -817,18 +818,11 @@ static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, if (count_y <= (s16)0) return; if (count_y > (s16)GRID_MAX_DIMENSION) count_y = GRID_MAX_DIMENSION; - u16 i; - s16 x, y, w, h; for (u16 cy = 0; cy < count_y; cy++) - for (u16 cx = 0; cx < count_x; cx++) { - i = id + cy * count_x + cx; - x = _x + _w * cx; - w = _w; - y = _y + _h * cy; - h = _h; - grid_init_fader(ss, SG.current_group, i, x, y, w, h, type, level, script); - } - + for (u16 cx = 0; cx < count_x; cx++) + grid_init_fader(ss, SG.current_group, id + cy * count_x + cx, + x + w * cx, y + h * cy, w, h, type, level, script); + SG.scr_dirty = SG.grid_dirty = 1; } @@ -836,10 +830,10 @@ static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 id = cs_pop(cs); - s16 _x = cs_pop(cs); - s16 _y = cs_pop(cs); - s16 _w = cs_pop(cs); - s16 _h = cs_pop(cs); + s16 x = cs_pop(cs); + s16 y = cs_pop(cs); + s16 w = cs_pop(cs); + s16 h = cs_pop(cs); s16 type = cs_pop(cs); s16 level = cs_pop(cs); s16 script = cs_pop(cs) - 1; @@ -851,18 +845,11 @@ static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, if (count_y <= (s16)0) return; if (count_y > (s16)GRID_MAX_DIMENSION) count_y = GRID_MAX_DIMENSION; - u16 i; - s16 x, y, w, h; for (u16 cy = 0; cy < count_y; cy++) - for (u16 cx = 0; cx < count_x; cx++) { - i = id + cy * count_x + cx; - x = _x + _w * cx; - w = _w; - y = _y + _h * cy; - h = _h; - grid_init_fader(ss, group, i, x, y, w, h, type, level, script); - } - + for (u16 cx = 0; cx < count_x; cx++) + grid_init_fader(ss, group, id + cy * count_x + cx, x + w * cx, + y + h * cy, w, h, type, level, script); + SG.scr_dirty = SG.grid_dirty = 1; } @@ -942,19 +929,8 @@ static void op_G_FDR_L_set(const void *NOTUSED(data), scene_state_t *ss, s16 level = cs_pop(cs); if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; - if (GF.type == FADER_H_FINE || GF.type == FADER_V_FINE) { - s16 maxlevel = ((GF.type == FADER_H_FINE ? GFC.w : GFC.h) << 4) - 1; - if (level < 0) - level = 0; - else if (level > maxlevel) - level = maxlevel; - } else { - if (level < (s16)LED_OFF) - level = LED_OFF; - else if (level > (s16)15) - level = 15; - } - + level = grid_fader_clamp_level(level, GF.type, GFC.w, GFC.h); + GF.value = scale(0, GFC.level, 0, level, GF.value); GFC.level = level; SG.scr_dirty = SG.grid_dirty = 1; } @@ -1057,20 +1033,10 @@ static void op_G_FDRL_set(const void *NOTUSED(data), scene_state_t *ss, exec_sta s16 level = cs_pop(cs); u16 i = SG.latest_fader; - if (GF.type == FADER_H_FINE || GF.type == FADER_V_FINE) { - s16 maxlevel = ((GF.type == FADER_H_FINE ? GFC.w : GFC.h) << 4) - 1; - if (level < 0) - level = 0; - else if (level > maxlevel) - level = maxlevel; - } else { - if (level < (s16)LED_OFF) - level = LED_OFF; - else if (level > (s16)15) - level = 15; - } - + level = grid_fader_clamp_level(level, GF.type, GFC.w, GFC.h); + GF.value = scale(0, GFC.level, 0, level, GF.value); GFC.level = level; + SG.scr_dirty = SG.grid_dirty = 1; } @@ -1126,39 +1092,11 @@ static void op_G_FDR_PR_get(const void *NOTUSED(data), scene_state_t *ss, if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; if (!GFC.enabled || !SG.group[GFC.group].enabled) return; + s16 maxvalue = grid_fader_max_value(ss, i); if (value < (s16)0) value = 0; - else if (GF.type && value >= (s16)GFC.h) value = GFC.h - 1; - else if (!GF.type && value >= (s16)GFC.w) value = GFC.w - 1; - - switch (GF.type) { - case FADER_H_BAR: - case FADER_H_DOT: - case FADER_V_BAR: - case FADER_V_DOT: - GF.value = value; - break; - case FADER_H_FINE: - if (value == 0) { - if (GF.value) GF.value--; - } else if (value == GFC.w - 1) { - if (GF.value < GFC.level) GF.value++; - } else { - GF.value = (((value << 4) + 8) * (GFC.level + 1)) / - (GFC.w << 4); - } - break; - case FADER_V_FINE: - if (value == 0) { - if (GF.value) GF.value--; - } else if (value == GFC.h - 1) { - if (GF.value < GFC.level) GF.value++; - } else { - GF.value = (((value << 4) + 8) * (GFC.level + 1)) / - (GFC.h << 4); - } - break; - } + else if (value > maxvalue) value = maxvalue; + GF.value = value; SG.latest_fader = i; SG.latest_group = GFC.group; @@ -1219,23 +1157,12 @@ static void op_G_GFDR_L_get(const void *NOTUSED(data), scene_state_t *ss, if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; - s16 level; u8 is_odd = 0; + s16 level; for (u16 i = 0; i < GRID_FADER_COUNT; i++) if (GFC.group == group) { - level = is_odd ? odd : even; - if (GF.type == FADER_H_FINE || GF.type == FADER_V_FINE) { - s16 maxlevel = ((GF.type == FADER_H_FINE ? GFC.w : GFC.h) << 4) - 1; - if (level < 0) - level = 0; - else if (level > maxlevel) - level = maxlevel; - } else { - if (level < (s16)LED_OFF) - level = LED_OFF; - else if (level > (s16)15) - level = 15; - } + level = grid_fader_clamp_level(is_odd ? odd : even, GF.type, GFC.w, GFC.h); + GF.value = scale(0, GFC.level, 0, level, GF.value); GFC.level = level; is_odd = !is_odd; } @@ -1302,6 +1229,8 @@ void grid_common_init(grid_common_t *gc) { gc->script = -1; } +// helpers + s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value) { if (a == b) return x; return (value - a) * (y - x) / (b - a) + x; @@ -1398,21 +1327,9 @@ static void grid_init_fader(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, if (h + y > (s16)GRID_MAX_DIMENSION) h = GRID_MAX_DIMENSION - y; if (w == 0 || h == 0) return; - if (type > FADER_V_FINE) type = FADER_H_BAR; + if (type < FADER_CH_BAR || type > FADER_FV_DOT) type = FADER_CH_BAR; - if (type == FADER_H_FINE || type == FADER_V_FINE) { - u8 size = type == FADER_H_FINE ? w : h; - s16 maxlevel = ((size - 2) << 4) - 1; - if (level < 0 || size < 3) - level = 0; - else if (level > maxlevel) - level = maxlevel; - } else { - if (level < (s16)LED_OFF) - level = LED_OFF; - else if (level > (s16)15) - level = 15; - } + level = grid_fader_clamp_level(level, type, w, h); if (script < 0 || script > INIT_SCRIPT) script = -1; @@ -1429,15 +1346,30 @@ static void grid_init_fader(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, static s16 grid_fader_max_value(scene_state_t *ss, u16 i) { switch (GF.type) { - case FADER_H_BAR: - case FADER_H_DOT: + case FADER_CH_BAR: + case FADER_CH_DOT: return GFC.w - 1; - case FADER_V_BAR: - case FADER_V_DOT: + case FADER_CV_BAR: + case FADER_CV_DOT: return GFC.h - 1; - case FADER_H_FINE: - case FADER_V_FINE: + case FADER_FH_BAR: + case FADER_FV_BAR: + case FADER_FH_DOT: + case FADER_FV_DOT: return GFC.level; } return 0; +} + +static s16 grid_fader_clamp_level(s16 level, s16 type, s16 w, s16 h) { + if (type > FADER_COARSE) { + u8 size = (type == FADER_FH_BAR || type == FADER_FH_DOT) ? w : h; + s16 maxlevel = ((size - 2) << 4) - 1; + if (level < 0 || size < 3) return 0; + if (level > maxlevel) return maxlevel; + } else { + if (level < (s16)LED_OFF) return LED_OFF; + if (level > (s16)15) return 15; + } + return level; } \ No newline at end of file diff --git a/src/state.c b/src/state.c index 2e268e4d..15f2c9c6 100644 --- a/src/state.c +++ b/src/state.c @@ -97,7 +97,7 @@ void ss_grid_init(scene_state_t *ss) { for (u8 i = 0; i < GRID_FADER_COUNT; i++) { ss_grid_common_init(&(ss->grid.fader[i].common)); - ss->grid.fader[i].type = FADER_H_BAR; + ss->grid.fader[i].type = FADER_CH_BAR; ss->grid.fader[i].value = 0; } diff --git a/src/state.h b/src/state.h index b3732e5e..2dbb0aa8 100644 --- a/src/state.h +++ b/src/state.h @@ -33,12 +33,17 @@ #define LED_DIM -1 #define LED_BRI -2 #define LED_OFF -3 -#define FADER_H_BAR 0 -#define FADER_V_BAR 1 -#define FADER_H_DOT 2 -#define FADER_V_DOT 3 -#define FADER_H_FINE 4 -#define FADER_V_FINE 5 +// H - horizontal, V - vertical +// C - coarse, F - fine +#define FADER_CH_BAR 0 +#define FADER_CV_BAR 1 +#define FADER_CH_DOT 2 +#define FADER_CV_DOT 3 +#define FADER_COARSE FADER_CV_DOT +#define FADER_FH_BAR 4 +#define FADER_FV_BAR 5 +#define FADER_FH_DOT 6 +#define FADER_FV_DOT 7 #define METRO_MIN_MS 25 #define METRO_MIN_UNSUPPORTED_MS 2 From 58915f22913116da68a3e4c668e3a2945e901a50 Mon Sep 17 00:00:00 2001 From: Brendon Cassidy Date: Thu, 11 Jan 2018 20:36:35 -0800 Subject: [PATCH 026/117] put bounds on the TELEX, 16N, and ER-301 commands for output numbers --- src/ops/er301.c | 3 +++ src/ops/fader.c | 3 +++ src/ops/telex.c | 6 ++++++ 3 files changed, 12 insertions(+) diff --git a/src/ops/er301.c b/src/ops/er301.c index 7249ec9f..3863d4cc 100644 --- a/src/ops/er301.c +++ b/src/ops/er301.c @@ -51,6 +51,9 @@ const tele_op_t op_SC_CV_OFF = void ERSend(uint8_t command, uint16_t output, int16_t value, bool set) { // zero-index the output output -= 1; + // return if out of range + if (output < 0 || output > 299) + return; // convert the output to the device and the port uint8_t port = output % 100; uint8_t device = output / 100; diff --git a/src/ops/fader.c b/src/ops/fader.c index 1deb71f7..4cc73900 100644 --- a/src/ops/fader.c +++ b/src/ops/fader.c @@ -21,6 +21,9 @@ static void op_FADER_get(const void *NOTUSED(data), scene_state_t *ss, uint16_t input = cs_pop(cs); // zero-index the input input -= 1; + // return if out of range + if (input < 0 || input > 15) + return; // convert the input to the device and the port uint8_t port = input % 16; uint8_t device = input / 16; diff --git a/src/ops/telex.c b/src/ops/telex.c index 39b74a5f..bc436b29 100644 --- a/src/ops/telex.c +++ b/src/ops/telex.c @@ -373,6 +373,9 @@ void TXSend(uint8_t model, uint8_t command, uint8_t output, int16_t value, bool set) { // zero-index the output output -= 1; + // return if out of range + if (output < 0 || output > 31) + return; // convert the output to the device and the port uint8_t port = output & 3; uint8_t device = output >> 2; @@ -408,6 +411,9 @@ void ReceiveIt(uint8_t address, uint8_t port, command_state_t *cs) { void TXReceive(uint8_t model, command_state_t *cs, uint8_t mode, bool shift) { // zero-index the output uint8_t input = cs_pop(cs) - 1; + // return if out of range + if (input < 0 || input > 31) + return; // send the port, device and address uint8_t port = input & 3; uint8_t device = input >> 2; From ee6629bece282643a468870d0dc3b35e1a99b2bf Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 12 Jan 2018 11:39:16 -0800 Subject: [PATCH 027/117] whats_new updated --- docs/whats_new.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/whats_new.md b/docs/whats_new.md index aa766c14..881f0c7a 100644 --- a/docs/whats_new.md +++ b/docs/whats_new.md @@ -1,5 +1,25 @@ # What's new? +## Version 2.3 + +### Grid Integration + +TBA + +### New Operators + +`P.MIN` `PN.MIN` `P.MAX` `PN.MAX` returns the position for the first smallest/largest value in a pattern between the `START` and `END` points. +`TO.CV.CALIB` allows you to lock-in an offset across power cycles to calibrate your TELEX CV output (`TO.CV.RESET` removes the calibration). +`TO.ENV` now accepts gate values (1/0) to trigger the attack and decay. + +### Support for the Orthogonal Devices ER-301 Sound Computer over i2c + +You now can connect up to three ER-301s via i2c and address up to 100 virtual CV channels and 100 virtual TR channels per ER-301. (The outputs range 1-100, 101-200, and 201-300 respectively.) To function, this requires a slight mod to current in-market ER-301s and a specialized i2c cable that reorders two of the pins. Find more information [on the Orthogonal Devices ER-301 Wiki Teletype Integration Page](http://wiki.orthogonaldevices.com/index.php/ER-301/Teletype_Integration). + +### Support for the 16n Faderbank via i2c + +The 16n Faderbank is an open-source sixteen fader controller with support for USB MIDI, standard MIDI, and i2c communication with the Teletype. It operates just like an IN or PARAM (or the TXi for that matter) in that you read values from the device. You use the operator FADER (or the alias FB) and the number of the slider you wish to poll (1-16). Know that longer cables may require that you use a powered bus board even if you only have one device on your Teletype's i2c bus. (You will know that you have a problem if your Teletype randomly hangs on reads.) + ## Version 2.1 Teletype version 2.1 introduces new operators that mature the syntax and capability of the Teletype, as well as several bug fixes and enhancement features. From 30c240b2c46018e1c87bb367609cd10af02b925e Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 12 Jan 2018 11:46:10 -0800 Subject: [PATCH 028/117] fader slide --- module/grid.c | 191 +++++++++++++++++++++++++++++++++++---------- src/ops/grid_ops.c | 2 + src/state.c | 1 + src/state.h | 6 ++ 4 files changed, 157 insertions(+), 43 deletions(-) diff --git a/module/grid.c b/module/grid.c index 048af7af..26d40214 100644 --- a/module/grid.c +++ b/module/grid.c @@ -6,7 +6,7 @@ #include "timers.h" #include "util.h" -#define GRID_MAX_KEY_PRESSED 5 +#define GRID_MAX_KEY_PRESSED 10 #define GRID_KEY_HOLD_DELAY 700 #define GRID_KEY_REPEAT_RATE 40 @@ -146,18 +146,17 @@ typedef struct { u8 key; u8 x; u8 y; - u8 ignore_rotate; scene_state_t *ss; softTimer_t timer; -} hold_repeat_timer; +} hold_repeat_info; static u16 size_x = 16, size_y = 8; static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION/2]; -static hold_repeat_timer hold_repeat_timers[GRID_MAX_KEY_PRESSED]; +static hold_repeat_info held_keys[GRID_MAX_KEY_PRESSED]; static u8 timers_uninitialized = 1; static void hold_repeat_timer_callback(void* o); -static void grid_process_key_hold_repeat(scene_state_t *ss, u8 _x, u8 _y, u8 ignore_rotate, u8 is_hold); +static void grid_process_key_hold_repeat(scene_state_t *ss, u8 x, u8 y, u8 is_hold); static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); @@ -169,33 +168,33 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { if (timers_uninitialized) { timers_uninitialized = 0; for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) - hold_repeat_timers[i].used = 0; + held_keys[i].used = 0; } - u8 key = (_y << 4) | _x; + u8 x = SG.rotate && !ignore_rotate ? monome_size_x() - _x - 1 : _x; + u8 y = SG.rotate && !ignore_rotate ? monome_size_y() - _y - 1 : _y; + + u8 key = (y << 4) | x; if (z) { for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) - if (!hold_repeat_timers[i].used || hold_repeat_timers[i].key == key) { - hold_repeat_timers[i].used = 1; - hold_repeat_timers[i].key = key; - hold_repeat_timers[i].x = _x; - hold_repeat_timers[i].y = _y; - hold_repeat_timers[i].ignore_rotate = ignore_rotate; - hold_repeat_timers[i].ss = ss; - timer_add(&hold_repeat_timers[i].timer, GRID_KEY_HOLD_DELAY, - &hold_repeat_timer_callback, (void *)&hold_repeat_timers[i]); + if (!held_keys[i].used || held_keys[i].key == key) { + held_keys[i].used = 1; + held_keys[i].key = key; + held_keys[i].x = x; + held_keys[i].y = y; + held_keys[i].ss = ss; + timer_add(&held_keys[i].timer, GRID_KEY_HOLD_DELAY, + &hold_repeat_timer_callback, (void *)&held_keys[i]); break; } } else { for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) - if (hold_repeat_timers[i].key == key) { - timer_remove(&hold_repeat_timers[i].timer); - hold_repeat_timers[i].used = 0; + if (held_keys[i].key == key) { + timer_remove(&held_keys[i].timer); + held_keys[i].used = 0; } } - u8 x = SG.rotate && !ignore_rotate ? monome_size_x() - _x - 1 : _x; - u8 y = SG.rotate && !ignore_rotate ? monome_size_y() - _y - 1 : _y; u8 refresh = 0; u8 scripts[SCRIPT_COUNT]; for (u8 i = 0; i < SCRIPT_COUNT; i++) scripts[i] = 0; @@ -212,38 +211,116 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { } u16 value; + s8 held; if (z) { for (u8 i = 0; i < GRID_FADER_COUNT; i++) { if (GFC.enabled && SG.group[GFC.group].enabled && grid_within_area(x, y, &GFC)) { + held = -1; + if (GF.type & 1) { + for (u8 j = 0; j < GRID_MAX_KEY_PRESSED; j++) + if (held_keys[j].used && (held_keys[j].y != y) && + grid_within_area(held_keys[j].x, held_keys[j].y, &GFC)) { + held = j; + break; + } + } else { + for (u8 j = 0; j < GRID_MAX_KEY_PRESSED; j++) + if (held_keys[j].used && (held_keys[j].x != x) && + grid_within_area(held_keys[j].x, held_keys[j].y, &GFC)) { + held = j; + break; + } + } + switch (GF.type) { case FADER_CH_BAR: case FADER_CH_DOT: - GF.value = x - GFC.x; + if (held == -1) { + GF.slide = 0; + GF.value = x - GFC.x; + } else { + GF.slide = 1; + GF.slide_acc = 0; + GF.slide_end = x - GFC.x; + GF.slide_delta = 16; + GF.slide_dir = GF.slide_end > GF.value; + } break; case FADER_CV_BAR: case FADER_CV_DOT: - GF.value = GFC.h + GFC.y - y - 1; + if (held == -1) { + GF.slide = 0; + GF.value = GFC.h + GFC.y - y - 1; + } else { + GF.slide = 1; + GF.slide_acc = 0; + GF.slide_end = GFC.h + GFC.y - y - 1; + GF.slide_delta = 16; + GF.slide_dir = GF.slide_end > GF.value; + } break; case FADER_FH_BAR: case FADER_FH_DOT: - if (x == GFC.x) { - if (GF.value) GF.value--; - } else if (x == GFC.x + GFC.w - 1) { - if (GF.value < GFC.level) GF.value++; + if (held != -1 && (held_keys[held].x == GFC.x || held_keys[held].x == (GFC.x + GFC.w - 1))) + held = -1; + if (held == -1) { + GF.slide = 0; + if (x == GFC.x) { + if (GF.value) GF.value--; + } else if (x == GFC.x + GFC.w - 1) { + if (GF.value < GFC.level) GF.value++; + } else { + value = ((((x - GFC.x - 1) << 1) + 1) * GFC.level) / (GFC.w - 2); + GF.value = (value >> 1) + (value & 1); + } } else { - value = ((((x - GFC.x - 1) << 1) + 1) * GFC.level) / (GFC.w - 2); - GF.value = (value >> 1) + (value & 1); + GF.slide = 1; + GF.slide_acc = 0; + if (x == GFC.x) + value = 0; + else if (x == (GFC.x + GFC.w - 1)) + value = GFC.level; + else { + value = ((((x - GFC.x - 1) << 1) + 1) * GFC.level) / (GFC.w - 2); + value = (value >> 1) + (value & 1); + } + GF.slide_end = value; + value = ((GFC.w - 2) << 4) / GFC.level; + if (value == 0) value = 1; + GF.slide_delta = value; + GF.slide_dir = GF.slide_end > GF.value; } break; case FADER_FV_BAR: case FADER_FV_DOT: - if (y == GFC.y) { - if (GF.value < GFC.level) GF.value++; - } else if (y == GFC.y + GFC.h - 1) { - if (GF.value) GF.value--; + if (held != -1 && (held_keys[held].y == GFC.y || held_keys[held].y == (GFC.y + GFC.h - 1))) + held = -1; + if (held == -1) { + GF.slide = 0; + if (y == GFC.y) { + if (GF.value < GFC.level) GF.value++; + } else if (y == GFC.y + GFC.h - 1) { + if (GF.value) GF.value--; + } else { + value = ((((GFC.h + GFC.y - y - 2) << 1) + 1) * GFC.level) / (GFC.h - 2); + GF.value = (value >> 1) + (value & 1); + } } else { - value = ((((GFC.h + GFC.y - y - 2) << 1) + 1) * GFC.level) / (GFC.h - 2); - GF.value = (value >> 1) + (value & 1); + GF.slide = 1; + GF.slide_acc = 0; + if (y == GFC.y) + value = GFC.level; + else if (y == (GFC.y + GFC.h - 1)) + value = 0; + else { + value = ((((GFC.h + GFC.y - y - 2) << 1) + 1) * GFC.level) / (GFC.h - 2); + value = (value >> 1) + (value & 1); + } + GF.slide_end = value; + value = ((GFC.h - 2) << 4) / GFC.level; + if (value == 0) value = 1; + GF.slide_delta = value; + GF.slide_dir = GF.slide_end > GF.value; } break; } @@ -281,9 +358,7 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { if (refresh) SG.grid_dirty = SG.scr_dirty = 1; } -void grid_process_key_hold_repeat(scene_state_t *ss, u8 _x, u8 _y, u8 ignore_rotate, u8 is_hold) { - u8 x = SG.rotate && !ignore_rotate ? monome_size_x() - _x - 1 : _x; - u8 y = SG.rotate && !ignore_rotate ? monome_size_y() - _y - 1 : _y; +void grid_process_key_hold_repeat(scene_state_t *ss, u8 x, u8 y, u8 is_hold) { u8 refresh = 0; u8 scripts[SCRIPT_COUNT]; for (u8 i = 0; i < SCRIPT_COUNT; i++) scripts[i] = 0; @@ -327,16 +402,46 @@ void grid_process_key_hold_repeat(scene_state_t *ss, u8 _x, u8 _y, u8 ignore_rot } void hold_repeat_timer_callback(void* o) { - hold_repeat_timer* timer = o; - u8 is_hold = timer->used == 1; + hold_repeat_info* hr = o; + u8 is_hold = hr->used == 1; if (is_hold) { - timer_set(&timer->timer, GRID_KEY_REPEAT_RATE); - timer->used = 2; + timer_set(&hr->timer, GRID_KEY_REPEAT_RATE); + hr->used = 2; } - grid_process_key_hold_repeat(timer->ss, timer->x, timer->y, timer->ignore_rotate, is_hold); + grid_process_key_hold_repeat(hr->ss, hr->x, hr->y, is_hold); } void grid_process_fader_slew(scene_state_t *ss) { + u8 refresh = 0; + u8 scripts[SCRIPT_COUNT]; + for (u8 i = 0; i < SCRIPT_COUNT; i++) scripts[i] = 0; + + for (u8 i = 0; i < GRID_FADER_COUNT; i++) { + if (!GF.slide) continue; + GF.slide_acc++; + if (GF.slide_acc >= GF.slide_delta) { + GF.slide_acc = 0; + if (GF.slide_dir) + GF.value++; + else + GF.value--; + if ((GF.slide_dir && GF.value >= GF.slide_end) || + (!GF.slide_dir && GF.value <= GF.slide_end)) { + GF.value = GF.slide_end; + GF.slide = 0; + } + SG.latest_fader = i; + SG.latest_group = GFC.group; + if (GFC.script != -1) run_script(ss, GFC.script); + if (SG.group[GFC.group].script != -1) scripts[SG.group[GFC.group].script] = 1; + refresh = 1; + } + } + + for (u8 i = 0; i < SCRIPT_COUNT; i++) + if (scripts[i]) run_script(ss, i); + + if (refresh) SG.grid_dirty = SG.scr_dirty = 1; } bool grid_within_area(u8 x, u8 y, grid_common_t *gc) { diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index f76fad8d..6d87c49f 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -237,6 +237,7 @@ static void op_G_RST_get(const void *NOTUSED(data), scene_state_t *ss, grid_common_init(&(GFC)); GF.type = FADER_CH_BAR; GF.value = 0; + GF.slide = 0; } for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { @@ -332,6 +333,7 @@ static void op_G_GRP_RST_get(const void *NOTUSED(data), scene_state_t *ss, grid_common_init(&(GFC)); GF.type = FADER_CH_BAR; GF.value = 0; + GF.slide = 0; } for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) diff --git a/src/state.c b/src/state.c index 15f2c9c6..04bb86fe 100644 --- a/src/state.c +++ b/src/state.c @@ -99,6 +99,7 @@ void ss_grid_init(scene_state_t *ss) { ss_grid_common_init(&(ss->grid.fader[i].common)); ss->grid.fader[i].type = FADER_CH_BAR; ss->grid.fader[i].value = 0; + ss->grid.fader[i].slide = 0; } for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { diff --git a/src/state.h b/src/state.h index 2dbb0aa8..07a04f3e 100644 --- a/src/state.h +++ b/src/state.h @@ -35,6 +35,7 @@ #define LED_OFF -3 // H - horizontal, V - vertical // C - coarse, F - fine +// H must be even, V must be odd #define FADER_CH_BAR 0 #define FADER_CV_BAR 1 #define FADER_CH_DOT 2 @@ -158,6 +159,11 @@ typedef struct { grid_common_t common; u8 type; u8 value; + u8 slide; + u8 slide_acc; + u8 slide_end; + u8 slide_delta; + u8 slide_dir; } grid_fader_t; typedef struct { From 8ec0f783bb1d88f94ca76b172f158fdd8b104159 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 12 Jan 2018 12:47:30 -0800 Subject: [PATCH 029/117] fixes for flash/USB save --- module/flash.c | 22 +++++++--------------- module/usb_disk_mode.c | 5 +++-- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/module/flash.c b/module/flash.c index 95031227..5e114109 100644 --- a/module/flash.c +++ b/module/flash.c @@ -11,11 +11,10 @@ #define FIRSTRUN_KEY 0x22 #define BUTTON_STATE_SIZE (GRID_BUTTON_COUNT >> 3) -#define FADER_STATE_SIZE (GRID_FADER_COUNT >> 1) typedef struct { uint8_t button_states[BUTTON_STATE_SIZE]; - uint8_t fader_states[FADER_STATE_SIZE]; + uint8_t fader_states[GRID_FADER_COUNT]; } grid_data_t; static grid_data_t grid_data; @@ -116,17 +115,13 @@ static void pack_grid(scene_state_t *scene) { for (uint16_t i = 0; i < GRID_BUTTON_COUNT; i++) { byte |= (scene->grid.button[i].state != 0) << (i & 7); if ((i & 7) == 7) { - if (++byte_count >= BUTTON_STATE_SIZE) break; grid_data.button_states[byte_count] = byte; byte = 0; + if (++byte_count >= BUTTON_STATE_SIZE) break; } } - for (uint16_t i = 0; i < GRID_FADER_COUNT; i += 2) { - byte = i >> 1; - if (byte >= FADER_STATE_SIZE) break; - grid_data.fader_states[byte] = - (scene->grid.fader[i].value << 4) + scene->grid.fader[i + 1].value; - } + for (uint16_t i = 0; i < GRID_FADER_COUNT; i++) + grid_data.fader_states[i] = scene->grid.fader[i].value; } static void unpack_grid(scene_state_t *scene) { @@ -134,9 +129,6 @@ static void unpack_grid(scene_state_t *scene) { scene->grid.button[i].state = 0 != (grid_data.button_states[i >> 3] & (1 << (i & 7))); } - for (uint16_t i = 0; i < GRID_FADER_COUNT; i += 2) { - scene->grid.fader[i].value = grid_data.fader_states[i >> 1] >> 4; - scene->grid.fader[i + 1].value = - grid_data.fader_states[i >> 1] & 0b1111; - } -} + for (uint16_t i = 0; i < GRID_FADER_COUNT; i++) + scene->grid.fader[i].value = grid_data.fader_states[i]; +} \ No newline at end of file diff --git a/module/usb_disk_mode.c b/module/usb_disk_mode.c index d642fe86..c0e728e0 100644 --- a/module/usb_disk_mode.c +++ b/module/usb_disk_mode.c @@ -417,6 +417,7 @@ void tele_usb_disk() { nav_exit(); } +char fvalue[36]; static void grid_usb_write(scene_state_t *scene) { file_putc('\n'); file_putc('#'); @@ -428,8 +429,8 @@ static void grid_usb_write(scene_state_t *scene) { } file_putc('\n'); for (uint16_t i = 0; i < GRID_FADER_COUNT; i++) { - if (scene->grid.fader[i].value >= 10) file_putc('1'); - file_putc('0' + (scene->grid.fader[i].value % 10)); + itoa(scene->grid.fader[i].value, fvalue, 10); + file_write_buf((uint8_t *)fvalue, strlen(fvalue)); file_putc((i & 15) == 15 ? '\n' : '\t'); } } From 26310518f9e0fccf248d7aac83be21c892fcefda Mon Sep 17 00:00:00 2001 From: Brendon Cassidy Date: Sun, 14 Jan 2018 10:49:33 -0800 Subject: [PATCH 030/117] fixed failing test by ensuring that out of bounds i2c reads return zero --- src/ops/fader.c | 4 +++- src/ops/telex.c | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ops/fader.c b/src/ops/fader.c index 4cc73900..4e0dbbf7 100644 --- a/src/ops/fader.c +++ b/src/ops/fader.c @@ -22,8 +22,10 @@ static void op_FADER_get(const void *NOTUSED(data), scene_state_t *ss, // zero-index the input input -= 1; // return if out of range - if (input < 0 || input > 15) + if (input < 0 || input > 15) { + cs_push(cs, 0); return; + } // convert the input to the device and the port uint8_t port = input % 16; uint8_t device = input / 16; diff --git a/src/ops/telex.c b/src/ops/telex.c index bc436b29..cbeed160 100644 --- a/src/ops/telex.c +++ b/src/ops/telex.c @@ -412,8 +412,11 @@ void TXReceive(uint8_t model, command_state_t *cs, uint8_t mode, bool shift) { // zero-index the output uint8_t input = cs_pop(cs) - 1; // return if out of range - if (input < 0 || input > 31) + if (input < 0 || input > 31) { + // need to put a zero on the stack for tests to pass + cs_push(cs, 0); return; + } // send the port, device and address uint8_t port = input & 3; uint8_t device = input >> 2; From 9cdd4b3bb37363bb5ff54b518859489e442c1fa4 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 15 Jan 2018 19:25:34 -0800 Subject: [PATCH 031/117] fix simulator build --- simulator/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/simulator/Makefile b/simulator/Makefile index 60d6424b..9d0a1331 100644 --- a/simulator/Makefile +++ b/simulator/Makefile @@ -10,7 +10,8 @@ OBJ = tt.o ../src/teletype.o ../src/command.o ../src/helpers.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/whitewhale.o \ - ../src/ops/init.o ../src/ops/grid_ops.o \ + ../src/ops/init.o ../src/ops/grid_ops.o ../src/ops/er301.o \ + ../src/ops/fader.o \ ../libavr32/src/euclidean/euclidean.o ../libavr32/src/euclidean/data.o \ ../libavr32/src/util.o From 43d70d9f9f88ff69784f3e29f7861f439bc0928c Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 18 Jan 2018 18:35:56 -0800 Subject: [PATCH 032/117] matrixarchate support pt1 --- module/config.mk | 1 + simulator/Makefile | 2 +- src/match_token.rl | 18 +++ src/ops/matrixarchate.c | 252 ++++++++++++++++++++++++++++++++++++++++ src/ops/matrixarchate.h | 25 ++++ src/ops/op.c | 8 +- src/ops/op_enum.h | 16 +++ tests/Makefile | 3 +- 8 files changed, 322 insertions(+), 3 deletions(-) create mode 100644 src/ops/matrixarchate.c create mode 100644 src/ops/matrixarchate.h diff --git a/module/config.mk b/module/config.mk index c5f6c8a5..f7ef4307 100644 --- a/module/config.mk +++ b/module/config.mk @@ -96,6 +96,7 @@ CSRCS = \ ../src/ops/init.c \ ../src/ops/justfriends.c \ ../src/ops/maths.c \ + ../src/ops/matrixarchate.c \ ../src/ops/meadowphysics.c \ ../src/ops/metronome.c \ ../src/ops/orca.c \ diff --git a/simulator/Makefile b/simulator/Makefile index 9d0a1331..72bbcdaf 100644 --- a/simulator/Makefile +++ b/simulator/Makefile @@ -11,7 +11,7 @@ OBJ = tt.o ../src/teletype.o ../src/command.o ../src/helpers.o \ ../src/ops/patterns.o ../src/ops/queue.o ../src/ops/stack.o \ ../src/ops/telex.o ../src/ops/variables.o ../src/ops/whitewhale.o \ ../src/ops/init.o ../src/ops/grid_ops.o ../src/ops/er301.o \ - ../src/ops/fader.o \ + ../src/ops/fader.o ../src/ops/matrixarchate.o \ ../libavr32/src/euclidean/euclidean.o ../libavr32/src/euclidean/data.o \ ../libavr32/src/util.o diff --git a/src/match_token.rl b/src/match_token.rl index f10a1fed..0be34b5f 100644 --- a/src/match_token.rl +++ b/src/match_token.rl @@ -551,6 +551,24 @@ "PROB" => { MATCH_MOD(E_MOD_PROB); }; "DEL" => { MATCH_MOD(E_MOD_DEL); }; + # matrixarchate + "MA.SELECT" => { MATCH_OP(E_OP_MA_SELECT); }; + "MA.STEP" => { MATCH_OP(E_OP_MA_STEP); }; + "MA.RESET" => { MATCH_OP(E_OP_MA_RESET); }; + "MA.PGM" => { MATCH_OP(E_OP_MA_PGM); }; + "MA.ON" => { MATCH_OP(E_OP_MA_ON); }; + "MA.PON" => { MATCH_OP(E_OP_MA_PON); }; + "MA.OFF" => { MATCH_OP(E_OP_MA_OFF); }; + "MA.POFF" => { MATCH_OP(E_OP_MA_POFF); }; + "MA.SET" => { MATCH_OP(E_OP_MA_SET); }; + "MA.PSET" => { MATCH_OP(E_OP_MA_PSET); }; + "MA.COL" => { MATCH_OP(E_OP_MA_COL); }; + "MA.PCOL" => { MATCH_OP(E_OP_MA_PCOL); }; + "MA.ROW" => { MATCH_OP(E_OP_MA_ROW); }; + "MA.PROW" => { MATCH_OP(E_OP_MA_PROW); }; + "MA.CLR" => { MATCH_OP(E_OP_MA_CLR); }; + "MA.PCLR" => { MATCH_OP(E_OP_MA_PCLR); }; + # stack "S" => { MATCH_MOD(E_MOD_S); }; *|; diff --git a/src/ops/matrixarchate.c b/src/ops/matrixarchate.c new file mode 100644 index 00000000..97fcbd99 --- /dev/null +++ b/src/ops/matrixarchate.c @@ -0,0 +1,252 @@ +#include "ops/matrixarchate.h" + +#include "helpers.h" +#include "ii.h" +#include "teletype.h" +#include "teletype_io.h" + +static void op_MA_SELECT_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_SELECT_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); + +static void op_MA_STEP_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_RESET_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_PGM_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); + +static void op_MA_ON_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_PON_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_OFF_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_POFF_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_SET_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_PSET_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); + +static void op_MA_COL_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_COL_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_PCOL_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_PCOL_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_ROW_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_ROW_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_PROW_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_PROW_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); + +static void op_MA_CLR_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_MA_PCLR_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); + +const tele_op_t op_MA_SELECT = MAKE_GET_SET_OP(MA.SELECT, op_MA_SELECT_get, op_MA_SELECT_set, 0, true); + +const tele_op_t op_MA_STEP = MAKE_GET_OP(MA.STEP, op_MA_STEP_get, 0, false); +const tele_op_t op_MA_RESET = MAKE_GET_OP(MA.RESET, op_MA_RESET_get, 0, false); +const tele_op_t op_MA_PGM = MAKE_GET_OP(MA.PGM, op_MA_PGM_get, 1, false); + +const tele_op_t op_MA_ON = MAKE_GET_OP(MA.ON, op_MA_ON_get, 2, false); +const tele_op_t op_MA_PON = MAKE_GET_OP(MA.PON, op_MA_PON_get, 3, false); +const tele_op_t op_MA_OFF = MAKE_GET_OP(MA.OFF, op_MA_OFF_get, 2, false); +const tele_op_t op_MA_POFF = MAKE_GET_OP(MA.POFF, op_MA_POFF_get, 3, false); +const tele_op_t op_MA_SET = MAKE_GET_OP(MA.SET, op_MA_SET_get, 3, false); +const tele_op_t op_MA_PSET = MAKE_GET_OP(MA.PSET, op_MA_PSET_get, 4, false); + +const tele_op_t op_MA_COL = MAKE_GET_SET_OP(MA.COL, op_MA_COL_get, op_MA_COL_set, 1, true); +const tele_op_t op_MA_PCOL = MAKE_GET_SET_OP(MA.PCOL, op_MA_PCOL_get, op_MA_PCOL_set, 2, true); +const tele_op_t op_MA_ROW = MAKE_GET_SET_OP(MA.ROW, op_MA_ROW_get, op_MA_ROW_set, 1, true); +const tele_op_t op_MA_PROW = MAKE_GET_SET_OP(MA.PROW, op_MA_PROW_get, op_MA_PROW_set, 2, true); + +const tele_op_t op_MA_CLR = MAKE_GET_OP(MA.CLR, op_MA_CLR_get, 0, false); +const tele_op_t op_MA_PCLR = MAKE_GET_OP(MA.PCLR, op_MA_PCLR_get, 1, false); + +u8 selected_ma = 0; + +static void ma_set(s16 row, s16 column, s16 value) { + if (row < 0 || row > 15 || column < 0 || column > 7) return; + uint8_t d[] = { value ? 0b10010000 : 0b10000000, (row << 3) + column, 128 }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 3); +} + +static void ma_set_pgm(s16 program, s16 row, s16 column, s16 value) { + if (program < 0 || program > 59 || row < 0 || row > 15 || column < 0 || column > 7) return; + uint8_t d[] = { value ? 0b10010000 : 0b10000000, (row << 3) + column, program }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 3); +} + +static void ma_set_col(s16 column, u16 value) { + if (column < 0 || column > 7) return; + uint8_t d[] = { 0b10110000, column, 128, value & 255, value >> 8 }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 5); +} + +static void ma_set_col_pgm(s16 program, s16 column, u16 value) { + if (program < 0 || program > 59 || column < 0 || column > 7) return; + uint8_t d[] = { 0b10110000, column, program, value & 255, value >> 8 }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 5); +} + +static void ma_set_row(s16 row, u16 value) { + if (row < 0 || row > 15) return; + uint8_t d[] = { 0b10110000, row | 128, 128, value & 255, value >> 8 }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 5); +} + +static void ma_set_row_pgm(s16 program, s16 row, u16 value) { + if (program < 0 || program > 59 || row < 0 || row > 15) return; + uint8_t d[] = { 0b10110000, row | 128, program, value & 255, value >> 8 }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 5); +} + +static void op_MA_SELECT_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, selected_ma + 1); +} + +static void op_MA_SELECT_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 i = cs_pop(cs) - 1; + if (i < 0 || i > 2) return; + selected_ma = i; +} + +static void op_MA_STEP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t d[] = { 0b11111000 }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 1); +} + +static void op_MA_RESET_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + uint8_t d[] = { 0b11111101 }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 1); +} + +static void op_MA_PGM_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 program = cs_pop(cs) - 1; + if (program < 0 || program > 59) return; + uint8_t d[] = { 0b11000000, program }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 2); +} + +static void op_MA_ON_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 row = cs_pop(cs); + s16 column = cs_pop(cs); + ma_set(row, column, 1); +} + +static void op_MA_PON_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 program = cs_pop(cs) - 1; + s16 row = cs_pop(cs); + s16 column = cs_pop(cs); + ma_set_pgm(program, row, column, 1); +} + +static void op_MA_OFF_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 row = cs_pop(cs); + s16 column = cs_pop(cs); + ma_set(row, column, 0); +} + +static void op_MA_POFF_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 program = cs_pop(cs) - 1; + s16 row = cs_pop(cs); + s16 column = cs_pop(cs); + ma_set_pgm(program, row, column, 0); +} + +static void op_MA_SET_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 row = cs_pop(cs); + s16 column = cs_pop(cs); + s16 value = cs_pop(cs); + ma_set(row, column, value); +} + +static void op_MA_PSET_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 program = cs_pop(cs) - 1; + s16 row = cs_pop(cs); + s16 column = cs_pop(cs); + s16 value = cs_pop(cs); + ma_set_pgm(program, row, column, value); +} + +static void op_MA_COL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 column = cs_pop(cs); + u16 value = 0; + if (column >= 0 && column <= 7) { + uint8_t d[] = { 0b11110101, column, 128 }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 3); + d[0] = 0; + d[1] = 0; + tele_ii_rx(MATRIXARCHATE + selected_ma, d, 2); + value = (d[1] << 8) + d[0]; + } + cs_push(cs, value); +} + +static void op_MA_COL_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 column = cs_pop(cs); + u16 value = cs_pop(cs); + ma_set_col(column, value); +} + +static void op_MA_PCOL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 program = cs_pop(cs) - 1; + s16 column = cs_pop(cs); + u16 value = 0; + if (column >= 0 && column <= 7 && program >= 0 && program <= 59) { + uint8_t d[] = { 0b11110101, column, program }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 3); + d[0] = 0; + d[1] = 0; + tele_ii_rx(MATRIXARCHATE + selected_ma, d, 2); + value = (d[1] << 8) + d[0]; + } + cs_push(cs, value); +} + +static void op_MA_PCOL_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 program = cs_pop(cs) - 1; + s16 column = cs_pop(cs); + u16 value = cs_pop(cs); + ma_set_col_pgm(program, column, value); +} + +static void op_MA_ROW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 row = cs_pop(cs); + u16 value = 0; + if (row >= 0 && row <= 15) { + uint8_t d[] = { 0b11110101, row | 128, 128 }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 3); + d[0] = 0; + d[1] = 0; + tele_ii_rx(MATRIXARCHATE + selected_ma, d, 2); + value = (d[1] << 8) + d[0]; + } + cs_push(cs, value); +} + +static void op_MA_ROW_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 row = cs_pop(cs); + u16 value = cs_pop(cs); + ma_set_row(row, value); +} + +static void op_MA_PROW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 program = cs_pop(cs) - 1; + s16 row = cs_pop(cs); + u16 value = 0; + if (row >= 0 && row <= 15 && program >= 0 && program <= 59) { + uint8_t d[] = { 0b11110101, row | 128, program }; + tele_ii_tx(MATRIXARCHATE + selected_ma, d, 3); + d[0] = 0; + d[1] = 0; + tele_ii_rx(MATRIXARCHATE + selected_ma, d, 2); + value = (d[1] << 8) + d[0]; + } + cs_push(cs, value); +} + +static void op_MA_PROW_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 program = cs_pop(cs) - 1; + s16 row = cs_pop(cs); + u16 value = cs_pop(cs); + ma_set_row_pgm(program, row, value); +} + +static void op_MA_CLR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + for (u8 i = 0; i < 8; i++) ma_set_col(i, 0); +} + +static void op_MA_PCLR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 program = cs_pop(cs) - 1; + for (u8 i = 0; i < 8; i++) ma_set_col_pgm(program, i, 0); +} diff --git a/src/ops/matrixarchate.h b/src/ops/matrixarchate.h new file mode 100644 index 00000000..857782a9 --- /dev/null +++ b/src/ops/matrixarchate.h @@ -0,0 +1,25 @@ +#ifndef _OPS_MATRIXARCHATE_H_ +#define _OPS_MATRIXARCHATE_H_ + +#include "ops/op.h" + +extern const tele_op_t op_MA_SELECT; +extern const tele_op_t op_MA_STEP; +extern const tele_op_t op_MA_RESET; +extern const tele_op_t op_MA_PGM; +extern const tele_op_t op_MA_ON; +extern const tele_op_t op_MA_PON; +extern const tele_op_t op_MA_OFF; +extern const tele_op_t op_MA_POFF; +extern const tele_op_t op_MA_SET; +extern const tele_op_t op_MA_PSET; +extern const tele_op_t op_MA_COL; +extern const tele_op_t op_MA_PCOL; +extern const tele_op_t op_MA_ROW; +extern const tele_op_t op_MA_PROW; +extern const tele_op_t op_MA_CLR; +extern const tele_op_t op_MA_PCLR; + +#define MATRIXARCHATE 0xB8 + +#endif \ No newline at end of file diff --git a/src/ops/op.c b/src/ops/op.c index 0b7c3fc2..7d782157 100644 --- a/src/ops/op.c +++ b/src/ops/op.c @@ -15,6 +15,7 @@ #include "ops/hardware.h" #include "ops/init.h" #include "ops/justfriends.h" +#include "ops/matrixarchate.h" #include "ops/maths.h" #include "ops/meadowphysics.h" #include "ops/metronome.h" @@ -184,7 +185,12 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_G_FDR_L, &op_G_FDR_X, &op_G_FDR_Y, &op_G_FDRI, &op_G_FDRV, &op_G_FDRN, &op_G_FDRL, &op_G_FDRX, &op_G_FDRY, &op_G_FDR_PR, &op_G_GFDR_V, &op_G_GFDR_N, &op_G_GFDR_L, &op_G_GFDR_RN, &op_G_XYP, &op_G_XYP_X, - &op_G_XYP_Y + &op_G_XYP_Y, + + // matrixarchate + &op_MA_SELECT, &op_MA_STEP, &op_MA_RESET, &op_MA_PGM, &op_MA_ON, &op_MA_PON, + &op_MA_OFF, &op_MA_POFF, &op_MA_SET, &op_MA_PSET, &op_MA_COL, &op_MA_PCOL, + &op_MA_ROW, &op_MA_PROW, &op_MA_CLR, &op_MA_PCLR }; ///////////////////////////////////////////////////////////////// diff --git a/src/ops/op_enum.h b/src/ops/op_enum.h index c565df2d..c0b1e50d 100644 --- a/src/ops/op_enum.h +++ b/src/ops/op_enum.h @@ -462,6 +462,22 @@ typedef enum { E_OP_G_XYP, E_OP_G_XYP_X, E_OP_G_XYP_Y, + E_OP_MA_SELECT, + E_OP_MA_STEP, + E_OP_MA_RESET, + E_OP_MA_PGM, + E_OP_MA_ON, + E_OP_MA_PON, + E_OP_MA_OFF, + E_OP_MA_POFF, + E_OP_MA_SET, + E_OP_MA_PSET, + E_OP_MA_COL, + E_OP_MA_PCOL, + E_OP_MA_ROW, + E_OP_MA_PROW, + E_OP_MA_CLR, + E_OP_MA_PCLR, E_OP__LENGTH, } tele_op_idx_t; diff --git a/tests/Makefile b/tests/Makefile index 7e7204e0..35b63275 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -16,8 +16,9 @@ tests: main.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/whitewhale.c \ + ../src/ops/telex.o ../src/ops/variables.o ../src/ops/whitewhale.o \ ../src/ops/turtle.o ../src/ops/init.o ../src/ops/grid_ops.o \ + ../src/ops/matrixarchate.o \ ../libavr32/src/euclidean/data.o ../libavr32/src/euclidean/euclidean.o \ ../libavr32/src/util.o $(CC) -o $@ $^ $(CFLAGS) From 4ee11ff7e02689dd13dd939e54ec0375aee24c10 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 19 Jan 2018 14:28:06 -0800 Subject: [PATCH 033/117] fix compilation after rebase --- module/live_mode.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/module/live_mode.c b/module/live_mode.c index da3fccea..e9341d33 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -339,6 +339,10 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // tilde: show the variables else if (match_no_mod(m, k, HID_TILDE)) { show_vars = !show_vars; + if (grid_mode != GRID_MODE_OFF) { + show_vars = 1; + grid_mode = GRID_MODE_OFF; + } if (show_vars) dirty |= D_VARS; // combined with this... dirty |= D_LIST; // cheap flag to indicate mode just switched } @@ -351,7 +355,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, } -bool screen_refresh_live(scene_state_t *ss) { +uint8_t screen_refresh_live(scene_state_t *ss) { uint8_t screen_dirty = 0; if (grid_mode != GRID_MODE_OFF && (grid_view_changed || ss->grid.scr_dirty)) { From 813693dc2cefc237317764f8e7dee5770beefe03 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 19 Jan 2018 15:48:26 -0800 Subject: [PATCH 034/117] fixes for live screen --- module/live_mode.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/module/live_mode.c b/module/live_mode.c index e9341d33..487a7b05 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -342,6 +342,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, if (grid_mode != GRID_MODE_OFF) { show_vars = 1; grid_mode = GRID_MODE_OFF; + activity_prev = 0xFF; } if (show_vars) dirty |= D_VARS; // combined with this... dirty |= D_LIST; // cheap flag to indicate mode just switched @@ -360,11 +361,11 @@ uint8_t screen_refresh_live(scene_state_t *ss) { if (grid_mode != GRID_MODE_OFF && (grid_view_changed || ss->grid.scr_dirty)) { grid_view_changed = 0; - screen_dirty = true; + screen_dirty = 0b111111; grid_screen_refresh(ss, grid_mode, grid_page, grid_ctrl, grid_x1, grid_y1, grid_x2, grid_y2); } - if (grid_mode == GRID_MODE_FULL) return true; + if (grid_mode == GRID_MODE_FULL) return 0b11111111; if (dirty & D_INPUT) { line_editor_draw(&le, '>', &line[7]); From b43938b9d2fcd1398204f41bd35528f733847d72 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sat, 20 Jan 2018 16:57:35 -0800 Subject: [PATCH 035/117] update libavr32 --- libavr32 | 2 +- src/ops/er301.h | 2 -- src/ops/fader.h | 2 -- src/ops/matrixarchate.h | 2 -- 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/libavr32 b/libavr32 index 3264a8e1..4d8074cb 160000 --- a/libavr32 +++ b/libavr32 @@ -1 +1 @@ -Subproject commit 3264a8e1ec7d971108a5aa7585392a95b3b60dda +Subproject commit 4d8074cb75bfc7cf6debaa0e2a789a2447503c7c diff --git a/src/ops/er301.h b/src/ops/er301.h index 14c1cc09..81b40f38 100644 --- a/src/ops/er301.h +++ b/src/ops/er301.h @@ -16,8 +16,6 @@ extern const tele_op_t op_SC_CV_SLEW; extern const tele_op_t op_SC_CV_SET; extern const tele_op_t op_SC_CV_OFF; -#define ER301 0xB0 - void ERSend(uint8_t command, uint16_t output, int16_t value, bool set); void ERSet(uint8_t command, command_state_t *cs); void ERCommand(uint8_t command, uint16_t output); diff --git a/src/ops/fader.h b/src/ops/fader.h index 7a02871c..2ac8e035 100644 --- a/src/ops/fader.h +++ b/src/ops/fader.h @@ -6,6 +6,4 @@ extern const tele_op_t op_FADER; extern const tele_op_t op_FB; -#define FADER 0x80 - #endif \ No newline at end of file diff --git a/src/ops/matrixarchate.h b/src/ops/matrixarchate.h index 857782a9..85c90eb4 100644 --- a/src/ops/matrixarchate.h +++ b/src/ops/matrixarchate.h @@ -20,6 +20,4 @@ extern const tele_op_t op_MA_PROW; extern const tele_op_t op_MA_CLR; extern const tele_op_t op_MA_PCLR; -#define MATRIXARCHATE 0xB8 - #endif \ No newline at end of file From 23a51b476715040719635bee09daed5538f33568 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 23 Jan 2018 14:31:49 -0800 Subject: [PATCH 036/117] improved editing --- module/edit_mode.c | 240 ++++++++++++++++++++++++++++++++---------- module/globals.h | 4 + module/line_editor.c | 34 ++++-- module/line_editor.h | 1 - module/live_mode.c | 50 +++++---- module/main.c | 25 ++--- module/pattern_mode.c | 15 +-- src/state.c | 5 + src/state.h | 6 +- 9 files changed, 274 insertions(+), 106 deletions(-) diff --git a/module/edit_mode.c b/module/edit_mode.c index 2d3e92c8..20184591 100644 --- a/module/edit_mode.c +++ b/module/edit_mode.c @@ -19,7 +19,7 @@ #include "usb_protocol_hid.h" static line_editor_t le; -static uint8_t line_no; +static uint8_t line_no1 = 0, line_no2 = 0; static uint8_t script; static error_t status; static char error_msg[TELE_ERROR_MSG_LENGTH]; @@ -33,9 +33,9 @@ static uint8_t dirty; void set_edit_mode() { status = E_OK; error_msg[0] = 0; - line_no = 0; + line_no2 = line_no1 = 0; line_editor_set_command( - &le, ss_get_script_command(&scene_state, script, line_no)); + &le, ss_get_script_command(&scene_state, script, line_no1)); dirty = D_ALL; } @@ -48,23 +48,38 @@ void set_edit_mode_script(uint8_t new_script) { void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { // or C-n: line down if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) { - if (line_no < (SCRIPT_MAX_COMMANDS - 1) && - line_no < ss_get_script_len(&scene_state, script)) { - line_no++; + if (line_no1 < (SCRIPT_MAX_COMMANDS - 1) && + line_no1 < ss_get_script_len(&scene_state, script)) { + line_no1++; line_editor_set_command( - &le, ss_get_script_command(&scene_state, script, line_no)); - dirty |= D_LIST; - dirty |= D_INPUT; + &le, ss_get_script_command(&scene_state, script, line_no1)); + dirty |= D_LIST | D_INPUT; } + line_no2 = line_no1; } // or C-p: line up else if (match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) { - if (line_no) { - line_no--; + if (line_no1) { + line_no1--; line_editor_set_command( - &le, ss_get_script_command(&scene_state, script, line_no)); - dirty |= D_LIST; - dirty |= D_INPUT; + &le, ss_get_script_command(&scene_state, script, line_no1)); + dirty |= D_LIST | D_INPUT; + } + line_no2 = line_no1; + } + // shift- or C-S-n: expand selection down + else if (match_shift(m, k, HID_DOWN) || match_shift_ctrl(m, k, HID_N)) { + if (line_no2 < (SCRIPT_MAX_COMMANDS - 1) && + line_no2 < ss_get_script_len(&scene_state, script) - 1) { + line_no2++; + dirty |= D_LIST | D_INPUT; + } + } + // shift- or C-S-p: expand selection up + else if (match_shift(m, k, HID_UP) || match_shift_ctrl(m, k, HID_P)) { + if (line_no2) { + line_no2--; + dirty |= D_LIST | D_INPUT; } } // [: previous script @@ -75,12 +90,12 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { script--; else script = SCRIPT_COUNT - 2; // due to TEMP_SCRIPT - if (line_no > ss_get_script_len(&scene_state, script)) - line_no = ss_get_script_len(&scene_state, script); + if (line_no1 > ss_get_script_len(&scene_state, script)) + line_no1 = ss_get_script_len(&scene_state, script); line_editor_set_command( - &le, ss_get_script_command(&scene_state, script, line_no)); - dirty |= D_LIST; - dirty |= D_INPUT; + &le, ss_get_script_command(&scene_state, script, line_no1)); + line_no2 = line_no1; + dirty |= D_LIST | D_INPUT; } // ]: next script else if (match_no_mod(m, k, HID_CLOSE_BRACKET)) { @@ -88,28 +103,123 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { error_msg[0] = 0; script++; if (script >= SCRIPT_COUNT - 1) script = 0; // due to TEMP_SCRIPT - if (line_no > ss_get_script_len(&scene_state, script)) - line_no = ss_get_script_len(&scene_state, script); + if (line_no1 > ss_get_script_len(&scene_state, script)) + line_no1 = ss_get_script_len(&scene_state, script); line_editor_set_command( - &le, ss_get_script_command(&scene_state, script, line_no)); - dirty |= D_LIST; - dirty |= D_INPUT; + &le, ss_get_script_command(&scene_state, script, line_no1)); + line_no2 = line_no1; + dirty |= D_LIST | D_INPUT; + } + // alt-: move selected lines down + else if (match_alt(m, k, HID_DOWN)) { + u8 l1 = min(line_no1, line_no2); + u8 l2 = max(line_no1, line_no2); + if (l2 < SCRIPT_MAX_COMMANDS - 1 && + l2 < ss_get_script_len(&scene_state, script) - 1) { + tele_command_t temp; + ss_copy_script_command(&temp, &scene_state, script, l2 + 1); + ss_delete_script_command(&scene_state, script, l2 + 1); + ss_insert_script_command(&scene_state, script, l1, &temp); + line_no1++; + line_no2++; + dirty |= D_LIST | D_INPUT; + } + } + // alt-: move selected lines up + else if (match_alt(m, k, HID_UP)) { + u8 l1 = min(line_no1, line_no2); + u8 l2 = max(line_no1, line_no2); + if (l1) { + tele_command_t temp; + ss_copy_script_command(&temp, &scene_state, script, l1 - 1); + ss_delete_script_command(&scene_state, script, l1 - 1); + ss_insert_script_command(&scene_state, script, l2, &temp); + line_no1--; + line_no2--; + dirty |= D_LIST | D_INPUT; + } } // ctrl-x or alt-x: override line editors cut else if (match_ctrl(m, k, HID_X) || match_alt(m, k, HID_X)) { - line_editor_set_copy_buffer(line_editor_get(&le)); - ss_delete_script_command(&scene_state, script, line_no); - if (line_no > ss_get_script_len(&scene_state, script)) { - line_no = ss_get_script_len(&scene_state, script); + if (line_no1 == line_no2) { + strcpy(copy_buffer[0], line_editor_get(&le)); + copy_buffer_len = 1; + ss_delete_script_command(&scene_state, script, line_no1); + } + else { + copy_buffer_len = 0; + for (u8 l = min(line_no1, line_no2); l <= max(line_no1, line_no2); + l++) + print_command(ss_get_script_command(&scene_state, script, l), + copy_buffer[copy_buffer_len++]); + for (s8 l = max(line_no1, line_no2); l >= min(line_no1, line_no2); + l--) + ss_delete_script_command(&scene_state, script, l); + } + + if (line_no1 > ss_get_script_len(&scene_state, script)) { + line_no1 = ss_get_script_len(&scene_state, script); } line_editor_set_command( - &le, ss_get_script_command(&scene_state, script, line_no)); + &le, ss_get_script_command(&scene_state, script, line_no1)); + line_no2 = line_no1; - dirty |= D_LIST; - dirty |= D_INPUT; + dirty |= D_LIST | D_INPUT; + } + // ctrl-c or alt-c: override line editors copy for multi selection + else if (match_ctrl(m, k, HID_C) || match_alt(m, k, HID_C)) { + if (line_no1 == line_no2) { + bool processed = line_editor_process_keys(&le, k, m, is_held_key); + if (processed) dirty |= D_INPUT; + return; + } + + copy_buffer_len = 0; + for (u8 l = min(line_no1, line_no2); l <= max(line_no1, line_no2); l++) + print_command(ss_get_script_command(&scene_state, script, l), + copy_buffer[copy_buffer_len++]); + } + // ctrl-v or alt-v: override line editors paste for multi selection + else if (match_ctrl(m, k, HID_V) || match_alt(m, k, HID_V)) { + if (copy_buffer_len == 0) return; + + u8 idx = min(line_no1, line_no2); + tele_command_t command; + for (u8 i = 0; i < copy_buffer_len; i++) { + if (parse(copy_buffer[i], &command, error_msg) != E_OK) continue; + if (validate(&command, error_msg) != E_OK) continue; + if (command.length == 0) continue; + + ss_insert_script_command(&scene_state, script, idx++, &command); + if (line_no1 < (SCRIPT_MAX_COMMANDS - 1)) line_no1++; + if (line_no2 < (SCRIPT_MAX_COMMANDS - 1)) line_no2++; + if (idx >= SCRIPT_MAX_COMMANDS) break; + } + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no1)); + dirty |= D_LIST | D_INPUT; + } + // alt-delete: remove selected lines + else if (match_alt(m, k, HID_DELETE)) { + for (s8 l = max(line_no1, line_no2); l >= min(line_no1, line_no2); l--) + ss_delete_script_command(&scene_state, script, l); + if (line_no1 > ss_get_script_len(&scene_state, script)) + line_no1 = ss_get_script_len(&scene_state, script); + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no1)); + line_no2 = line_no1; + dirty |= D_LIST | D_INPUT; } // : enter command else if (match_no_mod(m, k, HID_ENTER)) { + if (line_no1 != line_no2) { + line_no2 = line_no1; + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no1)); + dirty |= D_LIST | D_INPUT; + return; + } + dirty |= D_MESSAGE; // something will happen tele_command_t command; @@ -123,23 +233,31 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { return; // quit, screen_refresh_edit will display the error message if (command.length == 0) { // blank line, delete the command - ss_delete_script_command(&scene_state, script, line_no); - if (line_no > ss_get_script_len(&scene_state, script)) { - line_no = ss_get_script_len(&scene_state, script); + ss_delete_script_command(&scene_state, script, line_no1); + if (line_no1 > ss_get_script_len(&scene_state, script)) { + line_no1 = ss_get_script_len(&scene_state, script); } } else { - ss_overwrite_script_command(&scene_state, script, line_no, + ss_overwrite_script_command(&scene_state, script, line_no1, &command); - if (line_no < SCRIPT_MAX_COMMANDS - 1) { line_no++; } + if (line_no1 < SCRIPT_MAX_COMMANDS - 1) { line_no1++; } } line_editor_set_command( - &le, ss_get_script_command(&scene_state, script, line_no)); - dirty |= D_LIST; - dirty |= D_INPUT; + &le, ss_get_script_command(&scene_state, script, line_no1)); + line_no2 = line_no1; + dirty |= D_LIST | D_INPUT; } // shift-: insert command else if (match_shift(m, k, HID_ENTER)) { + if (line_no1 != line_no2) { + line_no2 = line_no1; + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no1)); + dirty |= D_LIST | D_INPUT; + return; + } + dirty |= D_MESSAGE; // something will happen tele_command_t command; @@ -153,21 +271,30 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { return; // quit, screen_refresh_edit will display the error message if (command.length > 0) { - ss_insert_script_command(&scene_state, script, line_no, &command); - if (line_no < (SCRIPT_MAX_COMMANDS - 1)) { line_no++; } + ss_insert_script_command(&scene_state, script, line_no1, &command); + if (line_no1 < (SCRIPT_MAX_COMMANDS - 1)) { line_no1++; } } line_editor_set_command( - &le, ss_get_script_command(&scene_state, script, line_no)); - dirty |= D_LIST; - dirty |= D_INPUT; + &le, ss_get_script_command(&scene_state, script, line_no1)); + line_no2 = line_no1; + dirty |= D_LIST | D_INPUT; } - // alt-slash comment toggle current line + // alt-slash comment toggle selected lines else if (match_alt(m, k, HID_SLASH)) { - ss_toggle_script_comment(&scene_state, script, line_no); + for (u8 l = min(line_no1, line_no2); l <= max(line_no1, line_no2); l++) + ss_toggle_script_comment(&scene_state, script, l); dirty |= D_LIST; } else { // pass the key though to the line editor + if (line_no1 != line_no2) { + line_no2 = line_no1; + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no1)); + dirty |= D_LIST | D_INPUT; + return; + } + bool processed = line_editor_process_keys(&le, k, m, is_held_key); if (processed) dirty |= D_INPUT; } @@ -179,6 +306,8 @@ void screen_mutes_updated() { uint8_t screen_refresh_edit() { uint8_t screen_dirty = 0; + u8 sel1 = min(line_no1, line_no2); + u8 sel2 = max(line_no1, line_no2); if (dirty & D_INPUT) { char prefix = script + '1'; @@ -187,12 +316,15 @@ uint8_t screen_refresh_edit() { else if (script == INIT_SCRIPT) prefix = 'I'; - line_editor_draw(&le, prefix, &line[7]); - // maybe find a better way than stomping it? - if (ss_get_mute(&scene_state, script)) { - char shaded[2] = { prefix, '\0' }; - font_string_region_clip(&line[7], shaded, 0, 0, 0x4, 0); - } + if (sel1 == sel2) + line_editor_draw(&le, prefix, &line[7]); + else + region_fill(&line[7], 0); + + char script_no[2] = { prefix, '\0' }; + font_string_region_clip(&line[7], script_no, 0, 0, + ss_get_mute(&scene_state, script) ? 4 : 15, 0); + screen_dirty |= (1 << 7); dirty &= ~D_INPUT; } @@ -220,14 +352,14 @@ uint8_t screen_refresh_edit() { dirty &= ~D_MESSAGE; } + char s[32]; if (dirty & D_LIST) { for (int i = 0; i < 6; i++) { - uint8_t a = line_no == i; + uint8_t a = i >= sel1 && i <= sel2; uint8_t fg = ss_get_script_comment(&scene_state, script, i) ? 0x7 : 0xf; region_fill(&line[i], a); if (ss_get_script_len(&scene_state, script) > i) { - char s[32]; print_command(ss_get_script_command(&scene_state, script, i), s); region_string(&line[i], s, 2, 0, fg, a, 0); diff --git a/module/globals.h b/module/globals.h index 774e0f89..4fdba14e 100644 --- a/module/globals.h +++ b/module/globals.h @@ -36,4 +36,8 @@ typedef enum { void set_mode(tele_mode_t mode); void set_last_mode(void); +// global copy buffer +extern char copy_buffer[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; +extern uint8_t copy_buffer_len; + #endif diff --git a/module/line_editor.c b/module/line_editor.c index 2e4c654e..c468b814 100644 --- a/module/line_editor.c +++ b/module/line_editor.c @@ -3,6 +3,7 @@ #include // this +#include "globals.h" #include "keyboard_helper.h" // teletype @@ -17,9 +18,6 @@ #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) { @@ -66,6 +64,22 @@ bool line_editor_process_keys(line_editor_t *le, uint8_t k, uint8_t m, le->cursor = le->length; return true; } + // ctrl-: move cursor to previous word + else if (match_ctrl(m, k, HID_LEFT)) { + while (le->cursor) { + le->cursor--; + if (!le->cursor || le->buffer[le->cursor - 1] == ' ') break; + } + return true; + } + // ctrl-: move cursor to next word + else if (match_ctrl(m, k, HID_RIGHT)) { + while (le->cursor < le->length) { + le->cursor++; + if (le->buffer[le->cursor - 1] == ' ') break; + } + return true; + } // 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) { @@ -103,7 +117,7 @@ bool line_editor_process_keys(line_editor_t *le, uint8_t k, uint8_t m, return true; } // alt- or ctrl-w: delete from cursor to beginning of word - else if (match_alt(m, k, HID_DELETE) || match_ctrl(m, k, HID_W)) { + else if (match_alt(m, k, HID_BACKSPACE) || match_ctrl(m, k, HID_W)) { while (le->cursor) { // delete a character le->cursor--; @@ -120,18 +134,20 @@ bool line_editor_process_keys(line_editor_t *le, uint8_t k, uint8_t m, } // 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); + strcpy(copy_buffer[0], le->buffer); + copy_buffer_len = 1; 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); + strcpy(copy_buffer[0], le->buffer); + copy_buffer_len = 1; 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); + line_editor_set(le, copy_buffer[0]); return true; } else if (no_mod(m) || mod_only_shift(m)) { @@ -164,7 +180,3 @@ void line_editor_draw(line_editor_t *le, char prefix, region *reg) { 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); -} diff --git a/module/line_editor.h b/module/line_editor.h index 6b4f48a2..902ada98 100644 --- a/module/line_editor.h +++ b/module/line_editor.h @@ -22,5 +22,4 @@ 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 diff --git a/module/live_mode.c b/module/live_mode.c index 487a7b05..99c70b88 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -109,8 +109,7 @@ void set_live_mode() { dirty = D_ALL; activity_prev = 0xFF; grid_view_changed = true; - if (grid_mode == GRID_MODE_FULL) - grid_mode = GRID_MODE_EDIT; + if (grid_mode == GRID_MODE_FULL) grid_mode = GRID_MODE_EDIT; } void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, @@ -151,7 +150,8 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, if (++grid_mode == GRID_MODE_LAST) { grid_mode = GRID_MODE_OFF; set_live_mode(); - } else { + } + else { if (grid_mode == GRID_MODE_FULL) { grid_x2 = grid_x1; grid_y2 = grid_y1; @@ -178,18 +178,30 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // C-: move grid cursor else if (match_ctrl(m, k, HID_LEFT) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_LEFT))) { - grid_x1 = (grid_x1 + GRID_MAX_DIMENSION - 1) % GRID_MAX_DIMENSION; - grid_x2 = grid_x1; - grid_y2 = grid_y1; - grid_view_changed = true; + if (grid_mode == GRID_MODE_OFF) { + bool processed = line_editor_process_keys(&le, k, m, is_held_key); + if (processed) dirty |= D_INPUT; + } + else { + grid_x1 = (grid_x1 + GRID_MAX_DIMENSION - 1) % GRID_MAX_DIMENSION; + grid_x2 = grid_x1; + grid_y2 = grid_y1; + grid_view_changed = true; + } } // C-: move grid cursor else if (match_ctrl(m, k, HID_RIGHT) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_RIGHT))) { - grid_x1 = (grid_x1 + 1) % GRID_MAX_DIMENSION; - grid_x2 = grid_x1; - grid_y2 = grid_y1; - grid_view_changed = true; + if (grid_mode == GRID_MODE_OFF) { + bool processed = line_editor_process_keys(&le, k, m, is_held_key); + if (processed) dirty |= D_INPUT; + } + else { + grid_x1 = (grid_x1 + 1) % GRID_MAX_DIMENSION; + grid_x2 = grid_x1; + grid_y2 = grid_y1; + grid_view_changed = true; + } } // C-S-: expand grid area up else if (match_shift_ctrl(m, k, HID_UP) && grid_mode != GRID_MODE_FULL) { @@ -230,7 +242,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, } // C-: insert coordinates / size else if (!is_held_key && match_ctrl(m, k, HID_PRINTSCREEN) && - grid_mode == GRID_MODE_EDIT) { + grid_mode == GRID_MODE_EDIT) { u8 area_x, area_y, area_w, area_h; if (grid_x1 < grid_x2) { area_x = grid_x1; @@ -286,7 +298,8 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, } // C-<\>: toggle control view else if (match_ctrl(m, k, HID_BACKSLASH) || - (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_BACKSLASH))) { + (grid_mode == GRID_MODE_FULL && + match_no_mod(m, k, HID_BACKSLASH))) { grid_ctrl = !grid_ctrl; grid_view_changed = true; } @@ -358,12 +371,13 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, uint8_t screen_refresh_live(scene_state_t *ss) { uint8_t screen_dirty = 0; - - if (grid_mode != GRID_MODE_OFF && (grid_view_changed || ss->grid.scr_dirty)) { + + if (grid_mode != GRID_MODE_OFF && + (grid_view_changed || ss->grid.scr_dirty)) { grid_view_changed = 0; screen_dirty = 0b111111; - grid_screen_refresh(ss, grid_mode, - grid_page, grid_ctrl, grid_x1, grid_y1, grid_x2, grid_y2); + grid_screen_refresh(ss, grid_mode, grid_page, grid_ctrl, grid_x1, + grid_y1, grid_x2, grid_y2); } if (grid_mode == GRID_MODE_FULL) return 0b11111111; @@ -407,7 +421,7 @@ uint8_t screen_refresh_live(scene_state_t *ss) { if (show_vars && ((dirty & D_VARS) || (dirty & D_LIST)) && grid_mode == GRID_MODE_OFF) { - int16_t* vp = + int16_t *vp = &scene_state.variables .a; // 8 int16_t all in a row, point at the first one // relies on variable ordering. see: src/state.h diff --git a/module/main.c b/module/main.c index 9c9eaee2..aa71efe8 100644 --- a/module/main.c +++ b/module/main.c @@ -51,11 +51,7 @@ #ifdef TELETYPE_PROFILE #include "profile.h" -profile_t - prof_Script[SCRIPT_COUNT], - prof_Delay[DELAY_SIZE], - prof_CV, - prof_ADC, +profile_t prof_Script[SCRIPT_COUNT], prof_Delay[DELAY_SIZE], prof_CV, prof_ADC, prof_ScreenRefresh; void tele_profile_script(size_t s) { @@ -87,6 +83,8 @@ region line[8] = { {.w = 128, .h = 8, .x = 0, .y = 32 }, {.w = 128, .h = 8, .x = 0, .y = 40 }, {.w = 128, .h = 8, .x = 0, .y = 48 }, {.w = 128, .h = 8, .x = 0, .y = 56 } }; +char copy_buffer[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; +uint8_t copy_buffer_len = 0; //////////////////////////////////////////////////////////////////////////////// @@ -124,7 +122,7 @@ static softTimer_t hidTimer = {.next = NULL, .prev = NULL }; static softTimer_t metroTimer = {.next = NULL, .prev = NULL }; static softTimer_t monomePollTimer = {.next = NULL, .prev = NULL }; static softTimer_t monomeRefreshTimer = {.next = NULL, .prev = NULL }; -static softTimer_t gridFaderTimer = { .next = NULL, .prev = NULL }; +static softTimer_t gridFaderTimer = {.next = NULL, .prev = NULL }; //////////////////////////////////////////////////////////////////////////////// @@ -429,9 +427,7 @@ void handler_MscConnect(int32_t data) { } void handler_Trigger(int32_t data) { - if (!ss_get_mute(&scene_state, data)) { - run_script(&scene_state, data); - } + if (!ss_get_mute(&scene_state, data)) { run_script(&scene_state, data); } } void handler_ScreenRefresh(int32_t data) { @@ -604,7 +600,8 @@ void set_last_mode() { //////////////////////////////////////////////////////////////////////////////// // key handling -void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key, bool is_release) { +void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key, + bool is_release) { // reset inactivity counter ss_counter = 0; if (mode == M_SCREENSAVER) { @@ -613,7 +610,7 @@ void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key, bool is_re return; #endif } - + // release is a special case for live mode if (is_release) { if (mode == M_LIVE) @@ -638,7 +635,8 @@ void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key, bool is_re process_preset_r_keys(key, mod_key, is_held_key); break; case M_HELP: process_help_keys(key, mod_key, is_held_key); break; - case M_SCREENSAVER: break; // impossible + case M_SCREENSAVER: + break; // impossible } } @@ -679,7 +677,7 @@ bool process_global_keys(uint8_t k, uint8_t m, bool is_held_key) { return true; } // -?: help text, or return to last mode - else if (match_shift_alt(m, k, HID_SLASH)) { + else if (match_shift_alt(m, k, HID_SLASH) || match_alt(m, k, HID_H)) { if (mode == M_HELP) set_last_mode(); else { @@ -974,7 +972,6 @@ int main(void) { print_dbg_ulong(profile_delta_us(&prof_ADC)); print_dbg("\r\nScreen Refresh:\t"); print_dbg_ulong(profile_delta_us(&prof_ScreenRefresh)); - } #endif } diff --git a/module/pattern_mode.c b/module/pattern_mode.c index 7bdcd651..6a9e954d 100644 --- a/module/pattern_mode.c +++ b/module/pattern_mode.c @@ -17,7 +17,7 @@ #include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h" #include "usb_protocol_hid.h" -static int16_t copy_buffer; +static int16_t value_copy_buffer; static uint8_t pattern; // which pattern are we editting static uint8_t base; // base + offset determine what we are editting static uint8_t offset; @@ -206,7 +206,8 @@ void process_pattern_keys(uint8_t k, uint8_t m, bool is_held_key) { // alt-x: cut value (n.b. ctrl-x not supported) else if (match_alt(m, k, HID_X)) { editing_number = false; - copy_buffer = ss_get_pattern_val(&scene_state, pattern, base + offset); + value_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); @@ -221,15 +222,16 @@ void process_pattern_keys(uint8_t k, uint8_t m, bool is_held_key) { // alt-c: copy value (n.b. ctrl-c not supported) else if (match_alt(m, k, HID_C)) { if (editing_number) - copy_buffer = edit_buffer; + value_copy_buffer = edit_buffer; else - copy_buffer = + value_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)) { editing_number = false; - ss_set_pattern_val(&scene_state, pattern, base + offset, copy_buffer); + ss_set_pattern_val(&scene_state, pattern, base + offset, + value_copy_buffer); dirty = true; } // shift-alt-v: insert value @@ -243,7 +245,8 @@ void process_pattern_keys(uint8_t k, uint8_t m, bool is_held_key) { 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); + ss_set_pattern_val(&scene_state, pattern, base + offset, + value_copy_buffer); dirty = true; } // shift-l: set length to current position diff --git a/src/state.c b/src/state.c index 04bb86fe..b73f778d 100644 --- a/src/state.c +++ b/src/state.c @@ -222,6 +222,11 @@ const tele_command_t *ss_get_script_command(scene_state_t *ss, return &ss->scripts[script_idx].c[c_idx]; } +void ss_copy_script_command(tele_command_t *dest, scene_state_t *ss, + script_number_t script_idx, size_t c_idx) { + memcpy(dest, &ss->scripts[script_idx].c[c_idx], sizeof(tele_command_t)); +} + // private static void ss_set_script_command(scene_state_t *ss, script_number_t script_idx, size_t c_idx, const tele_command_t *cmd) { diff --git a/src/state.h b/src/state.h index 07a04f3e..fee7b0eb 100644 --- a/src/state.h +++ b/src/state.h @@ -53,7 +53,7 @@ // SCENE STATE ///////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -//clang-format off +// clang-format off typedef struct { // Maintaining this order allows for efficient access to the group // WARNING: DO NOT CHANGE THE ORDER OF VARIABLES a THROUGH t @@ -100,7 +100,7 @@ typedef struct { scale_data_t param_range; scale_t param_scale; } scene_variables_t; -//clang-format on +// clang-format on typedef struct { int16_t idx; @@ -243,6 +243,8 @@ uint8_t ss_get_script_len(scene_state_t *ss, script_number_t idx); const tele_command_t *ss_get_script_command(scene_state_t *ss, script_number_t script_idx, size_t c_idx); +void ss_copy_script_command(tele_command_t *dest, scene_state_t *ss, + script_number_t script_idx, size_t c_idx); bool ss_get_script_comment(scene_state_t *ss, script_number_t script_idx, size_t c_idx); void ss_toggle_script_comment(scene_state_t *ss, script_number_t script_idx, From 92ecce9c9c388598fad36c14ad3bc635626ec41a Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 23 Jan 2018 15:49:59 -0800 Subject: [PATCH 037/117] update grid visualizer --- module/grid.c | 4 +- module/live_mode.c | 101 ++++++++++++++++++++------------------------- 2 files changed, 46 insertions(+), 59 deletions(-) diff --git a/module/grid.c b/module/grid.c index 26d40214..bc33e394 100644 --- a/module/grid.c +++ b/module/grid.c @@ -833,8 +833,8 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, _x1 = min(x1, x2) * cell; _y1 = min(y1, y2) * cell; if (full_grid) { - _x2 = _x1 + size + 1; - _y2 = _y1 + size + 1; + _x2 = (max(x1, x2) + 1) * cell - 2; + _y2 = (max(y1, y2) + 1) * cell - 2; } else { _x2 = (max(x1, x2) + 1) * cell - 1; _y2 = (max(y1, y2) + 1) * cell - 1; diff --git a/module/live_mode.c b/module/live_mode.c index 99c70b88..e40c7074 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -115,9 +115,11 @@ void set_live_mode() { void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, scene_state_t *ss) { if (is_release) { - if (match_ctrl(m, k, HID_SPACEBAR) || + if (match_alt(m, k, HID_SPACEBAR) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SPACEBAR))) { grid_process_key(ss, grid_x1, grid_y1, 0, 1); + if (grid_x1 != grid_x2 || grid_y1 != grid_y2) + grid_process_key(ss, grid_x2, grid_y2, 0, 1); } return; } @@ -144,104 +146,89 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, dirty |= D_INPUT; } } - // C-G: toggle grid view - else if (match_ctrl(m, k, HID_G) || + // A-G: toggle grid view + else if (match_alt(m, k, HID_G) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_G))) { if (++grid_mode == GRID_MODE_LAST) { grid_mode = GRID_MODE_OFF; set_live_mode(); } - else { - if (grid_mode == GRID_MODE_FULL) { - grid_x2 = grid_x1; - grid_y2 = grid_y1; - } - grid_view_changed = true; - } + grid_view_changed = true; } - // C-: move grid cursor - else if (match_ctrl(m, k, HID_UP) || + // A-: move grid cursor + else if (match_alt(m, k, HID_UP) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_UP))) { grid_y1 = (grid_y1 + GRID_MAX_DIMENSION - 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; grid_view_changed = true; } - // C-: move grid cursor - else if (match_ctrl(m, k, HID_DOWN) || + // A-: move grid cursor + else if (match_alt(m, k, HID_DOWN) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_DOWN))) { grid_y1 = (grid_y1 + 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; grid_view_changed = true; } - // C-: move grid cursor - else if (match_ctrl(m, k, HID_LEFT) || + // A-: move grid cursor + else if (match_alt(m, k, HID_LEFT) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_LEFT))) { - if (grid_mode == GRID_MODE_OFF) { - bool processed = line_editor_process_keys(&le, k, m, is_held_key); - if (processed) dirty |= D_INPUT; - } - else { - grid_x1 = (grid_x1 + GRID_MAX_DIMENSION - 1) % GRID_MAX_DIMENSION; - grid_x2 = grid_x1; - grid_y2 = grid_y1; - grid_view_changed = true; - } + grid_x1 = (grid_x1 + GRID_MAX_DIMENSION - 1) % GRID_MAX_DIMENSION; + grid_x2 = grid_x1; + grid_y2 = grid_y1; + grid_view_changed = true; } - // C-: move grid cursor - else if (match_ctrl(m, k, HID_RIGHT) || + // A-: move grid cursor + else if (match_alt(m, k, HID_RIGHT) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_RIGHT))) { - if (grid_mode == GRID_MODE_OFF) { - bool processed = line_editor_process_keys(&le, k, m, is_held_key); - if (processed) dirty |= D_INPUT; - } - else { - grid_x1 = (grid_x1 + 1) % GRID_MAX_DIMENSION; - grid_x2 = grid_x1; - grid_y2 = grid_y1; - grid_view_changed = true; - } + grid_x1 = (grid_x1 + 1) % GRID_MAX_DIMENSION; + grid_x2 = grid_x1; + grid_y2 = grid_y1; + grid_view_changed = true; } - // C-S-: expand grid area up - else if (match_shift_ctrl(m, k, HID_UP) && grid_mode != GRID_MODE_FULL) { + // A-S-: expand grid area up + else if (match_shift_alt(m, k, HID_UP) || + (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_UP))) { if (grid_y2 > 0) { grid_y2--; grid_view_changed = true; } } - // C-S-: expand grid area down - else if (match_shift_ctrl(m, k, HID_DOWN) && grid_mode != GRID_MODE_FULL) { + // A-S-: expand grid area down + else if (match_shift_alt(m, k, HID_DOWN) || + (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_DOWN))) { if (grid_y2 < GRID_MAX_DIMENSION - 1) { grid_y2++; grid_view_changed = true; } } - // C-S-: expand grid area left - else if (match_shift_ctrl(m, k, HID_LEFT) && grid_mode != GRID_MODE_FULL) { + // A-S-: expand grid area left + else if (match_shift_alt(m, k, HID_LEFT) || + (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_LEFT))) { if (grid_x2 > 0) { grid_x2--; grid_view_changed = true; } } - // C-S-: expand grid area right - else if (match_shift_ctrl(m, k, HID_RIGHT) && grid_mode != GRID_MODE_FULL) { + // A-S-: expand grid area right + else if (match_shift_alt(m, k, HID_RIGHT) || + (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_RIGHT))) { if (grid_x2 < GRID_MAX_DIMENSION - 1) { grid_x2++; grid_view_changed = true; } } - // C-: emulate grid press - else if (!is_held_key && (match_ctrl(m, k, HID_SPACEBAR) || + // A-: emulate grid press + else if (!is_held_key && (match_alt(m, k, HID_SPACEBAR) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SPACEBAR)))) { - grid_x2 = grid_x1; - grid_y2 = grid_y1; - grid_view_changed = true; grid_process_key(ss, grid_x1, grid_y1, 1, 1); + if (grid_x1 != grid_x2 || grid_y1 != grid_y2) + grid_process_key(ss, grid_x2, grid_y2, 1, 1); } - // C-: insert coordinates / size - else if (!is_held_key && match_ctrl(m, k, HID_PRINTSCREEN) && + // A-: insert coordinates / size + else if (!is_held_key && match_alt(m, k, HID_PRINTSCREEN) && grid_mode == GRID_MODE_EDIT) { u8 area_x, area_y, area_w, area_h; if (grid_x1 < grid_x2) { @@ -290,14 +277,14 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, line_editor_process_keys(&le, HID_SPACEBAR, HID_MODIFIER_NONE, false); dirty |= D_INPUT; } - // C-: toggle grid page - else if (match_ctrl(m, k, HID_SLASH) || + // A-: toggle grid page + else if (match_alt(m, k, HID_SLASH) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SLASH))) { if (++grid_page > 1) grid_page = 0; grid_view_changed = true; } - // C-<\>: toggle control view - else if (match_ctrl(m, k, HID_BACKSLASH) || + // A-<\>: toggle control view + else if (match_alt(m, k, HID_BACKSLASH) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_BACKSLASH))) { grid_ctrl = !grid_ctrl; From d33059d0a49aa66a52dfee5c2ad7d400baa8d2c9 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 23 Jan 2018 18:56:04 -0800 Subject: [PATCH 038/117] fixes, adjustments for brightness --- module/grid.c | 132 +++++++++++++++++++++++++-------------------- src/ops/grid_ops.c | 9 ++-- src/state.h | 2 +- 3 files changed, 81 insertions(+), 62 deletions(-) diff --git a/module/grid.c b/module/grid.c index bc33e394..543f41ca 100644 --- a/module/grid.c +++ b/module/grid.c @@ -9,6 +9,7 @@ #define GRID_MAX_KEY_PRESSED 10 #define GRID_KEY_HOLD_DELAY 700 #define GRID_KEY_REPEAT_RATE 40 +#define GRID_ON_BRIGHTNESS 13 static const u8 glyph[16][6] = { { @@ -161,8 +162,8 @@ static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); static bool grid_within_area(u8 x, u8 y, grid_common_t *gc); -static void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level); -static void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page); +static void grid_fill_area(u8 x, u8 y, u8 w, u8 h, s8 level); +static void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, s8 level, u8 page); void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { if (timers_uninitialized) { @@ -462,7 +463,7 @@ void grid_refresh(scene_state_t *ss) { y = GXYC.y + GXY.value_y; grid_fill_area(GXYC.x, y, GXYC.w, 1, GXYC.level); grid_fill_area(x, GXYC.y, 1, GXYC.h, GXYC.level); - grid_fill_area(x, y, 1, 1, 15); + grid_fill_area(x, y, 1, 1, GRID_ON_BRIGHTNESS); } } } @@ -472,56 +473,56 @@ void grid_refresh(scene_state_t *ss) { if (GFC.enabled && SG.group[GFC.group].enabled) { switch (GF.type) { case FADER_CH_BAR: - grid_fill_area(GFC.x, GFC.y, GF.value + 1, GFC.h, 15); + grid_fill_area(GFC.x, GFC.y, GF.value + 1, GFC.h, GRID_ON_BRIGHTNESS); grid_fill_area(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.level); break; case FADER_CV_BAR: grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.level); - grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, 15); + grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, GRID_ON_BRIGHTNESS); break; case FADER_CH_DOT: - grid_fill_area(GFC.x + GF.value, GFC.y, 1, GFC.h, 15); + grid_fill_area(GFC.x + GF.value, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS); break; case FADER_CV_DOT: - grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, 15); + grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, GRID_ON_BRIGHTNESS); break; case FADER_FH_BAR: fv = (((GFC.w - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; - grid_fill_area(GFC.x, GFC.y, ff + 1, GFC.h, 15); + grid_fill_area(GFC.x, GFC.y, ff + 1, GFC.h, GRID_ON_BRIGHTNESS); if (fp) grid_fill_area(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp); - grid_fill_area(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, 15); + grid_fill_area(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS); break; case FADER_FV_BAR: fv = (((GFC.h - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; - grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff + 1, 15); + grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff + 1, GRID_ON_BRIGHTNESS); if (fp) grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, fp); - grid_fill_area(GFC.x, GFC.y, GFC.w, 1, 15); + grid_fill_area(GFC.x, GFC.y, GFC.w, 1, GRID_ON_BRIGHTNESS); break; case FADER_FH_DOT: - grid_fill_area(GFC.x, GFC.y, 1, GFC.h, 15); - grid_fill_area(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, 15); + grid_fill_area(GFC.x, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS); + grid_fill_area(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS); fv = (((GFC.w - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; if (fp) grid_fill_area(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp); else if (ff) - grid_fill_area(GFC.x + ff, GFC.y, 1, GFC.h, 15); + grid_fill_area(GFC.x + ff, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS); break; case FADER_FV_DOT: - grid_fill_area(GFC.x, GFC.y + GFC.h - 1, GFC.w, 1, 15); - grid_fill_area(GFC.x, GFC.y, GFC.w, 1, 15); + grid_fill_area(GFC.x, GFC.y + GFC.h - 1, GFC.w, 1, GRID_ON_BRIGHTNESS); + grid_fill_area(GFC.x, GFC.y, GFC.w, 1, GRID_ON_BRIGHTNESS); fv = (((GFC.h - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; if (fp) grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, fp); else if (ff) - grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, 1, 15); + grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, 1, GRID_ON_BRIGHTNESS); break; } } @@ -529,7 +530,7 @@ void grid_refresh(scene_state_t *ss) { for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.enabled && SG.group[GBC.group].enabled) - grid_fill_area(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.level); + grid_fill_area(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? GRID_ON_BRIGHTNESS : GBC.level); u16 led; for (u16 i = 0; i < size_x; i++) @@ -539,14 +540,17 @@ void grid_refresh(scene_state_t *ss) { if (SG.leds[i][j] >= 0) monomeLedBuffer[led] = SG.leds[i][j]; - else if (SG.leds[i][j] == LED_DIM) - monomeLedBuffer[led] >>= 1; + else if (SG.leds[i][j] == LED_DIM) { + if (monomeLedBuffer[led] > 3) + monomeLedBuffer[led] -= 3; + else + monomeLedBuffer[led] = 0; + } else if (SG.leds[i][j] == LED_BRI) { - monomeLedBuffer[led] <<= 1; - if (monomeLedBuffer[led] > 15) + if (monomeLedBuffer[led] > 12) monomeLedBuffer[led] = 15; - else if (monomeLedBuffer[led] < 1) - monomeLedBuffer[led] = 1; + else + monomeLedBuffer[led] += 3; } if (monomeLedBuffer[led] < SG.dim) @@ -569,7 +573,7 @@ void grid_refresh(scene_state_t *ss) { SG.grid_dirty = 0; } -void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level) { +void grid_fill_area(u8 x, u8 y, u8 w, u8 h, s8 level) { if (level == LED_OFF) return; u16 index; @@ -580,7 +584,12 @@ void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level) { for (u16 _x = x; _x < x_end; _x++) for (u16 _y = y; _y < y_end; _y++) { index = _x + _y * size_x; - if (index < MONOME_MAX_LED_BYTES) monomeLedBuffer[index] >>= 1; + if (index < MONOME_MAX_LED_BYTES) { + if (monomeLedBuffer[index] > 3) + monomeLedBuffer[index] -= 3; + else + monomeLedBuffer[index] = 0; + } } } else if (level == LED_BRI) { @@ -588,9 +597,10 @@ void grid_fill_area(u8 x, u8 y, u8 w, u8 h, u8 level) { for (u16 _y = y; _y < y_end; _y++) { index = _x + _y * size_x; if (index < MONOME_MAX_LED_BYTES) { - monomeLedBuffer[index] <<= 1; - if (monomeLedBuffer[index] > 15) + if (monomeLedBuffer[index] > 12) monomeLedBuffer[index] = 15; + else + monomeLedBuffer[index] += 3; } } } @@ -706,7 +716,7 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, y = GXYC.y + GXY.value_y; grid_fill_area_scr(GXYC.x, y, GXYC.w, 1, GXYC.level, page); grid_fill_area_scr(x, GXYC.y, 1, GXYC.h, GXYC.level, page); - grid_fill_area_scr(x, y, 1, 1, 15, page); + grid_fill_area_scr(x, y, 1, 1, GRID_ON_BRIGHTNESS, page); } } } @@ -716,56 +726,56 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, if (GFC.enabled && SG.group[GFC.group].enabled) { switch (GF.type) { case FADER_CH_BAR: - grid_fill_area_scr(GFC.x, GFC.y, GF.value + 1, GFC.h, 15, page); + grid_fill_area_scr(GFC.x, GFC.y, GF.value + 1, GFC.h, GRID_ON_BRIGHTNESS, page); grid_fill_area_scr(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.level, page); break; case FADER_CV_BAR: grid_fill_area_scr(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.level, page); - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, 15, page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, GRID_ON_BRIGHTNESS, page); break; case FADER_CH_DOT: - grid_fill_area_scr(GFC.x + GF.value, GFC.y, 1, GFC.h, 15, page); + grid_fill_area_scr(GFC.x + GF.value, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS, page); break; case FADER_CV_DOT: - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, 15, page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, GRID_ON_BRIGHTNESS, page); break; case FADER_FH_BAR: fv = (((GFC.w - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; - grid_fill_area_scr(GFC.x, GFC.y, ff + 1, GFC.h, 15, page); + grid_fill_area_scr(GFC.x, GFC.y, ff + 1, GFC.h, GRID_ON_BRIGHTNESS, page); if (fp) grid_fill_area_scr(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp, page); - grid_fill_area_scr(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, 15, page); + grid_fill_area_scr(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS, page); break; case FADER_FV_BAR: fv = (((GFC.h - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff + 1, 15, page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff + 1, GRID_ON_BRIGHTNESS, page); if (fp) grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, fp, page); - grid_fill_area_scr(GFC.x, GFC.y, GFC.w, 1, 15, page); + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, 1, GRID_ON_BRIGHTNESS, page); break; case FADER_FH_DOT: - grid_fill_area_scr(GFC.x, GFC.y, 1, GFC.h, 15, page); - grid_fill_area_scr(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, 15, page); + grid_fill_area_scr(GFC.x, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS, page); fv = (((GFC.w - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; if (fp) grid_fill_area_scr(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp, page); else if (ff) - grid_fill_area_scr(GFC.x + ff, GFC.y, 1, GFC.h, 15, page); + grid_fill_area_scr(GFC.x + ff, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS, page); break; case FADER_FV_DOT: - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - 1, GFC.w, 1, 15, page); - grid_fill_area_scr(GFC.x, GFC.y, GFC.w, 1, 15, page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - 1, GFC.w, 1, GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, 1, GRID_ON_BRIGHTNESS, page); fv = (((GFC.h - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; if (fp) grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, fp, page); else if (ff) - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, 1, 15, page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, 1, GRID_ON_BRIGHTNESS, page); break; } } @@ -773,7 +783,7 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.enabled && SG.group[GBC.group].enabled) - grid_fill_area_scr(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? 15 : GBC.level, page); + grid_fill_area_scr(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? GRID_ON_BRIGHTNESS : GBC.level, page); u16 pd = page ? 8 : 0; s8 l; @@ -782,14 +792,17 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, l = SG.leds[i][j + pd]; if (l >= 0) screen[i][j] = l; - else if (l == LED_DIM) - screen[i][j] >>= 1; + else if (l == LED_DIM) { + if (screen[i][j] > 3) + screen[i][j] -= 3; + else + screen[i][j] = 0; + } else if (l == LED_BRI) { - screen[i][j] <<= 1; - if (screen[i][j] > 15) + if (screen[i][j] > 12) screen[i][j] = 15; - else if (screen[i][j] < 1) - screen[i][j] = 1; + else + screen[i][j] += 3; } } @@ -970,7 +983,7 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, line[1].data[2 + 512] = l; } -void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page) { +void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, s8 level, u8 page) { if (level == LED_OFF) return; u16 x_end = min(GRID_MAX_DIMENSION, x + w); @@ -989,17 +1002,20 @@ void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, u8 level, u8 page) { } if (level == LED_DIM) { - for (u16 _x = x; _x < x_end; _x++) { + for (u16 _x = x; _x < x_end; _x++) for (u16 _y = y1; _y <= y2; _y++) - screen[_x][_y] >>= 1; - } + if (screen[_x][_y] > 3) + screen[_x][_y] -= 3; + else + screen[_x][_y] = 0; } else if (level == LED_BRI) { for (u16 _x = x; _x < x_end; _x++) - for (u16 _y = y1; _y <= y2; _y++) { - screen[_x][_y] <<= 1; - if (screen[_x][_y] > 15) screen[_x][_y] = 15; - } + for (u16 _y = y1; _y <= y2; _y++) + if (screen[_x][_y] > 12) + screen[_x][_y] = 15; + else + screen[_x][_y] += 3; } else { for (u16 _x = x; _x < x_end; _x++) diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 6d87c49f..b6a4e1c4 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -932,7 +932,8 @@ static void op_G_FDR_L_set(const void *NOTUSED(data), scene_state_t *ss, if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; level = grid_fader_clamp_level(level, GF.type, GFC.w, GFC.h); - GF.value = scale(0, GFC.level, 0, level, GF.value); + if (GF.type > FADER_COARSE) + GF.value = scale(0, GFC.level, 0, level, GF.value); GFC.level = level; SG.scr_dirty = SG.grid_dirty = 1; } @@ -1036,7 +1037,8 @@ static void op_G_FDRL_set(const void *NOTUSED(data), scene_state_t *ss, exec_sta u16 i = SG.latest_fader; level = grid_fader_clamp_level(level, GF.type, GFC.w, GFC.h); - GF.value = scale(0, GFC.level, 0, level, GF.value); + if (GF.type > FADER_COARSE) + GF.value = scale(0, GFC.level, 0, level, GF.value); GFC.level = level; SG.scr_dirty = SG.grid_dirty = 1; @@ -1164,7 +1166,8 @@ static void op_G_GFDR_L_get(const void *NOTUSED(data), scene_state_t *ss, for (u16 i = 0; i < GRID_FADER_COUNT; i++) if (GFC.group == group) { level = grid_fader_clamp_level(is_odd ? odd : even, GF.type, GFC.w, GFC.h); - GF.value = scale(0, GFC.level, 0, level, GF.value); + if (GF.type > FADER_COARSE) + GF.value = scale(0, GFC.level, 0, level, GF.value); GFC.level = level; is_odd = !is_odd; } diff --git a/src/state.h b/src/state.h index fee7b0eb..7ce163df 100644 --- a/src/state.h +++ b/src/state.h @@ -138,7 +138,7 @@ typedef struct { u8 group; u8 x, y; u8 w, h; - u8 level; + s8 level; s8 script; } grid_common_t; From b537759dd18d3cd27300328fa21e80500fca1b9c Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 23 Jan 2018 19:24:30 -0800 Subject: [PATCH 039/117] ternary if and alias for script --- src/match_token.rl | 2 ++ src/ops/controlflow.c | 2 ++ src/ops/controlflow.h | 1 + src/ops/maths.c | 11 +++++++++++ src/ops/maths.h | 1 + src/ops/op.c | 5 +++-- src/ops/op_enum.h | 2 ++ 7 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/match_token.rl b/src/match_token.rl index 0be34b5f..64f52ede 100644 --- a/src/match_token.rl +++ b/src/match_token.rl @@ -194,6 +194,7 @@ "CHAOS" => { MATCH_OP(E_OP_CHAOS); }; "CHAOS.R" => { MATCH_OP(E_OP_CHAOS_R); }; "CHAOS.ALG" => { MATCH_OP(E_OP_CHAOS_ALG); }; + "?" => { MATCH_OP(E_OP_TIF); }; "+" => { MATCH_OP(E_OP_SYM_PLUS); }; "-" => { MATCH_OP(E_OP_SYM_DASH); }; "*" => { MATCH_OP(E_OP_SYM_STAR); }; @@ -219,6 +220,7 @@ # controlflow "SCRIPT" => { MATCH_OP(E_OP_SCRIPT); }; + "$" => { MATCH_OP(E_OP_SYM_DOLLAR); }; "KILL" => { MATCH_OP(E_OP_KILL); }; "SCENE" => { MATCH_OP(E_OP_SCENE); }; "BREAK" => { MATCH_OP(E_OP_BREAK); }; diff --git a/src/ops/controlflow.c b/src/ops/controlflow.c index 73762127..86f4fea6 100644 --- a/src/ops/controlflow.c +++ b/src/ops/controlflow.c @@ -60,6 +60,8 @@ const tele_mod_t mod_OTHER = MAKE_MOD(OTHER, mod_OTHER_func, 0); const tele_op_t op_SCRIPT = MAKE_GET_SET_OP(SCRIPT, op_SCRIPT_get, op_SCRIPT_set, 0, true); +const tele_op_t op_SYM_DOLLAR = MAKE_ALIAS_OP($, op_SCRIPT_get, op_SCRIPT_set, 0, + true); const tele_op_t op_KILL = MAKE_GET_OP(KILL, op_KILL_get, 0, false); const tele_op_t op_SCENE = MAKE_GET_SET_OP(SCENE, op_SCENE_get, op_SCENE_set, 0, true); diff --git a/src/ops/controlflow.h b/src/ops/controlflow.h index 08057461..acc76cac 100644 --- a/src/ops/controlflow.h +++ b/src/ops/controlflow.h @@ -20,5 +20,6 @@ extern const tele_op_t op_BREAK; extern const tele_op_t op_BRK; extern const tele_op_t op_SYNC; +extern const tele_op_t op_SYM_DOLLAR; #endif diff --git a/src/ops/maths.c b/src/ops/maths.c index dc697611..63e2eb07 100644 --- a/src/ops/maths.c +++ b/src/ops/maths.c @@ -113,6 +113,8 @@ static void op_CHAOS_ALG_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_CHAOS_ALG_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_TIF_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); // clang-format off const tele_op_t op_ADD = MAKE_GET_OP(ADD , op_ADD_get , 2, true); @@ -163,6 +165,7 @@ const tele_op_t op_BCLR = MAKE_GET_OP(BCLR , op_BCLR_get , 2, true); const tele_op_t op_CHAOS = MAKE_GET_SET_OP(CHAOS, op_CHAOS_get, op_CHAOS_set, 0, true); const tele_op_t op_CHAOS_R = MAKE_GET_SET_OP(CHAOS.R, op_CHAOS_R_get, op_CHAOS_R_set, 0, true); const tele_op_t op_CHAOS_ALG = MAKE_GET_SET_OP(CHAOS.ALG, op_CHAOS_ALG_get, op_CHAOS_ALG_set, 0, true); +const tele_op_t op_TIF = MAKE_GET_OP(?, op_TIF_get, 3, true); const tele_op_t op_XOR = MAKE_ALIAS_OP(XOR, op_NE_get, NULL, 2, true); @@ -677,3 +680,11 @@ static void op_CHAOS_ALG_set(const void *NOTUSED(data), exec_state_t *NOTUSED(es), command_state_t *cs) { chaos_set_alg(cs_pop(cs)); } + +static void op_TIF_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 condition = cs_pop(cs); + s16 a = cs_pop(cs); + s16 b = cs_pop(cs); + cs_push(cs, condition ? a : b); +} diff --git a/src/ops/maths.h b/src/ops/maths.h index 5598b1d2..ad840ddc 100644 --- a/src/ops/maths.h +++ b/src/ops/maths.h @@ -51,6 +51,7 @@ extern const tele_op_t op_BCLR; extern const tele_op_t op_CHAOS; extern const tele_op_t op_CHAOS_R; extern const tele_op_t op_CHAOS_ALG; +extern const tele_op_t op_TIF; // ternary if extern const tele_op_t op_XOR; // XOR alias NE diff --git a/src/ops/op.c b/src/ops/op.c index 7d782157..1d5406f8 100644 --- a/src/ops/op.c +++ b/src/ops/op.c @@ -82,13 +82,14 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_SYM_PERCENTAGE, &op_SYM_EQUAL_x2, &op_SYM_EXCLAMATION_EQUAL, &op_SYM_LEFT_ANGLED, &op_SYM_RIGHT_ANGLED, &op_SYM_LEFT_ANGLED_EQUAL, &op_SYM_RIGHT_ANGLED_EQUAL, &op_SYM_EXCLAMATION, &op_SYM_LEFT_ANGLED_x2, - &op_SYM_RIGHT_ANGLED_x2, &op_SYM_AMPERSAND_x2, &op_SYM_PIPE_x2, + &op_SYM_RIGHT_ANGLED_x2, &op_SYM_AMPERSAND_x2, &op_SYM_PIPE_x2, &op_TIF, // stack &op_S_ALL, &op_S_POP, &op_S_CLR, &op_S_L, // controlflow - &op_SCRIPT, &op_KILL, &op_SCENE, &op_BREAK, &op_BRK, &op_SYNC, + &op_SCRIPT, &op_SYM_DOLLAR, &op_KILL, &op_SCENE, &op_BREAK, &op_BRK, + &op_SYNC, // delay &op_DEL_CLR, diff --git a/src/ops/op_enum.h b/src/ops/op_enum.h index c0b1e50d..c81af43f 100644 --- a/src/ops/op_enum.h +++ b/src/ops/op_enum.h @@ -183,11 +183,13 @@ typedef enum { E_OP_SYM_RIGHT_ANGLED_x2, E_OP_SYM_AMPERSAND_x2, E_OP_SYM_PIPE_x2, + E_OP_TIF, E_OP_S_ALL, E_OP_S_POP, E_OP_S_CLR, E_OP_S_L, E_OP_SCRIPT, + E_OP_SYM_DOLLAR, E_OP_KILL, E_OP_SCENE, E_OP_BREAK, From 44f87b5d9a10525f05999ed445d7368485a14006 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 27 Feb 2018 17:33:55 -0800 Subject: [PATCH 040/117] fixes for multiline editing --- module/edit_mode.c | 92 ++++++++++++++++++++++++++---------------- module/usb_disk_mode.c | 1 + src/command.h | 2 + src/state.c | 11 ++--- src/state.h | 1 - src/teletype.c | 1 + 6 files changed, 67 insertions(+), 41 deletions(-) diff --git a/module/edit_mode.c b/module/edit_mode.c index 20184591..b3a5d385 100644 --- a/module/edit_mode.c +++ b/module/edit_mode.c @@ -55,7 +55,11 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { &le, ss_get_script_command(&scene_state, script, line_no1)); dirty |= D_LIST | D_INPUT; } - line_no2 = line_no1; + // reset selection + if (line_no2 != line_no1) { + line_no2 = line_no1; + dirty |= D_LIST | D_INPUT; + } } // or C-p: line up else if (match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) { @@ -65,19 +69,31 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { &le, ss_get_script_command(&scene_state, script, line_no1)); dirty |= D_LIST | D_INPUT; } - line_no2 = line_no1; + // reset selection + if (line_no2 != line_no1) { + line_no2 = line_no1; + dirty |= D_LIST | D_INPUT; + } } // shift- or C-S-n: expand selection down else if (match_shift(m, k, HID_DOWN) || match_shift_ctrl(m, k, HID_N)) { if (line_no2 < (SCRIPT_MAX_COMMANDS - 1) && - line_no2 < ss_get_script_len(&scene_state, script) - 1) { + line_no2 < max(1, ss_get_script_len(&scene_state, script)) - 1) { line_no2++; dirty |= D_LIST | D_INPUT; } } // shift- or C-S-p: expand selection up else if (match_shift(m, k, HID_UP) || match_shift_ctrl(m, k, HID_P)) { - if (line_no2) { + if (line_no1 >= ss_get_script_len(&scene_state, script)) { + // if currently on blank line move up first + if (line_no1) { + line_no2 = --line_no1; + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no1)); + dirty |= D_LIST | D_INPUT; + } + } else if (line_no2) { line_no2--; dirty |= D_LIST | D_INPUT; } @@ -115,7 +131,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { u8 l1 = min(line_no1, line_no2); u8 l2 = max(line_no1, line_no2); if (l2 < SCRIPT_MAX_COMMANDS - 1 && - l2 < ss_get_script_len(&scene_state, script) - 1) { + l2 < max(1, ss_get_script_len(&scene_state, script)) - 1) { tele_command_t temp; ss_copy_script_command(&temp, &scene_state, script, l2 + 1); ss_delete_script_command(&scene_state, script, l2 + 1); @@ -129,7 +145,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { else if (match_alt(m, k, HID_UP)) { u8 l1 = min(line_no1, line_no2); u8 l2 = max(line_no1, line_no2); - if (l1) { + if (l1 && l2 < ss_get_script_len(&scene_state, script)) { tele_command_t temp; ss_copy_script_command(&temp, &scene_state, script, l1 - 1); ss_delete_script_command(&scene_state, script, l1 - 1); @@ -142,18 +158,20 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { // ctrl-x or alt-x: override line editors cut else if (match_ctrl(m, k, HID_X) || match_alt(m, k, HID_X)) { if (line_no1 == line_no2) { - strcpy(copy_buffer[0], line_editor_get(&le)); - copy_buffer_len = 1; - ss_delete_script_command(&scene_state, script, line_no1); + if (line_no1 < ss_get_script_len(&scene_state, script)) { + strcpy(copy_buffer[0], line_editor_get(&le)); + copy_buffer_len = 1; + ss_delete_script_command(&scene_state, script, line_no1); + } } else { + u8 l1 = min(line_no1, line_no2); + u8 l2 = max(line_no1, line_no2); copy_buffer_len = 0; - for (u8 l = min(line_no1, line_no2); l <= max(line_no1, line_no2); - l++) + for (u8 l = l1; l <= l2; l++) print_command(ss_get_script_command(&scene_state, script, l), copy_buffer[copy_buffer_len++]); - for (s8 l = max(line_no1, line_no2); l >= min(line_no1, line_no2); - l--) + for (s8 l = l2; l >= l1; l--) ss_delete_script_command(&scene_state, script, l); } @@ -169,46 +187,53 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { // ctrl-c or alt-c: override line editors copy for multi selection else if (match_ctrl(m, k, HID_C) || match_alt(m, k, HID_C)) { if (line_no1 == line_no2) { + // not a multi line selection, pass it to line editor bool processed = line_editor_process_keys(&le, k, m, is_held_key); if (processed) dirty |= D_INPUT; - return; } - - copy_buffer_len = 0; - for (u8 l = min(line_no1, line_no2); l <= max(line_no1, line_no2); l++) - print_command(ss_get_script_command(&scene_state, script, l), - copy_buffer[copy_buffer_len++]); + else { + copy_buffer_len = 0; + for (u8 l = min(line_no1, line_no2); l <= max(line_no1, line_no2); l++) + print_command(ss_get_script_command(&scene_state, script, l), + copy_buffer[copy_buffer_len++]); + } } // ctrl-v or alt-v: override line editors paste for multi selection else if (match_ctrl(m, k, HID_V) || match_alt(m, k, HID_V)) { if (copy_buffer_len == 0) return; u8 idx = min(line_no1, line_no2); + line_no1 = idx; tele_command_t command; + command.comment = false; for (u8 i = 0; i < copy_buffer_len; i++) { if (parse(copy_buffer[i], &command, error_msg) != E_OK) continue; if (validate(&command, error_msg) != E_OK) continue; if (command.length == 0) continue; ss_insert_script_command(&scene_state, script, idx++, &command); - if (line_no1 < (SCRIPT_MAX_COMMANDS - 1)) line_no1++; if (line_no2 < (SCRIPT_MAX_COMMANDS - 1)) line_no2++; if (idx >= SCRIPT_MAX_COMMANDS) break; } + line_no2 = idx > line_no1 ? idx - 1 : line_no1; line_editor_set_command( &le, ss_get_script_command(&scene_state, script, line_no1)); dirty |= D_LIST | D_INPUT; } // alt-delete: remove selected lines else if (match_alt(m, k, HID_DELETE)) { - for (s8 l = max(line_no1, line_no2); l >= min(line_no1, line_no2); l--) - ss_delete_script_command(&scene_state, script, l); - if (line_no1 > ss_get_script_len(&scene_state, script)) - line_no1 = ss_get_script_len(&scene_state, script); - line_editor_set_command( - &le, ss_get_script_command(&scene_state, script, line_no1)); - line_no2 = line_no1; - dirty |= D_LIST | D_INPUT; + u8 l1 = min(line_no1, line_no2); + u8 l2 = max(line_no1, line_no2); + if (l1 < ss_get_script_len(&scene_state, script)) { + for (s8 l = l2; l >= l1; l--) + ss_delete_script_command(&scene_state, script, l); + if (line_no1 > ss_get_script_len(&scene_state, script)) + line_no1 = ss_get_script_len(&scene_state, script); + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no1)); + line_no2 = line_no1; + dirty |= D_LIST | D_INPUT; + } } // : enter command else if (match_no_mod(m, k, HID_ENTER)) { @@ -223,6 +248,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { dirty |= D_MESSAGE; // something will happen tele_command_t command; + command.comment = false; status = parse(line_editor_get(&le), &command, error_msg); if (status != E_OK) @@ -250,17 +276,12 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { } // shift-: insert command else if (match_shift(m, k, HID_ENTER)) { - if (line_no1 != line_no2) { - line_no2 = line_no1; - line_editor_set_command( - &le, ss_get_script_command(&scene_state, script, line_no1)); - dirty |= D_LIST | D_INPUT; - return; - } + if (line_no1 != line_no2) return; dirty |= D_MESSAGE; // something will happen tele_command_t command; + command.comment = false; status = parse(line_editor_get(&le), &command, error_msg); if (status != E_OK) @@ -282,6 +303,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { } // alt-slash comment toggle selected lines else if (match_alt(m, k, HID_SLASH)) { + if (line_no1 >= ss_get_script_len(&scene_state, script)) return; for (u8 l = min(line_no1, line_no2); l <= max(line_no1, line_no2); l++) ss_toggle_script_comment(&scene_state, script, l); dirty |= D_LIST; diff --git a/module/usb_disk_mode.c b/module/usb_disk_mode.c index c0e728e0..67d98039 100644 --- a/module/usb_disk_mode.c +++ b/module/usb_disk_mode.c @@ -302,6 +302,7 @@ void tele_usb_disk() { if (c == '\n') { if (p && l < SCRIPT_MAX_COMMANDS) { tele_command_t temp; + temp.comment = false; error_t status; char error_msg[TELE_ERROR_MSG_LENGTH]; status = parse(input, &temp, error_msg); diff --git a/src/command.h b/src/command.h index ff6fc991..82a7de20 100644 --- a/src/command.h +++ b/src/command.h @@ -1,6 +1,7 @@ #ifndef _COMMAND_H_ #define _COMMAND_H_ +#include #include #define COMMAND_MAX_LENGTH 16 @@ -16,6 +17,7 @@ typedef struct { uint8_t length; int8_t separator; tele_data_t data[COMMAND_MAX_LENGTH]; + bool comment; } tele_command_t; void copy_command(tele_command_t *dst, const tele_command_t *src); diff --git a/src/state.c b/src/state.c index b73f778d..f32fea0c 100644 --- a/src/state.c +++ b/src/state.c @@ -235,13 +235,13 @@ static void ss_set_script_command(scene_state_t *ss, script_number_t script_idx, bool ss_get_script_comment(scene_state_t *ss, script_number_t script_idx, size_t c_idx) { - return ss->scripts[script_idx].comment[c_idx]; + return ss->scripts[script_idx].c[c_idx].comment; } void ss_toggle_script_comment(scene_state_t *ss, script_number_t script_idx, size_t c_idx) { - ss->scripts[script_idx].comment[c_idx] = - !ss->scripts[script_idx].comment[c_idx]; + ss->scripts[script_idx].c[c_idx].comment = + !ss->scripts[script_idx].c[c_idx].comment; } void ss_overwrite_script_command(scene_state_t *ss, script_number_t script_idx, @@ -292,9 +292,9 @@ void ss_insert_script_command(scene_state_t *ss, script_number_t script_idx, void ss_delete_script_command(scene_state_t *ss, script_number_t script_idx, size_t command_idx) { - if (command_idx >= SCRIPT_MAX_COMMANDS) return; - uint8_t script_len = ss_get_script_len(ss, script_idx); + if (command_idx >= SCRIPT_MAX_COMMANDS || command_idx >= script_len) return; + if (script_len && ss_get_script_command(ss, script_idx, command_idx)->length) { script_len--; @@ -308,6 +308,7 @@ void ss_delete_script_command(scene_state_t *ss, script_number_t script_idx, tele_command_t blank_command; blank_command.length = 0; + blank_command.comment = false; ss_set_script_command(ss, script_idx, script_len, &blank_command); } } diff --git a/src/state.h b/src/state.h index 7ce163df..dcb43f75 100644 --- a/src/state.h +++ b/src/state.h @@ -128,7 +128,6 @@ typedef struct { typedef struct { uint8_t l; tele_command_t c[SCRIPT_MAX_COMMANDS]; - bool comment[SCRIPT_MAX_COMMANDS]; every_count_t every[SCRIPT_MAX_COMMANDS]; int16_t last_time; } scene_script_t; diff --git a/src/teletype.c b/src/teletype.c index e155b401..e4c0b13a 100644 --- a/src/teletype.c +++ b/src/teletype.c @@ -274,6 +274,7 @@ process_result_t process_command(scene_state_t *ss, exec_state_t *es, } else if (word_type == MOD) { tele_command_t post_command; + post_command.comment = false; copy_post_command(&post_command, c); tele_mods[word_value]->func(ss, es, &cs, &post_command); } From 4b5ac8b1f8ce2c61378313eb87e019b1e8185b7a Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 27 Feb 2018 17:40:28 -0800 Subject: [PATCH 041/117] fix docs for LSH / RSH --- docs/ops/maths.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ops/maths.toml b/docs/ops/maths.toml index ceb688bf..0d222f49 100644 --- a/docs/ops/maths.toml +++ b/docs/ops/maths.toml @@ -102,12 +102,12 @@ short = "`x` is not `0`" [LSH] prototype = "LSH x y" aliases = ["<<"] -short = "left shift `x` by `y` bits, in effect multiply by `2` to the power of `x`" +short = "left shift `x` by `y` bits, in effect multiply `x` by `2` to the power of `y`" [RSH] prototype = "RSH x y" aliases = [">>"] -short = "right shift `x` by `y` bits, in effect divide by `2` to the power of `x`" +short = "right shift `x` by `y` bits, in effect divide `x` by `2` to the power of `y`" ["|"] prototype = "| x y" From 96f4412fe68fc53bd4454ce5a26c4f5b0ea98754 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 27 Feb 2018 18:41:25 -0800 Subject: [PATCH 042/117] fix "stuck" grid presses --- module/grid.c | 7 +++++++ module/grid.h | 1 + module/live_mode.c | 25 ++++++++++++++++++++----- module/main.c | 1 + 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/module/grid.c b/module/grid.c index 543f41ca..0d204669 100644 --- a/module/grid.c +++ b/module/grid.c @@ -445,6 +445,13 @@ void grid_process_fader_slew(scene_state_t *ss) { if (refresh) SG.grid_dirty = SG.scr_dirty = 1; } +void grid_clear_held_keys() { + for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) { + held_keys[i].used = 0; + timer_remove(&held_keys[i].timer); + } +} + bool grid_within_area(u8 x, u8 y, grid_common_t *gc) { return x >= gc->x && x < (gc->x + gc->w) && y >= gc->y && y < (gc->y + gc->h); } diff --git a/module/grid.h b/module/grid.h index 04ad7af1..9bc6a6b4 100644 --- a/module/grid.h +++ b/module/grid.h @@ -25,5 +25,6 @@ extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 ignore_rotate); extern void grid_process_fader_slew(scene_state_t *ss); +extern void grid_clear_held_keys(void); #endif diff --git a/module/live_mode.c b/module/live_mode.c index e40c7074..523b08f4 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -34,6 +34,7 @@ static bool show_welcome_message; static screen_grid_mode grid_mode = GRID_MODE_OFF; static uint8_t grid_page = 0, grid_ctrl = 0, grid_view_changed = 0; static uint8_t grid_x1 = 0, grid_y1 = 0, grid_x2 = 0, grid_y2 = 0; +static uint8_t grid_pressed = 0; static const uint8_t D_INPUT = 1 << 0; static const uint8_t D_LIST = 1 << 1; @@ -112,15 +113,19 @@ void set_live_mode() { if (grid_mode == GRID_MODE_FULL) grid_mode = GRID_MODE_EDIT; } +static void emulate_grid_release(scene_state_t *ss) { + grid_process_key(ss, grid_x1, grid_y1, 0, 1); + if (grid_x1 != grid_x2 || grid_y1 != grid_y2) + grid_process_key(ss, grid_x2, grid_y2, 0, 1); + grid_pressed = 0; +} + void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, scene_state_t *ss) { if (is_release) { if (match_alt(m, k, HID_SPACEBAR) || - (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SPACEBAR))) { - grid_process_key(ss, grid_x1, grid_y1, 0, 1); - if (grid_x1 != grid_x2 || grid_y1 != grid_y2) - grid_process_key(ss, grid_x2, grid_y2, 0, 1); - } + (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_SPACEBAR))) + emulate_grid_release(ss); return; } @@ -158,6 +163,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // A-: move grid cursor else if (match_alt(m, k, HID_UP) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_UP))) { + if (grid_pressed) emulate_grid_release(ss); grid_y1 = (grid_y1 + GRID_MAX_DIMENSION - 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; @@ -166,6 +172,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // A-: move grid cursor else if (match_alt(m, k, HID_DOWN) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_DOWN))) { + if (grid_pressed) emulate_grid_release(ss); grid_y1 = (grid_y1 + 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; @@ -174,6 +181,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // A-: move grid cursor else if (match_alt(m, k, HID_LEFT) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_LEFT))) { + if (grid_pressed) emulate_grid_release(ss); grid_x1 = (grid_x1 + GRID_MAX_DIMENSION - 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; @@ -182,6 +190,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // A-: move grid cursor else if (match_alt(m, k, HID_RIGHT) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_RIGHT))) { + if (grid_pressed) emulate_grid_release(ss); grid_x1 = (grid_x1 + 1) % GRID_MAX_DIMENSION; grid_x2 = grid_x1; grid_y2 = grid_y1; @@ -191,6 +200,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, else if (match_shift_alt(m, k, HID_UP) || (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_UP))) { if (grid_y2 > 0) { + if (grid_pressed) emulate_grid_release(ss); grid_y2--; grid_view_changed = true; } @@ -199,6 +209,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, else if (match_shift_alt(m, k, HID_DOWN) || (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_DOWN))) { if (grid_y2 < GRID_MAX_DIMENSION - 1) { + if (grid_pressed) emulate_grid_release(ss); grid_y2++; grid_view_changed = true; } @@ -207,6 +218,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, else if (match_shift_alt(m, k, HID_LEFT) || (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_LEFT))) { if (grid_x2 > 0) { + if (grid_pressed) emulate_grid_release(ss); grid_x2--; grid_view_changed = true; } @@ -215,6 +227,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, else if (match_shift_alt(m, k, HID_RIGHT) || (grid_mode == GRID_MODE_FULL && match_shift(m, k, HID_RIGHT))) { if (grid_x2 < GRID_MAX_DIMENSION - 1) { + if (grid_pressed) emulate_grid_release(ss); grid_x2++; grid_view_changed = true; } @@ -226,6 +239,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, grid_process_key(ss, grid_x1, grid_y1, 1, 1); if (grid_x1 != grid_x2 || grid_y1 != grid_y2) grid_process_key(ss, grid_x2, grid_y2, 1, 1); + grid_pressed = 1; } // A-: insert coordinates / size else if (!is_held_key && match_alt(m, k, HID_PRINTSCREEN) && @@ -296,6 +310,7 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, dirty |= D_INPUT; tele_command_t command; + command.comment = false; status = parse(line_editor_get(&le), &command, error_msg); if (status != E_OK) diff --git a/module/main.c b/module/main.c index aa71efe8..5f67d2ee 100644 --- a/module/main.c +++ b/module/main.c @@ -480,6 +480,7 @@ static void handler_FtdiDisconnect(s32 data) { static void handler_MonomeConnect(s32 data) { timers_set_monome(); scene_state.grid.grid_dirty = 1; + grid_clear_held_keys(); } static void handler_MonomePoll(s32 data) { From 5ed2beac71d65346e3d0a52e7df5e79c08601dcc Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 27 Feb 2018 18:44:41 -0800 Subject: [PATCH 043/117] allow G.BTN.PR / G.FDR.PR for disabled controls --- src/ops/grid_ops.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index b6a4e1c4..9cddc626 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -721,7 +721,6 @@ static void op_G_BTN_PR_get(const void *NOTUSED(data), scene_state_t *ss, s16 action = cs_pop(cs); if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; - if (!GBC.enabled || !SG.group[GBC.group].enabled) return; GB.state = GB.latch ? !GB.state : action != 0; SG.latest_button = i; @@ -1094,7 +1093,6 @@ static void op_G_FDR_PR_get(const void *NOTUSED(data), scene_state_t *ss, s16 value = cs_pop(cs) - 1; if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; - if (!GFC.enabled || !SG.group[GFC.group].enabled) return; s16 maxvalue = grid_fader_max_value(ss, i); if (value < (s16)0) value = 0; From 1014a57a2dd115a1f8bdb15435fb0853b321b0a4 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Wed, 28 Feb 2018 17:30:47 -0800 Subject: [PATCH 044/117] fix tracker not updating after PN.HERE --- src/ops/patterns.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/ops/patterns.c b/src/ops/patterns.c index 8237aa19..a06ca760 100644 --- a/src/ops/patterns.c +++ b/src/ops/patterns.c @@ -82,6 +82,7 @@ static void p_set(scene_state_t *ss, int16_t pn, int16_t idx, int16_t val) { pn = normalise_pn(pn); idx = normalise_idx(ss, pn, idx); ss_set_pattern_val(ss, pn, idx, val); + tele_pattern_updated(); } static void op_P_set(const void *NOTUSED(data), scene_state_t *ss, @@ -90,7 +91,6 @@ static void op_P_set(const void *NOTUSED(data), scene_state_t *ss, int16_t a = cs_pop(cs); int16_t b = cs_pop(cs); p_set(ss, pn, a, b); - tele_pattern_updated(); } static void op_PN_set(const void *NOTUSED(data), scene_state_t *ss, @@ -99,7 +99,6 @@ static void op_PN_set(const void *NOTUSED(data), scene_state_t *ss, int16_t a = cs_pop(cs); int16_t b = cs_pop(cs); p_set(ss, pn, a, b); - tele_pattern_updated(); } // Make ops @@ -132,6 +131,7 @@ static void p_l_set(scene_state_t *ss, int16_t pn, int16_t l) { ss_set_pattern_len(ss, pn, PATTERN_LENGTH); else ss_set_pattern_len(ss, pn, l); + tele_pattern_updated(); } static void op_P_L_set(const void *NOTUSED(data), scene_state_t *ss, @@ -139,7 +139,6 @@ static void op_P_L_set(const void *NOTUSED(data), scene_state_t *ss, int16_t pn = ss->variables.p_n; int16_t a = cs_pop(cs); p_l_set(ss, pn, a); - tele_pattern_updated(); } static void op_PN_L_set(const void *NOTUSED(data), scene_state_t *ss, @@ -147,7 +146,6 @@ static void op_PN_L_set(const void *NOTUSED(data), scene_state_t *ss, int16_t pn = cs_pop(cs); int16_t a = cs_pop(cs); p_l_set(ss, pn, a); - tele_pattern_updated(); } // Make ops @@ -204,6 +202,13 @@ static void op_P_START_get(const void *NOTUSED(data), scene_state_t *ss, cs_push(cs, ss_get_pattern_start(ss, pn)); } +static void op_PN_START_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = normalise_pn(cs_pop(cs)); + cs_push(cs, ss_get_pattern_start(ss, pn)); +} + +// Set static void op_P_START_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t pn = normalise_pn(ss->variables.p_n); @@ -212,13 +217,6 @@ static void op_P_START_set(const void *NOTUSED(data), scene_state_t *ss, tele_pattern_updated(); } -// Set -static void op_PN_START_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t pn = normalise_pn(cs_pop(cs)); - cs_push(cs, ss_get_pattern_start(ss, pn)); -} - static void op_PN_START_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t pn = normalise_pn(cs_pop(cs)); @@ -301,6 +299,7 @@ static void p_i_set(scene_state_t *ss, int16_t pn, int16_t i) { ss_set_pattern_idx(ss, pn, len - 1); else ss_set_pattern_idx(ss, pn, i); + tele_pattern_updated(); } static void op_P_I_set(const void *NOTUSED(data), scene_state_t *ss, @@ -308,7 +307,6 @@ static void op_P_I_set(const void *NOTUSED(data), scene_state_t *ss, int16_t pn = ss->variables.p_n; int16_t a = cs_pop(cs); p_i_set(ss, pn, a); - tele_pattern_updated(); } static void op_PN_I_set(const void *NOTUSED(data), scene_state_t *ss, @@ -316,7 +314,6 @@ static void op_PN_I_set(const void *NOTUSED(data), scene_state_t *ss, int16_t pn = cs_pop(cs); int16_t a = cs_pop(cs); p_i_set(ss, pn, a); - tele_pattern_updated(); } // Make ops @@ -347,6 +344,7 @@ static void op_P_HERE_set(const void *NOTUSED(data), scene_state_t *ss, int16_t pn = normalise_pn(ss->variables.p_n); int16_t a = cs_pop(cs); ss_set_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn), a); + tele_pattern_updated(); } static void op_PN_HERE_set(const void *NOTUSED(data), scene_state_t *ss, @@ -354,6 +352,7 @@ static void op_PN_HERE_set(const void *NOTUSED(data), scene_state_t *ss, int16_t pn = normalise_pn(cs_pop(cs)); int16_t a = cs_pop(cs); ss_set_pattern_val(ss, pn, ss_get_pattern_idx(ss, pn), a); + tele_pattern_updated(); } // Make ops @@ -605,6 +604,8 @@ static void p_push_get(scene_state_t *ss, int16_t pn, int16_t val) { ss_set_pattern_val(ss, pn, len, val); ss_set_pattern_len(ss, pn, len + 1); } + + tele_pattern_updated(); } static void op_P_PUSH_get(const void *NOTUSED(data), scene_state_t *ss, @@ -612,7 +613,6 @@ static void op_P_PUSH_get(const void *NOTUSED(data), scene_state_t *ss, int16_t pn = ss->variables.p_n; int16_t a = cs_pop(cs); p_push_get(ss, pn, a); - tele_pattern_updated(); } static void op_PN_PUSH_get(const void *NOTUSED(data), scene_state_t *ss, @@ -620,7 +620,6 @@ static void op_PN_PUSH_get(const void *NOTUSED(data), scene_state_t *ss, int16_t pn = cs_pop(cs); int16_t a = cs_pop(cs); p_push_get(ss, pn, a); - tele_pattern_updated(); } // Make ops @@ -640,19 +639,18 @@ static int16_t p_pop_get(scene_state_t *ss, int16_t pn) { } else return 0; + tele_pattern_updated(); } static void op_P_POP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, p_pop_get(ss, ss->variables.p_n)); - tele_pattern_updated(); } static void op_PN_POP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t pn = cs_pop(cs); cs_push(cs, p_pop_get(ss, pn)); - tele_pattern_updated(); } // Make ops From 3d2ccb91c4171cee0275d06eb644339635776f13 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Wed, 28 Feb 2018 18:26:11 -0800 Subject: [PATCH 045/117] fix levels for fine faders --- src/state.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state.h b/src/state.h index dcb43f75..4c52171b 100644 --- a/src/state.h +++ b/src/state.h @@ -137,7 +137,7 @@ typedef struct { u8 group; u8 x, y; u8 w, h; - s8 level; + s16 level; s8 script; } grid_common_t; From 5e70a8befdb6ad156ec562c138b61a6ce492f83f Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 2 Apr 2018 19:22:10 -0700 Subject: [PATCH 046/117] grid control 1 --- module/grid.c | 91 ++++++++++++++++++++++++++++++++++++--------------- module/grid.h | 3 +- module/main.c | 13 +++++++- 3 files changed, 79 insertions(+), 28 deletions(-) diff --git a/module/grid.c b/module/grid.c index 0d204669..a6a46727 100644 --- a/module/grid.c +++ b/module/grid.c @@ -151,13 +151,17 @@ typedef struct { softTimer_t timer; } hold_repeat_info; +static u8 control_mode = 0; +static tele_mode_t tt_mode = M_LIVE; static u16 size_x = 16, size_y = 8; static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION/2]; static hold_repeat_info held_keys[GRID_MAX_KEY_PRESSED]; static u8 timers_uninitialized = 1; +static void grid_control_refresh(void); +static void grid_control_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 from_held); static void hold_repeat_timer_callback(void* o); -static void grid_process_key_hold_repeat(scene_state_t *ss, u8 x, u8 y, u8 is_hold); +static void grid_process_key_hold_repeat(scene_state_t *ss, u8 x, u8 y); static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); @@ -165,37 +169,60 @@ static bool grid_within_area(u8 x, u8 y, grid_common_t *gc); static void grid_fill_area(u8 x, u8 y, u8 w, u8 h, s8 level); static void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, s8 level, u8 page); -void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { +void grid_set_control_mode(u8 control) { + control_mode = control; + grid_clear_held_keys(); +} + +void grid_control_refresh(void) { + +} + +static void grid_control_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 from_held) { +} + +void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { if (timers_uninitialized) { timers_uninitialized = 0; for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) held_keys[i].used = 0; } - u8 x = SG.rotate && !ignore_rotate ? monome_size_x() - _x - 1 : _x; - u8 y = SG.rotate && !ignore_rotate ? monome_size_y() - _y - 1 : _y; + size_x = monome_size_x(); + size_y = monome_size_y(); + u8 x = SG.rotate && !emulated ? size_x - _x - 1 : _x; + u8 y = SG.rotate && !emulated ? size_y - _y - 1 : _y; - u8 key = (y << 4) | x; - if (z) { - for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) - if (!held_keys[i].used || held_keys[i].key == key) { - held_keys[i].used = 1; - held_keys[i].key = key; - held_keys[i].x = x; - held_keys[i].y = y; - held_keys[i].ss = ss; - timer_add(&held_keys[i].timer, GRID_KEY_HOLD_DELAY, - &hold_repeat_timer_callback, (void *)&held_keys[i]); - break; - } - } else { - for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) - if (held_keys[i].key == key) { - timer_remove(&held_keys[i].timer); - held_keys[i].used = 0; - } + if (control_mode ? !emulated : true) { + u8 key = (y << 4) | x; + if (z) { + for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) + if (!held_keys[i].used || held_keys[i].key == key) { + held_keys[i].used = 1; + held_keys[i].key = key; + held_keys[i].x = x; + held_keys[i].y = y; + held_keys[i].ss = ss; + timer_add(&held_keys[i].timer, GRID_KEY_HOLD_DELAY, + &hold_repeat_timer_callback, (void *)&held_keys[i]); + break; + } + } else { + for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) + if (held_keys[i].key == key) { + timer_remove(&held_keys[i].timer); + held_keys[i].used = 0; + } + } } + if (control_mode) { + if (!emulated && (size_x <= 8 || tt_mode != M_LIVE || x > 7)) { + grid_control_process_key(ss, x, y, z, 0); + return; + } + } + u8 refresh = 0; u8 scripts[SCRIPT_COUNT]; for (u8 i = 0; i < SCRIPT_COUNT; i++) scripts[i] = 0; @@ -359,7 +386,14 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 ignore_rotate) { if (refresh) SG.grid_dirty = SG.scr_dirty = 1; } -void grid_process_key_hold_repeat(scene_state_t *ss, u8 x, u8 y, u8 is_hold) { +void grid_process_key_hold_repeat(scene_state_t *ss, u8 x, u8 y) { + if (control_mode) { + if (size_x <= 8 || tt_mode != M_LIVE || x > 7) { + grid_control_process_key(ss, x, y, 1, 1); + return; + } + } + u8 refresh = 0; u8 scripts[SCRIPT_COUNT]; for (u8 i = 0; i < SCRIPT_COUNT; i++) scripts[i] = 0; @@ -409,7 +443,7 @@ void hold_repeat_timer_callback(void* o) { timer_set(&hr->timer, GRID_KEY_REPEAT_RATE); hr->used = 2; } - grid_process_key_hold_repeat(hr->ss, hr->x, hr->y, is_hold); + grid_process_key_hold_repeat(hr->ss, hr->x, hr->y); } void grid_process_fader_slew(scene_state_t *ss) { @@ -461,7 +495,12 @@ void grid_refresh(scene_state_t *ss) { size_y = monome_size_y(); grid_fill_area(0, 0, size_x, size_y, 0); - + + if (control_mode) { + grid_control_refresh(); + return; + } + u16 x, y; for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { if (GXYC.enabled && SG.group[GXYC.group].enabled) { diff --git a/module/grid.h b/module/grid.h index 9bc6a6b4..7fe93052 100644 --- a/module/grid.h +++ b/module/grid.h @@ -19,11 +19,12 @@ typedef enum { GRID_MODE_LAST } screen_grid_mode; +extern void grid_set_control_mode(u8 control); extern void grid_refresh(scene_state_t *ss); extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 ctrl, u8 x1, u8 y1, u8 x2, u8 y2); extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, - u8 ignore_rotate); + u8 emulated); extern void grid_process_fader_slew(scene_state_t *ss); extern void grid_clear_held_keys(void); diff --git a/module/main.c b/module/main.c index 5f67d2ee..eb7ba115 100644 --- a/module/main.c +++ b/module/main.c @@ -93,6 +93,8 @@ uint8_t copy_buffer_len = 0; static tele_mode_t mode = M_LIVE; static tele_mode_t last_mode = M_LIVE; static uint32_t ss_counter = 0; +static u8 grid_connected = 0; +static u8 grid_control_mode = 0; static uint16_t adc[4]; @@ -303,6 +305,12 @@ void handler_Front(int32_t data) { return; } if (data == 0) { + if (grid_connected) { + grid_control_mode = !grid_control_mode; + grid_set_control_mode(grid_control_mode); + return; + } + if (mode != M_PRESET_R) { front_timer = 0; set_preset_r_mode(adc[1]); @@ -351,7 +359,7 @@ void handler_PollADC(int32_t data) { void handler_KeyTimer(int32_t data) { if (front_timer) { - if (front_timer == 1) { + if (front_timer == 1 && !grid_connected) { if (mode == M_PRESET_R) { process_preset_r_long_front(); } front_timer = 0; } @@ -475,9 +483,11 @@ static void handler_FtdiConnect(s32 data) { } static void handler_FtdiDisconnect(s32 data) { timers_unset_monome(); + grid_connected = 0; } static void handler_MonomeConnect(s32 data) { + grid_connected = 1; timers_set_monome(); scene_state.grid.grid_dirty = 1; grid_clear_held_keys(); @@ -486,6 +496,7 @@ static void handler_MonomeConnect(s32 data) { static void handler_MonomePoll(s32 data) { monome_read_serial(); } + static void handler_MonomeRefresh(s32 data) { grid_refresh(&scene_state); monomeFrameDirty = 0b1111; From a436f3282b23a1d470db0c22bca80b4d2169c0ff Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 12 Apr 2018 22:22:41 -0700 Subject: [PATCH 047/117] grid control pt 2 --- module/edit_mode.c | 4 + module/edit_mode.h | 1 + module/globals.h | 1 + module/grid.c | 458 ++++++++++++++++++++++++++++++++++++++--- module/grid.h | 3 +- module/live_mode.c | 147 ++++++++----- module/live_mode.h | 6 + module/main.c | 40 ++-- module/preset_r_mode.c | 41 ++-- module/preset_r_mode.h | 8 +- src/ops/init.c | 6 +- src/state.c | 5 + src/state.h | 2 + 13 files changed, 604 insertions(+), 118 deletions(-) diff --git a/module/edit_mode.c b/module/edit_mode.c index b3a5d385..a3a20d5c 100644 --- a/module/edit_mode.c +++ b/module/edit_mode.c @@ -45,6 +45,10 @@ void set_edit_mode_script(uint8_t new_script) { dirty = D_ALL; } +void edit_mode_refresh() { + dirty = D_ALL; +} + void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { // or C-n: line down if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) { diff --git a/module/edit_mode.h b/module/edit_mode.h index 951cffe1..01b8c4ba 100644 --- a/module/edit_mode.h +++ b/module/edit_mode.h @@ -6,6 +6,7 @@ void set_edit_mode(void); void set_edit_mode_script(uint8_t new_script); +void edit_mode_refresh(void); void process_edit_keys(uint8_t key, uint8_t mod_key, bool is_held_key); void screen_mutes_updated(void); uint8_t screen_refresh_edit(void); diff --git a/module/globals.h b/module/globals.h index 4fdba14e..334faf91 100644 --- a/module/globals.h +++ b/module/globals.h @@ -35,6 +35,7 @@ typedef enum { void set_mode(tele_mode_t mode); void set_last_mode(void); +void clear_delays_and_slews(scene_state_t *ss); // global copy buffer extern char copy_buffer[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; diff --git a/module/grid.c b/module/grid.c index a6a46727..89451869 100644 --- a/module/grid.c +++ b/module/grid.c @@ -3,14 +3,28 @@ #include "globals.h" #include "state.h" #include "teletype.h" +#include "teletype_io.h" #include "timers.h" #include "util.h" +#include "edit_mode.h" +#include "live_mode.h" +#include "preset_r_mode.h" +#include "flash.h" #define GRID_MAX_KEY_PRESSED 10 #define GRID_KEY_HOLD_DELAY 700 #define GRID_KEY_REPEAT_RATE 40 #define GRID_ON_BRIGHTNESS 13 +typedef enum { + G_LIVE_V, + G_LIVE_G, + G_LIVE_GF, + G_EDIT, + G_TRACKER, + G_PRESET +} grid_control_mode_t; + static const u8 glyph[16][6] = { { 0b000000, @@ -151,15 +165,23 @@ typedef struct { softTimer_t timer; } hold_repeat_info; -static u8 control_mode = 0; -static tele_mode_t tt_mode = M_LIVE; +typedef struct { + u8 on; + scene_state_t *ss; + softTimer_t timer; +} script_trigger_info; + +static grid_control_mode_t tt_mode = G_LIVE_V, tt_last_mode = G_LIVE_V; +static u8 control_mode_on = 0, tt_script = 0, variable_edit = 0; +static u8 preset_write = 0; static u16 size_x = 16, size_y = 8; static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION/2]; static hold_repeat_info held_keys[GRID_MAX_KEY_PRESSED]; static u8 timers_uninitialized = 1; +static script_trigger_info script_triggers[11]; -static void grid_control_refresh(void); -static void grid_control_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 from_held); +static void grid_control_refresh(scene_state_t *ss); +static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_held); static void hold_repeat_timer_callback(void* o); static void grid_process_key_hold_repeat(scene_state_t *ss, u8 x, u8 y); static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); @@ -169,16 +191,411 @@ static bool grid_within_area(u8 x, u8 y, grid_common_t *gc); static void grid_fill_area(u8 x, u8 y, u8 w, u8 h, s8 level); static void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, s8 level, u8 page); -void grid_set_control_mode(u8 control) { - control_mode = control; +void grid_set_control_mode(u8 control, scene_state_t *ss) { + control_mode_on = control; grid_clear_held_keys(); + ss->grid.grid_dirty = 1; } -void grid_control_refresh(void) { +void grid_control_refresh(scene_state_t *ss) { + u16 d = size_y == 16 ? 128 : 0; + if (size_x == 16) d += 8; + + u8 l = 4; + u8 m = 6; + u8 b = 8; + u8 h = 15; + + for (u16 i = 0; i < 8; i++) + for (u16 j = 0; j < 8; j++) + monomeLedBuffer[d+i+size_x*j] = 0; + + if (tt_mode == G_TRACKER) { + // TODO finish tracker view + monomeLedBuffer[d+6] = h; + return; + } + // mode selection + monomeLedBuffer[d] = tt_mode == G_EDIT && tt_script == 8 ? h : m; + monomeLedBuffer[d+1] = tt_mode == G_EDIT && tt_script == 9 ? h : m; + monomeLedBuffer[d+3] = tt_mode == G_LIVE_V ? h : m; + monomeLedBuffer[d+4] = tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF ? h : m; + monomeLedBuffer[d+7] = tt_mode == G_PRESET ? h : m; + d += size_x; + for (u16 i = 0; i < 7; i++) + monomeLedBuffer[d+i] = tt_mode == G_EDIT && tt_script == i ? h : m; + d += size_x; + + if (tt_mode == G_PRESET) { + monomeLedBuffer[d+6] = h; + for (u8 j = 0; j < 25; j += 8) { + for (u16 i = 0; i < 7; i++) + monomeLedBuffer[d+i] = i + j == preset_select ? h : l; + d += size_x; + } + + monomeLedBuffer[d+7] = m; + d += size_x; + monomeLedBuffer[d+2] = b; + monomeLedBuffer[d+4] = b; + monomeLedBuffer[d+7] = m; + return; + + } else if (tt_mode == G_LIVE_V) { + monomeLedBuffer[d+3] = variable_edit == 1 ? h : l; + monomeLedBuffer[d+4] = variable_edit == 2 ? h : l; + d += size_x; + monomeLedBuffer[d] = ss->variables.m_act ? l : b; + monomeLedBuffer[d+1] = script_triggers[10].on ? h : b; + monomeLedBuffer[d+3] = variable_edit == 3 ? h : l; + monomeLedBuffer[d+4] = variable_edit == 4 ? h : l; + monomeLedBuffer[d+6] = m; + d += size_x; + monomeLedBuffer[d] = script_triggers[8].on ? h : m; + monomeLedBuffer[d+1] = script_triggers[9].on ? h : m; + monomeLedBuffer[d+3] = variable_edit == 5 ? h : l; + monomeLedBuffer[d+4] = variable_edit == 6 ? h : l; + monomeLedBuffer[d+6] = m; + monomeLedBuffer[d+7] = b; + d += size_x; + monomeLedBuffer[d+3] = variable_edit == 7 ? h : l; + monomeLedBuffer[d+4] = variable_edit == 8 ? h : l; + + } else if (tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF) { + d += size_x; + monomeLedBuffer[d] = ss_get_mute(ss, 8) ? b : l; + monomeLedBuffer[d+1] = script_triggers[10].on ? h : b; + monomeLedBuffer[d+3] = grid_page == 1 ? b : l; + monomeLedBuffer[d+7] = m; + d += size_x; + monomeLedBuffer[d] = script_triggers[8].on ? h : m; + monomeLedBuffer[d+1] = script_triggers[9].on ? h : m; + monomeLedBuffer[d+3] = grid_page == 2 ? b : l; + monomeLedBuffer[d+5] = grid_show_controls ? b : l; + monomeLedBuffer[d+7] = m; + d += size_x; + + } else if (tt_mode == G_EDIT) { + d += size_x; + monomeLedBuffer[d] = ss_get_mute(ss, 8) ? b : l; + monomeLedBuffer[d+1] = script_triggers[10].on ? h : b; + monomeLedBuffer[d+3] = ss_get_script_comment(ss, tt_script, 0) ? b : l; + monomeLedBuffer[d+4] = ss_get_script_comment(ss, tt_script, 1) ? b : l; + monomeLedBuffer[d+5] = ss_get_script_comment(ss, tt_script, 2) ? b : l; + monomeLedBuffer[d+7] = m; + d += size_x; + monomeLedBuffer[d] = script_triggers[8].on ? h : m; + monomeLedBuffer[d+1] = script_triggers[9].on ? h : m; + monomeLedBuffer[d+3] = ss_get_script_comment(ss, tt_script, 3) ? b : l; + monomeLedBuffer[d+4] = ss_get_script_comment(ss, tt_script, 4) ? b : l; + monomeLedBuffer[d+5] = ss_get_script_comment(ss, tt_script, 5) ? b : l; + monomeLedBuffer[d+7] = m; + d += size_x; + + } + d += size_x; + + // script mutes + for (u16 i = 0; i < 8; i++) + monomeLedBuffer[d+i] = ss_get_mute(ss, i) ? b : l; + d += size_x; + + // triggered scripts + for (u16 i = 0; i < 8; i++) + monomeLedBuffer[d+i] = script_triggers[i].on ? h : m; + + if (variable_edit) { + s16 *v = &(ss->variables.a) - sizeof(s16); + if (size_x == 8) { + if (v[variable_edit] < 0 || v[variable_edit] > 8) + for (u16 i = 0; i < 8; i++) + monomeLedBuffer[d+i] = l; + else + for (u16 i = 0; i < 8; i++) + monomeLedBuffer[d+i] = i < v[variable_edit] ? b : l; + } else { + d -= 8; + if (v[variable_edit] < 0 || v[variable_edit] > 16) + for (u16 i = 0; i < 16; i++) + monomeLedBuffer[d+i] = l; + else + for (u16 i = 0; i < 16; i++) + monomeLedBuffer[d+i] = i < v[variable_edit] ? b : l; + } + } +} + +static void script_triggers_callback(void* o) { + script_trigger_info* st = o; + timer_remove(&st->timer); + st->on = 0; + st->ss->grid.grid_dirty = 1; +} + +void grid_metro_triggered(scene_state_t *ss) { + script_triggers[8].on = 1; + script_triggers[8].ss = ss; + timer_add(&script_triggers[8].timer, 50, + &script_triggers_callback, (void *)&script_triggers[8]); + ss->grid.grid_dirty = 1; +} + +static void restore_last_mode(scene_state_t *ss) { + tt_mode = tt_last_mode; + if (tt_mode == G_EDIT) { + set_edit_mode_script(tt_script); + set_mode(M_EDIT); + } else if (tt_mode == G_PRESET) { + set_mode(M_PRESET_R); + } else if (tt_mode == G_LIVE_V) { + set_mode(M_LIVE); + set_live_submode(1); + } else if (tt_mode == G_LIVE_G) { + set_mode(M_LIVE); + set_live_submode(2); + } else if (tt_mode == G_LIVE_GF) { + set_mode(M_LIVE); + set_live_submode(3); + } + ss->grid.grid_dirty = 1; } -static void grid_control_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 from_held) { +static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_held) { + if (size_y == 16) { + if (y < 8) return 0; + y -= 8; + } + + if (variable_edit && y == 7) { + if (!z || from_held) return 1; + + s16 *v = &(ss->variables.a) - 1; + v[variable_edit] = v[variable_edit] == x + 1 ? 0 : x + 1; + set_vars_updated(); + ss->grid.grid_dirty = 1; + return 1; + } + + if (size_x == 16) { + if (x < 8) return 0; + x -= 8; + } + + if (tt_mode == G_TRACKER) { + // TODO tracker + if (x == 7 && y == 0 && !from_held && z) restore_last_mode(ss); + return 1; + } + + // select page + if (y == 0) { + if (!z || from_held) return 1; + + switch (x) { + case 0: + case 1: + tt_mode = G_EDIT; + tt_script = x + 8; + set_edit_mode_script(tt_script); + set_mode(M_EDIT); + ss->grid.grid_dirty = 1; + break; + case 3: + if (tt_mode != G_LIVE_V) { + tt_mode = G_LIVE_V; + set_mode(M_LIVE); + set_live_submode(1); + ss->grid.grid_dirty = 1; + } + break; + case 4: + tt_mode = tt_mode == G_LIVE_G ? G_LIVE_GF : G_LIVE_G; + set_mode(M_LIVE); + set_live_submode(tt_mode == G_LIVE_G ? 2 : 3); + ss->grid.grid_dirty = 1; + break; + case 6: + tt_last_mode = tt_mode; + tt_mode = G_TRACKER; + set_mode(M_PATTERN); + ss->grid.grid_dirty = 1; + break; + case 7: + tt_last_mode = tt_mode; + tt_mode = G_PRESET; + set_mode(M_PRESET_R); + ss->grid.grid_dirty = 1; + break; + default: + break; + } + return 1; + } + + // scripts + if (y == 1) { + if (!z || from_held) return 1; + tt_mode = G_EDIT; + tt_script = x; + set_edit_mode_script(tt_script); + set_mode(M_EDIT); + ss->grid.grid_dirty = 1; + return 1; + } + + // presets + if (tt_mode == G_PRESET) { + if (!z) return 1; + if (y > 1 && y < 6 && !from_held) { + if (preset_write) { + preset_write = 0; + set_mode(M_PRESET_R); + } + process_preset_r_preset(x + ((y - 2) << 3)); + ss->grid.grid_dirty = 1; + } else if (y == 6 && x == 7) { + if (preset_write) { + preset_write = 0; + set_mode(M_PRESET_R); + } + preset_line_up(); + ss->grid.grid_dirty = 1; + } else if (y == 7 && x == 7) { + if (preset_write) { + preset_write = 0; + set_mode(M_PRESET_R); + } + preset_line_down(); + ss->grid.grid_dirty = 1; + } else if (y == 7 && x == 2 && !from_held) { + if (preset_write) { + preset_write = 0; + set_mode(M_PRESET_R); + } else { + process_preset_r_load(); + set_mode(M_PRESET_R); + restore_last_mode(ss); + } + ss->grid.grid_dirty = 1; + } else if (y == 7 && x == 4 && !from_held) { + if (preset_write) { + flash_write(preset_select, ss, &scene_text); + flash_update_last_saved_scene(preset_select); + preset_write = 0; + restore_last_mode(ss); + } else { + set_mode(M_PRESET_W); + preset_write = 1; + } + ss->grid.grid_dirty = 1; + } else { + preset_write = 0; + set_mode(M_PRESET_R); + } + return 1; + } + + // mutes + if (y == 6) { + if (!z || from_held) return 1; + bool muted = ss_get_mute(ss, x); + ss_set_mute(ss, x, !muted); + screen_mutes_updated(); + ss->grid.grid_dirty = 1; + return 1; + } + + // trigger scripts + if (y == 7) { + if (!z) return 1; + script_triggers[x].on = 1; + script_triggers[x].ss = ss; + timer_add(&script_triggers[x].timer, 50, + &script_triggers_callback, (void *)&script_triggers[x]); + ss->grid.grid_dirty = 1; + run_script(ss, x); + return 1; + } + + // live variables + if (tt_mode == G_LIVE_V) { + if (y > 1 && y < 6 && x > 10 && x <13 && !from_held) { + variable_edit = z ? x - 2 + ((y - 2) << 1) : 0; + ss->grid.grid_dirty = 1; + return 1; + } + + if (!z) return 1; + + if (y == 3 && x == 0 && !from_held) { + ss->variables.m_act = !ss->variables.m_act; + screen_mutes_updated(); + tele_metro_updated(); + ss->grid.grid_dirty = 1; + } else if (y == 3 && x == 1 && !from_held) { + clear_delays_and_slews(ss); + ss->grid.grid_dirty = 1; + } else if (y == 4 && x < 2) { + x += 8; + script_triggers[x].on = 1; + script_triggers[x].ss = ss; + timer_add(&script_triggers[x].timer, 50, + &script_triggers_callback, (void *)&script_triggers[x]); + ss->grid.grid_dirty = 1; + run_script(ss, x); + } else if (y == 3 && x == 6) { + history_prev(); + } else if (y == 4 && x == 6) { + history_next(); + } else if (y == 4 && x == 7 && !from_held) { + execute_line(); + } + + return 1; + } + + // scripts + if (tt_mode == G_EDIT) { + if (!z || from_held) return 1; + + if (y == 3 && x == 0) { + ss->variables.m_act = !ss->variables.m_act; + screen_mutes_updated(); + tele_metro_updated(); + ss->grid.grid_dirty = 1; + } else if (y == 3 && x == 1) { + clear_delays_and_slews(ss); + ss->grid.grid_dirty = 1; + } else if (y == 4 && x < 2) { + x += 8; + script_triggers[x].on = 1; + script_triggers[x].ss = ss; + timer_add(&script_triggers[x].timer, 50, + &script_triggers_callback, (void *)&script_triggers[x]); + ss->grid.grid_dirty = 1; + run_script(ss, x); + } else if (y > 2 && y < 5 && x > 2 && x < 6) { + u8 i = x - 3 + (y - 3) * 3; + if (i >= ss_get_script_len(ss, tt_script)) return 1; + ss_toggle_script_comment(ss, tt_script, i); + edit_mode_refresh(); + ss->grid.grid_dirty = 1; + } else if (y == 3 && x == 7) { + for (u8 i = 0; i < ss_get_script_len(ss, tt_script); i++) + ss_set_script_comment(ss, tt_script, i, 1); + edit_mode_refresh(); + ss->grid.grid_dirty = 1; + } else if (y == 4 && x == 7) { + for (u8 i = 0; i < ss_get_script_len(ss, tt_script); i++) + ss_set_script_comment(ss, tt_script, i, 0); + edit_mode_refresh(); + ss->grid.grid_dirty = 1; + } + return 1; + } + + return 1; } void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { @@ -193,7 +610,7 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { u8 x = SG.rotate && !emulated ? size_x - _x - 1 : _x; u8 y = SG.rotate && !emulated ? size_y - _y - 1 : _y; - if (control_mode ? !emulated : true) { + if (control_mode_on ? !emulated : true) { u8 key = (y << 4) | x; if (z) { for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) @@ -216,12 +633,8 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { } } - if (control_mode) { - if (!emulated && (size_x <= 8 || tt_mode != M_LIVE || x > 7)) { - grid_control_process_key(ss, x, y, z, 0); - return; - } - } + if (control_mode_on && !emulated) + if (grid_control_process_key(ss, x, y, z, 0)) return; u8 refresh = 0; u8 scripts[SCRIPT_COUNT]; @@ -387,12 +800,8 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { } void grid_process_key_hold_repeat(scene_state_t *ss, u8 x, u8 y) { - if (control_mode) { - if (size_x <= 8 || tt_mode != M_LIVE || x > 7) { - grid_control_process_key(ss, x, y, 1, 1); - return; - } - } + if (control_mode_on) + if (grid_control_process_key(ss, x, y, 1, 1)) return; u8 refresh = 0; u8 scripts[SCRIPT_COUNT]; @@ -496,11 +905,6 @@ void grid_refresh(scene_state_t *ss) { grid_fill_area(0, 0, size_x, size_y, 0); - if (control_mode) { - grid_control_refresh(); - return; - } - u16 x, y; for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { if (GXYC.enabled && SG.group[GXYC.group].enabled) { @@ -616,6 +1020,8 @@ void grid_refresh(scene_state_t *ss) { } } + if (control_mode_on) grid_control_refresh(ss); + SG.grid_dirty = 0; } diff --git a/module/grid.h b/module/grid.h index 7fe93052..130ac9ab 100644 --- a/module/grid.h +++ b/module/grid.h @@ -19,7 +19,8 @@ typedef enum { GRID_MODE_LAST } screen_grid_mode; -extern void grid_set_control_mode(u8 control); +extern void grid_set_control_mode(u8 control, scene_state_t *ss); +extern void grid_metro_triggered(scene_state_t *ss); extern void grid_refresh(scene_state_t *ss); extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 ctrl, u8 x1, u8 y1, u8 x2, u8 y2); diff --git a/module/live_mode.c b/module/live_mode.c index 523b08f4..57e7b5de 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -32,9 +32,11 @@ static error_t status; static char error_msg[TELE_ERROR_MSG_LENGTH]; static bool show_welcome_message; static screen_grid_mode grid_mode = GRID_MODE_OFF; -static uint8_t grid_page = 0, grid_ctrl = 0, grid_view_changed = 0; +static uint8_t grid_view_changed = 0; static uint8_t grid_x1 = 0, grid_y1 = 0, grid_x2 = 0, grid_y2 = 0; static uint8_t grid_pressed = 0; +uint8_t grid_page = 0; +uint8_t grid_show_controls = 0; static const uint8_t D_INPUT = 1 << 0; static const uint8_t D_LIST = 1 << 1; @@ -113,6 +115,89 @@ void set_live_mode() { if (grid_mode == GRID_MODE_FULL) grid_mode = GRID_MODE_EDIT; } +void set_live_submode(u8 submode) { + line_editor_set(&le, ""); + history_line = -1; + if (submode == 0) { + show_vars = 0; + grid_mode = GRID_MODE_OFF; + } else if (submode == 1) { + show_vars = 1; + grid_mode = GRID_MODE_OFF; + } else if (submode == 2) { + show_vars = 0; + grid_mode = GRID_MODE_EDIT; + } else if (submode == 3) { + show_vars = 0; + grid_mode = GRID_MODE_FULL; + } else return; + dirty = D_ALL; + activity_prev = 0xFF; + grid_view_changed = true; +} + +void history_next() { + if (history_line > 0) { + history_line--; + line_editor_set_command(&le, &history[history_line]); + } + else { + history_line = -1; + line_editor_set(&le, ""); + } + dirty |= D_INPUT; +} + +void history_prev() { + if (history_line < history_top) { + history_line++; + line_editor_set_command(&le, &history[history_line]); + dirty |= D_INPUT; + } +} + +void execute_line() { + dirty |= D_MESSAGE; // something will definitely happen + dirty |= D_INPUT; + + tele_command_t command; + command.comment = false; + + 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 + + if (command.length) { + // increase history_size up to a maximum + history_top++; + if (history_top >= MAX_HISTORY_SIZE) + history_top = MAX_HISTORY_SIZE - 1; + + // shuffle the history up + // should really use some sort of ring buffer + for (size_t i = history_top; i > 0; i--) { + memcpy(&history[i], &history[i - 1], sizeof(command)); + } + memcpy(&history[0], &command, sizeof(command)); + + ss_clear_script(&scene_state, TEMP_SCRIPT); + ss_overwrite_script_command(&scene_state, TEMP_SCRIPT, 0, &command); + exec_state_t es; + es_init(&es); + es_push(&es); + es_variables(&es)->script_number = TEMP_SCRIPT; + + output = run_script_with_exec_state(&scene_state, &es, TEMP_SCRIPT); + } + + history_line = -1; + line_editor_set(&le, ""); +} + static void emulate_grid_release(scene_state_t *ss) { grid_process_key(ss, grid_x1, grid_y1, 0, 1); if (grid_x1 != grid_x2 || grid_y1 != grid_y2) @@ -132,24 +217,12 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, // or C-n: history next if ((match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) && grid_mode != GRID_MODE_FULL) { - if (history_line > 0) { - history_line--; - line_editor_set_command(&le, &history[history_line]); - } - else { - history_line = -1; - line_editor_set(&le, ""); - } - dirty |= D_INPUT; + history_next(); } // or C-p: history previous else if ((match_no_mod(m, k, HID_UP) || match_ctrl(m, k, HID_P)) && grid_mode != GRID_MODE_FULL) { - if (history_line < history_top) { - history_line++; - line_editor_set_command(&le, &history[history_line]); - dirty |= D_INPUT; - } + history_prev(); } // A-G: toggle grid view else if (match_alt(m, k, HID_G) || @@ -301,50 +374,12 @@ void process_live_keys(uint8_t k, uint8_t m, bool is_held_key, bool is_release, else if (match_alt(m, k, HID_BACKSLASH) || (grid_mode == GRID_MODE_FULL && match_no_mod(m, k, HID_BACKSLASH))) { - grid_ctrl = !grid_ctrl; + grid_show_controls = !grid_show_controls; grid_view_changed = true; } // : execute command else if (match_no_mod(m, k, HID_ENTER) && grid_mode != GRID_MODE_FULL) { - dirty |= D_MESSAGE; // something will definitely happen - dirty |= D_INPUT; - - tele_command_t command; - command.comment = false; - - 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 - - if (command.length) { - // increase history_size up to a maximum - history_top++; - if (history_top >= MAX_HISTORY_SIZE) - history_top = MAX_HISTORY_SIZE - 1; - - // shuffle the history up - // should really use some sort of ring buffer - for (size_t i = history_top; i > 0; i--) { - memcpy(&history[i], &history[i - 1], sizeof(command)); - } - memcpy(&history[0], &command, sizeof(command)); - - ss_clear_script(&scene_state, TEMP_SCRIPT); - ss_overwrite_script_command(&scene_state, TEMP_SCRIPT, 0, &command); - exec_state_t es; - es_init(&es); - es_push(&es); - es_variables(&es)->script_number = TEMP_SCRIPT; - - output = run_script_with_exec_state(&scene_state, &es, TEMP_SCRIPT); - } - - history_line = -1; - line_editor_set(&le, ""); + execute_line(); } // [ or ]: switch to edit mode else if (match_no_mod(m, k, HID_OPEN_BRACKET) || @@ -378,7 +413,7 @@ uint8_t screen_refresh_live(scene_state_t *ss) { (grid_view_changed || ss->grid.scr_dirty)) { grid_view_changed = 0; screen_dirty = 0b111111; - grid_screen_refresh(ss, grid_mode, grid_page, grid_ctrl, grid_x1, + grid_screen_refresh(ss, grid_mode, grid_page, grid_show_controls, grid_x1, grid_y1, grid_x2, grid_y2); } if (grid_mode == GRID_MODE_FULL) return 0b11111111; diff --git a/module/live_mode.h b/module/live_mode.h index 4b6ea010..5f187834 100644 --- a/module/live_mode.h +++ b/module/live_mode.h @@ -10,8 +10,14 @@ void set_slew_icon(bool display); void set_metro_icon(bool display); void init_live_mode(void); void set_live_mode(void); +void set_live_submode(u8 submode); +void history_next(void); +void history_prev(void); +void execute_line(void); void process_live_keys(uint8_t key, uint8_t mod_key, bool is_held_key, bool is_release, scene_state_t *ss); uint8_t screen_refresh_live(scene_state_t *ss); void set_vars_updated(void); +extern uint8_t grid_page; +extern uint8_t grid_show_controls; #endif diff --git a/module/main.c b/module/main.c index eb7ba115..d67c0332 100644 --- a/module/main.c +++ b/module/main.c @@ -307,13 +307,13 @@ void handler_Front(int32_t data) { if (data == 0) { if (grid_connected) { grid_control_mode = !grid_control_mode; - grid_set_control_mode(grid_control_mode); + grid_set_control_mode(grid_control_mode, &scene_state); return; } if (mode != M_PRESET_R) { front_timer = 0; - set_preset_r_mode(adc[1]); + set_preset_r_mode(adc[1] >> 7); set_mode(M_PRESET_R); } else @@ -346,8 +346,8 @@ void handler_PollADC(int32_t data) { process_pattern_knob(adc[1], mod_key); ss_set_param(&scene_state, adc[1] << 2); } - else if (mode == M_PRESET_R) { - process_preset_r_knob(adc[1], mod_key); + else if (mode == M_PRESET_R && !(grid_connected && grid_control_mode)) { + process_preset_r_preset(adc[1] >> 7); } else { ss_set_param(&scene_state, adc[1] << 2); @@ -360,7 +360,7 @@ void handler_PollADC(int32_t data) { void handler_KeyTimer(int32_t data) { if (front_timer) { if (front_timer == 1 && !grid_connected) { - if (mode == M_PRESET_R) { process_preset_r_long_front(); } + if (mode == M_PRESET_R) { process_preset_r_load(); } front_timer = 0; } else @@ -454,8 +454,11 @@ void handler_ScreenRefresh(int32_t data) { case M_SCREENSAVER: screen_dirty = screen_refresh_screensaver(); break; } + u8 grid = 0; for (size_t i = 0; i < 8; i++) - if (screen_dirty & (1 << i)) { region_draw(&line[i]); } + if (screen_dirty & (1 << i)) { grid = 1; region_draw(&line[i]); } + if (grid_connected && grid_control_mode && grid) + scene_state.grid.grid_dirty = 1; #ifdef TELETYPE_PROFILE profile_update(&prof_ScreenRefresh); #endif @@ -473,6 +476,8 @@ void handler_AppCustom(int32_t data) { if (ss_get_script_len(&scene_state, METRO_SCRIPT)) { set_metro_icon(true); run_script(&scene_state, METRO_SCRIPT); + if (grid_connected && grid_control_mode) + grid_metro_triggered(&scene_state); } else set_metro_icon(false); @@ -581,7 +586,7 @@ void set_mode(tele_mode_t m) { mode = M_PRESET_W; break; case M_PRESET_R: - set_preset_r_mode(adc[1]); + set_preset_r_mode(adc[1] >> 7); mode = M_PRESET_R; break; case M_HELP: @@ -608,6 +613,11 @@ void set_last_mode() { set_mode(M_LIVE); } +// defined in globals.h +void clear_delays_and_slews(scene_state_t *ss) { + clear_delays(ss); + for (int i = 0; i < 4; i++) { aout[i].step = 1; } +} //////////////////////////////////////////////////////////////////////////////// // key handling @@ -682,10 +692,7 @@ bool process_global_keys(uint8_t k, uint8_t m, bool is_held_key) { } // win-: clear delays, stack and slews else if (match_win(m, k, HID_ESCAPE)) { - if (!is_held_key) { - clear_delays(&scene_state); - for (int i = 0; i < 4; i++) { aout[i].step = 1; } - } + if (!is_held_key) clear_delays_and_slews(&scene_state); return true; } // -?: help text, or return to last mode @@ -713,13 +720,13 @@ bool process_global_keys(uint8_t k, uint8_t m, bool is_held_key) { return true; } // ctrl- through ctrl- mute triggers - // ctrl- toggle metro else if (mod_only_ctrl(m) && k >= HID_F1 && k <= HID_F8) { bool muted = ss_get_mute(&scene_state, (k - HID_F1)); ss_set_mute(&scene_state, (k - HID_F1), !muted); screen_mutes_updated(); return true; } + // ctrl- toggle metro else if (mod_only_ctrl(m) && k == HID_F9) { scene_state.variables.m_act = !scene_state.variables.m_act; tele_metro_updated(); @@ -790,10 +797,15 @@ void tele_metro_updated() { set_metro_icon(true); else set_metro_icon(false); + + if (grid_connected && grid_control_mode) scene_state.grid.grid_dirty = 1; } void tele_metro_reset() { - if (metro_timer_enabled) { timer_reset(&metroTimer); } + if (metro_timer_enabled) { + timer_reset(&metroTimer); + if (grid_connected && grid_control_mode) scene_state.grid.grid_dirty = 1; + } } void tele_tr(uint8_t i, int16_t v) { @@ -953,7 +965,7 @@ int main(void) { // wait 50ms before running the init script to allow for any i2c devices to // fully initalise - delay_ms(50); + delay_ms(1500); run_script(&scene_state, INIT_SCRIPT); scene_state.initializing = false; diff --git a/module/preset_r_mode.c b/module/preset_r_mode.c index 055c8577..6a2fa27d 100644 --- a/module/preset_r_mode.c +++ b/module/preset_r_mode.c @@ -15,44 +15,51 @@ #include "usb_protocol_hid.h" static uint8_t offset; -static uint8_t knob_last; +static uint8_t preset_last; static bool dirty; static void do_preset_read(void); -void set_preset_r_mode(uint16_t knob) { - knob_last = knob >> 7; +void set_preset_r_mode(uint8_t preset) { + preset_last = preset; 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; +void process_preset_r_preset(uint8_t preset) { + if (preset != preset_last) { + preset_select = preset; + preset_last = preset; dirty = true; } } -void process_preset_r_long_front() { +void process_preset_r_load() { do_preset_read(); } +void preset_line_down() { + if (offset < SCENE_TEXT_LINES - 8) { + offset++; + dirty = true; + } +} + +void preset_line_up() { + if (offset) { + offset--; + dirty = true; + } +} + void process_preset_r_keys(uint8_t k, uint8_t m, bool is_held_key) { // 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; - } + preset_line_down(); } // 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; - } + preset_line_up(); } // or [: preset down else if (match_no_mod(m, k, HID_LEFT) || diff --git a/module/preset_r_mode.h b/module/preset_r_mode.h index b6aa68ad..3bd8a43d 100644 --- a/module/preset_r_mode.h +++ b/module/preset_r_mode.h @@ -4,9 +4,11 @@ #include #include -void set_preset_r_mode(uint16_t knob); -void process_preset_r_knob(uint16_t knob, uint8_t mod_key); -void process_preset_r_long_front(void); +void set_preset_r_mode(uint8_t preset); +void process_preset_r_preset(uint8_t preset); +void preset_line_down(void); +void preset_line_up(void); +void process_preset_r_load(void); void process_preset_r_keys(uint8_t key, uint8_t mod_key, bool is_held_key); uint8_t screen_refresh_preset_r(void); diff --git a/src/ops/init.c b/src/ops/init.c index 972834b4..8370efb5 100644 --- a/src/ops/init.c +++ b/src/ops/init.c @@ -98,13 +98,17 @@ static void op_INIT_SCRIPT_ALL_get(const void *NOTUSED(data), scene_state_t *ss, static void op_INIT_P_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t v = cs_pop(cs); - if (v >= 0 && v < 4) ss_pattern_init(ss, v); + if (v >= 0 && v < 4) { + ss_pattern_init(ss, v); + tele_pattern_updated(); + } } static void op_INIT_P_ALL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *NOTUSED(cs)) { ss_patterns_init(ss); + tele_pattern_updated(); } static void op_INIT_CV_get(const void *NOTUSED(data), scene_state_t *ss, diff --git a/src/state.c b/src/state.c index b450ae36..821f9fb1 100644 --- a/src/state.c +++ b/src/state.c @@ -238,6 +238,11 @@ bool ss_get_script_comment(scene_state_t *ss, script_number_t script_idx, return ss->scripts[script_idx].c[c_idx].comment; } +void ss_set_script_comment(scene_state_t *ss, script_number_t script_idx, + size_t c_idx, uint8_t on) { + ss->scripts[script_idx].c[c_idx].comment = on; +} + void ss_toggle_script_comment(scene_state_t *ss, script_number_t script_idx, size_t c_idx) { ss->scripts[script_idx].c[c_idx].comment = diff --git a/src/state.h b/src/state.h index 4c52171b..11adabfe 100644 --- a/src/state.h +++ b/src/state.h @@ -246,6 +246,8 @@ void ss_copy_script_command(tele_command_t *dest, scene_state_t *ss, script_number_t script_idx, size_t c_idx); bool ss_get_script_comment(scene_state_t *ss, script_number_t script_idx, size_t c_idx); +void ss_set_script_comment(scene_state_t *ss, script_number_t script_idx, + size_t c_idx, uint8_t on); void ss_toggle_script_comment(scene_state_t *ss, script_number_t script_idx, size_t c_idx); void ss_overwrite_script_command(scene_state_t *ss, script_number_t script_idx, From e49733bab2dd198a3f4d3da8a19e4456b9f844be Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 16 Apr 2018 19:00:29 -0700 Subject: [PATCH 048/117] grid control pt 3 --- module/grid.c | 57 +++++++++++++++++++++++++++++++++++++------ module/pattern_mode.c | 54 ++++++++++++++++++++++++++++++---------- module/pattern_mode.h | 6 +++++ 3 files changed, 97 insertions(+), 20 deletions(-) diff --git a/module/grid.c b/module/grid.c index 89451869..651393dc 100644 --- a/module/grid.c +++ b/module/grid.c @@ -8,6 +8,7 @@ #include "util.h" #include "edit_mode.h" #include "live_mode.h" +#include "pattern_mode.h" #include "preset_r_mode.h" #include "flash.h" @@ -173,7 +174,7 @@ typedef struct { static grid_control_mode_t tt_mode = G_LIVE_V, tt_last_mode = G_LIVE_V; static u8 control_mode_on = 0, tt_script = 0, variable_edit = 0; -static u8 preset_write = 0; +static u8 preset_write = 0, tracker_pressed = 0; static u16 size_x = 16, size_y = 8; static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION/2]; static hold_repeat_info held_keys[GRID_MAX_KEY_PRESSED]; @@ -211,8 +212,30 @@ void grid_control_refresh(scene_state_t *ss) { monomeLedBuffer[d+i+size_x*j] = 0; if (tt_mode == G_TRACKER) { - // TODO finish tracker view - monomeLedBuffer[d+6] = h; + monomeLedBuffer[d+7] = h; + u8 offset = get_pattern_offset(), in, off, rem; + for (u16 j = 0; j < 8; j++) { + for (u16 i = 0; i < 4; i++) { + in = offset + j >= ss_get_pattern_start(ss, i) && + offset + j <= ss_get_pattern_end(ss, i); + monomeLedBuffer[d+i+2+(j*size_x)] = + tracker_pressed ? h : + (ss_get_pattern_val(ss, i, j + offset) ? + (in ? h : b) : (in ? m : l)); + } + off = offset >> 3; + rem = (offset & 7) >> 1; + monomeLedBuffer[d+j*size_x] = + j == off ? b - rem : (j == off + 1 ? l + rem: l); + } + d += size_x * 3; + monomeLedBuffer[d+7] = m; + d += size_x; + monomeLedBuffer[d+7] = m; + d += size_x << 1; + monomeLedBuffer[d+7] = m; + d += size_x; + monomeLedBuffer[d+7] = m; return; } @@ -221,16 +244,17 @@ void grid_control_refresh(scene_state_t *ss) { monomeLedBuffer[d+1] = tt_mode == G_EDIT && tt_script == 9 ? h : m; monomeLedBuffer[d+3] = tt_mode == G_LIVE_V ? h : m; monomeLedBuffer[d+4] = tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF ? h : m; + monomeLedBuffer[d+7] = m; monomeLedBuffer[d+7] = tt_mode == G_PRESET ? h : m; d += size_x; - for (u16 i = 0; i < 7; i++) + for (u16 i = 0; i < 8; i++) monomeLedBuffer[d+i] = tt_mode == G_EDIT && tt_script == i ? h : m; d += size_x; if (tt_mode == G_PRESET) { monomeLedBuffer[d+6] = h; for (u8 j = 0; j < 25; j += 8) { - for (u16 i = 0; i < 7; i++) + for (u16 i = 0; i < 8; i++) monomeLedBuffer[d+i] = i + j == preset_select ? h : l; d += size_x; } @@ -357,6 +381,9 @@ static void restore_last_mode(scene_state_t *ss) { } else if (tt_mode == G_LIVE_GF) { set_mode(M_LIVE); set_live_submode(3); + } else if (tt_mode == G_TRACKER) { + tt_mode = G_TRACKER; + set_mode(M_PATTERN); } ss->grid.grid_dirty = 1; } @@ -382,9 +409,25 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ x -= 8; } + // tracker if (tt_mode == G_TRACKER) { - // TODO tracker - if (x == 7 && y == 0 && !from_held && z) restore_last_mode(ss); + if (tracker_pressed) { + return 1; + } + + if (x == 7 && y == 0 && !from_held && z) { + restore_last_mode(ss); + ss->grid.grid_dirty = 1; + } else if (x == 0 && !from_held && z) { + set_pattern_offset(y); + ss->grid.grid_dirty = 1; + } else if (x == 7 && y == 6 && z) { + pattern_up(); + ss->grid.grid_dirty = 1; + } else if (x == 7 && y == 7 && z) { + pattern_down(); + ss->grid.grid_dirty = 1; + } return 1; } diff --git a/module/pattern_mode.c b/module/pattern_mode.c index 6a9e954d..1c18af09 100644 --- a/module/pattern_mode.c +++ b/module/pattern_mode.c @@ -39,16 +39,49 @@ void set_pattern_mode() { edit_buffer = 0; } +uint8_t get_pattern_offset() { + return offset; +} + +void set_pattern_offset(uint8_t o) { + base = 0; + offset = o; + dirty = true; +} + +void set_pattern_editing(uint8_t on) { + editing_number = on; + dirty = true; +} + +void set_pattern_pattern(uint8_t p) { + pattern = p; + dirty = true; +} + +void pattern_up() { + editing_number = false; + if (base) + base--; + else if (offset) + offset--; + dirty = true; +} + +void pattern_down() { + editing_number = false; + base++; + if (base == 8) { + base = 7; + if (offset < 56) { offset++; } + } + dirty = true; +} + void process_pattern_keys(uint8_t k, uint8_t m, bool is_held_key) { // : move down if (match_no_mod(m, k, HID_DOWN)) { - editing_number = false; - base++; - if (base == 8) { - base = 7; - if (offset < 56) { offset++; } - } - dirty = true; + pattern_down(); } // alt-: move a page down else if (match_alt(m, k, HID_DOWN)) { @@ -63,12 +96,7 @@ void process_pattern_keys(uint8_t k, uint8_t m, bool is_held_key) { } // : move up else if (match_no_mod(m, k, HID_UP)) { - editing_number = false; - if (base) - base--; - else if (offset) - offset--; - dirty = true; + pattern_up(); } // alt-: move a page up else if (match_alt(m, k, HID_UP)) { diff --git a/module/pattern_mode.h b/module/pattern_mode.h index 1b9133f3..94d326f9 100644 --- a/module/pattern_mode.h +++ b/module/pattern_mode.h @@ -8,5 +8,11 @@ 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); uint8_t screen_refresh_pattern(void); +uint8_t get_pattern_offset(void); +void set_pattern_offset(uint8_t offset); +void set_pattern_editing(uint8_t on); +void set_pattern_pattern(uint8_t pattern); +void pattern_up(void); +void pattern_down(void); #endif From e51c7bebbd9776aeb308b9d5ae08346481fdaef1 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 13 May 2018 19:17:44 -0700 Subject: [PATCH 049/117] undo for script editing --- module/edit_mode.c | 65 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/module/edit_mode.c b/module/edit_mode.c index a3a20d5c..d5368e36 100644 --- a/module/edit_mode.c +++ b/module/edit_mode.c @@ -18,11 +18,18 @@ #include "conf_usb_host.h" // needed in order to include "usb_protocol_hid.h" #include "usb_protocol_hid.h" +#define UNDO_DEPTH 3 + static line_editor_t le; -static uint8_t line_no1 = 0, line_no2 = 0; +static uint8_t line_no1, line_no2; static uint8_t script; static error_t status; static char error_msg[TELE_ERROR_MSG_LENGTH]; +static tele_command_t undo_buffer[UNDO_DEPTH][SCRIPT_MAX_COMMANDS]; +static uint8_t undo_comments[UNDO_DEPTH][SCRIPT_MAX_COMMANDS]; +static uint8_t undo_length[UNDO_DEPTH]; +static uint8_t undo_line_no1[UNDO_DEPTH], undo_line_no2[UNDO_DEPTH]; +static uint8_t undo_count, undo_pos; static const uint8_t D_INPUT = 1 << 0; static const uint8_t D_LIST = 1 << 1; @@ -36,12 +43,50 @@ void set_edit_mode() { line_no2 = line_no1 = 0; line_editor_set_command( &le, ss_get_script_command(&scene_state, script, line_no1)); + undo_count = 0; dirty = D_ALL; } void set_edit_mode_script(uint8_t new_script) { script = new_script; if (script >= SCRIPT_COUNT) script = SCRIPT_COUNT - 2; + undo_count = 0; + dirty = D_ALL; +} + +static void save_undo(void) { + if (++undo_count > 3) undo_count = 3; + undo_pos = (undo_pos + 1) % UNDO_DEPTH; + undo_line_no1[undo_pos] = line_no1; + undo_line_no2[undo_pos] = line_no2; + undo_length[undo_pos] = ss_get_script_len(&scene_state, script); + for (u8 l = 0; l < undo_length[undo_pos]; l++) { + undo_comments[undo_pos][l] = ss_get_script_comment(&scene_state, + script, l); + ss_copy_script_command(&undo_buffer[undo_pos][l], + &scene_state, script, l); + } +} + +static void undo(void) { + if (undo_count == 0) return; + undo_count--; + + ss_clear_script(&scene_state, script); + for (u8 l = 0; l < undo_length[undo_pos]; l++) { + ss_insert_script_command(&scene_state, script, l, + &undo_buffer[undo_pos][l]); + ss_set_script_comment(&scene_state, script, l, + undo_comments[undo_pos][l]); + } + + line_no1 = undo_line_no1[undo_pos]; + line_no2 = undo_line_no2[undo_pos]; + + undo_pos = (undo_pos + UNDO_DEPTH - 1) % UNDO_DEPTH; + + line_editor_set_command( + &le, ss_get_script_command(&scene_state, script, line_no1)); dirty = D_ALL; } @@ -50,8 +95,12 @@ void edit_mode_refresh() { } void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { + // C-z: undo + if (match_ctrl(m, k, HID_Z)) { + undo(); + } // or C-n: line down - if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) { + else if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) { if (line_no1 < (SCRIPT_MAX_COMMANDS - 1) && line_no1 < ss_get_script_len(&scene_state, script)) { line_no1++; @@ -116,6 +165,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { &le, ss_get_script_command(&scene_state, script, line_no1)); line_no2 = line_no1; dirty |= D_LIST | D_INPUT; + undo_count = 0; } // ]: next script else if (match_no_mod(m, k, HID_CLOSE_BRACKET)) { @@ -129,6 +179,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { &le, ss_get_script_command(&scene_state, script, line_no1)); line_no2 = line_no1; dirty |= D_LIST | D_INPUT; + undo_count = 0; } // alt-: move selected lines down else if (match_alt(m, k, HID_DOWN)) { @@ -136,6 +187,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { u8 l2 = max(line_no1, line_no2); if (l2 < SCRIPT_MAX_COMMANDS - 1 && l2 < max(1, ss_get_script_len(&scene_state, script)) - 1) { + save_undo(); tele_command_t temp; ss_copy_script_command(&temp, &scene_state, script, l2 + 1); ss_delete_script_command(&scene_state, script, l2 + 1); @@ -150,6 +202,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { u8 l1 = min(line_no1, line_no2); u8 l2 = max(line_no1, line_no2); if (l1 && l2 < ss_get_script_len(&scene_state, script)) { + save_undo(); tele_command_t temp; ss_copy_script_command(&temp, &scene_state, script, l1 - 1); ss_delete_script_command(&scene_state, script, l1 - 1); @@ -163,12 +216,14 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { else if (match_ctrl(m, k, HID_X) || match_alt(m, k, HID_X)) { if (line_no1 == line_no2) { if (line_no1 < ss_get_script_len(&scene_state, script)) { + save_undo(); strcpy(copy_buffer[0], line_editor_get(&le)); copy_buffer_len = 1; ss_delete_script_command(&scene_state, script, line_no1); } } else { + save_undo(); u8 l1 = min(line_no1, line_no2); u8 l2 = max(line_no1, line_no2); copy_buffer_len = 0; @@ -196,6 +251,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { if (processed) dirty |= D_INPUT; } else { + save_undo(); copy_buffer_len = 0; for (u8 l = min(line_no1, line_no2); l <= max(line_no1, line_no2); l++) print_command(ss_get_script_command(&scene_state, script, l), @@ -206,6 +262,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { else if (match_ctrl(m, k, HID_V) || match_alt(m, k, HID_V)) { if (copy_buffer_len == 0) return; + save_undo(); u8 idx = min(line_no1, line_no2); line_no1 = idx; tele_command_t command; @@ -229,6 +286,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { u8 l1 = min(line_no1, line_no2); u8 l2 = max(line_no1, line_no2); if (l1 < ss_get_script_len(&scene_state, script)) { + save_undo(); for (s8 l = l2; l >= l1; l--) ss_delete_script_command(&scene_state, script, l); if (line_no1 > ss_get_script_len(&scene_state, script)) @@ -262,6 +320,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { if (status != E_OK) return; // quit, screen_refresh_edit will display the error message + save_undo(); if (command.length == 0) { // blank line, delete the command ss_delete_script_command(&scene_state, script, line_no1); if (line_no1 > ss_get_script_len(&scene_state, script)) { @@ -295,6 +354,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { if (status != E_OK) return; // quit, screen_refresh_edit will display the error message + save_undo(); if (command.length > 0) { ss_insert_script_command(&scene_state, script, line_no1, &command); if (line_no1 < (SCRIPT_MAX_COMMANDS - 1)) { line_no1++; } @@ -308,6 +368,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { // alt-slash comment toggle selected lines else if (match_alt(m, k, HID_SLASH)) { if (line_no1 >= ss_get_script_len(&scene_state, script)) return; + save_undo(); for (u8 l = min(line_no1, line_no2); l <= max(line_no1, line_no2); l++) ss_toggle_script_comment(&scene_state, script, l); dirty |= D_LIST; From 0d19a6d264b6d22055265db76b2cd180217018b5 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 13 May 2018 19:18:48 -0700 Subject: [PATCH 050/117] grid control pt 4 --- module/grid.c | 469 +++++++++++++++++++++++++++++++----------- module/pattern_mode.c | 8 +- module/pattern_mode.h | 3 +- 3 files changed, 353 insertions(+), 127 deletions(-) diff --git a/module/grid.c b/module/grid.c index 651393dc..05422e38 100644 --- a/module/grid.c +++ b/module/grid.c @@ -173,8 +173,10 @@ typedef struct { } script_trigger_info; static grid_control_mode_t tt_mode = G_LIVE_V, tt_last_mode = G_LIVE_V; -static u8 control_mode_on = 0, tt_script = 0, variable_edit = 0; -static u8 preset_write = 0, tracker_pressed = 0; +static u8 control_mode_on, tt_script, variable_edit; +static u8 preset_write, tracker_pressed, tracker_x, tracker_y; +static u8 tracker_changed, tracker_select, tracker_selected; +static s16 tracker_last; static u16 size_x = 16, size_y = 8; static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION/2]; static hold_repeat_info held_keys[GRID_MAX_KEY_PRESSED]; @@ -202,150 +204,226 @@ void grid_control_refresh(scene_state_t *ss) { u16 d = size_y == 16 ? 128 : 0; if (size_x == 16) d += 8; - u8 l = 4; - u8 m = 6; - u8 b = 8; - u8 h = 15; + u8 mode_on = 15; + u8 mode_off = 7; + u8 exec = 15; + u8 trig = 7; + u8 kill = 11; + u8 tracker_in = 6; + u8 tracker_out = 3; + u8 tracker_on = 13; + u8 tracker_pos = 2; + u8 tracker_page_on = 11; + u8 tracker_page_off = 5; + u8 tracker_loop = 5; + u8 tracker_control = 11; + u8 preset_selected = 15; + u8 preset_unselected = 4; + u8 preset_scroll = 8; + u8 preset_load = 11; + u8 preset_save = 15; + u8 var_edit_on = 11; + u8 var_edit_off = 6; + u8 var_value_on = 11; + u8 var_value_off = 4; + u8 live_hist = 7; + u8 live_exec = 11; + u8 mute_on = 8; + u8 mute_off = 4; + u8 grid_page_on = 8; + u8 grid_page_off = 4; + u8 line_on = 8; + u8 line_off = 4; + u8 script_control = 8; + + if (!monome_is_vari()) { + mode_on = 15; + mode_off = 15; + exec = 15; + trig = 15; + kill = 15; + tracker_in = 0; + tracker_out = 0; + tracker_on = 15; + tracker_page_on = 15; + tracker_page_off = 0; + tracker_loop = 15; + tracker_control = 15; + preset_selected = 15; + preset_unselected = 15; + preset_scroll = 15; + preset_load = 15; + preset_save = 15; + var_edit_on = 15; + var_edit_off = 15; + var_value_on = 15; + var_value_off = 0; + live_hist = 15; + live_exec = 15; + mute_on = 15; + mute_off = 15; + grid_page_on = 15; + grid_page_off = 15; + line_on = 15; + line_off = 15; + script_control = 15; + } for (u16 i = 0; i < 8; i++) for (u16 j = 0; j < 8; j++) monomeLedBuffer[d+i+size_x*j] = 0; if (tt_mode == G_TRACKER) { - monomeLedBuffer[d+7] = h; + monomeLedBuffer[d+7] = mode_on; u8 offset = get_pattern_offset(), in, off, rem; for (u16 j = 0; j < 8; j++) { for (u16 i = 0; i < 4; i++) { in = offset + j >= ss_get_pattern_start(ss, i) && offset + j <= ss_get_pattern_end(ss, i); monomeLedBuffer[d+i+2+(j*size_x)] = - tracker_pressed ? h : - (ss_get_pattern_val(ss, i, j + offset) ? - (in ? h : b) : (in ? m : l)); + ss_get_pattern_val(ss, i, j + offset) ? + tracker_on : (in ? tracker_in : tracker_out); } off = offset >> 3; rem = (offset & 7) >> 1; monomeLedBuffer[d+j*size_x] = - j == off ? b - rem : (j == off + 1 ? l + rem: l); + j == off ? tracker_page_on - rem : + (j == off + 1 ? tracker_page_off + rem : tracker_page_off); } - d += size_x * 3; - monomeLedBuffer[d+7] = m; - d += size_x; - monomeLedBuffer[d+7] = m; + for (u16 i = 0; i < 4; i++) { + u8 index = ss_get_pattern_idx(ss, i); + if (index >= offset && index <= offset + 7) { + monomeLedBuffer[d+i+2+(index*size_x)] += tracker_pos; + } + } + d += size_x << 1; - monomeLedBuffer[d+7] = m; + monomeLedBuffer[d+7] = tracker_control; d += size_x; - monomeLedBuffer[d+7] = m; + monomeLedBuffer[d+7] = + turtle_get_shown(&ss->turtle) ? tracker_control : tracker_loop; + d += size_x; + monomeLedBuffer[d+7] = tracker_loop; + d += size_x; + monomeLedBuffer[d+7] = tracker_loop; + d += size_x; + monomeLedBuffer[d+7] = tracker_control; + d += size_x; + monomeLedBuffer[d+7] = tracker_control; return; } // mode selection - monomeLedBuffer[d] = tt_mode == G_EDIT && tt_script == 8 ? h : m; - monomeLedBuffer[d+1] = tt_mode == G_EDIT && tt_script == 9 ? h : m; - monomeLedBuffer[d+3] = tt_mode == G_LIVE_V ? h : m; - monomeLedBuffer[d+4] = tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF ? h : m; - monomeLedBuffer[d+7] = m; - monomeLedBuffer[d+7] = tt_mode == G_PRESET ? h : m; + monomeLedBuffer[d] = + tt_mode == G_EDIT && tt_script == 8 ? mode_on : mode_off; + monomeLedBuffer[d+1] = + tt_mode == G_EDIT && tt_script == 9 ? mode_on : mode_off; + monomeLedBuffer[d+3] = tt_mode == G_LIVE_V ? mode_on : mode_off; + monomeLedBuffer[d+4] = + tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF ? mode_on : mode_off; + monomeLedBuffer[d+6] = tt_mode == G_PRESET ? mode_on : mode_off; + monomeLedBuffer[d+7] = mode_off; d += size_x; for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = tt_mode == G_EDIT && tt_script == i ? h : m; + monomeLedBuffer[d+i] = + tt_mode == G_EDIT && tt_script == i ? mode_on : mode_off; d += size_x; if (tt_mode == G_PRESET) { - monomeLedBuffer[d+6] = h; for (u8 j = 0; j < 25; j += 8) { for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = i + j == preset_select ? h : l; + monomeLedBuffer[d+i] = i + j == + preset_select ? preset_selected : preset_unselected; d += size_x; } - monomeLedBuffer[d+7] = m; + monomeLedBuffer[d+7] = preset_scroll; d += size_x; - monomeLedBuffer[d+2] = b; - monomeLedBuffer[d+4] = b; - monomeLedBuffer[d+7] = m; + monomeLedBuffer[d+2] = preset_load; + monomeLedBuffer[d+4] = preset_save; + monomeLedBuffer[d+7] = preset_scroll; return; - - } else if (tt_mode == G_LIVE_V) { - monomeLedBuffer[d+3] = variable_edit == 1 ? h : l; - monomeLedBuffer[d+4] = variable_edit == 2 ? h : l; + } + + monomeLedBuffer[d+size_x] = ss->variables.m_act ? mute_off : mute_on; + monomeLedBuffer[d+size_x+1] = script_triggers[10].on ? exec : kill; + monomeLedBuffer[d+size_x+size_x] = script_triggers[8].on ? exec : trig; + monomeLedBuffer[d+size_x+size_x+1] = script_triggers[9].on ? exec : trig; + + if (tt_mode == G_LIVE_V) { + monomeLedBuffer[d+3] = variable_edit == 1 ? var_edit_on : var_edit_off; + monomeLedBuffer[d+4] = variable_edit == 2 ? var_edit_on : var_edit_off; d += size_x; - monomeLedBuffer[d] = ss->variables.m_act ? l : b; - monomeLedBuffer[d+1] = script_triggers[10].on ? h : b; - monomeLedBuffer[d+3] = variable_edit == 3 ? h : l; - monomeLedBuffer[d+4] = variable_edit == 4 ? h : l; - monomeLedBuffer[d+6] = m; + monomeLedBuffer[d+3] = variable_edit == 3 ? var_edit_on : var_edit_off; + monomeLedBuffer[d+4] = variable_edit == 4 ? var_edit_on : var_edit_off; + monomeLedBuffer[d+6] = live_hist; d += size_x; - monomeLedBuffer[d] = script_triggers[8].on ? h : m; - monomeLedBuffer[d+1] = script_triggers[9].on ? h : m; - monomeLedBuffer[d+3] = variable_edit == 5 ? h : l; - monomeLedBuffer[d+4] = variable_edit == 6 ? h : l; - monomeLedBuffer[d+6] = m; - monomeLedBuffer[d+7] = b; + monomeLedBuffer[d+3] = variable_edit == 5 ? var_edit_on : var_edit_off; + monomeLedBuffer[d+4] = variable_edit == 6 ? var_edit_on : var_edit_off; + monomeLedBuffer[d+6] = live_hist; + monomeLedBuffer[d+7] = live_exec; d += size_x; - monomeLedBuffer[d+3] = variable_edit == 7 ? h : l; - monomeLedBuffer[d+4] = variable_edit == 8 ? h : l; + monomeLedBuffer[d+3] = variable_edit == 7 ? var_edit_on : var_edit_off; + monomeLedBuffer[d+4] = variable_edit == 8 ? var_edit_on : var_edit_off; } else if (tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF) { d += size_x; - monomeLedBuffer[d] = ss_get_mute(ss, 8) ? b : l; - monomeLedBuffer[d+1] = script_triggers[10].on ? h : b; - monomeLedBuffer[d+3] = grid_page == 1 ? b : l; - monomeLedBuffer[d+7] = m; + monomeLedBuffer[d+7] = grid_page == 0 ? grid_page_on : grid_page_off; d += size_x; - monomeLedBuffer[d] = script_triggers[8].on ? h : m; - monomeLedBuffer[d+1] = script_triggers[9].on ? h : m; - monomeLedBuffer[d+3] = grid_page == 2 ? b : l; - monomeLedBuffer[d+5] = grid_show_controls ? b : l; - monomeLedBuffer[d+7] = m; + monomeLedBuffer[d+5] = + grid_show_controls ? grid_page_on : grid_page_off; + monomeLedBuffer[d+7] = grid_page == 1 ? grid_page_on : grid_page_off; d += size_x; } else if (tt_mode == G_EDIT) { d += size_x; - monomeLedBuffer[d] = ss_get_mute(ss, 8) ? b : l; - monomeLedBuffer[d+1] = script_triggers[10].on ? h : b; - monomeLedBuffer[d+3] = ss_get_script_comment(ss, tt_script, 0) ? b : l; - monomeLedBuffer[d+4] = ss_get_script_comment(ss, tt_script, 1) ? b : l; - monomeLedBuffer[d+5] = ss_get_script_comment(ss, tt_script, 2) ? b : l; - monomeLedBuffer[d+7] = m; + monomeLedBuffer[d+3] = + ss_get_script_comment(ss, tt_script, 0) ? line_off : line_on; + monomeLedBuffer[d+4] = + ss_get_script_comment(ss, tt_script, 3) ? line_off : line_on; + monomeLedBuffer[d+7] = script_control; d += size_x; - monomeLedBuffer[d] = script_triggers[8].on ? h : m; - monomeLedBuffer[d+1] = script_triggers[9].on ? h : m; - monomeLedBuffer[d+3] = ss_get_script_comment(ss, tt_script, 3) ? b : l; - monomeLedBuffer[d+4] = ss_get_script_comment(ss, tt_script, 4) ? b : l; - monomeLedBuffer[d+5] = ss_get_script_comment(ss, tt_script, 5) ? b : l; - monomeLedBuffer[d+7] = m; + monomeLedBuffer[d+3] = + ss_get_script_comment(ss, tt_script, 1) ? line_off : line_on; + monomeLedBuffer[d+4] = + ss_get_script_comment(ss, tt_script, 4) ? line_off : line_on; + monomeLedBuffer[d+7] = script_control; d += size_x; - + monomeLedBuffer[d+3] = + ss_get_script_comment(ss, tt_script, 2) ? line_off : line_on; + monomeLedBuffer[d+4] = + ss_get_script_comment(ss, tt_script, 5) ? line_off : line_on; } d += size_x; // script mutes for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = ss_get_mute(ss, i) ? b : l; + monomeLedBuffer[d+i] = ss_get_mute(ss, i) ? mute_on : mute_off; d += size_x; // triggered scripts for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = script_triggers[i].on ? h : m; + monomeLedBuffer[d+i] = script_triggers[i].on ? exec : trig; if (variable_edit) { s16 *v = &(ss->variables.a) - sizeof(s16); if (size_x == 8) { if (v[variable_edit] < 0 || v[variable_edit] > 8) for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = l; + monomeLedBuffer[d+i] = var_value_off; else for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = i < v[variable_edit] ? b : l; + monomeLedBuffer[d+i] = + i < v[variable_edit] ? var_value_on : var_value_off; } else { d -= 8; if (v[variable_edit] < 0 || v[variable_edit] > 16) for (u16 i = 0; i < 16; i++) - monomeLedBuffer[d+i] = l; + monomeLedBuffer[d+i] = var_value_off; else for (u16 i = 0; i < 16; i++) - monomeLedBuffer[d+i] = i < v[variable_edit] ? b : l; + monomeLedBuffer[d+i] = + i < v[variable_edit] ? var_value_on : var_value_off; } } } @@ -411,22 +489,154 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ // tracker if (tt_mode == G_TRACKER) { + u8 offset = get_pattern_offset(); + if (tracker_pressed) { + s16 value = ss_get_pattern_val(ss, tracker_x-2, tracker_y+offset); + + if (x == tracker_x && y == tracker_y && !z) { + if (!tracker_changed) { + s16 value = ss_get_pattern_val(ss, tracker_x-2, + tracker_y+get_pattern_offset()); + if (value) { + tracker_last = value; + value = 0; + } else { + value = tracker_last ? tracker_last : 1; + } + ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, value); + } + tracker_pressed = 0; + tele_pattern_updated(); + ss->grid.grid_dirty = 1; + return 1; + } + + if (!z) return 1; + + u8 updated = 0; + if (y == tracker_y) { + if (x == tracker_x + 1) { + if (value < 32767) { + ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, + value + 1); + updated = 1; + } + } else if (x == tracker_x + 2) { + if (value < 32758) { + ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, + value + 10); + updated = 1; + } else if (value < 32767) { + ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, + 32767); + updated = 1; + } + } else if (x == tracker_x - 1) { + if (value > -32768) { + ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, + value - 1); + updated = 1; + } + } else if (x == tracker_x - 2) { + if (value > -32759) { + ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, + value - 10); + updated = 1; + } else if (value > -32768) { + ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, + -32768); + updated = 1; + } + } + } else if (x > 1 && x < 6) { + // set loop + if (from_held) return 1; + for (u8 i = min(tracker_x, x); i <= max(tracker_x, x); i++) { + ss_set_pattern_start(ss, i - 2, min(y, tracker_y)+offset); + ss_set_pattern_end(ss, i - 2, max(y, tracker_y)+offset); + ss_set_pattern_len(ss, i - 2, max(y, tracker_y)+offset+1); + } + updated = 1; + } + + if (updated) { + tracker_changed = 1; + tele_pattern_updated(); + ss->grid.grid_dirty = 1; + } return 1; } - if (x == 7 && y == 0 && !from_held && z) { + if (tracker_select) { + if (x == 7 && y == tracker_select && !z) { + if (y == 3 && !tracker_selected) { + turtle_set_shown(&ss->turtle, !turtle_get_shown(&ss->turtle)); + tele_pattern_updated(); + ss->grid.grid_dirty = 1; + } + tracker_select = 0; + } else if (x > 1 && x < 6 && z && !from_held) { + if (tracker_select == 2) { + // set current position + tracker_selected = 1; + ss_set_pattern_idx(ss, x - 2, offset + y); + tele_pattern_updated(); + ss->grid.grid_dirty = 1; + } else if (tracker_select == 3) { + // set turtle position + tracker_selected = 1; + turtle_set_x(&ss->turtle, x - 2); + turtle_set_y(&ss->turtle, offset + y); + turtle_set_shown(&ss->turtle, 1); + tele_pattern_updated(); + ss->grid.grid_dirty = 1; + } else if (tracker_select == 4) { + // set start + tracker_selected = 1; + ss_set_pattern_start(ss, x - 2, y + offset); + tele_pattern_updated(); + ss->grid.grid_dirty = 1; + } else if (tracker_select == 5) { + // set end + tracker_selected = 1; + ss_set_pattern_end(ss, x - 2, y + offset); + ss_set_pattern_len(ss, x - 2, y + offset + 1); + tele_pattern_updated(); + ss->grid.grid_dirty = 1; + } + } + return 1; + } + + if (x > 1 && x < 6 && z) { + // pattern value selected + tracker_pressed = 1; + tracker_changed = 0; + tracker_x = x; + tracker_y = y; + set_pattern_selected_value(x - 2, y); + tele_pattern_updated(); + ss->grid.grid_dirty = 1; + } else if (x == 7 && y == 0 && !from_held && z) { + // exit tracker restore_last_mode(ss); ss->grid.grid_dirty = 1; } else if (x == 0 && !from_held && z) { - set_pattern_offset(y); + // select page + set_pattern_offset(y << 3); ss->grid.grid_dirty = 1; } else if (x == 7 && y == 6 && z) { - pattern_up(); + u8 offset = get_pattern_offset(); + if (offset) set_pattern_offset(offset - 1); ss->grid.grid_dirty = 1; } else if (x == 7 && y == 7 && z) { - pattern_down(); + u8 offset = get_pattern_offset(); + if (offset < 56) set_pattern_offset(offset + 1); ss->grid.grid_dirty = 1; + } else if (x == 7 && y > 1 && z) { + tracker_select = y; + tracker_selected = 0; } return 1; } @@ -460,14 +670,14 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ break; case 6: tt_last_mode = tt_mode; - tt_mode = G_TRACKER; - set_mode(M_PATTERN); + tt_mode = G_PRESET; + set_mode(M_PRESET_R); ss->grid.grid_dirty = 1; break; case 7: tt_last_mode = tt_mode; - tt_mode = G_PRESET; - set_mode(M_PRESET_R); + tt_mode = G_TRACKER; + set_mode(M_PATTERN); ss->grid.grid_dirty = 1; break; default: @@ -476,7 +686,7 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ return 1; } - // scripts + // select script for editing if (y == 1) { if (!z || from_held) return 1; tt_mode = G_EDIT; @@ -561,6 +771,38 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ return 1; } + // metro on/off + if (y == 3 && x == 0 && !from_held && !z) { + ss->variables.m_act = !ss->variables.m_act; + screen_mutes_updated(); + tele_metro_updated(); + ss->grid.grid_dirty = 1; + return 1; + } + + // kill slews/delays + if (y == 3 && x == 1 && !from_held && !z) { + script_triggers[10].on = 1; + script_triggers[10].ss = ss; + timer_add(&script_triggers[10].timer, 50, + &script_triggers_callback, (void *)&script_triggers[10]); + clear_delays_and_slews(ss); + ss->grid.grid_dirty = 1; + return 1; + } + + // trigger metro/init + if (y == 4 && x < 2 && !z) { + x += 8; + script_triggers[x].on = 1; + script_triggers[x].ss = ss; + timer_add(&script_triggers[x].timer, 50, + &script_triggers_callback, (void *)&script_triggers[x]); + ss->grid.grid_dirty = 1; + run_script(ss, x); + return 1; + } + // live variables if (tt_mode == G_LIVE_V) { if (y > 1 && y < 6 && x > 10 && x <13 && !from_held) { @@ -571,23 +813,7 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ if (!z) return 1; - if (y == 3 && x == 0 && !from_held) { - ss->variables.m_act = !ss->variables.m_act; - screen_mutes_updated(); - tele_metro_updated(); - ss->grid.grid_dirty = 1; - } else if (y == 3 && x == 1 && !from_held) { - clear_delays_and_slews(ss); - ss->grid.grid_dirty = 1; - } else if (y == 4 && x < 2) { - x += 8; - script_triggers[x].on = 1; - script_triggers[x].ss = ss; - timer_add(&script_triggers[x].timer, 50, - &script_triggers_callback, (void *)&script_triggers[x]); - ss->grid.grid_dirty = 1; - run_script(ss, x); - } else if (y == 3 && x == 6) { + if (y == 3 && x == 6) { history_prev(); } else if (y == 4 && x == 6) { history_next(); @@ -598,28 +824,33 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ return 1; } - // scripts - if (tt_mode == G_EDIT) { + // live grid preview + if (tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF) { if (!z || from_held) return 1; - if (y == 3 && x == 0) { - ss->variables.m_act = !ss->variables.m_act; - screen_mutes_updated(); - tele_metro_updated(); - ss->grid.grid_dirty = 1; - } else if (y == 3 && x == 1) { - clear_delays_and_slews(ss); + if (y == 3 && x == 7) { + grid_page = 0; + edit_mode_refresh(); + ss->grid.grid_dirty = 1; + } else if (y == 4 && x == 7) { + grid_page = 1; + edit_mode_refresh(); ss->grid.grid_dirty = 1; - } else if (y == 4 && x < 2) { - x += 8; - script_triggers[x].on = 1; - script_triggers[x].ss = ss; - timer_add(&script_triggers[x].timer, 50, - &script_triggers_callback, (void *)&script_triggers[x]); + } else if (y == 4 && x == 5) { + grid_show_controls = !grid_show_controls; + edit_mode_refresh(); ss->grid.grid_dirty = 1; - run_script(ss, x); - } else if (y > 2 && y < 5 && x > 2 && x < 6) { - u8 i = x - 3 + (y - 3) * 3; + } + + return 1; + } + + // edit scripts + if (tt_mode == G_EDIT) { + if (!z || from_held) return 1; + + if (y > 2 && y < 6 && x > 2 && x < 5) { + u8 i = (x - 3) * 3 + y - 3; if (i >= ss_get_script_len(ss, tt_script)) return 1; ss_toggle_script_comment(ss, tt_script, i); edit_mode_refresh(); diff --git a/module/pattern_mode.c b/module/pattern_mode.c index 1c18af09..b53bc7ed 100644 --- a/module/pattern_mode.c +++ b/module/pattern_mode.c @@ -49,13 +49,9 @@ void set_pattern_offset(uint8_t o) { dirty = true; } -void set_pattern_editing(uint8_t on) { - editing_number = on; - dirty = true; -} - -void set_pattern_pattern(uint8_t p) { +void set_pattern_selected_value(uint8_t p, uint8_t offset) { pattern = p; + base = offset; dirty = true; } diff --git a/module/pattern_mode.h b/module/pattern_mode.h index 94d326f9..512e400a 100644 --- a/module/pattern_mode.h +++ b/module/pattern_mode.h @@ -10,8 +10,7 @@ void process_pattern_knob(uint16_t knob, uint8_t mod_key); uint8_t screen_refresh_pattern(void); uint8_t get_pattern_offset(void); void set_pattern_offset(uint8_t offset); -void set_pattern_editing(uint8_t on); -void set_pattern_pattern(uint8_t pattern); +void set_pattern_selected_value(uint8_t pattern, uint8_t offset); void pattern_up(void); void pattern_down(void); From 8e5ec7475244b9d9b134256f6811afa2ae9b959b Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 13 May 2018 19:19:47 -0700 Subject: [PATCH 051/117] add delay to allow for er-301 i2c noise --- module/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/module/main.c b/module/main.c index d67c0332..396d2015 100644 --- a/module/main.c +++ b/module/main.c @@ -466,7 +466,7 @@ void handler_ScreenRefresh(int32_t data) { void handler_EventTimer(int32_t data) { ss_counter++; - if (ss_counter > SS_TIMEOUT) set_mode(M_SCREENSAVER); + if (ss_counter > SS_TIMEOUT && !grid_control_mode) set_mode(M_SCREENSAVER); tele_tick(&scene_state, RATE_CLOCK); } @@ -911,6 +911,10 @@ int main(void) { init_usb_host(); init_monome(); init_oled(); + + // wait to allow for any i2c devices to fully initalise + delay_ms(1500); + init_i2c_master(); print_dbg("\r\n\r\n// teletype! //////////////////////////////// "); @@ -963,10 +967,6 @@ int main(void) { init_live_mode(); set_mode(M_LIVE); - // wait 50ms before running the init script to allow for any i2c devices to - // fully initalise - delay_ms(1500); - run_script(&scene_state, INIT_SCRIPT); scene_state.initializing = false; From 120a2cb79f09ce85dfabc0f47ef4aef5af94fae7 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 15 May 2018 20:25:54 -0700 Subject: [PATCH 052/117] fix rendering for grid 64 --- module/grid.c | 67 +++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/module/grid.c b/module/grid.c index 05422e38..8706250c 100644 --- a/module/grid.c +++ b/module/grid.c @@ -201,6 +201,9 @@ void grid_set_control_mode(u8 control, scene_state_t *ss) { } void grid_control_refresh(scene_state_t *ss) { + size_x = monome_size_x(); + size_y = monome_size_y(); + u16 d = size_y == 16 ? 128 : 0; if (size_x == 16) d += 8; @@ -271,7 +274,7 @@ void grid_control_refresh(scene_state_t *ss) { for (u16 i = 0; i < 8; i++) for (u16 j = 0; j < 8; j++) - monomeLedBuffer[d+i+size_x*j] = 0; + monomeLedBuffer[d+i+(j<<4)] = 0; if (tt_mode == G_TRACKER) { monomeLedBuffer[d+7] = mode_on; @@ -280,35 +283,35 @@ void grid_control_refresh(scene_state_t *ss) { for (u16 i = 0; i < 4; i++) { in = offset + j >= ss_get_pattern_start(ss, i) && offset + j <= ss_get_pattern_end(ss, i); - monomeLedBuffer[d+i+2+(j*size_x)] = + monomeLedBuffer[d+i+2+(j<<4)] = ss_get_pattern_val(ss, i, j + offset) ? tracker_on : (in ? tracker_in : tracker_out); } off = offset >> 3; rem = (offset & 7) >> 1; - monomeLedBuffer[d+j*size_x] = + monomeLedBuffer[d+(j<<4)] = j == off ? tracker_page_on - rem : (j == off + 1 ? tracker_page_off + rem : tracker_page_off); } for (u16 i = 0; i < 4; i++) { u8 index = ss_get_pattern_idx(ss, i); if (index >= offset && index <= offset + 7) { - monomeLedBuffer[d+i+2+(index*size_x)] += tracker_pos; + monomeLedBuffer[d+i+2+(index<<4)] += tracker_pos; } } - d += size_x << 1; + d += 32; monomeLedBuffer[d+7] = tracker_control; - d += size_x; + d += 16; monomeLedBuffer[d+7] = turtle_get_shown(&ss->turtle) ? tracker_control : tracker_loop; - d += size_x; + d += 16; monomeLedBuffer[d+7] = tracker_loop; - d += size_x; + d += 16; monomeLedBuffer[d+7] = tracker_loop; - d += size_x; + d += 16; monomeLedBuffer[d+7] = tracker_control; - d += size_x; + d += 16; monomeLedBuffer[d+7] = tracker_control; return; } @@ -323,83 +326,83 @@ void grid_control_refresh(scene_state_t *ss) { tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF ? mode_on : mode_off; monomeLedBuffer[d+6] = tt_mode == G_PRESET ? mode_on : mode_off; monomeLedBuffer[d+7] = mode_off; - d += size_x; + d += 16; for (u16 i = 0; i < 8; i++) monomeLedBuffer[d+i] = tt_mode == G_EDIT && tt_script == i ? mode_on : mode_off; - d += size_x; + d += 16; if (tt_mode == G_PRESET) { for (u8 j = 0; j < 25; j += 8) { for (u16 i = 0; i < 8; i++) monomeLedBuffer[d+i] = i + j == preset_select ? preset_selected : preset_unselected; - d += size_x; + d += 16; } monomeLedBuffer[d+7] = preset_scroll; - d += size_x; + d += 16; monomeLedBuffer[d+2] = preset_load; monomeLedBuffer[d+4] = preset_save; monomeLedBuffer[d+7] = preset_scroll; return; } - monomeLedBuffer[d+size_x] = ss->variables.m_act ? mute_off : mute_on; - monomeLedBuffer[d+size_x+1] = script_triggers[10].on ? exec : kill; - monomeLedBuffer[d+size_x+size_x] = script_triggers[8].on ? exec : trig; - monomeLedBuffer[d+size_x+size_x+1] = script_triggers[9].on ? exec : trig; + monomeLedBuffer[d+16] = ss->variables.m_act ? mute_off : mute_on; + monomeLedBuffer[d+17] = script_triggers[10].on ? exec : kill; + monomeLedBuffer[d+32] = script_triggers[8].on ? exec : trig; + monomeLedBuffer[d+33] = script_triggers[9].on ? exec : trig; if (tt_mode == G_LIVE_V) { monomeLedBuffer[d+3] = variable_edit == 1 ? var_edit_on : var_edit_off; monomeLedBuffer[d+4] = variable_edit == 2 ? var_edit_on : var_edit_off; - d += size_x; + d += 16; monomeLedBuffer[d+3] = variable_edit == 3 ? var_edit_on : var_edit_off; monomeLedBuffer[d+4] = variable_edit == 4 ? var_edit_on : var_edit_off; monomeLedBuffer[d+6] = live_hist; - d += size_x; + d += 16; monomeLedBuffer[d+3] = variable_edit == 5 ? var_edit_on : var_edit_off; monomeLedBuffer[d+4] = variable_edit == 6 ? var_edit_on : var_edit_off; monomeLedBuffer[d+6] = live_hist; monomeLedBuffer[d+7] = live_exec; - d += size_x; + d += 16; monomeLedBuffer[d+3] = variable_edit == 7 ? var_edit_on : var_edit_off; monomeLedBuffer[d+4] = variable_edit == 8 ? var_edit_on : var_edit_off; } else if (tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF) { - d += size_x; + d += 16; monomeLedBuffer[d+7] = grid_page == 0 ? grid_page_on : grid_page_off; - d += size_x; + d += 16; monomeLedBuffer[d+5] = grid_show_controls ? grid_page_on : grid_page_off; monomeLedBuffer[d+7] = grid_page == 1 ? grid_page_on : grid_page_off; - d += size_x; + d += 16; } else if (tt_mode == G_EDIT) { - d += size_x; + d += 16; monomeLedBuffer[d+3] = ss_get_script_comment(ss, tt_script, 0) ? line_off : line_on; monomeLedBuffer[d+4] = ss_get_script_comment(ss, tt_script, 3) ? line_off : line_on; monomeLedBuffer[d+7] = script_control; - d += size_x; + d += 16; monomeLedBuffer[d+3] = ss_get_script_comment(ss, tt_script, 1) ? line_off : line_on; monomeLedBuffer[d+4] = ss_get_script_comment(ss, tt_script, 4) ? line_off : line_on; monomeLedBuffer[d+7] = script_control; - d += size_x; + d += 16; monomeLedBuffer[d+3] = ss_get_script_comment(ss, tt_script, 2) ? line_off : line_on; monomeLedBuffer[d+4] = ss_get_script_comment(ss, tt_script, 5) ? line_off : line_on; } - d += size_x; + d += 16; // script mutes for (u16 i = 0; i < 8; i++) monomeLedBuffer[d+i] = ss_get_mute(ss, i) ? mute_on : mute_off; - d += size_x; + d += 16; // triggered scripts for (u16 i = 0; i < 8; i++) @@ -1309,7 +1312,7 @@ void grid_fill_area(u8 x, u8 y, u8 w, u8 h, s8 level) { if (level == LED_DIM) { for (u16 _x = x; _x < x_end; _x++) for (u16 _y = y; _y < y_end; _y++) { - index = _x + _y * size_x; + index = _x + (_y << 4); if (index < MONOME_MAX_LED_BYTES) { if (monomeLedBuffer[index] > 3) monomeLedBuffer[index] -= 3; @@ -1321,7 +1324,7 @@ void grid_fill_area(u8 x, u8 y, u8 w, u8 h, s8 level) { else if (level == LED_BRI) { for (u16 _x = x; _x < x_end; _x++) for (u16 _y = y; _y < y_end; _y++) { - index = _x + _y * size_x; + index = _x + (_y << 4); if (index < MONOME_MAX_LED_BYTES) { if (monomeLedBuffer[index] > 12) monomeLedBuffer[index] = 15; @@ -1333,7 +1336,7 @@ void grid_fill_area(u8 x, u8 y, u8 w, u8 h, s8 level) { else { for (u16 _x = x; _x < x_end; _x++) for (u16 _y = y; _y < y_end; _y++) { - index = _x + _y * size_x; + index = _x + (_y << 4); if (index < MONOME_MAX_LED_BYTES) monomeLedBuffer[index] = level; } From d689629427dd17f15c116f3fcd23f11b18b054d3 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Wed, 16 May 2018 18:52:28 -0700 Subject: [PATCH 053/117] fix rendering for grid 64 --- module/grid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/grid.c b/module/grid.c index 8706250c..ab1e141a 100644 --- a/module/grid.c +++ b/module/grid.c @@ -1262,7 +1262,7 @@ void grid_refresh(scene_state_t *ss) { u16 led; for (u16 i = 0; i < size_x; i++) for (u16 j = 0; j < size_y; j++) { - led = j * size_x + i; + led = (j << 4) + i; if (led >= MONOME_MAX_LED_BYTES) continue; if (SG.leds[i][j] >= 0) From 58bd186d8247cd31ae9feca8edf9c7eb494dfff2 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 20 May 2018 11:30:18 -0700 Subject: [PATCH 054/117] aliases for WRAP, SCALE, RAND, RRAND --- src/match_token.rl | 4 ++++ src/ops/maths.c | 4 ++++ src/ops/maths.h | 4 ++++ src/ops/op.c | 23 ++++++++++++----------- src/ops/op_enum.h | 4 ++++ 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/match_token.rl b/src/match_token.rl index c131edcd..91439d48 100644 --- a/src/match_token.rl +++ b/src/match_token.rl @@ -151,7 +151,9 @@ "DIV" => { MATCH_OP(E_OP_DIV); }; "MOD" => { MATCH_OP(E_OP_MOD); }; "RAND" => { MATCH_OP(E_OP_RAND); }; + "RND" => { MATCH_OP(E_OP_RND); }; "RRAND" => { MATCH_OP(E_OP_RRAND); }; + "RRND" => { MATCH_OP(E_OP_RRND); }; "R" => { MATCH_OP(E_OP_R); }; "R.MIN" => { MATCH_OP(E_OP_R_MIN); }; "R.MAX" => { MATCH_OP(E_OP_R_MAX); }; @@ -160,6 +162,7 @@ "MAX" => { MATCH_OP(E_OP_MAX); }; "LIM" => { MATCH_OP(E_OP_LIM); }; "WRAP" => { MATCH_OP(E_OP_WRAP); }; + "WRP" => { MATCH_OP(E_OP_WRP); }; "QT" => { MATCH_OP(E_OP_QT); }; "AVG" => { MATCH_OP(E_OP_AVG); }; "EQ" => { MATCH_OP(E_OP_EQ); }; @@ -178,6 +181,7 @@ "OR" => { MATCH_OP(E_OP_OR); }; "JI" => { MATCH_OP(E_OP_JI); }; "SCALE" => { MATCH_OP(E_OP_SCALE); }; + "SCL" => { MATCH_OP(E_OP_SCL); }; "N" => { MATCH_OP(E_OP_N); }; "V" => { MATCH_OP(E_OP_V); }; "VV" => { MATCH_OP(E_OP_VV); }; diff --git a/src/ops/maths.c b/src/ops/maths.c index 0ee6a9e5..d5321bdd 100644 --- a/src/ops/maths.c +++ b/src/ops/maths.c @@ -123,7 +123,9 @@ const tele_op_t op_MUL = MAKE_GET_OP(MUL , op_MUL_get , 2, true); const tele_op_t op_DIV = MAKE_GET_OP(DIV , op_DIV_get , 2, true); const tele_op_t op_MOD = MAKE_GET_OP(MOD , op_MOD_get , 2, true); const tele_op_t op_RAND = MAKE_GET_OP(RAND , op_RAND_get , 1, true); +const tele_op_t op_RND = MAKE_GET_OP(RND , op_RAND_get , 1, true); const tele_op_t op_RRAND = MAKE_GET_OP(RRAND , op_RRAND_get , 2, true); +const tele_op_t op_RRND = MAKE_GET_OP(RRND , op_RRAND_get , 2, true); const tele_op_t op_R = MAKE_GET_OP(R , op_R_get , 0, true); const tele_op_t op_R_MIN = MAKE_GET_SET_OP(R.MIN, op_R_MIN_get, op_R_MIN_set, 0, true); const tele_op_t op_R_MAX = MAKE_GET_SET_OP(R.MAX, op_R_MAX_get, op_R_MAX_set, 0, true); @@ -132,6 +134,7 @@ const tele_op_t op_MIN = MAKE_GET_OP(MIN , op_MIN_get , 2, true); const tele_op_t op_MAX = MAKE_GET_OP(MAX , op_MAX_get , 2, true); const tele_op_t op_LIM = MAKE_GET_OP(LIM , op_LIM_get , 3, true); const tele_op_t op_WRAP = MAKE_GET_OP(WRAP , op_WRAP_get , 3, true); +const tele_op_t op_WRP = MAKE_GET_OP(WRP , op_WRAP_get , 3, true); const tele_op_t op_QT = MAKE_GET_OP(QT , op_QT_get , 2, true); const tele_op_t op_AVG = MAKE_GET_OP(AVG , op_AVG_get , 2, true); const tele_op_t op_EQ = MAKE_GET_OP(EQ , op_EQ_get , 2, true); @@ -150,6 +153,7 @@ const tele_op_t op_AND = MAKE_GET_OP(AND , op_AND_get , 2, true); const tele_op_t op_OR = MAKE_GET_OP(OR , op_OR_get , 2, true); const tele_op_t op_JI = MAKE_GET_OP(JI , op_JI_get , 2, true); const tele_op_t op_SCALE = MAKE_GET_OP(SCALE , op_SCALE_get , 5, true); +const tele_op_t op_SCL = MAKE_GET_OP(SCL , op_SCALE_get , 5, true); const tele_op_t op_N = MAKE_GET_OP(N , op_N_get , 1, 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); diff --git a/src/ops/maths.h b/src/ops/maths.h index ad840ddc..bdac59da 100644 --- a/src/ops/maths.h +++ b/src/ops/maths.h @@ -9,7 +9,9 @@ extern const tele_op_t op_MUL; extern const tele_op_t op_DIV; extern const tele_op_t op_MOD; extern const tele_op_t op_RAND; +extern const tele_op_t op_RND; extern const tele_op_t op_RRAND; +extern const tele_op_t op_RRND; extern const tele_op_t op_R; extern const tele_op_t op_R_MIN; extern const tele_op_t op_R_MAX; @@ -18,6 +20,7 @@ extern const tele_op_t op_MIN; extern const tele_op_t op_MAX; extern const tele_op_t op_LIM; extern const tele_op_t op_WRAP; +extern const tele_op_t op_WRP; extern const tele_op_t op_QT; extern const tele_op_t op_AVG; extern const tele_op_t op_EQ; @@ -36,6 +39,7 @@ extern const tele_op_t op_AND; extern const tele_op_t op_OR; extern const tele_op_t op_JI; extern const tele_op_t op_SCALE; +extern const tele_op_t op_SCL; extern const tele_op_t op_N; extern const tele_op_t op_V; extern const tele_op_t op_VV; diff --git a/src/ops/op.c b/src/ops/op.c index 0f12f740..5422efd0 100644 --- a/src/ops/op.c +++ b/src/ops/op.c @@ -72,17 +72,18 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_MUTE, &op_STATE, // maths - &op_ADD, &op_SUB, &op_MUL, &op_DIV, &op_MOD, &op_RAND, &op_RRAND, &op_R, &op_R_MIN, &op_R_MAX, &op_TOSS, - &op_MIN, &op_MAX, &op_LIM, &op_WRAP, &op_QT, &op_AVG, &op_EQ, &op_NE, - &op_LT, &op_GT, &op_LTE, &op_GTE, &op_NZ, &op_EZ, &op_RSH, &op_LSH, &op_EXP, - &op_ABS, &op_AND, &op_OR, &op_JI, &op_SCALE, &op_N, &op_V, &op_VV, &op_ER, - &op_BPM, &op_BIT_OR, &op_BIT_AND, &op_BIT_NOT, &op_BIT_XOR, &op_BSET, - &op_BGET, &op_BCLR, &op_XOR, &op_CHAOS, &op_CHAOS_R, &op_CHAOS_ALG, - &op_SYM_PLUS, &op_SYM_DASH, &op_SYM_STAR, &op_SYM_FORWARD_SLASH, - &op_SYM_PERCENTAGE, &op_SYM_EQUAL_x2, &op_SYM_EXCLAMATION_EQUAL, - &op_SYM_LEFT_ANGLED, &op_SYM_RIGHT_ANGLED, &op_SYM_LEFT_ANGLED_EQUAL, - &op_SYM_RIGHT_ANGLED_EQUAL, &op_SYM_EXCLAMATION, &op_SYM_LEFT_ANGLED_x2, - &op_SYM_RIGHT_ANGLED_x2, &op_SYM_AMPERSAND_x2, &op_SYM_PIPE_x2, &op_TIF, + &op_ADD, &op_SUB, &op_MUL, &op_DIV, &op_MOD, &op_RAND, &op_RND, &op_RRAND, + &op_RRND, &op_R, &op_R_MIN, &op_R_MAX, &op_TOSS, &op_MIN, &op_MAX, &op_LIM, + &op_WRAP, &op_WRP, &op_QT, &op_AVG, &op_EQ, &op_NE, &op_LT, &op_GT, &op_LTE, + &op_GTE, &op_NZ, &op_EZ, &op_RSH, &op_LSH, &op_EXP, &op_ABS, &op_AND, + &op_OR, &op_JI, &op_SCALE, &op_SCL, &op_N, &op_V, &op_VV, &op_ER, &op_BPM, + &op_BIT_OR, &op_BIT_AND, &op_BIT_NOT, &op_BIT_XOR, &op_BSET, &op_BGET, + &op_BCLR, &op_XOR, &op_CHAOS, &op_CHAOS_R, &op_CHAOS_ALG, &op_SYM_PLUS, + &op_SYM_DASH, &op_SYM_STAR, &op_SYM_FORWARD_SLASH, &op_SYM_PERCENTAGE, + &op_SYM_EQUAL_x2, &op_SYM_EXCLAMATION_EQUAL, &op_SYM_LEFT_ANGLED, + &op_SYM_RIGHT_ANGLED, &op_SYM_LEFT_ANGLED_EQUAL, &op_SYM_RIGHT_ANGLED_EQUAL, + &op_SYM_EXCLAMATION, &op_SYM_LEFT_ANGLED_x2, &op_SYM_RIGHT_ANGLED_x2, + &op_SYM_AMPERSAND_x2, &op_SYM_PIPE_x2, &op_TIF, // stack &op_S_ALL, &op_S_POP, &op_S_CLR, &op_S_L, diff --git a/src/ops/op_enum.h b/src/ops/op_enum.h index 67ef928a..73b64803 100644 --- a/src/ops/op_enum.h +++ b/src/ops/op_enum.h @@ -124,7 +124,9 @@ typedef enum { E_OP_DIV, E_OP_MOD, E_OP_RAND, + E_OP_RND, E_OP_RRAND, + E_OP_RRND, E_OP_R, E_OP_R_MIN, E_OP_R_MAX, @@ -133,6 +135,7 @@ typedef enum { E_OP_MAX, E_OP_LIM, E_OP_WRAP, + E_OP_WRP, E_OP_QT, E_OP_AVG, E_OP_EQ, @@ -151,6 +154,7 @@ typedef enum { E_OP_OR, E_OP_JI, E_OP_SCALE, + E_OP_SCL, E_OP_N, E_OP_V, E_OP_VV, From 2ef9685d19d265ff9c2e87dd88a92f6557274aec Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 20 May 2018 11:31:05 -0700 Subject: [PATCH 055/117] fixes for grid control --- module/grid.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/module/grid.c b/module/grid.c index ab1e141a..8bdfde7a 100644 --- a/module/grid.c +++ b/module/grid.c @@ -614,6 +614,7 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ if (x > 1 && x < 6 && z) { // pattern value selected + if (x != tracker_x || y != tracker_y) tracker_last = 0; tracker_pressed = 1; tracker_changed = 0; tracker_x = x; @@ -784,7 +785,7 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ } // kill slews/delays - if (y == 3 && x == 1 && !from_held && !z) { + if (y == 3 && x == 1 && !from_held && z) { script_triggers[10].on = 1; script_triggers[10].ss = ss; timer_add(&script_triggers[10].timer, 50, @@ -795,7 +796,7 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ } // trigger metro/init - if (y == 4 && x < 2 && !z) { + if (y == 4 && x < 2 && z) { x += 8; script_triggers[x].on = 1; script_triggers[x].ss = ss; @@ -1126,7 +1127,7 @@ void hold_repeat_timer_callback(void* o) { hold_repeat_info* hr = o; u8 is_hold = hr->used == 1; if (is_hold) { - timer_set(&hr->timer, GRID_KEY_REPEAT_RATE); + timer_set(&hr->timer, GRID_KEY_REPEAT_RATE + (control_mode_on ? 20 : 0)); hr->used = 2; } grid_process_key_hold_repeat(hr->ss, hr->x, hr->y); From 331a537b88fa43caf69a474bdd39afbf69dc8d38 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 20 May 2018 14:58:10 -0700 Subject: [PATCH 056/117] ignore duplicate commands in history --- module/live_mode.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/module/live_mode.c b/module/live_mode.c index 57e7b5de..18b47bc6 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -172,14 +172,24 @@ void execute_line() { return; // quit, screen_refresh_live will display the error message if (command.length) { - // increase history_size up to a maximum - history_top++; - if (history_top >= MAX_HISTORY_SIZE) - history_top = MAX_HISTORY_SIZE - 1; + s16 found = -1; + for (s16 i = history_top; i >= 0; i--) + if (command.length == history[i].length && + memcmp(&(command.data), &(history[i].data), + command.length * sizeof(tele_data_t)) == 0) { + found = i; + break; + } + + if (found == -1) { + // increase history_size up to a maximum + if (history_top < MAX_HISTORY_SIZE - 1) history_top++; + found = history_top; + } // shuffle the history up // should really use some sort of ring buffer - for (size_t i = history_top; i > 0; i--) { + for (size_t i = found; i > 0; i--) { memcpy(&history[i], &history[i - 1], sizeof(command)); } memcpy(&history[0], &command, sizeof(command)); From df1363fe551f6c421f3e60b44f234cb8d32e5216 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 20 May 2018 14:59:28 -0700 Subject: [PATCH 057/117] fixes for grid control --- module/grid.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/module/grid.c b/module/grid.c index 8bdfde7a..cad915a5 100644 --- a/module/grid.c +++ b/module/grid.c @@ -15,7 +15,9 @@ #define GRID_MAX_KEY_PRESSED 10 #define GRID_KEY_HOLD_DELAY 700 #define GRID_KEY_REPEAT_RATE 40 +#define GRID_KEY_REPEAT_RATE_CTL 120 #define GRID_ON_BRIGHTNESS 13 +#define GRID_SCRIPT_TRIGGER 60 typedef enum { G_LIVE_V, @@ -441,7 +443,9 @@ static void script_triggers_callback(void* o) { void grid_metro_triggered(scene_state_t *ss) { script_triggers[8].on = 1; script_triggers[8].ss = ss; - timer_add(&script_triggers[8].timer, 50, + timer_remove(&script_triggers[8].timer); + timer_add(&script_triggers[8].timer, + min(GRID_SCRIPT_TRIGGER, ss->variables.m >> 1), &script_triggers_callback, (void *)&script_triggers[8]); ss->grid.grid_dirty = 1; } @@ -768,7 +772,8 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ if (!z) return 1; script_triggers[x].on = 1; script_triggers[x].ss = ss; - timer_add(&script_triggers[x].timer, 50, + timer_remove(&script_triggers[x].timer); + timer_add(&script_triggers[x].timer, GRID_SCRIPT_TRIGGER, &script_triggers_callback, (void *)&script_triggers[x]); ss->grid.grid_dirty = 1; run_script(ss, x); @@ -788,7 +793,8 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ if (y == 3 && x == 1 && !from_held && z) { script_triggers[10].on = 1; script_triggers[10].ss = ss; - timer_add(&script_triggers[10].timer, 50, + timer_remove(&script_triggers[x].timer); + timer_add(&script_triggers[10].timer, GRID_SCRIPT_TRIGGER, &script_triggers_callback, (void *)&script_triggers[10]); clear_delays_and_slews(ss); ss->grid.grid_dirty = 1; @@ -800,7 +806,8 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ x += 8; script_triggers[x].on = 1; script_triggers[x].ss = ss; - timer_add(&script_triggers[x].timer, 50, + timer_remove(&script_triggers[x].timer); + timer_add(&script_triggers[x].timer, GRID_SCRIPT_TRIGGER, &script_triggers_callback, (void *)&script_triggers[x]); ss->grid.grid_dirty = 1; run_script(ss, x); @@ -1127,7 +1134,8 @@ void hold_repeat_timer_callback(void* o) { hold_repeat_info* hr = o; u8 is_hold = hr->used == 1; if (is_hold) { - timer_set(&hr->timer, GRID_KEY_REPEAT_RATE + (control_mode_on ? 20 : 0)); + timer_reset_set(&hr->timer, + control_mode_on && hr->x > 7 ? GRID_KEY_REPEAT_RATE_CTL : GRID_KEY_REPEAT_RATE); hr->used = 2; } grid_process_key_hold_repeat(hr->ss, hr->x, hr->y); From 868326d82664590e4fbf044b6fb20f5630544898 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 24 May 2018 20:36:58 -0700 Subject: [PATCH 058/117] fix stuck held keys when grid rotated --- module/grid.c | 5 +++++ src/ops/grid_ops.c | 2 +- src/state.c | 2 +- src/state.h | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/module/grid.c b/module/grid.c index cad915a5..7b49415e 100644 --- a/module/grid.c +++ b/module/grid.c @@ -895,6 +895,11 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { u8 x = SG.rotate && !emulated ? size_x - _x - 1 : _x; u8 y = SG.rotate && !emulated ? size_y - _y - 1 : _y; + if (SG.clear_held) { + grid_clear_held_keys(); + SG.clear_held = 0; + } + if (control_mode_on ? !emulated : true) { u8 key = (y << 4) | x; if (z) { diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 9cddc626..742bfc94 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -261,7 +261,7 @@ static void op_G_ROTATE_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 rotate = cs_pop(cs); SG.rotate = rotate != 0; - SG.scr_dirty = SG.grid_dirty = 1; + SG.scr_dirty = SG.grid_dirty = SG.clear_held = 1; } static void op_G_DIM_get(const void *NOTUSED(data), scene_state_t *ss, diff --git a/src/state.c b/src/state.c index 821f9fb1..51ee0996 100644 --- a/src/state.c +++ b/src/state.c @@ -108,7 +108,7 @@ void ss_grid_init(scene_state_t *ss) { ss->grid.xypad[i].value_y = 0; } - ss->grid.grid_dirty = ss->grid.scr_dirty = true; + ss->grid.grid_dirty = ss->grid.scr_dirty = ss->grid.clear_held = true; } void ss_grid_common_init(grid_common_t *gc) { diff --git a/src/state.h b/src/state.h index 11adabfe..43b68658 100644 --- a/src/state.h +++ b/src/state.h @@ -174,6 +174,7 @@ typedef struct { typedef struct { u8 grid_dirty; u8 scr_dirty; + u8 clear_held; u8 rotate; u8 dim; From ce1699ac7c780bdc78a3c00f96b0794c0208cb61 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 24 May 2018 20:41:44 -0700 Subject: [PATCH 059/117] remember last view fixes #139 --- module/edit_mode.c | 4 ++++ module/edit_mode.h | 1 + module/flash.c | 10 ++++++++++ module/flash.h | 2 ++ module/grid.c | 17 ++++++++++++++++- module/grid.h | 2 +- module/live_mode.c | 6 +++++- module/live_mode.h | 2 ++ module/main.c | 12 +++++++++--- module/preset_r_mode.c | 4 ++++ module/preset_r_mode.h | 1 + 11 files changed, 55 insertions(+), 6 deletions(-) diff --git a/module/edit_mode.c b/module/edit_mode.c index d5368e36..863c6193 100644 --- a/module/edit_mode.c +++ b/module/edit_mode.c @@ -54,6 +54,10 @@ void set_edit_mode_script(uint8_t new_script) { dirty = D_ALL; } +uint8_t get_edit_script() { + return script; +} + static void save_undo(void) { if (++undo_count > 3) undo_count = 3; undo_pos = (undo_pos + 1) % UNDO_DEPTH; diff --git a/module/edit_mode.h b/module/edit_mode.h index 01b8c4ba..f208ec7b 100644 --- a/module/edit_mode.h +++ b/module/edit_mode.h @@ -6,6 +6,7 @@ void set_edit_mode(void); void set_edit_mode_script(uint8_t new_script); +uint8_t get_edit_script(void); void edit_mode_refresh(void); void process_edit_keys(uint8_t key, uint8_t mod_key, bool is_held_key); void screen_mutes_updated(void); diff --git a/module/flash.c b/module/flash.c index 5e114109..625e9ae6 100644 --- a/module/flash.c +++ b/module/flash.c @@ -29,6 +29,7 @@ typedef const struct { typedef const struct { nvram_scene_t scenes[SCENE_SLOTS]; uint8_t last_scene; + tele_mode_t last_mode; uint8_t fresh; cal_data_t cal; } nvram_data_t; @@ -59,6 +60,7 @@ void flash_prepare() { cal_data_t cal = { 0, 16383, 0, 16383 }; flashc_memcpy((void *)&f.cal, &cal, sizeof(cal), true); flash_update_last_saved_scene(0); + flash_update_last_mode(M_LIVE); flashc_memset8((void *)&f.fresh, FIRSTRUN_KEY, 1, true); } @@ -101,6 +103,14 @@ const char *flash_scene_text(uint8_t preset_no, size_t line) { return f.scenes[preset_no].text[line]; } +tele_mode_t flash_last_mode() { + return f.last_mode; +} + +void flash_update_last_mode(tele_mode_t mode) { + flashc_memset8((void *)&f.last_mode, mode, sizeof(tele_mode_t), true); +} + void flash_update_cal(cal_data_t *cal) { flashc_memcpy((void *)&f.cal, cal, sizeof(cal_data_t), true); } diff --git a/module/flash.h b/module/flash.h index eb2a36ef..4e99fbe7 100644 --- a/module/flash.h +++ b/module/flash.h @@ -17,6 +17,8 @@ void flash_write(uint8_t preset_no, scene_state_t *scene, uint8_t flash_last_saved_scene(void); void flash_update_last_saved_scene(uint8_t preset_no); const char *flash_scene_text(uint8_t preset_no, size_t line); +tele_mode_t flash_last_mode(void); +void flash_update_last_mode(tele_mode_t mode); void flash_update_cal(cal_data_t *); void flash_get_cal(cal_data_t *); diff --git a/module/grid.c b/module/grid.c index 7b49415e..a71fabde 100644 --- a/module/grid.c +++ b/module/grid.c @@ -196,7 +196,22 @@ static bool grid_within_area(u8 x, u8 y, grid_common_t *gc); static void grid_fill_area(u8 x, u8 y, u8 w, u8 h, s8 level); static void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, s8 level, u8 page); -void grid_set_control_mode(u8 control, scene_state_t *ss) { +void grid_set_control_mode(u8 control, u8 mode, scene_state_t *ss) { + if (mode == M_LIVE) { + if (grid_mode == GRID_MODE_EDIT) + tt_mode = G_LIVE_G; + else if (grid_mode == GRID_MODE_FULL) + tt_mode = G_LIVE_GF; + else + tt_mode = G_LIVE_V; + } else if (mode == M_EDIT) { + tt_mode = G_EDIT; + tt_script = get_edit_script(); + } else if (mode == M_PATTERN) { + tt_mode = G_TRACKER; + } else if (mode == M_PRESET_W || mode == M_PRESET_R) { + tt_mode = G_PRESET; + } control_mode_on = control; grid_clear_held_keys(); ss->grid.grid_dirty = 1; diff --git a/module/grid.h b/module/grid.h index 130ac9ab..97af3ea3 100644 --- a/module/grid.h +++ b/module/grid.h @@ -19,7 +19,7 @@ typedef enum { GRID_MODE_LAST } screen_grid_mode; -extern void grid_set_control_mode(u8 control, scene_state_t *ss); +extern void grid_set_control_mode(u8 control, u8 mode, scene_state_t *ss); extern void grid_metro_triggered(scene_state_t *ss); extern void grid_refresh(scene_state_t *ss); extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, diff --git a/module/live_mode.c b/module/live_mode.c index 18b47bc6..0a3465e1 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -31,10 +31,10 @@ static process_result_t output; static error_t status; static char error_msg[TELE_ERROR_MSG_LENGTH]; static bool show_welcome_message; -static screen_grid_mode grid_mode = GRID_MODE_OFF; static uint8_t grid_view_changed = 0; static uint8_t grid_x1 = 0, grid_y1 = 0, grid_x2 = 0, grid_y2 = 0; static uint8_t grid_pressed = 0; +screen_grid_mode grid_mode = GRID_MODE_OFF; uint8_t grid_page = 0; uint8_t grid_show_controls = 0; @@ -95,6 +95,10 @@ void set_vars_updated() { dirty |= D_VARS; } +void set_grid_updated() { + grid_view_changed = true; +} + // main mode functions void init_live_mode() { status = E_OK; diff --git a/module/live_mode.h b/module/live_mode.h index 5f187834..ae5a4b60 100644 --- a/module/live_mode.h +++ b/module/live_mode.h @@ -11,12 +11,14 @@ void set_metro_icon(bool display); void init_live_mode(void); void set_live_mode(void); void set_live_submode(u8 submode); +void set_grid_updated(void); void history_next(void); void history_prev(void); void execute_line(void); void process_live_keys(uint8_t key, uint8_t mod_key, bool is_held_key, bool is_release, scene_state_t *ss); uint8_t screen_refresh_live(scene_state_t *ss); void set_vars_updated(void); +extern uint8_t grid_mode; extern uint8_t grid_page; extern uint8_t grid_show_controls; diff --git a/module/main.c b/module/main.c index 396d2015..a1e0e418 100644 --- a/module/main.c +++ b/module/main.c @@ -302,12 +302,13 @@ void handler_Front(int32_t data) { ss_counter = 0; if (mode == M_SCREENSAVER) { set_last_mode(); - return; + if (!grid_connected || data) return; } if (data == 0) { if (grid_connected) { grid_control_mode = !grid_control_mode; - grid_set_control_mode(grid_control_mode, &scene_state); + if (grid_control_mode && mode == M_HELP) set_mode(M_LIVE); + grid_set_control_mode(grid_control_mode, mode, &scene_state); return; } @@ -494,6 +495,10 @@ static void handler_FtdiDisconnect(s32 data) { static void handler_MonomeConnect(s32 data) { grid_connected = 1; timers_set_monome(); + + if (grid_control_mode && mode == M_HELP) set_mode(M_LIVE); + grid_set_control_mode(grid_control_mode, mode, &scene_state); + scene_state.grid.grid_dirty = 1; grid_clear_held_keys(); } @@ -598,6 +603,7 @@ void set_mode(tele_mode_t m) { mode = M_SCREENSAVER; break; } + flash_update_last_mode(mode); } // defined in globals.h @@ -965,7 +971,7 @@ int main(void) { aout[3].slew = 1; init_live_mode(); - set_mode(M_LIVE); + set_mode(flash_last_mode()); run_script(&scene_state, INIT_SCRIPT); scene_state.initializing = false; diff --git a/module/preset_r_mode.c b/module/preset_r_mode.c index 6a2fa27d..aa124fdf 100644 --- a/module/preset_r_mode.c +++ b/module/preset_r_mode.c @@ -20,6 +20,10 @@ static bool dirty; static void do_preset_read(void); +uint8_t get_preset() { + return preset_last; +} + void set_preset_r_mode(uint8_t preset) { preset_last = preset; offset = 0; diff --git a/module/preset_r_mode.h b/module/preset_r_mode.h index 3bd8a43d..010c69b1 100644 --- a/module/preset_r_mode.h +++ b/module/preset_r_mode.h @@ -4,6 +4,7 @@ #include #include +uint8_t get_preset(void); void set_preset_r_mode(uint8_t preset); void process_preset_r_preset(uint8_t preset); void preset_line_down(void); From aa43c4ded357ea9715a906d3b5bff1d756add4e0 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 24 May 2018 20:48:58 -0700 Subject: [PATCH 060/117] preset knob jitter fix #146 --- module/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/module/main.c b/module/main.c index a1e0e418..ef72c997 100644 --- a/module/main.c +++ b/module/main.c @@ -348,7 +348,11 @@ void handler_PollADC(int32_t data) { ss_set_param(&scene_state, adc[1] << 2); } else if (mode == M_PRESET_R && !(grid_connected && grid_control_mode)) { - process_preset_r_preset(adc[1] >> 7); + uint8_t preset = adc[1] >> 6; + uint8_t deadzone = preset & 1; + preset >>= 1; + if (!deadzone || abs(preset - get_preset()) > 1) + process_preset_r_preset(preset); } else { ss_set_param(&scene_state, adc[1] << 2); From 5d9802bc355bb4884dfa57026c44f24ffa26c1ca Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 24 May 2018 20:50:08 -0700 Subject: [PATCH 061/117] grid control variable edit --- module/grid.c | 116 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 25 deletions(-) diff --git a/module/grid.c b/module/grid.c index a71fabde..dab7e930 100644 --- a/module/grid.c +++ b/module/grid.c @@ -175,10 +175,10 @@ typedef struct { } script_trigger_info; static grid_control_mode_t tt_mode = G_LIVE_V, tt_last_mode = G_LIVE_V; -static u8 control_mode_on, tt_script, variable_edit; +static u8 control_mode_on, tt_script, variable_edit, variable_changed; static u8 preset_write, tracker_pressed, tracker_x, tracker_y; static u8 tracker_changed, tracker_select, tracker_selected; -static s16 tracker_last; +static s16 tracker_last, variable_last; static u16 size_x = 16, size_y = 8; static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION/2]; static hold_repeat_info held_keys[GRID_MAX_KEY_PRESSED]; @@ -230,7 +230,7 @@ void grid_control_refresh(scene_state_t *ss) { u8 trig = 7; u8 kill = 11; u8 tracker_in = 6; - u8 tracker_out = 3; + u8 tracker_out = 2; u8 tracker_on = 13; u8 tracker_pos = 2; u8 tracker_page_on = 11; @@ -390,6 +390,7 @@ void grid_control_refresh(scene_state_t *ss) { d += 16; monomeLedBuffer[d+7] = grid_page == 0 ? grid_page_on : grid_page_off; d += 16; + monomeLedBuffer[d+3] = ss->grid.rotate ? grid_page_on : grid_page_off; monomeLedBuffer[d+5] = grid_show_controls ? grid_page_on : grid_page_off; monomeLedBuffer[d+7] = grid_page == 1 ? grid_page_on : grid_page_off; @@ -426,24 +427,31 @@ void grid_control_refresh(scene_state_t *ss) { monomeLedBuffer[d+i] = script_triggers[i].on ? exec : trig; if (variable_edit) { - s16 *v = &(ss->variables.a) - sizeof(s16); + u8 ve = variable_edit - 1; + int16_t *v = &(ss->variables.a); if (size_x == 8) { - if (v[variable_edit] < 0 || v[variable_edit] > 8) + if (v[ve] < 0) for (u16 i = 0; i < 8; i++) monomeLedBuffer[d+i] = var_value_off; + else if (v[ve] > 8) + for (u16 i = 0; i < 8; i++) + monomeLedBuffer[d+i] = var_value_on; else for (u16 i = 0; i < 8; i++) monomeLedBuffer[d+i] = - i < v[variable_edit] ? var_value_on : var_value_off; + i < v[ve] ? var_value_on : var_value_off; } else { d -= 8; - if (v[variable_edit] < 0 || v[variable_edit] > 16) + if (v[ve] < 0) for (u16 i = 0; i < 16; i++) monomeLedBuffer[d+i] = var_value_off; + else if (v[ve] > 16) + for (u16 i = 0; i < 16; i++) + monomeLedBuffer[d+i] = var_value_on; else for (u16 i = 0; i < 16; i++) monomeLedBuffer[d+i] = - i < v[variable_edit] ? var_value_on : var_value_off; + i < v[ve] ? var_value_on : var_value_off; } } } @@ -497,8 +505,9 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ if (variable_edit && y == 7) { if (!z || from_held) return 1; - s16 *v = &(ss->variables.a) - 1; - v[variable_edit] = v[variable_edit] == x + 1 ? 0 : x + 1; + int16_t *v = &(ss->variables.a); + v[variable_edit - 1] = v[variable_edit - 1] == x + 1 ? 0 : x + 1; + variable_changed = 1; set_vars_updated(); ss->grid.grid_dirty = 1; return 1; @@ -795,6 +804,38 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ return 1; } + if (variable_edit && y > 1 && y < 6) { + int16_t *v = &(ss->variables.a); + u8 ve = variable_edit - 1; + + if (!z && x > 2 && x < 5 && variable_edit == x - 2 + ((y - 2) << 1)) { + if (!variable_changed) v[ve] = v[ve] ? 0 : variable_last; + variable_edit = 0; + set_vars_updated(); + ss->grid.grid_dirty = 1; + return 1; + } + if (!z) return 1; + + u8 v_x = 3 + (ve & 1); + if (x == v_x + 1) { + if (v[ve] < 32767) v[ve]++; + } else if (x == v_x + 2) { + if (v[ve] < 32758) v[ve] += 10; + else v[ve] = 32767; + } else if (x == v_x - 1) { + if (v[ve] > -32768) v[ve]--; + } else if (x == v_x - 2) { + if (v[ve] > -32759) v[ve] -= 10; + else v[ve] = -32768; + } + + variable_changed = 1; + set_vars_updated(); + ss->grid.grid_dirty = 1; + return 1; + } + // metro on/off if (y == 3 && x == 0 && !from_held && !z) { ss->variables.m_act = !ss->variables.m_act; @@ -831,8 +872,13 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ // live variables if (tt_mode == G_LIVE_V) { - if (y > 1 && y < 6 && x > 10 && x <13 && !from_held) { + if (y > 1 && y < 6 && x > 2 && x < 5 && !from_held) { variable_edit = z ? x - 2 + ((y - 2) << 1) : 0; + if (variable_edit) { + variable_changed = 0; + int16_t *v = &(ss->variables.a); + variable_last = v[variable_edit - 1]; + } ss->grid.grid_dirty = 1; return 1; } @@ -856,15 +902,19 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ if (y == 3 && x == 7) { grid_page = 0; - edit_mode_refresh(); + set_grid_updated(); ss->grid.grid_dirty = 1; - } else if (y == 4 && x == 7) { - grid_page = 1; - edit_mode_refresh(); + } else if (y == 4 && x == 3) { + ss->grid.rotate = ss->grid.rotate == 0; + set_grid_updated(); ss->grid.grid_dirty = 1; } else if (y == 4 && x == 5) { grid_show_controls = !grid_show_controls; - edit_mode_refresh(); + set_grid_updated(); + ss->grid.grid_dirty = 1; + } else if (y == 4 && x == 7) { + grid_page = 1; + set_grid_updated(); ss->grid.grid_dirty = 1; } @@ -1237,9 +1287,11 @@ void grid_refresh(scene_state_t *ss) { grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, GRID_ON_BRIGHTNESS); break; case FADER_CH_DOT: + grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h, GFC.level); grid_fill_area(GFC.x + GF.value, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS); break; case FADER_CV_DOT: + grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h, GFC.level); grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, GRID_ON_BRIGHTNESS); break; case FADER_FH_BAR: @@ -1315,19 +1367,31 @@ void grid_refresh(scene_state_t *ss) { monomeLedBuffer[led] -= SG.dim; } + if (control_mode_on) grid_control_refresh(ss); + + u8 temp; if (SG.rotate) { - u16 total = size_x * size_y; - if (total > MONOME_MAX_LED_BYTES) total = MONOME_MAX_LED_BYTES; - u8 temp; - for (u16 i = 0; i < (total >> 1); i++) { - temp = monomeLedBuffer[i]; - monomeLedBuffer[i] = monomeLedBuffer[total - i - 1]; - monomeLedBuffer[total - i - 1] = temp; + if (size_x == 8) { + u16 a, b; + for (u16 row = 0; row < 8; row++) + for (u16 col = 0; col < 8; col++) { + a = (row << 4) + col; + b = ((7 - row) << 4) + 7 - col; + temp = monomeLedBuffer[a]; + monomeLedBuffer[a] = monomeLedBuffer[b]; + monomeLedBuffer[b] = temp; + } + } else { + u16 total = size_x * size_y; + if (total > MONOME_MAX_LED_BYTES) total = MONOME_MAX_LED_BYTES; + for (u16 i = 0; i < (total >> 1); i++) { + temp = monomeLedBuffer[i]; + monomeLedBuffer[i] = monomeLedBuffer[total - i - 1]; + monomeLedBuffer[total - i - 1] = temp; + } } } - if (control_mode_on) grid_control_refresh(ss); - SG.grid_dirty = 0; } @@ -1492,9 +1556,11 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, GRID_ON_BRIGHTNESS, page); break; case FADER_CH_DOT: + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, GFC.h, GFC.level, page); grid_fill_area_scr(GFC.x + GF.value, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS, page); break; case FADER_CV_DOT: + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, GFC.h, GFC.level, page); grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, GRID_ON_BRIGHTNESS, page); break; case FADER_FH_BAR: From 798b52d64dfa59124fad596cca02d936f90988b4 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 25 May 2018 20:05:21 -0700 Subject: [PATCH 062/117] fix for grid ctrl var toggling --- module/grid.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/module/grid.c b/module/grid.c index dab7e930..ce7fc7f6 100644 --- a/module/grid.c +++ b/module/grid.c @@ -809,7 +809,14 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ u8 ve = variable_edit - 1; if (!z && x > 2 && x < 5 && variable_edit == x - 2 + ((y - 2) << 1)) { - if (!variable_changed) v[ve] = v[ve] ? 0 : variable_last; + if (!variable_changed) { + if (v[ve]) { + variable_last = v[ve]; + v[ve] = 0; + } else { + v[ve] = variable_last ? variable_last : 1; + } + } variable_edit = 0; set_vars_updated(); ss->grid.grid_dirty = 1; From c29a0466d3a602ef930dff103400b9946fab20a2 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Wed, 30 May 2018 20:21:01 -0700 Subject: [PATCH 063/117] 1ms TIME/LAST fixes #144 --- module/flash.c | 6 ++++++ module/main.c | 4 ++++ simulator/tt.c | 4 ++++ src/ops/init.c | 4 +++- src/ops/variables.c | 41 +++++++++++++++++++++++++++++++++++++++-- src/state.c | 14 ++++++++------ src/state.h | 6 +++--- src/teletype.c | 4 ---- src/teletype_io.h | 3 +++ tests/main.c | 3 +++ 10 files changed, 73 insertions(+), 16 deletions(-) diff --git a/module/flash.c b/module/flash.c index 625e9ae6..74440336 100644 --- a/module/flash.c +++ b/module/flash.c @@ -5,6 +5,7 @@ // asf #include "flashc.h" #include "print_funcs.h" +#include "init_teletype.h" // this #include "teletype.h" @@ -89,6 +90,11 @@ void flash_read(uint8_t preset_no, scene_state_t *scene, unpack_grid(scene); memcpy(text, &f.scenes[preset_no].text, SCENE_TEXT_LINES * SCENE_TEXT_CHARS); + // need to reset timestamps + uint32_t ticks = get_ticks(); + for (size_t i = 0; i < TEMP_SCRIPT; i++) + scene->scripts[i].last_time = ticks; + scene->variables.time = 0; } uint8_t flash_last_saved_scene() { diff --git a/module/main.c b/module/main.c index ef72c997..5e3f47f1 100644 --- a/module/main.c +++ b/module/main.c @@ -783,6 +783,10 @@ void render_init(void) { //////////////////////////////////////////////////////////////////////////////// // teletype_io.h +uint32_t tele_get_ticks() { + return get_ticks(); +} + void tele_metro_updated() { uint32_t metro_time = scene_state.variables.m; diff --git a/simulator/tt.c b/simulator/tt.c index faea5718..9ff47fdd 100644 --- a/simulator/tt.c +++ b/simulator/tt.c @@ -11,6 +11,10 @@ #include "util.h" +uint32_t tele_get_ticks() { + return 0; +} + void tele_metro_updated() { printf("METRO UPDATED"); printf("\n"); diff --git a/src/ops/init.c b/src/ops/init.c index 8370efb5..09d675ee 100644 --- a/src/ops/init.c +++ b/src/ops/init.c @@ -169,6 +169,8 @@ static void op_INIT_TIME_get(const void *NOTUSED(data), scene_state_t *ss, command_state_t *NOTUSED(cs)) { clear_delays(ss); ss->variables.time = 0; - for (uint8_t i = 0; i < TEMP_SCRIPT; i++) ss->scripts[i].last_time = 0; + uint32_t ticks = tele_get_ticks(); + for (uint8_t i = 0; i < TEMP_SCRIPT; i++) ss->scripts[i].last_time = ticks; + ss->variables.time = 0; ss_sync_every(ss, 0); } diff --git a/src/ops/variables.c b/src/ops/variables.c index bf16adb1..62c288fe 100644 --- a/src/ops/variables.c +++ b/src/ops/variables.c @@ -5,6 +5,7 @@ #include "helpers.h" #include "ops/op.h" #include "teletype.h" +#include "teletype_io.h" static void op_LAST_get(const void *data, scene_state_t *ss, exec_state_t *es, @@ -25,6 +26,14 @@ static void op_I_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_I_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_TIME_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_TIME_set(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_TIME_ACT_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_TIME_ACT_set(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); // clang-format off const tele_op_t op_A = MAKE_SIMPLE_VARIABLE_OP(A , variables.a ); @@ -39,8 +48,8 @@ const tele_op_t op_O_MAX = MAKE_SIMPLE_VARIABLE_OP(O.MAX , variables.o_ const tele_op_t op_O_MIN = MAKE_SIMPLE_VARIABLE_OP(O.MIN , variables.o_min ); const tele_op_t op_O_WRAP = MAKE_SIMPLE_VARIABLE_OP(O.WRAP , variables.o_wrap ); const tele_op_t op_T = MAKE_SIMPLE_VARIABLE_OP(T , variables.t ); -const tele_op_t op_TIME = MAKE_SIMPLE_VARIABLE_OP(TIME , variables.time ); -const tele_op_t op_TIME_ACT = MAKE_SIMPLE_VARIABLE_OP(TIME.ACT , variables.time_act ); +const tele_op_t op_TIME = MAKE_GET_SET_OP(TIME, op_TIME_get, op_TIME_set, 0, true); +const tele_op_t op_TIME_ACT = MAKE_GET_SET_OP(TIME.ACT, op_TIME_ACT_get, op_TIME_ACT_set, 0, true); const tele_op_t op_LAST = MAKE_GET_OP(LAST , op_LAST_get, 1, true); const tele_op_t op_X = MAKE_SIMPLE_VARIABLE_OP(X , variables.x ); const tele_op_t op_Y = MAKE_SIMPLE_VARIABLE_OP(Y , variables.y ); @@ -52,6 +61,34 @@ const tele_op_t op_O = MAKE_GET_SET_OP(O , op_O_get , op_O_set , 0, const tele_op_t op_I = MAKE_GET_SET_OP(I , op_I_get, op_I_set, 0, true); // clang-format on +static void op_TIME_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int64_t delta = ss->variables.time_act ? + tele_get_ticks() - ss->variables.time : ss->variables.time; + cs_push(cs, delta & 0x7fff); +} + +static void op_TIME_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t new_time = cs_pop(cs); + ss->variables.time = ss->variables.time_act ? + tele_get_ticks() - new_time : new_time; +} + +static void op_TIME_ACT_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, ss->variables.time_act ? 1 : 0); +} + +static void op_TIME_ACT_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t act = cs_pop(cs); + if (act && ss->variables.time_act) return; + if (!act && !ss->variables.time_act) return; + ss->variables.time_act = act ? 1 : 0; + ss->variables.time = tele_get_ticks() - ss->variables.time; +} + static void op_LAST_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t script_number = cs_pop(cs) - 1; diff --git a/src/state.c b/src/state.c index 51ee0996..2d63d0ea 100644 --- a/src/state.c +++ b/src/state.c @@ -17,6 +17,11 @@ void ss_init(scene_state_t *ss) { ss->stack_op.top = 0; memset(&ss->scripts, 0, ss_scripts_size()); turtle_init(&ss->turtle); + uint32_t ticks = tele_get_ticks(); + for (size_t i = 0; i < TEMP_SCRIPT; i++) + ss->scripts[i].last_time = ticks; + ss->variables.time = 0; + ss->variables.time_act = 1; } void ss_variables_init(scene_state_t *ss) { @@ -331,17 +336,14 @@ size_t ss_scripts_size() { } int16_t ss_get_script_last(scene_state_t *ss, script_number_t idx) { - int16_t now = ss->variables.time; if (idx < TT_SCRIPT_1) return 0; if (idx > INIT_SCRIPT) return 0; - int16_t last = ss->scripts[idx].last_time; - if (now < last) - return (INT16_MAX - last) + (now - INT16_MIN); // I must be dense? - return now - last; + uint32_t delta = (tele_get_ticks() - ss->scripts[idx].last_time) & 0x7fff; + return delta; } void ss_update_script_last(scene_state_t *ss, script_number_t idx) { - ss->scripts[idx].last_time = ss->variables.time; + ss->scripts[idx].last_time = tele_get_ticks(); } every_count_t *ss_get_every(scene_state_t *ss, script_number_t idx, diff --git a/src/state.h b/src/state.h index 43b68658..1dfc8294 100644 --- a/src/state.h +++ b/src/state.h @@ -90,8 +90,8 @@ typedef struct { int16_t r_min; int16_t r_max; int16_t scene; - int16_t time; - int16_t time_act; + int64_t time; + uint8_t time_act; int16_t tr[TR_COUNT]; int16_t tr_pol[TR_COUNT]; int16_t tr_time[TR_COUNT]; @@ -129,7 +129,7 @@ typedef struct { uint8_t l; tele_command_t c[SCRIPT_MAX_COMMANDS]; every_count_t every[SCRIPT_MAX_COMMANDS]; - int16_t last_time; + uint32_t last_time; } scene_script_t; typedef struct { diff --git a/src/teletype.c b/src/teletype.c index e4c0b13a..8bc642f3 100644 --- a/src/teletype.c +++ b/src/teletype.c @@ -299,10 +299,6 @@ process_result_t process_command(scene_state_t *ss, exec_state_t *es, // TICK ///////////////////////////////////////////////////////// void tele_tick(scene_state_t *ss, uint8_t time) { - // time is the basic resolution of all code henceforth called - // hardware 2.0: get an RTC! - if (ss->variables.time_act) ss->variables.time += time; - // could be a while() if there is reason to expect a user to cascade moves // with SCRIPTs without the tick delay if (ss->turtle.stepped && ss->turtle.script_number != TEMP_SCRIPT) { diff --git a/src/teletype_io.h b/src/teletype_io.h index a5d7f8ac..526c4809 100644 --- a/src/teletype_io.h +++ b/src/teletype_io.h @@ -7,6 +7,9 @@ // These functions are for interacting with the teletype hardware, each target // must provide it's own implementation +// used for TIME and LAST +extern uint32_t tele_get_ticks(void); + // called when M or M.ACT are updated extern void tele_metro_updated(void); diff --git a/tests/main.c b/tests/main.c index 49d8e4ef..ebade6f6 100644 --- a/tests/main.c +++ b/tests/main.c @@ -11,6 +11,9 @@ #include "process_tests.h" #include "turtle_tests.h" +uint32_t tele_get_ticks() { + return 0; +} void tele_metro_updated() {} void tele_metro_reset() {} void tele_tr(uint8_t i, int16_t v) {} From c94551b087f5fa8cc1408cb53fe3277d164b216e Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Wed, 30 May 2018 20:50:33 -0700 Subject: [PATCH 064/117] fix for grid control var toggle --- module/grid.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/module/grid.c b/module/grid.c index ce7fc7f6..f621dfde 100644 --- a/module/grid.c +++ b/module/grid.c @@ -881,11 +881,7 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ if (tt_mode == G_LIVE_V) { if (y > 1 && y < 6 && x > 2 && x < 5 && !from_held) { variable_edit = z ? x - 2 + ((y - 2) << 1) : 0; - if (variable_edit) { - variable_changed = 0; - int16_t *v = &(ss->variables.a); - variable_last = v[variable_edit - 1]; - } + if (variable_edit) variable_changed = 0; ss->grid.grid_dirty = 1; return 1; } From 57fbc45bacdaee457a4db0fe70eec456110ab5a3 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 31 May 2018 20:40:12 -0700 Subject: [PATCH 065/117] help screen updates --- module/help_mode.c | 261 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 239 insertions(+), 22 deletions(-) diff --git a/module/help_mode.c b/module/help_mode.c index 66c2d5c5..7a125ff6 100644 --- a/module/help_mode.c +++ b/module/help_mode.c @@ -15,10 +15,10 @@ //////////////////////////////////////////////////////////////////////////////// // Help text /////////////////////////////////////////////////////////////////// -#define HELP_PAGES 8 +#define HELP_PAGES 10 #define HELP1_LENGTH 47 -const char* help1[HELP1_LENGTH] = { "1/8 HELP", +const char* help1[HELP1_LENGTH] = { "1/10 HELP", "[ ] NAVIGATE HELP PAGES", "UP/DOWN TO SCROLL", " ", @@ -67,7 +67,7 @@ const char* help1[HELP1_LENGTH] = { "1/8 HELP", "SHIFT-2|SHOW/HIDE TURTLE" }; #define HELP2_LENGTH 13 -const char* help2[HELP2_LENGTH] = { "2/8 VARIABLES", +const char* help2[HELP2_LENGTH] = { "2/10 VARIABLES", " ", "X, Y, Z|GENERAL PURPOSE", "T|USE FOR TIME", @@ -81,8 +81,8 @@ const char* help2[HELP2_LENGTH] = { "2/8 VARIABLES", "Q.N|SET Q LENGTH", "Q.AVG|AVERAGE OF ALL Q" }; -#define HELP3_LENGTH 22 -const char* help3[HELP3_LENGTH] = { "3/8 PARAMETERS", +#define HELP3_LENGTH 26 +const char* help3[HELP3_LENGTH] = { "3/10 PARAMETERS", " ", "TR A-D|SET TR VALUE (0,1)", "TR.TIME A-D|TR PULSE TIME", @@ -92,7 +92,11 @@ const char* help3[HELP3_LENGTH] = { "3/8 PARAMETERS", "CV.OFF 1-4|ADD CV OFFSET", " ", "IN|GET IN JACK VAL", + "IN.SCALE X Y", + " SCALE IN RANGE", "PARAM|GET KNOB VAL", + "PARAM.SCALE X Y", + " SCALE KNOB RANGE", " ", "M|METRO TIME (MS)", "M.ACT|ENABLE METRO (0/1)", @@ -105,8 +109,8 @@ const char* help3[HELP3_LENGTH] = { "3/8 PARAMETERS", "SCENE|GET/SET SCENE #", "LAST N|GET SCRIPT LAST RUN" }; -#define HELP4_LENGTH 10 -const char* help4[HELP4_LENGTH] = { "4/8 DATA AND TABLES", +#define HELP4_LENGTH 11 +const char* help4[HELP4_LENGTH] = { "4/10 DATA AND TABLES", " ", "ALL PARAMS HAVE 16B RANGE", "-32768 TO 32767", @@ -115,10 +119,11 @@ const char* help4[HELP4_LENGTH] = { "4/8 DATA AND TABLES", "N 0-127|CONVERT TO 1V/8VE", "V 0-10|VOLT LOOKUP", "VV 0-1000|V WITH 2 DECIMALS", - "BPM 2-MAX|MS PER BPM" }; + "BPM 2-MAX|MS PER BPM", + "EXP X|EXPO LOOKUP" }; -#define HELP5_LENGTH 46 -const char* help5[HELP5_LENGTH] = { "5/8 OPERATORS", +#define HELP5_LENGTH 55 +const char* help5[HELP5_LENGTH] = { "5/10 OPERATORS", " ", "RAND A|RANDOM 0 - A", "RRAND A B|RANDOM A - B", @@ -159,14 +164,23 @@ const char* help5[HELP5_LENGTH] = { "5/8 OPERATORS", " ", "LIM A B C|CLAMP A WITHIN B-C", "WRAP A B C|WRAP A AROUND B-C", + "SCALE A B X Y I", + " SCALE I FROM A..B TO X..Y", "QT A B|QUANTIZE A TO B*X", " ", + "// EUCLIDEAN OPERATOR", + "ER F L I", + " F = FILL (1-32)", + " L = LENGTH (1-32)", + " I = STEP (ANY)", + " RETURNS 0 OR 1", + " ", "// SPECIAL OPERATORS", "TR.TOG X|FLIP STATE OF TR X", "TR.PULSE X|PULSE TR X" }; #define HELP6_LENGTH 31 -const char* help6[HELP6_LENGTH] = { "6/8 PRE :", +const char* help6[HELP6_LENGTH] = { "6/10 PRE :", " ", "EACH PRE NEEDS A : FOLLOWED", "BY A COMMAND TO OPERATE ON", @@ -196,12 +210,10 @@ const char* help6[HELP6_LENGTH] = { "6/8 PRE :", "OTHER:|EXECUTE OTHERWISE", "SYNC X|SYNC TO STEP X", " ", - "BREAK|STOP EXECUTION" - -}; + "BREAK|STOP EXECUTION" }; #define HELP7_LENGTH 26 -const char* help7[HELP7_LENGTH] = { "7/8 PATTERNS", +const char* help7[HELP7_LENGTH] = { "7/10 PATTERNS", " ", "// DIRECT ACCESS", "P A|GET VAL AT INDEX A", @@ -228,7 +240,7 @@ const char* help7[HELP7_LENGTH] = { "7/8 PATTERNS", "P.NEXT A|GET/SET NEXT POS", "P.PREV A|GET/SET PREV POS" }; #define HELP8_LENGTH 17 -const char* help8[HELP8_LENGTH] = { "8/8 TURTLE", +const char* help8[HELP8_LENGTH] = { "8/10 TURTLE", " ", "// CRAWLS TRACKER DATA", "@|GET/SET DATA", @@ -246,16 +258,221 @@ const char* help8[HELP8_LENGTH] = { "8/8 TURTLE", "@SCRIPT N|GET/SET EDGE SCRIPT", "@SHOW 1/0|DISPLAY < ON TRACKER" }; +#define HELP9_LENGTH 36 +const char* help9[HELP9_LENGTH] = { "9/10 TELEX INPUT", + " ", + "TI.PARAM X|(TI.PRM)", + " GET KNOB VALUE", + "TI.PARAM.QT X", + " KNOB VALUE QUANTIZED", + "TI.PARAM.N X", + " KNOB AS SCALE NOTE", + "TI.PARAM.SCALE X", + " SELECT KNOB QUANT SCALE", + "TI.PARAM.MAP X Y Z", + " MAP KNOB VALUE TO Y..Z", + "TI.IN X", + " GET INPUT VAL", + "TI.IN.QT X", + " IN VALUE QUANTIZED", + "TI.IN.N X", + " IN AS SCALE NOTE", + "TI.IN.SCALE X", + " SELECT IN QUANT SCALE", + "TI.IN.MAP X Y Z", + " MAP IN VALUE TO Y..Z", + "TI.PARAM.INIT X", + " RESET KNOB X", + "TI.IN.INIT X", + " RESET IN X", + "TI.INIT D", + " RESET DEVICE D", + "TI.PARAM.CALIB X Y", + " CALIBRATE KNOB X", + "TI.IN.CALIB X Y", + " CALIBRATE IN X", + "TI.STORE D", + " STORE CALIB FOR DEVICE D", + "TI.RESET D", + " RESET CALIB FOR DEVICE D" }; + +#define HELP10_LENGTH 164 +const char* help10[HELP10_LENGTH] = { + "10/10 TELEX OUTPUT", + " ", + "TO.TR X Y", + " SET TR VALUE (0/1)", + "TO.TR.TOG X", + " TOGGLE TR", + "TO.TR.P X", + " PULSE TR", + "TO.TR.P.DIV X Y", + " SET TR X CLOCK DIV TO Y", + "TO.TR.P.MUTE X Y", + " MUTE TR X (0/1)", + "TO.TR.TIME X Y", + " SET TR PULSE TIME (MS)", + "TO.TR.TIME.S X Y", + " SET TR PULSE TIME (SEC)", + "TO.TR.TIME.M", + " SET TR PULSE TIME (MIN)", + "TO.TR.WIDTH X Y", + " SET TR DUTY (%)", + "TO.TR.POL X Y", + " SET TR POLARITY", + "TO.TR.M.ACT X Y", + " ENABLE METRO (0/1)", + "TO.TR.M X Y", + " SET METRO RATE (MS)", + "TO.TR.M.S X Y", + " SET METRO RATE (SEC)", + "TO.TR.M.M X Y", + " SET METRO RATE (MIN)", + "TO.TR.M.BPM X Y", + " SET METRO RATE (BPM)", + "TO.TR.M.COUNT X Y", + " SET METRO REPEAT", + "TO.TR.M.MUL X Y", + " SET METRO MULT", + "TO.TR.M.SYNC X", + " SYNC METRO", + "TO.M.ACT D Y", + " ENABLE DEVICE METRO (0/1)", + "TO.M D Y", + " SET DEVICE METRO RATE (MS)", + "TO.M.S D Y", + " AS ABOVE IN SECONDS", + "TO.M.M D Y", + " AS ABOVE IN MINUTES", + "TO.M.BPM D Y", + " AS ABOVE IN BPM", + "TO.M.COUNT D Y", + " SET DEVICE METRO REPEAT", + "TO.M.SYNC D", + " SYNC DEVICE METRO", + "TO.CV X Y", + " SET CV WITH SLEW", + "TO.CV.SLEW X Y", + " SET CV SLEW (MS)", + "TO.CV.SLEW.S X Y", + " SET CV SLEW (SEC)", + "TO.CV.SLEW.M", + " SET CV SLEW (MIN)", + "TO.CV.SET X Y", + " SET CV WITH NO SLEW", + "TO.CV.OFF X Y", + " SET CV OFFSET", + "TO.CV.QT X Y", + " SET CV QUANTIZED", + "TO.CV.QT.SET X Y", + " AS ABOVE NO SLEW", + "TO.CV.N X Y", + " SET CV TO SCALE NOTE", + "TO.CV.N.SET X Y", + " AS ABOVE NO SLEW", + "TO.CV.LOG X Y", + " SET CV LOG MODE", + "TO.OSC X Y", + " SET CV OSC FREQ", + "TO.OSC.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.QT X Y", + " SET CV OSC QUANTIZED", + "TO.OSC.QT.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.N X Y", + " SET CV OSC TO SCALE NOTE", + "TO.OSC.N.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.FQ X Y", + " SET CV OSC (HZ)", + "TO.OSC.LFO X Y", + " SET CV LFO RATE (MILLIHZ)", + "TO.OSC.LFO.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.CYC X Y", + " SET CV OSC CYCLE (MS)", + "TO.OSC.CYC.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.CYC.S X Y", + " SET CV OSC CYCLE (SEC)", + "TO.OSC.CYC.S.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.CYC.M X Y", + " SET CV OSC CYCLE (MIN)", + "TO.OSC.CYC.M.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.SCALE X Y", + " CV X QT SCALE Y", + "TO.OSC.WAVE X Y", + " SELECT CV OSC WAVEFORM", + "TO.OSC.RECT X Y", + " SET OSC RECTIFY (-2..2)", + "TO.OSC.WIDTH X Y", + " SET OSC PULSEWIDTH", + "TO.OSC.SYNC X", + " RESET OSC PHASE", + "TO.OSC.PHASE X Y", + " SET OSC PHASE", + "TO.OSC.SLEW X Y", + " SET OSC SLEW (MS)", + "TO.OSC.SLEW.S X Y", + " SET OSC SLEW (SEC)", + "TO.OSC.SLEW.M X Y", + " SET OSC SLEW (MIN)", + "TO.OSC.CTR X Y", + " SET OSC CENTER", + "TO.ENV.ACT X Y", + " ENABLE ENV (1/0)", + "TO.ENV X Y", + " SET ENV GATE (1/0)", + "TO.ENV.TRIG X Y", + " TRIGGER ENV", + "TO.ENV.ATT X Y", + " SET ENV ATTACK (MS)", + "TO.ENV.ATT.S X Y", + " SET ENV ATTACK (SEC)", + "TO.ENV.ATT.M X Y", + " SET ENV ATTACK (MIN)", + "TO.ENV.DEC X Y", + " SET ENV DECAY (MS)", + "TO.ENV.DEC.S X Y", + " SET ENV DECAY (SEC)", + "TO.ENV.DEC.M X Y", + " SET ENV DECAY (MIN)", + "TO.ENV.EOR X N", + " PULSE TR N AT END OF RISE", + " TR ON SAME DEVICE", + "TO.ENV.EOC X N", + " AS ABOVE FOR END OF CYCLE", + "TO.ENV.LOOP X Y", + " LOOP ENV Y TIMES", + " 0 TO LOOP INDEFINITELY", + "TO.TR.INIT X", + " RESET TR", + "TO.CV.INIT X", + " RESET CV", + "TO.INIT D", + " RESET DEVICE", + "TO.KILL D", + " CANCEL DEVICE TR PULSES", + " AND CV SLEW", + "TO.CV.CALIB X", + " SAVE TO.CV.OFF X", + " AS CALIB VALUE", + "TO.CV.RESET X", + " RESET CV CALIB"}; + //////////////////////////////////////////////////////////////////////////////// // 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 }; +const char** help_pages[HELP_PAGES] = { help1, help2, help3, help4, help5, + help6, help7, help8, help9, help10 }; +const uint8_t help_length[HELP_PAGES] = { + HELP1_LENGTH, HELP2_LENGTH, HELP3_LENGTH, HELP4_LENGTH, HELP5_LENGTH, + HELP6_LENGTH, HELP7_LENGTH, HELP8_LENGTH, HELP9_LENGTH, HELP10_LENGTH +}; static uint8_t page_no; static uint8_t offset; From 0fafed9c28bd9d8342601cacbd5058000f212dd3 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sat, 16 Jun 2018 17:56:58 -0700 Subject: [PATCH 066/117] fixes #148 --- src/ops/controlflow.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/ops/controlflow.c b/src/ops/controlflow.c index 86f4fea6..37f9c0a9 100644 --- a/src/ops/controlflow.c +++ b/src/ops/controlflow.c @@ -120,16 +120,20 @@ static void mod_L_func(scene_state_t *ss, exec_state_t *es, command_state_t *cs, // using a pointer means that the loop contents can a interact with the // iterator, allowing users to roll back a loop or advance it faster int16_t *i = &es_variables(es)->i; - + *i = a; + // Forward loop if (a < b) { // continue the loop whenever the _pointed-to_ I meets the condition // this means that I can be interacted with inside the loop command - for (*i = a; *i <= b; (*i)++) { - // the increment statement has careful syntax, because the - // ++ operator has precedence over the dereference * operator + + // iterate with higher precision to account for b == 32767 + for (int32_t l = a; l <= b; l++) { process_command(ss, es, post_command); if (es_variables(es)->breaking) break; + // the increment statement has careful syntax, because the + // ++ operator has precedence over the dereference * operator + (*i)++; } if (!es_variables(es)->breaking) @@ -137,8 +141,10 @@ static void mod_L_func(scene_state_t *ss, exec_state_t *es, command_state_t *cs, } // Reverse loop (also works for equal values (either loop would)) else { - for (*i = a; *i >= b && !es_variables(es)->breaking; (*i)--) + for (int32_t l = a; l >= b && !es_variables(es)->breaking; l--) { process_command(ss, es, post_command); + (*i)--; + } if (!es_variables(es)->breaking) (*i)++; } } From 8088e2767427ad3c5f8987fa06ecfbad304d6b16 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sat, 16 Jun 2018 17:57:51 -0700 Subject: [PATCH 067/117] fixes #143 --- src/ops/maths.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ops/maths.c b/src/ops/maths.c index d5321bdd..13c0d734 100644 --- a/src/ops/maths.c +++ b/src/ops/maths.c @@ -233,12 +233,13 @@ static void op_RAND_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), if (a == -1) cs_push(cs, 0); else - cs_push(cs, rand() % (a + 1)); + cs_push(cs, a == 32767 ? rand() : rand() % (a + 1)); } static void op_RRAND_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a, b, min, max, range; + int16_t a, b, min, max; + int64_t range; a = cs_pop(cs); b = cs_pop(cs); if (a < b) { @@ -252,8 +253,11 @@ static void op_RRAND_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), range = max - min + 1; if (range == 0) cs_push(cs, a); - else - cs_push(cs, rand() % range + min); + else { + int64_t rrand = ((int32_t)rand() << 16) + rand(); + rrand = rrand % range + min; + cs_push(cs, rrand); + } } From f5c8838fd25990d4721d05061703b01f7ed98e9f Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sat, 16 Jun 2018 17:59:09 -0700 Subject: [PATCH 068/117] fixes #150 --- src/ops/patterns.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ops/patterns.c b/src/ops/patterns.c index a06ca760..7df0387e 100644 --- a/src/ops/patterns.c +++ b/src/ops/patterns.c @@ -558,12 +558,14 @@ static int16_t p_rm_get(scene_state_t *ss, int16_t pn, int16_t idx) { idx = normalise_idx(ss, pn, idx); int16_t ret = ss_get_pattern_val(ss, pn, idx); - for (int16_t i = idx; i < len; i++) { - int16_t v = ss_get_pattern_val(ss, pn, i + 1); - ss_set_pattern_val(ss, pn, i, v); - } + if (idx < len) { + for (int16_t i = idx; i < len; i++) { + int16_t v = ss_get_pattern_val(ss, pn, i + 1); + ss_set_pattern_val(ss, pn, i, v); + } - ss_set_pattern_len(ss, pn, len - 1); + ss_set_pattern_len(ss, pn, len - 1); + } return ret; } From 83533e9126becf5884063c6629211d9dbeaafcfe Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sat, 16 Jun 2018 18:03:28 -0700 Subject: [PATCH 069/117] fixes #149 --- src/ops/patterns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ops/patterns.c b/src/ops/patterns.c index 7df0387e..28ac573f 100644 --- a/src/ops/patterns.c +++ b/src/ops/patterns.c @@ -577,7 +577,7 @@ static void op_P_RM_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t pn = ss->variables.p_n; int16_t a = cs_pop(cs); - cs_push(cs, p_rm_get(ss, pn, a - 1)); // a is 1-indexed + cs_push(cs, p_rm_get(ss, pn, a)); tele_pattern_updated(); } From ef004d0efa2f2d2c528c654ef3560473d38b6f6c Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sat, 16 Jun 2018 18:04:47 -0700 Subject: [PATCH 070/117] fixes #151 --- src/ops/patterns.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ops/patterns.c b/src/ops/patterns.c index 28ac573f..f2f68e9e 100644 --- a/src/ops/patterns.c +++ b/src/ops/patterns.c @@ -641,18 +641,19 @@ static int16_t p_pop_get(scene_state_t *ss, int16_t pn) { } else return 0; - tele_pattern_updated(); } static void op_P_POP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, p_pop_get(ss, ss->variables.p_n)); + tele_pattern_updated(); } static void op_PN_POP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t pn = cs_pop(cs); cs_push(cs, p_pop_get(ss, pn)); + tele_pattern_updated(); } // Make ops From 0a5de9850b68811a0a18a18045bfbdbe551db35d Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sat, 16 Jun 2018 18:05:20 -0700 Subject: [PATCH 071/117] new pattern ops --- src/match_token.rl | 10 +++ src/ops/op.c | 2 + src/ops/op_enum.h | 10 +++ src/ops/patterns.c | 154 +++++++++++++++++++++++++++++++++++++++++++++ src/ops/patterns.h | 11 ++++ 5 files changed, 187 insertions(+) diff --git a/src/match_token.rl b/src/match_token.rl index 91439d48..9ef579ff 100644 --- a/src/match_token.rl +++ b/src/match_token.rl @@ -113,6 +113,16 @@ "PN.MIN" => { MATCH_OP(E_OP_PN_MIN); }; "P.MAX" => { MATCH_OP(E_OP_P_MAX); }; "PN.MAX" => { MATCH_OP(E_OP_PN_MAX); }; + "P.RND" => { MATCH_OP(E_OP_P_RND); }; + "PN.RND" => { MATCH_OP(E_OP_PN_RND); }; + "P.+" => { MATCH_OP(E_OP_P_ADD); }; + "PN.+" => { MATCH_OP(E_OP_PN_ADD); }; + "P.-" => { MATCH_OP(E_OP_P_SUB); }; + "PN.-" => { MATCH_OP(E_OP_PN_SUB); }; + "P.+W" => { MATCH_OP(E_OP_P_ADDW); }; + "PN.+W" => { MATCH_OP(E_OP_PN_ADDW); }; + "P.-W" => { MATCH_OP(E_OP_P_SUBW); }; + "PN.-W" => { MATCH_OP(E_OP_PN_SUBW); }; # queue "Q" => { MATCH_OP(E_OP_Q); }; diff --git a/src/ops/op.c b/src/ops/op.c index 5422efd0..ecc50d6c 100644 --- a/src/ops/op.c +++ b/src/ops/op.c @@ -60,6 +60,8 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_P_HERE, &op_PN_HERE, &op_P_NEXT, &op_PN_NEXT, &op_P_PREV, &op_PN_PREV, &op_P_INS, &op_PN_INS, &op_P_RM, &op_PN_RM, &op_P_PUSH, &op_PN_PUSH, &op_P_POP, &op_PN_POP, &op_P_MIN, &op_PN_MIN, &op_P_MAX, &op_PN_MAX, + &op_P_RND, &op_PN_RND, &op_P_ADD, &op_PN_ADD, &op_P_SUB, &op_PN_SUB, + &op_P_ADDW, &op_PN_ADDW, &op_P_SUBW, &op_PN_SUBW, // queue &op_Q, &op_Q_AVG, &op_Q_N, diff --git a/src/ops/op_enum.h b/src/ops/op_enum.h index 73b64803..8ed89bb7 100644 --- a/src/ops/op_enum.h +++ b/src/ops/op_enum.h @@ -92,6 +92,16 @@ typedef enum { E_OP_PN_MIN, E_OP_P_MAX, E_OP_PN_MAX, + E_OP_P_RND, + E_OP_PN_RND, + E_OP_P_ADD, + E_OP_PN_ADD, + E_OP_P_SUB, + E_OP_PN_SUB, + E_OP_P_ADDW, + E_OP_PN_ADDW, + E_OP_P_SUBW, + E_OP_PN_SUBW, E_OP_Q, E_OP_Q_AVG, E_OP_Q_N, diff --git a/src/ops/patterns.c b/src/ops/patterns.c index f2f68e9e..6d17ad0f 100644 --- a/src/ops/patterns.c +++ b/src/ops/patterns.c @@ -1,5 +1,7 @@ #include "ops/patterns.h" +#include // rand + #include "helpers.h" #include "teletype.h" #include "teletype_io.h" @@ -35,6 +37,20 @@ static int16_t normalise_idx(scene_state_t *ss, const int16_t pn, int16_t idx) { return idx; } +static int16_t wrap(int16_t value, int16_t a, int16_t b) { + int16_t c, i = value; + 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; + } + return i; +} //////////////////////////////////////////////////////////////////////////////// // P.N ///////////////////////////////////////////////////////////////////////// @@ -741,3 +757,141 @@ static void op_PN_MAX_get(const void *NOTUSED(data), scene_state_t *ss, // Make ops const tele_op_t op_P_MAX = MAKE_GET_OP(P.MAX, op_P_MAX_get, 0, true); const tele_op_t op_PN_MAX = MAKE_GET_OP(PN.MAX, op_PN_MAX_get, 1, true); + +//////////////////////////////////////////////////////////////////////////////// +// P.RND /////////////////////////////////////////////////////////////////////// + +static int16_t p_rnd_get(scene_state_t *ss, int16_t pn) { + pn = normalise_pn(pn); + int16_t start = ss_get_pattern_start(ss, pn); + int16_t end = ss_get_pattern_end(ss, pn); + if (end < start) return 0; + return ss_get_pattern_val(ss, pn, rand() % (end - start + 1) + start); +} + +static void op_P_RND_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + cs_push(cs, p_rnd_get(ss, ss->variables.p_n)); +} + +static void op_PN_RND_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + cs_push(cs, p_rnd_get(ss, pn)); +} + +// Make ops +const tele_op_t op_P_RND = MAKE_GET_OP(P.RND, op_P_RND_get, 0, true); +const tele_op_t op_PN_RND = MAKE_GET_OP(PN.RND, op_PN_RND_get, 1, true); + +//////////////////////////////////////////////////////////////////////////////// +// P.+ P.+W //////////////////////////////////////////////////////////////////// + +static void p_add_get(scene_state_t *ss, int16_t pn, int16_t idx, + int16_t delta, uint8_t wrap_value, int16_t min, int16_t max) { + pn = normalise_pn(pn); + idx = normalise_idx(ss, pn, idx); + int16_t value = ss_get_pattern_val(ss, pn, idx) + delta; + if (wrap_value) value = wrap(value, min, max); + ss_set_pattern_val(ss, pn, idx, value); +} + +static void op_P_ADD_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t idx = cs_pop(cs); + int16_t delta = cs_pop(cs); + p_add_get(ss, ss->variables.p_n, idx, delta, 0, 0, 0); + tele_pattern_updated(); +} + +static void op_PN_ADD_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + int16_t idx = cs_pop(cs); + int16_t delta = cs_pop(cs); + p_add_get(ss, pn, idx, delta, 0, 0, 0); + tele_pattern_updated(); +} + +static void op_P_ADDW_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t idx = cs_pop(cs); + int16_t delta = cs_pop(cs); + int16_t min = cs_pop(cs); + int16_t max = cs_pop(cs); + p_add_get(ss, ss->variables.p_n, idx, delta, 1, min, max); + tele_pattern_updated(); +} + +static void op_PN_ADDW_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + int16_t idx = cs_pop(cs); + int16_t delta = cs_pop(cs); + int16_t min = cs_pop(cs); + int16_t max = cs_pop(cs); + p_add_get(ss, pn, idx, delta, 1, min, max); + tele_pattern_updated(); +} + +// Make ops +const tele_op_t op_P_ADD = MAKE_GET_OP(P.+, op_P_ADD_get, 2, false); +const tele_op_t op_PN_ADD = MAKE_GET_OP(PN.+, op_PN_ADD_get, 3, false); +const tele_op_t op_P_ADDW = MAKE_GET_OP(P.+W, op_P_ADDW_get, 4, false); +const tele_op_t op_PN_ADDW = MAKE_GET_OP(PN.+W, op_PN_ADDW_get, 5, false); + +//////////////////////////////////////////////////////////////////////////////// +// P.- P.-W //////////////////////////////////////////////////////////////////// + +static void p_sub_get(scene_state_t *ss, int16_t pn, int16_t idx, + int16_t delta, uint8_t wrap_value, int16_t min, int16_t max) { + pn = normalise_pn(pn); + idx = normalise_idx(ss, pn, idx); + int16_t value = ss_get_pattern_val(ss, pn, idx) - delta; + if (wrap_value) value = wrap(value, min, max); + ss_set_pattern_val(ss, pn, idx, value); +} + +static void op_P_SUB_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t idx = cs_pop(cs); + int16_t delta = cs_pop(cs); + p_sub_get(ss, ss->variables.p_n, idx, delta, 0, 0, 0); + tele_pattern_updated(); +} + +static void op_PN_SUB_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + int16_t idx = cs_pop(cs); + int16_t delta = cs_pop(cs); + p_sub_get(ss, pn, idx, delta, 0, 0, 0); + tele_pattern_updated(); +} + +static void op_P_SUBW_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t idx = cs_pop(cs); + int16_t delta = cs_pop(cs); + int16_t min = cs_pop(cs); + int16_t max = cs_pop(cs); + p_sub_get(ss, ss->variables.p_n, idx, delta, 1, min, max); + tele_pattern_updated(); +} + +static void op_PN_SUBW_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t pn = cs_pop(cs); + int16_t idx = cs_pop(cs); + int16_t delta = cs_pop(cs); + int16_t min = cs_pop(cs); + int16_t max = cs_pop(cs); + p_sub_get(ss, pn, idx, delta, 1, min, max); + tele_pattern_updated(); +} + +// Make ops +const tele_op_t op_P_SUB = MAKE_GET_OP(P.-, op_P_SUB_get, 2, false); +const tele_op_t op_PN_SUB = MAKE_GET_OP(PN.-, op_PN_SUB_get, 3, false); +const tele_op_t op_P_SUBW = MAKE_GET_OP(P.-W, op_P_SUBW_get, 4, false); +const tele_op_t op_PN_SUBW = MAKE_GET_OP(PN.-W, op_PN_SUBW_get, 5, false); diff --git a/src/ops/patterns.h b/src/ops/patterns.h index bbebf99f..0ab67fb3 100644 --- a/src/ops/patterns.h +++ b/src/ops/patterns.h @@ -36,4 +36,15 @@ extern const tele_op_t op_PN_MIN; extern const tele_op_t op_P_MAX; extern const tele_op_t op_PN_MAX; +extern const tele_op_t op_P_RND; +extern const tele_op_t op_PN_RND; +extern const tele_op_t op_P_ADD; +extern const tele_op_t op_PN_ADD; +extern const tele_op_t op_P_ADDW; +extern const tele_op_t op_PN_ADDW; +extern const tele_op_t op_P_SUB; +extern const tele_op_t op_PN_SUB; +extern const tele_op_t op_P_SUBW; +extern const tele_op_t op_PN_SUBW; + #endif From 481761ba197edda81734f32ac30d0355d5a228b5 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sat, 16 Jun 2018 18:10:02 -0700 Subject: [PATCH 072/117] update libavr32 (i2c address changes) --- libavr32 | 2 +- src/ops/er301.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libavr32 b/libavr32 index 535cd965..b49b2bfd 160000 --- a/libavr32 +++ b/libavr32 @@ -1 +1 @@ -Subproject commit 535cd965cc51de762493dc6f374d9aab0bf7ead2 +Subproject commit b49b2bfda708ea1e05d5db8f3444dd01831b3850 diff --git a/src/ops/er301.c b/src/ops/er301.c index 3863d4cc..4e898666 100644 --- a/src/ops/er301.c +++ b/src/ops/er301.c @@ -57,7 +57,7 @@ void ERSend(uint8_t command, uint16_t output, int16_t value, bool set) { // convert the output to the device and the port uint8_t port = output % 100; uint8_t device = output / 100; - uint8_t address = ER301 + device; + uint8_t address = ER301_1 + device; // put the package in the i2c mail SendIt(address, command, port, value, set); } From 507bc954a4a2a28f33e1296c0fbb573e609c2872 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 17 Jun 2018 15:51:13 -0700 Subject: [PATCH 073/117] more grid ops --- src/match_token.rl | 8 +++ src/ops/grid_ops.c | 174 +++++++++++++++++++++++++++++++++++++++++++++ src/ops/grid_ops.h | 8 +++ src/ops/op.c | 3 +- src/ops/op_enum.h | 8 +++ 5 files changed, 200 insertions(+), 1 deletion(-) diff --git a/src/match_token.rl b/src/match_token.rl index 9ef579ff..9bdc8740 100644 --- a/src/match_token.rl +++ b/src/match_token.rl @@ -530,6 +530,14 @@ "G.BTN.SW" => { MATCH_OP(E_OP_G_BTN_SW); }; "G.GBTN.V" => { MATCH_OP(E_OP_G_GBTN_V); }; "G.GBTN.L" => { MATCH_OP(E_OP_G_GBTN_L); }; + "G.GBTN.C" => { MATCH_OP(E_OP_G_GBTN_C); }; + "G.GBTN.I" => { MATCH_OP(E_OP_G_GBTN_I); }; + "G.GBTN.W" => { MATCH_OP(E_OP_G_GBTN_W); }; + "G.GBTN.H" => { MATCH_OP(E_OP_G_GBTN_H); }; + "G.GBTN.X1" => { MATCH_OP(E_OP_G_GBTN_X1); }; + "G.GBTN.X2" => { MATCH_OP(E_OP_G_GBTN_X2); }; + "G.GBTN.Y1" => { MATCH_OP(E_OP_G_GBTN_Y1); }; + "G.GBTN.Y2" => { MATCH_OP(E_OP_G_GBTN_Y2); }; "G.FDR" => { MATCH_OP(E_OP_G_FDR); }; "G.FDX" => { MATCH_OP(E_OP_G_FDX); }; diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 742bfc94..2267084e 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -103,6 +103,14 @@ static void op_G_BTN_SW_get (const void *data, scene_state_t *ss, exec_state_t * static void op_G_BTN_PR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GBTN_V_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_GBTN_L_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GBTN_C_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GBTN_I_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GBTN_W_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GBTN_H_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GBTN_X1_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GBTN_X2_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GBTN_Y1_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); +static void op_G_GBTN_Y2_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDR_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_G_FDX_get (const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); @@ -177,6 +185,14 @@ const tele_op_t op_G_BTN_SW = MAKE_GET_OP(G.BTN.SW, op_G_BTN_SW_get, 1, false); const tele_op_t op_G_BTN_PR = MAKE_GET_OP(G.BTN.PR, op_G_BTN_PR_get, 2, false); const tele_op_t op_G_GBTN_V = MAKE_GET_OP(G.GBTN.V, op_G_GBTN_V_get, 2, false); const tele_op_t op_G_GBTN_L = MAKE_GET_OP(G.GBTN.L, op_G_GBTN_L_get, 3, false); +const tele_op_t op_G_GBTN_C = MAKE_GET_OP(G.GBTN.C, op_G_GBTN_C_get, 1, true); +const tele_op_t op_G_GBTN_I = MAKE_GET_OP(G.GBTN.I, op_G_GBTN_I_get, 2, true); +const tele_op_t op_G_GBTN_W = MAKE_GET_OP(G.GBTN.W, op_G_GBTN_W_get, 1, true); +const tele_op_t op_G_GBTN_H = MAKE_GET_OP(G.GBTN.H, op_G_GBTN_H_get, 1, true); +const tele_op_t op_G_GBTN_X1 = MAKE_GET_OP(G.GBTN.X1, op_G_GBTN_X1_get, 1, true); +const tele_op_t op_G_GBTN_X2 = MAKE_GET_OP(G.GBTN.X2, op_G_GBTN_X2_get, 1, true); +const tele_op_t op_G_GBTN_Y1 = MAKE_GET_OP(G.GBTN.Y1, op_G_GBTN_Y1_get, 1, true); +const tele_op_t op_G_GBTN_Y2 = MAKE_GET_OP(G.GBTN.Y2, op_G_GBTN_Y2_get, 1, true); const tele_op_t op_G_FDR = MAKE_GET_OP(G.FDR, op_G_FDR_get, 8, false); const tele_op_t op_G_FDX = MAKE_GET_OP(G.FDX, op_G_FDX_get, 10, false); @@ -772,6 +788,164 @@ static void op_G_GBTN_L_get(const void *NOTUSED(data), scene_state_t *ss, SG.scr_dirty = SG.grid_dirty = 1; } +static void op_G_GBTN_C_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) { + cs_push(cs, 0); + return; + } + + s16 count = 0; + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) + if (GBC.group == group && GB.state) count++; + cs_push(cs, count); +} + +static void op_G_GBTN_I_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + s16 index = cs_pop(cs); + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) { + cs_push(cs, -1); + return; + } + + s16 id = -1; + s16 count = -1; + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { + if (GBC.group == group && GB.state) count++; + if (count == index) { + id = i; + break; + } + } + + cs_push(cs, id); +} + +static void op_G_GBTN_W_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) { + cs_push(cs, 0); + return; + } + + s16 x1 = 32767, x2 = -32768; + u8 atleastone = 0; + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { + if (GBC.group == group && GB.state) { + if (GBC.x < x1) x1 = GBC.x; + if (GBC.x > x2) x2 = GBC.x; + atleastone = 1; + } + } + + cs_push(cs, atleastone ? x2 - x1 + 1 : 0); +} + +static void op_G_GBTN_H_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) { + cs_push(cs, 0); + return; + } + + s16 y1 = 32767, y2 = -32768; + u8 atleastone = 0; + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { + if (GBC.group == group && GB.state) { + if (GBC.y < y1) y1 = GBC.y; + if (GBC.y > y2) y2 = GBC.y; + atleastone = 1; + } + } + + cs_push(cs, atleastone ? y2 - y1 + 1 : 0); +} + +static void op_G_GBTN_X1_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) { + cs_push(cs, -1); + return; + } + + s16 x1 = 32767; + u8 atleastone = 0; + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { + if (GBC.group == group && GB.state) { + if (GBC.x < x1) x1 = GBC.x; + atleastone = 1; + } + } + + cs_push(cs, atleastone ? x1 : -1); +} + +static void op_G_GBTN_X2_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) { + cs_push(cs, -1); + return; + } + + s16 x2 = -32768; + u8 atleastone = 0; + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { + if (GBC.group == group && GB.state) { + if (GBC.x > x2) x2 = GBC.x; + atleastone = 1; + } + } + + cs_push(cs, atleastone ? x2 : -1); +} + +static void op_G_GBTN_Y1_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) { + cs_push(cs, -1); + return; + } + + s16 y1 = 32767; + u8 atleastone = 0; + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { + if (GBC.group == group && GB.state) { + if (GBC.y < y1) y1 = GBC.y; + atleastone = 1; + } + } + + cs_push(cs, atleastone ? y1 : -1); +} + +static void op_G_GBTN_Y2_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { + s16 group = cs_pop(cs); + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) { + cs_push(cs, -1); + return; + } + + s16 y2 = -32768; + u8 atleastone = 0; + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { + if (GBC.group == group && GB.state) { + if (GBC.y > y2) y2 = GBC.y; + atleastone = 1; + } + } + + cs_push(cs, atleastone ? y2 : -1); +} + static void op_G_FDR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); diff --git a/src/ops/grid_ops.h b/src/ops/grid_ops.h index a92d95f1..3e4637c6 100644 --- a/src/ops/grid_ops.h +++ b/src/ops/grid_ops.h @@ -39,6 +39,14 @@ extern const tele_op_t op_G_BTN_SW; extern const tele_op_t op_G_BTN_PR; extern const tele_op_t op_G_GBTN_V; extern const tele_op_t op_G_GBTN_L; +extern const tele_op_t op_G_GBTN_C; +extern const tele_op_t op_G_GBTN_I; +extern const tele_op_t op_G_GBTN_W; +extern const tele_op_t op_G_GBTN_H; +extern const tele_op_t op_G_GBTN_X1; +extern const tele_op_t op_G_GBTN_X2; +extern const tele_op_t op_G_GBTN_Y1; +extern const tele_op_t op_G_GBTN_Y2; extern const tele_op_t op_G_FDR; extern const tele_op_t op_G_FDX; diff --git a/src/ops/op.c b/src/ops/op.c index ecc50d6c..a6313c75 100644 --- a/src/ops/op.c +++ b/src/ops/op.c @@ -190,7 +190,8 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_G_FDR_L, &op_G_FDR_X, &op_G_FDR_Y, &op_G_FDRI, &op_G_FDRV, &op_G_FDRN, &op_G_FDRL, &op_G_FDRX, &op_G_FDRY, &op_G_FDR_PR, &op_G_GFDR_V, &op_G_GFDR_N, &op_G_GFDR_L, &op_G_GFDR_RN, &op_G_XYP, &op_G_XYP_X, - &op_G_XYP_Y, + &op_G_XYP_Y, &op_G_GBTN_C, &op_G_GBTN_I, &op_G_GBTN_W, &op_G_GBTN_H, + &op_G_GBTN_X1, &op_G_GBTN_X2, &op_G_GBTN_Y1, &op_G_GBTN_Y2, // matrixarchate &op_MA_SELECT, &op_MA_STEP, &op_MA_RESET, &op_MA_PGM, &op_MA_ON, &op_MA_PON, diff --git a/src/ops/op_enum.h b/src/ops/op_enum.h index 8ed89bb7..5c776fd6 100644 --- a/src/ops/op_enum.h +++ b/src/ops/op_enum.h @@ -483,6 +483,14 @@ typedef enum { E_OP_G_XYP, E_OP_G_XYP_X, E_OP_G_XYP_Y, + E_OP_G_GBTN_C, + E_OP_G_GBTN_I, + E_OP_G_GBTN_W, + E_OP_G_GBTN_H, + E_OP_G_GBTN_X1, + E_OP_G_GBTN_X2, + E_OP_G_GBTN_Y1, + E_OP_G_GBTN_Y2, E_OP_MA_SELECT, E_OP_MA_STEP, E_OP_MA_RESET, From 34dc4175689c498da83ccf61a612fb6b90b098b4 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 17 Jun 2018 18:06:38 -0700 Subject: [PATCH 074/117] fix rotation for grid 64 --- module/grid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/grid.c b/module/grid.c index f621dfde..8cc5841f 100644 --- a/module/grid.c +++ b/module/grid.c @@ -1376,8 +1376,8 @@ void grid_refresh(scene_state_t *ss) { if (SG.rotate) { if (size_x == 8) { u16 a, b; - for (u16 row = 0; row < 8; row++) - for (u16 col = 0; col < 8; col++) { + for (u16 row = 0; row < 4; row++) + for (u16 col = 0; col < 4; col++) { a = (row << 4) + col; b = ((7 - row) << 4) + 7 - col; temp = monomeLedBuffer[a]; From 10302e0bbf00c61c4227a2611a202838c7d4831a Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 17 Jun 2018 18:07:43 -0700 Subject: [PATCH 075/117] fix screensaver for grid --- module/main.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/module/main.c b/module/main.c index 5e3f47f1..94d28ec6 100644 --- a/module/main.c +++ b/module/main.c @@ -299,10 +299,11 @@ void grid_fader_timer_callback(void* o) { void handler_None(int32_t data) {} void handler_Front(int32_t data) { + ss_counter = 0; if (mode == M_SCREENSAVER) { set_last_mode(); - if (!grid_connected || data) return; + return; } if (data == 0) { if (grid_connected) { @@ -471,7 +472,7 @@ void handler_ScreenRefresh(int32_t data) { void handler_EventTimer(int32_t data) { ss_counter++; - if (ss_counter > SS_TIMEOUT && !grid_control_mode) set_mode(M_SCREENSAVER); + if (ss_counter > SS_TIMEOUT) set_mode(M_SCREENSAVER); tele_tick(&scene_state, RATE_CLOCK); } @@ -498,6 +499,7 @@ static void handler_FtdiDisconnect(s32 data) { static void handler_MonomeConnect(s32 data) { grid_connected = 1; + hold_key = 0; timers_set_monome(); if (grid_control_mode && mode == M_HELP) set_mode(M_LIVE); @@ -518,6 +520,12 @@ static void handler_MonomeRefresh(s32 data) { } static void handler_MonomeGridKey(s32 data) { + if (mode == M_SCREENSAVER && grid_control_mode) { + set_last_mode(); + ss_counter = 0; + return; + } + u8 x, y, z; monome_grid_key_parse_event_data(data, &x, &y, &z); grid_process_key(&scene_state, x, y, z, 0); @@ -607,7 +615,7 @@ void set_mode(tele_mode_t m) { mode = M_SCREENSAVER; break; } - flash_update_last_mode(mode); + if (mode != M_SCREENSAVER) flash_update_last_mode(mode); } // defined in globals.h From 7ab66f63a39747bff67bb1cc4419d4a31ff9cb4c Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 17 Jun 2018 18:38:08 -0700 Subject: [PATCH 076/117] fix tests and simulator --- simulator/Makefile | 2 +- tests/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/simulator/Makefile b/simulator/Makefile index 72bbcdaf..67cb679d 100644 --- a/simulator/Makefile +++ b/simulator/Makefile @@ -11,7 +11,7 @@ OBJ = tt.o ../src/teletype.o ../src/command.o ../src/helpers.o \ ../src/ops/patterns.o ../src/ops/queue.o ../src/ops/stack.o \ ../src/ops/telex.o ../src/ops/variables.o ../src/ops/whitewhale.o \ ../src/ops/init.o ../src/ops/grid_ops.o ../src/ops/er301.o \ - ../src/ops/fader.o ../src/ops/matrixarchate.o \ + ../src/ops/fader.o ../src/ops/matrixarchate.o ../src/ops/wslash.o \ ../libavr32/src/euclidean/euclidean.o ../libavr32/src/euclidean/data.o \ ../libavr32/src/util.o diff --git a/tests/Makefile b/tests/Makefile index 35b63275..7e763ec6 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -18,7 +18,7 @@ tests: main.o \ ../src/ops/patterns.o ../src/ops/queue.o ../src/ops/stack.o \ ../src/ops/telex.o ../src/ops/variables.o ../src/ops/whitewhale.o \ ../src/ops/turtle.o ../src/ops/init.o ../src/ops/grid_ops.o \ - ../src/ops/matrixarchate.o \ + ../src/ops/matrixarchate.o ../src/ops/wslash.o \ ../libavr32/src/euclidean/data.o ../libavr32/src/euclidean/euclidean.o \ ../libavr32/src/util.o $(CC) -o $@ $^ $(CFLAGS) From bcff289820b0dc4189f0c0696cb6baf6002037f2 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 18 Jun 2018 07:27:08 -0700 Subject: [PATCH 077/117] fix rotation for grid64 (again) --- module/grid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/grid.c b/module/grid.c index 8cc5841f..8f1e5a06 100644 --- a/module/grid.c +++ b/module/grid.c @@ -1377,7 +1377,7 @@ void grid_refresh(scene_state_t *ss) { if (size_x == 8) { u16 a, b; for (u16 row = 0; row < 4; row++) - for (u16 col = 0; col < 4; col++) { + for (u16 col = 0; col < 8; col++) { a = (row << 4) + col; b = ((7 - row) << 4) + 7 - col; temp = monomeLedBuffer[a]; From 6aec7c17e3279c476e10e3303645665f000c83ef Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 18 Jun 2018 20:43:02 -0700 Subject: [PATCH 078/117] fix weirdness with switching modes --- module/grid.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/module/grid.c b/module/grid.c index 8f1e5a06..0186c505 100644 --- a/module/grid.c +++ b/module/grid.c @@ -493,6 +493,7 @@ static void restore_last_mode(scene_state_t *ss) { tt_mode = G_TRACKER; set_mode(M_PATTERN); } + grid_clear_held_keys(); ss->grid.grid_dirty = 1; } @@ -715,6 +716,7 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ default: break; } + grid_clear_held_keys(); return 1; } From 24445b932dd2942436f8d54be3700e7afa18d591 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 18 Jun 2018 20:43:26 -0700 Subject: [PATCH 079/117] update builtin help --- module/help_mode.c | 206 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 184 insertions(+), 22 deletions(-) diff --git a/module/help_mode.c b/module/help_mode.c index 7a125ff6..65d49581 100644 --- a/module/help_mode.c +++ b/module/help_mode.c @@ -15,10 +15,10 @@ //////////////////////////////////////////////////////////////////////////////// // Help text /////////////////////////////////////////////////////////////////// -#define HELP_PAGES 10 +#define HELP_PAGES 11 -#define HELP1_LENGTH 47 -const char* help1[HELP1_LENGTH] = { "1/10 HELP", +#define HELP1_LENGTH 59 +const char* help1[HELP1_LENGTH] = { "1/11 HELP", "[ ] NAVIGATE HELP PAGES", "UP/DOWN TO SCROLL", " ", @@ -40,14 +40,26 @@ const char* help1[HELP1_LENGTH] = { "1/10 HELP", "ENTER|EXECUTE", "UP|PREVIOUS", "SH-BSP|CLEAR", + "CTRL-L/R|JUMP WORDS", "~|TOGGLE VARS", + "ALT-G|GRID VISUALIZER", + "ALT-ARROWS|MOVE IN GRID", + "ALT-SH-ARRS|SELECT AREA", + "ALT-SPACE|PRESS IN GRID", + "ALT-PRTSC|INSERT X Y W H", + "ALT-/|CHANGE GRID PAGE", + "ALT-\\|TOGGLE CONTROL VIEW", " ", "// EDIT", "[ ]|PREV, NEXT SCRIPT", "ENTER|ADD/OVERWRITE", + "CTRL-Z|UNDO", "SH-ENTER|INSERT", "SH-BSP|CLEAR", - "ALT-SLASH|DISABLE LINE", + "SH-UP/DOWN|SELECT LINES", + "ALT-SLASH|DISABLE LINE(S)", + "ALT-DELETE|DELETE LINE(S)", + "ALT-UP/DN|MOVE LINE(S)", " ", "// PATTERN", "ARROWS|NAVIGATE", @@ -67,7 +79,7 @@ const char* help1[HELP1_LENGTH] = { "1/10 HELP", "SHIFT-2|SHOW/HIDE TURTLE" }; #define HELP2_LENGTH 13 -const char* help2[HELP2_LENGTH] = { "2/10 VARIABLES", +const char* help2[HELP2_LENGTH] = { "2/11 VARIABLES", " ", "X, Y, Z|GENERAL PURPOSE", "T|USE FOR TIME", @@ -82,7 +94,7 @@ const char* help2[HELP2_LENGTH] = { "2/10 VARIABLES", "Q.AVG|AVERAGE OF ALL Q" }; #define HELP3_LENGTH 26 -const char* help3[HELP3_LENGTH] = { "3/10 PARAMETERS", +const char* help3[HELP3_LENGTH] = { "3/11 PARAMETERS", " ", "TR A-D|SET TR VALUE (0,1)", "TR.TIME A-D|TR PULSE TIME", @@ -110,7 +122,7 @@ const char* help3[HELP3_LENGTH] = { "3/10 PARAMETERS", "LAST N|GET SCRIPT LAST RUN" }; #define HELP4_LENGTH 11 -const char* help4[HELP4_LENGTH] = { "4/10 DATA AND TABLES", +const char* help4[HELP4_LENGTH] = { "4/11 DATA AND TABLES", " ", "ALL PARAMS HAVE 16B RANGE", "-32768 TO 32767", @@ -122,8 +134,8 @@ const char* help4[HELP4_LENGTH] = { "4/10 DATA AND TABLES", "BPM 2-MAX|MS PER BPM", "EXP X|EXPO LOOKUP" }; -#define HELP5_LENGTH 55 -const char* help5[HELP5_LENGTH] = { "5/10 OPERATORS", +#define HELP5_LENGTH 56 +const char* help5[HELP5_LENGTH] = { "5/11 OPERATORS", " ", "RAND A|RANDOM 0 - A", "RRAND A B|RANDOM A - B", @@ -151,6 +163,7 @@ const char* help5[HELP5_LENGTH] = { "5/10 OPERATORS", "LT A B|A LESS THAN B", "EZ A|A EQUALS 0", "NZ A|A NOT EQUAL TO 0", + "? A B C|TERNARY IF", " ", "RSH A B|BITSHIFT A RIGHT B", "LSH A B|BITSHIFT A LEFT B", @@ -180,7 +193,7 @@ const char* help5[HELP5_LENGTH] = { "5/10 OPERATORS", "TR.PULSE X|PULSE TR X" }; #define HELP6_LENGTH 31 -const char* help6[HELP6_LENGTH] = { "6/10 PRE :", +const char* help6[HELP6_LENGTH] = { "6/11 PRE :", " ", "EACH PRE NEEDS A : FOLLOWED", "BY A COMMAND TO OPERATE ON", @@ -212,8 +225,8 @@ const char* help6[HELP6_LENGTH] = { "6/10 PRE :", " ", "BREAK|STOP EXECUTION" }; -#define HELP7_LENGTH 26 -const char* help7[HELP7_LENGTH] = { "7/10 PATTERNS", +#define HELP7_LENGTH 37 +const char* help7[HELP7_LENGTH] = { "7/11 PATTERNS", " ", "// DIRECT ACCESS", "P A|GET VAL AT INDEX A", @@ -238,9 +251,156 @@ const char* help7[HELP7_LENGTH] = { "7/10 PATTERNS", "P.I A|GET/SET POSITION", "P.HERE A|GET/SET VAL AT P.I", "P.NEXT A|GET/SET NEXT POS", - "P.PREV A|GET/SET PREV POS" }; -#define HELP8_LENGTH 17 -const char* help8[HELP8_LENGTH] = { "8/10 TURTLE", + "P.PREV A|GET/SET PREV POS", + "P.RND A|GET RANDOM VALUE", + "P.MIN A|GET MIN VALUE", + "P.MAX A|GET MAX VALUE", + " ", + "// INCREMENT/DECREMENT", + "P.+ A B|INC VALUE A BY B", + "P.- A B|DEC VALUE A BY B", + "P.+W A B C D", + " |INC AND WRAP TO C..D", + "P.-W A B C D", + " |DEC AND WRAP TO C..D" }; +#define HELP8_LENGTH 135 +const char* help8[HELP8_LENGTH] = { "8/11 GRID", + " ", + "G.RST|RESET EVERYTHING", + "G.CLR|CLEAR ALL LEDS", + "G.DIM level|SET DIM LEVEL", + "G.ROTATE 1/0", + " |ROTATE GRID", + "G.KEY x y action", + " |EMULATE KEY PRESS", + " ", + "GROUPS", + "G.GRP id|CURRENT GROUP", + "G.GRP.EN id|ENABLE GROUP", + "G.GRP.RST id|RESET GROUP", + "G.GRP.SW id|SWITCH TO GROUP", + "G.GRP.SC id|ASSIGN SCRIPT", + "G.GRPI|GET LATEST GROUP", + " ", + "LEDS / RECTANGLES", + "-1 DIM", + "-2 BRIGHTEN", + "-3 CLEAR", + "G.LED x y l|DRAW DOT", + "G.LED.C x y|CLEAR DOT", + "G.REC x y w h fill border", + "G.RCT x1 y1 x2 y2 fill border", + " DRAW RECTANGLE", + " ", + "BUTTONS", + "G.BTN id x y w h ", + " latch level script", + "G.GBT grp id x y w h", + " latch level script", + "G.BTX id x y w h", + " lt lvl scr cols rows", + "G.GBX grp id x y w h lt", + " lt lvl scr cols rows", + " ", + "G.BTN.EN id", + " ENABLE BUTTON", + "G.BTN.X id|G.BTN.X id x", + " GET OR SET X COORDINATE", + "G.BTN.Y id|G.BTN.Y id y", + " GET OR SET Y COORDINATE", + "G.BTN.V id|G.BTN.V id val", + " GET OR SET VALUE", + "G.BTN.L id G.BTN.L id level", + " GET OR SET LEVEL", + "G.BTNI", + " ID OF LAST PRESSED", + "G.BTNX|G.BTNX x", + " GET/SET X OF LAST PR", + "G.BTNY|G.BTNY y", + " GET/SET Y OF LAST PR", + "G.BTNV|G.BTNV value", + " GET/SET VALUE OF LAST PR", + "G.BTNL G.BTNL level", + " GET/SET LEVEL OF LAST PRESSED", + "G.BTN.SW id", + " SWITCH BUTTON", + "G.BTN.PR id action", + " EMULATE BUTTON PRESS", + "G.GBTN.V group value", + " SET VALUE FOR ALL IN GROUP", + "G.GBTN.L grp odd_lvl even_lvl", + " SET LEVEL FOR ALL IN GROUP", + "G.GBTN.C group", + " GET COUNT OF ALL PRESSED", + "G.GBTN.I group index", + " GET IDS OF PRESSED BY INX", + "G.GBTN.W group", + " GET PRESSED WIDTH", + "G.GBTN.H group", + " GET PRESSED HEIGHT", + "G.GBTN.X1 group", + " GET LEFTMOST PRESSED X", + "G.GBTN.X2 group", + " GET RIGHTMOST PRESSED X", + "G.GBTN.Y1 group", + " GET HIGHEST PRESSED", + "G.GBTN.Y2 group", + " GET LOWEST PRESSED", + " ", + "FADERS", + "0 COARSE HORIZ BAR", + "1 COARSE VERT BAR", + "2 COARSE HORIZ DOT", + "3 COARSE VERT DOT", + "4 FINE HORIZ BAR", + "5 FINE VERT BAR", + "6 FINE HORIZ DOT", + "7 FINE VERT DOT", + "G.FDR id x y w h", + " type level script", + "G.GFD group id x y w h", + " type level script", + "G.FDX id x y w h", + " type lvl scr cols rows", + "G.GFX group id x y w h", + " type lvl scr cols rows", + " ", + "G.FDR.EN id|G.FDR.EN id 1/0", + " ENABLE FADER", + "G.FDR.X id|G.FDR.X id x", + " GET OR SET X COORDINATE", + "G.FDR.Y id|G.FDR.Y id y", + " GET OR SET Y COORDINATE", + "G.FDR.V id|G.FDR.V id value", + " GET OR SET VALUE", + "G.FDR.N id|G.FDR.N id value", + " GET OR SET VALUE (UNITS)", + "G.FDR.L id|G.FDR.L id level", + " GET OR SET LEVEL", + "G.FDRI", + " ID OF LAST PRESSED", + "G.FDRX|G.FDRX x", + " GET/SET X OF LAST PRESSED", + "G.FDRY|G.FDRY y", + " GET/SET Y OF LAST PRESSED", + "G.FDRV|G.FDRV value", + " GET/SET VALUE OF LAST PR", + "G.FDRN|G.FDRN value", + " AS ABOVE IN LED UNITS", + "G.FDRL G.FDRL level", + " GET/SET LEVEL OF LAST PR", + "G.FDR.PR id value", + " EMULATE FADER PRESS", + "G.GFDR.V group value", + " SET VALUE FOR ALL IN GROUP", + "G.GFDR.N group value", + " AS ABOVE IN LED UNITS", + "G.GFDR.L grp odd_lvl even_lvl", + " SET LEVEL FOR ALL IN GROUP", + "G.GFDR.RN group min max", + " SET FADER RANGE FOR .V" }; +#define HELP9_LENGTH 17 +const char* help9[HELP9_LENGTH] = { "9/11 TURTLE", " ", "// CRAWLS TRACKER DATA", "@|GET/SET DATA", @@ -258,8 +418,8 @@ const char* help8[HELP8_LENGTH] = { "8/10 TURTLE", "@SCRIPT N|GET/SET EDGE SCRIPT", "@SHOW 1/0|DISPLAY < ON TRACKER" }; -#define HELP9_LENGTH 36 -const char* help9[HELP9_LENGTH] = { "9/10 TELEX INPUT", +#define HELP10_LENGTH 36 +const char* help10[HELP10_LENGTH] = { "10/11 TELEX INPUT", " ", "TI.PARAM X|(TI.PRM)", " GET KNOB VALUE", @@ -296,9 +456,9 @@ const char* help9[HELP9_LENGTH] = { "9/10 TELEX INPUT", "TI.RESET D", " RESET CALIB FOR DEVICE D" }; -#define HELP10_LENGTH 164 -const char* help10[HELP10_LENGTH] = { - "10/10 TELEX OUTPUT", +#define HELP11_LENGTH 164 +const char* help11[HELP11_LENGTH] = { + "11/11 TELEX OUTPUT", " ", "TO.TR X Y", " SET TR VALUE (0/1)", @@ -468,10 +628,12 @@ const char* help10[HELP10_LENGTH] = { // Help mode /////////////////////////////////////////////////////////////////// const char** help_pages[HELP_PAGES] = { help1, help2, help3, help4, help5, - help6, help7, help8, help9, help10 }; + help6, help7, help8, help9, help10, + help11 }; const uint8_t help_length[HELP_PAGES] = { HELP1_LENGTH, HELP2_LENGTH, HELP3_LENGTH, HELP4_LENGTH, HELP5_LENGTH, - HELP6_LENGTH, HELP7_LENGTH, HELP8_LENGTH, HELP9_LENGTH, HELP10_LENGTH + HELP6_LENGTH, HELP7_LENGTH, HELP8_LENGTH, HELP9_LENGTH, HELP10_LENGTH, + HELP11_LENGTH }; static uint8_t page_no; From ca8a618af0708a237bc0efed5ee69b6670a31de6 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 19 Jun 2018 20:07:46 -0700 Subject: [PATCH 080/117] don't save help screen --- module/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/main.c b/module/main.c index 94d28ec6..6f052ec5 100644 --- a/module/main.c +++ b/module/main.c @@ -615,7 +615,7 @@ void set_mode(tele_mode_t m) { mode = M_SCREENSAVER; break; } - if (mode != M_SCREENSAVER) flash_update_last_mode(mode); + if (mode != M_SCREENSAVER && mode != M_HELP) flash_update_last_mode(mode); } // defined in globals.h From 3395e3848701467a1bddafaeec7047df793c4131 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 19 Jun 2018 20:09:27 -0700 Subject: [PATCH 081/117] fix random ops --- src/ops/maths.c | 51 +++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/src/ops/maths.c b/src/ops/maths.c index 13c0d734..7383a1b8 100644 --- a/src/ops/maths.c +++ b/src/ops/maths.c @@ -230,18 +230,16 @@ static void op_MOD_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), static void op_RAND_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); - if (a == -1) - cs_push(cs, 0); + if (a < 0) + cs_push(cs, -(rand() % (1 - a))); + else if (a == 32767) + cs_push(cs, rand()); else - cs_push(cs, a == 32767 ? rand() : rand() % (a + 1)); + cs_push(cs, rand() % (a + 1)); } -static void op_RRAND_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a, b, min, max; - int64_t range; - a = cs_pop(cs); - b = cs_pop(cs); +static int16_t push_random(int16_t a, int16_t b) { + int16_t min, max; if (a < b) { min = a; max = b; @@ -250,31 +248,26 @@ static void op_RRAND_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), min = b; max = a; } - range = max - min + 1; - if (range == 0) - cs_push(cs, a); - else { - int64_t rrand = ((int32_t)rand() << 16) + rand(); - rrand = rrand % range + min; - cs_push(cs, rrand); - } + int64_t range = max - min + 1; + if (range == 0 || min == max) return min; + + int64_t rrand = ((int64_t)rand() << 15) + rand(); + rrand = rrand % range + min; + return rrand; +} + +static void op_RRAND_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { + int16_t a, b; + a = cs_pop(cs); + b = cs_pop(cs); + cs_push(cs, push_random(a, b)); } static void op_R_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t min = ss->variables.r_min; - int16_t max = ss->variables.r_max; - if (max < min) { - int16_t temp = min; - min = max; - max = temp; - } - int16_t range = max - min + 1; - if (range == 0) - cs_push(cs, min); - else - cs_push(cs, rand() % range + min); + cs_push(cs, push_random(ss->variables.r_min, ss->variables.r_max)); } static void op_R_MIN_get(const void *NOTUSED(data), scene_state_t *ss, From e0270545286551c0ef5df07b634607a6549bb51d Mon Sep 17 00:00:00 2001 From: Duncan Foster Date: Thu, 21 Jun 2018 20:53:10 +0100 Subject: [PATCH 082/117] Fixes for doc build. Add latex safe to handle chars in BIT prototypes and add mapping for ops. --- utils/cheatsheet.py | 2 +- utils/common/__init__.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/utils/cheatsheet.py b/utils/cheatsheet.py index abd3cdd4..60536ce0 100755 --- a/utils/cheatsheet.py +++ b/utils/cheatsheet.py @@ -93,7 +93,7 @@ def cheatsheet_tex(): validate_toml(ops) ops_array = pool.map(inject_latex, ops.values()) for op in ops_array: - prototype = op["prototype"] + prototype = latex_safe(op["prototype"]) if "prototype_set" in op: prototype += " / " + op["prototype_set"] output += "\\begin{op}" diff --git a/utils/common/__init__.py b/utils/common/__init__.py index b7415447..582e68c9 100644 --- a/utils/common/__init__.py +++ b/utils/common/__init__.py @@ -65,6 +65,10 @@ def _convert_struct_name_to_op_name(name): "SYM_RIGHT_ANGLED_x2": ">>", "SYM_AMPERSAND_x2": "&&", "SYM_PIPE_x2": "||", + "BIT_OR": "|", + "BIT_AND": "&", + "BIT_NOT": "~", + "BIT_XOR": "^", "M_SYM_EXCLAMATION": "M!", "TURTLE": "@", "TURTLE_X": "@X", From 6390c049d7fc2d027c5f9dd95c0c433e1d45c56c Mon Sep 17 00:00:00 2001 From: Sam Doshi Date: Sat, 23 Jun 2018 13:43:36 +0100 Subject: [PATCH 083/117] fixes for Pandoc >= 2 --- utils/docs.py | 7 ++++++- utils/templates/latex_preamble.jinja2.md | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/utils/docs.py b/utils/docs.py index 98544747..f7480a74 100755 --- a/utils/docs.py +++ b/utils/docs.py @@ -66,6 +66,7 @@ def deep_merge_dict(source, destination): def common_md(): + print(f"Pandoc version: {pypandoc.get_pandoc_version()}") print(f"Using docs directory: {DOCS_DIR}") print(f"Using ops docs directory: {OP_DOCS_DIR}") print() @@ -170,6 +171,10 @@ def main(): latex = latex_preamble \ .render(title=_VERSION_STR_, fonts_dir=FONTS_DIR) + "\n\n" latex += output + pandoc_version = int(pypandoc.get_pandoc_version()[0]) + engine = ("--pdf-engine=xelatex" + if pandoc_version >= 2 + else "--latex-engine=xelatex") pypandoc.convert_text( latex, format=input_format, @@ -179,7 +184,7 @@ def main(): "--column=80", "--toc", "--toc-depth=2", - "--latex-engine=xelatex", + engine, "--variable=papersize:A4"]) diff --git a/utils/templates/latex_preamble.jinja2.md b/utils/templates/latex_preamble.jinja2.md index 6b71b0c6..9c285203 100644 --- a/utils/templates/latex_preamble.jinja2.md +++ b/utils/templates/latex_preamble.jinja2.md @@ -21,6 +21,7 @@ header-includes: - \usepackage{titlesec} - \titleformat{\chapter}{\normalfont\LARGE\bfseries}{\thechapter.}{1em}{} - \titlespacing*{\chapter}{0pt}{3.5ex plus 1ex minus .2ex}{2.3ex plus .2ex} +- \usepackage{etoolbox} - \AtBeginEnvironment{longtable}{\small}{}{} - \renewcommand\arraystretch{1.3} --- From 0cd3021fe9c21794980d23abf5efe57b03a052c0 Mon Sep 17 00:00:00 2001 From: Sam Doshi Date: Sat, 23 Jun 2018 14:00:17 +0100 Subject: [PATCH 084/117] python tidying (PEP8, etc) --- utils/cheatsheet.py | 12 ++++++------ utils/docs.py | 17 +++++++++-------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/utils/cheatsheet.py b/utils/cheatsheet.py index 60536ce0..a428abc6 100755 --- a/utils/cheatsheet.py +++ b/utils/cheatsheet.py @@ -19,9 +19,9 @@ DOCS_DIR = ROOT_DIR / "docs" OP_DOCS_DIR = DOCS_DIR / "ops" FONTS_DIR = ROOT_DIR / "utils" / "fonts" -_VERSION_ = get_tt_version() -_VERSION_STR_ = "Teletype " + \ - _VERSION_["tag"] + " " + _VERSION_["hash"] + " Cheatsheet" +TT_VERSION = get_tt_version() +VERSION_STR = " ".join(["Teletype", TT_VERSION["tag"], TT_VERSION["hash"], + "Documentation"]) # We want to run inject_latex in parallel as it's quite slow, and we must run @@ -82,11 +82,11 @@ def cheatsheet_tex(): print(f"Using ops docs directory: {OP_DOCS_DIR}") print() - output = _VERSION_STR_ + "\n\n" + output = VERSION_STR + "\n\n" for (section, title, new_page) in OPS_SECTIONS: toml_file = Path(OP_DOCS_DIR, section + ".toml") if toml_file.exists() and toml_file.is_file(): - output += f"\group{{{ title }}}\n\n" + output += f"\\group{{{ title }}}\n\n" print(f"Reading {toml_file}") # n.b. Python 3.6 dicts maintain insertion order ops = toml.loads(toml_file.read_text()) @@ -105,7 +105,7 @@ def cheatsheet_tex(): output += "\\end{op}" output += "\n\n" if new_page: - output += "\pagebreak\n\n" + output += "\\pagebreak\n\n" return output diff --git a/utils/docs.py b/utils/docs.py index f7480a74..ba01432e 100755 --- a/utils/docs.py +++ b/utils/docs.py @@ -6,7 +6,6 @@ import jinja2 import pypandoc import pytoml as toml -import subprocess from common import list_ops, list_mods, validate_toml, get_tt_version @@ -19,8 +18,9 @@ DOCS_DIR = ROOT_DIR / "docs" OP_DOCS_DIR = DOCS_DIR / "ops" FONTS_DIR = ROOT_DIR / "utils" / "fonts" -_VERSION_ = get_tt_version() -_VERSION_STR_ = "Teletype " + _VERSION_["tag"] + " " + _VERSION_["hash"] + " Documentation" +TT_VERSION = get_tt_version() +VERSION_STR = " ".join(["Teletype", TT_VERSION["tag"], TT_VERSION["hash"], + "Documentation"]) env = jinja2.Environment( autoescape=False, @@ -75,8 +75,8 @@ def common_md(): op_extended_template = env.get_template("op_extended.jinja2.md") output = "" - output += Path(DOCS_DIR / "intro.md").read_text() \ - .replace("VERSION", _VERSION_["tag"][1:]) + "\n\n" + output += Path(DOCS_DIR / "intro.md") \ + .read_text().replace("VERSION", TT_VERSION["tag"][1:]) + "\n\n" output += Path(DOCS_DIR / "whats_new.md").read_text() + "\n\n" output += Path(DOCS_DIR / "quickstart.md").read_text() + "\n\n" output += Path(DOCS_DIR / "keys.md").read_text() + "\n\n" @@ -154,7 +154,7 @@ def main(): if ext == ".md": p.write_text(output) elif ext == ".html": - output = "# " + _VERSION_STR_ + "\n\n" + output + output = "# " + VERSION_STR + "\n\n" + output pypandoc.convert_text( output, format=input_format, @@ -165,11 +165,12 @@ def main(): "--toc", "--toc-depth=2", "--css=" + str(TEMPLATE_DIR / "docs.css"), - "--template=" + str(TEMPLATE_DIR / "template.html5")]) + "--template=" + str(TEMPLATE_DIR / + "template.html5")]) elif ext == ".pdf" or ext == ".tex": latex_preamble = env.get_template("latex_preamble.jinja2.md") latex = latex_preamble \ - .render(title=_VERSION_STR_, fonts_dir=FONTS_DIR) + "\n\n" + .render(title=VERSION_STR, fonts_dir=FONTS_DIR) + "\n\n" latex += output pandoc_version = int(pypandoc.get_pandoc_version()[0]) engine = ("--pdf-engine=xelatex" From b623cec2ae0427d3ba2a53b977272ba71376eff7 Mon Sep 17 00:00:00 2001 From: Sam Doshi Date: Sat, 23 Jun 2018 14:02:39 +0100 Subject: [PATCH 085/117] fix ~ in cheatsheet --- utils/cheatsheet.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/cheatsheet.py b/utils/cheatsheet.py index a428abc6..3ed82c89 100755 --- a/utils/cheatsheet.py +++ b/utils/cheatsheet.py @@ -71,9 +71,11 @@ def inject_latex(value): def latex_safe(s): # backslash must be first, otherwise it will duplicate itself - unsafe = ["\\", "&", "%", "$", "#", "_", "{", "}", "~", "^"] + unsafe = ["\\", "&", "%", "$", "#", "_", "{", "}", "^"] for u in unsafe: s = s.replace(u, "\\" + u) + # ~ is special + s = s.replace("~", "\\~{}") return s From 91a620372f25b75ffd34a44fecae4a6fe68fbef0 Mon Sep 17 00:00:00 2001 From: Sam Doshi Date: Sat, 23 Jun 2018 14:05:22 +0100 Subject: [PATCH 086/117] add er301 and fader sections to cheatsheet --- utils/cheatsheet.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/utils/cheatsheet.py b/utils/cheatsheet.py index 3ed82c89..0d68fd41 100755 --- a/utils/cheatsheet.py +++ b/utils/cheatsheet.py @@ -45,7 +45,8 @@ def inject_latex(value): lstrip_blocks=True ) -# determines the order in which sections are displayed +# determines the order in which sections are displayed, +# final column indicates that a new page is inserted _after_ that section OPS_SECTIONS = [ ("variables", "Variables", False), ("hardware", "Hardware", False), @@ -61,9 +62,11 @@ def inject_latex(value): ("whitewhale", "Whitewhale", False), ("meadowphysics", "Meadowphysics", False), ("earthsea", "Earthsea", False), - ("orca", "Orca", False), - ("justfriends", "Just Friends", True), - ("wslash", "W/", True), + ("orca", "Orca", True), + ("justfriends", "Just Friends", False), + ("wslash", "W/", False), + ("er301", "ER-301", False), + ("fader", "Fader", True), ("telex_i", "TELEXi", False), ("telex_o", "TELEXo", False) ] From 37fb2df9a7be314d2692fd89b91f1f26b99819fe Mon Sep 17 00:00:00 2001 From: Sam Doshi Date: Sat, 23 Jun 2018 14:38:45 +0100 Subject: [PATCH 087/117] add docs for $ (as alias to SCRIPT) --- docs/ops/controlflow.toml | 1 + utils/common/__init__.py | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/ops/controlflow.toml b/docs/ops/controlflow.toml index 89afca56..ee63268f 100644 --- a/docs/ops/controlflow.toml +++ b/docs/ops/controlflow.toml @@ -159,6 +159,7 @@ short = "potentially execute command with probability `x` (0-100)" [SCRIPT] prototype = "SCRIPT" prototype_set = "SCRIPT x" +aliases = ["$"] short = "get current script number, or execute script `x` (1-8), recursion allowed" description = """ Execute script `x` (1-8), recursion allowed. diff --git a/utils/common/__init__.py b/utils/common/__init__.py index 582e68c9..40e7454e 100644 --- a/utils/common/__init__.py +++ b/utils/common/__init__.py @@ -54,6 +54,7 @@ def _convert_struct_name_to_op_name(name): "SYM_STAR": "*", "SYM_FORWARD_SLASH": "/", "SYM_PERCENTAGE": "%", + "SYM_DOLLAR": "$", "SYM_EQUAL_x2": "==", "SYM_EXCLAMATION_EQUAL": "!=", "SYM_LEFT_ANGLED": "<", From 234d777d45a0551429bfab7f25b201020d903d2d Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Wed, 27 Jun 2018 20:40:51 -0700 Subject: [PATCH 088/117] fixes #153 and #154 --- module/main.c | 12 ++++++++---- simulator/tt.c | 4 ++-- src/ops/hardware.c | 3 ++- src/state.c | 1 + src/teletype_io.h | 2 +- tests/main.c | 2 +- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/module/main.c b/module/main.c index 6f052ec5..d101cae8 100644 --- a/module/main.c +++ b/module/main.c @@ -112,7 +112,7 @@ static aout_t aout[4]; static bool metro_timer_enabled; static uint8_t front_timer; static uint8_t mod_key = 0, hold_key, hold_key_count = 0; -static uint64_t last_in_tick = 0; +static uint64_t last_adc_tick = 0; // timers static softTimer_t clockTimer = {.next = NULL, .prev = NULL }; @@ -867,11 +867,12 @@ void tele_cv_off(uint8_t i, int16_t v) { aout[i].off = v; } -void tele_update_in(void) { - if (get_ticks() == last_in_tick) return; - last_in_tick = get_ticks(); +void tele_update_adc(u8 force) { + if (!force && get_ticks() == last_adc_tick) return; + last_adc_tick = get_ticks(); adc_convert(&adc); ss_set_in(&scene_state, adc[0] << 2); + ss_set_param(&scene_state, adc[1] << 2); } void tele_ii_tx(uint8_t addr, uint8_t* data, uint8_t l) { @@ -973,6 +974,9 @@ int main(void) { timer_add(&refreshTimer, 63, &refreshTimer_callback, NULL); timer_add(&gridFaderTimer, 25, &grid_fader_timer_callback, NULL); + // update IN and PARAM in case Init uses them + tele_update_adc(1); + // manually call tele_metro_updated to sync metro to scene_state metro_timer_enabled = false; tele_metro_updated(); diff --git a/simulator/tt.c b/simulator/tt.c index 9ff47fdd..6a0f2dfe 100644 --- a/simulator/tt.c +++ b/simulator/tt.c @@ -40,8 +40,8 @@ void tele_cv_slew(uint8_t i, int16_t v) { printf("\n"); } -void tele_update_in(void) { - printf("UPDATE IN"); +void tele_update_adc(uint8_t force) { + printf("UPDATE ADC force:%s", force ? "true" : "false"); printf("\n"); } diff --git a/src/ops/hardware.c b/src/ops/hardware.c index ceecabc9..d9205d3f 100644 --- a/src/ops/hardware.c +++ b/src/ops/hardware.c @@ -215,7 +215,7 @@ static void op_CV_OFF_set(const void *NOTUSED(data), scene_state_t *ss, static void op_IN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - tele_update_in(); + tele_update_adc(0); cs_push(cs, ss_get_in(ss)); } @@ -247,6 +247,7 @@ static void op_IN_CAL_RESET_set(const void *NOTUSED(data), scene_state_t *ss, static void op_PARAM_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { + tele_update_adc(0); cs_push(cs, ss_get_param(ss)); } diff --git a/src/state.c b/src/state.c index 2d63d0ea..20f865e5 100644 --- a/src/state.c +++ b/src/state.c @@ -52,6 +52,7 @@ void ss_variables_init(scene_state_t *ss) { }; memcpy(&ss->variables, &default_variables, sizeof(default_variables)); + tele_update_adc(1); ss_update_param_scale(ss); ss_update_in_scale(ss); } diff --git a/src/teletype_io.h b/src/teletype_io.h index 526c4809..3574cc23 100644 --- a/src/teletype_io.h +++ b/src/teletype_io.h @@ -20,7 +20,7 @@ extern void tele_tr(uint8_t i, int16_t v); extern void tele_cv(uint8_t i, int16_t v, uint8_t s); extern void tele_cv_slew(uint8_t i, int16_t v); -extern void tele_update_in(void); +extern void tele_update_adc(uint8_t force); // inform target if there are delays extern void tele_has_delays(bool has_delays); diff --git a/tests/main.c b/tests/main.c index ebade6f6..7ed472ef 100644 --- a/tests/main.c +++ b/tests/main.c @@ -19,7 +19,7 @@ void tele_metro_reset() {} void tele_tr(uint8_t i, int16_t v) {} void tele_cv(uint8_t i, int16_t v, uint8_t s) {} void tele_cv_slew(uint8_t i, int16_t v) {} -void tele_update_in(void) {} +void tele_update_adc(uint8_t force) {} void tele_has_delays(bool i) {} void tele_has_stack(bool i) {} void tele_cv_off(uint8_t i, int16_t v) {} From 66351713052ca85ca973d0f7f0a28401afb82a99 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Wed, 27 Jun 2018 20:42:09 -0700 Subject: [PATCH 089/117] fix for screensaver --- module/config.mk | 1 - module/globals.h | 3 +- module/main.c | 74 +++++++++++++++++++++------------------ module/screensaver_mode.c | 18 ---------- module/screensaver_mode.h | 12 ------- 5 files changed, 40 insertions(+), 68 deletions(-) delete mode 100644 module/screensaver_mode.c delete mode 100644 module/screensaver_mode.h diff --git a/module/config.mk b/module/config.mk index 4a252f8d..ade5461a 100644 --- a/module/config.mk +++ b/module/config.mk @@ -73,7 +73,6 @@ CSRCS = \ ../module/preset_r_mode.c \ ../module/preset_w_mode.c \ ../module/usb_disk_mode.c \ - ../module/screensaver_mode.c \ ../src/command.c \ ../src/every.c \ ../src/helpers.c \ diff --git a/module/globals.h b/module/globals.h index 334faf91..5c69f472 100644 --- a/module/globals.h +++ b/module/globals.h @@ -29,8 +29,7 @@ typedef enum { M_PATTERN, M_PRESET_W, M_PRESET_R, - M_HELP, - M_SCREENSAVER + M_HELP } tele_mode_t; void set_mode(tele_mode_t mode); diff --git a/module/main.c b/module/main.c index d101cae8..906ea7bb 100644 --- a/module/main.c +++ b/module/main.c @@ -43,7 +43,6 @@ #include "pattern_mode.h" #include "preset_r_mode.h" #include "preset_w_mode.h" -#include "screensaver_mode.h" #include "teletype.h" #include "teletype_io.h" #include "usb_disk_mode.h" @@ -69,6 +68,7 @@ void tele_profile_delay(uint8_t d) { #define RATE_CLOCK 10 #define RATE_CV 6 +#define SS_TIMEOUT 90 /* minutes */ * 60 * 100 //////////////////////////////////////////////////////////////////////////////// @@ -173,6 +173,7 @@ void timers_unset_monome(void); // other static void render_init(void); +static void exit_screensaver(void); //////////////////////////////////////////////////////////////////////////////// @@ -299,12 +300,12 @@ void grid_fader_timer_callback(void* o) { void handler_None(int32_t data) {} void handler_Front(int32_t data) { - - ss_counter = 0; - if (mode == M_SCREENSAVER) { - set_last_mode(); + if (ss_counter >= SS_TIMEOUT) { + exit_screensaver(); return; } + ss_counter = 0; + if (data == 0) { if (grid_connected) { grid_control_mode = !grid_control_mode; @@ -338,9 +339,9 @@ void handler_PollADC(int32_t data) { ss_set_in(&scene_state, adc[0] << 2); - if (mode == M_SCREENSAVER && (adc[1] >> 8 != last_knob >> 8)) { - ss_counter = 0; - set_last_mode(); + if (ss_counter >= SS_TIMEOUT && (adc[1] >> 8 != last_knob >> 8)) { + exit_screensaver(); + return; } last_knob = adc[1]; @@ -449,7 +450,7 @@ void handler_ScreenRefresh(int32_t data) { profile_update(&prof_ScreenRefresh); #endif uint8_t screen_dirty = 0; - + switch (mode) { case M_PATTERN: screen_dirty = screen_refresh_pattern(); break; case M_PRESET_W: screen_dirty = screen_refresh_preset_w(); break; @@ -457,23 +458,33 @@ void handler_ScreenRefresh(int32_t data) { case M_HELP: screen_dirty = screen_refresh_help(); break; case M_LIVE: screen_dirty = screen_refresh_live(&scene_state); break; case M_EDIT: screen_dirty = screen_refresh_edit(); break; - case M_SCREENSAVER: screen_dirty = screen_refresh_screensaver(); break; } u8 grid = 0; for (size_t i = 0; i < 8; i++) - if (screen_dirty & (1 << i)) { grid = 1; region_draw(&line[i]); } - if (grid_connected && grid_control_mode && grid) - scene_state.grid.grid_dirty = 1; + if (screen_dirty & (1 << i)) { + grid = 1; + if (ss_counter < SS_TIMEOUT) region_draw(&line[i]); + } + if (grid_control_mode && grid) scene_state.grid.grid_dirty = 1; + #ifdef TELETYPE_PROFILE profile_update(&prof_ScreenRefresh); #endif } void handler_EventTimer(int32_t data) { - ss_counter++; - if (ss_counter > SS_TIMEOUT) set_mode(M_SCREENSAVER); tele_tick(&scene_state, RATE_CLOCK); + + if (ss_counter < SS_TIMEOUT) { + ss_counter++; + if (ss_counter == SS_TIMEOUT) { + u8 empty = 0; + for (int i = 0; i < 64; i++) + for (int j = 0; j < 64; j++) + screen_draw_region(i << 1, j, 2, 1, &empty); + } + } } void handler_AppCustom(int32_t data) { @@ -520,11 +531,11 @@ static void handler_MonomeRefresh(s32 data) { } static void handler_MonomeGridKey(s32 data) { - if (mode == M_SCREENSAVER && grid_control_mode) { - set_last_mode(); - ss_counter = 0; + if (grid_control_mode && ss_counter >= SS_TIMEOUT) { + exit_screensaver(); return; } + if (grid_control_mode) ss_counter = 0; u8 x, y, z; monome_grid_key_parse_event_data(data, &x, &y, &z); @@ -583,7 +594,6 @@ void check_events(void) { // defined in globals.h void set_mode(tele_mode_t m) { - if (m == mode && m == M_SCREENSAVER) return; last_mode = mode; switch (m) { case M_LIVE: @@ -610,22 +620,15 @@ void set_mode(tele_mode_t m) { set_help_mode(); mode = M_HELP; break; - case M_SCREENSAVER: - set_screensaver_mode(); - mode = M_SCREENSAVER; - break; } - if (mode != M_SCREENSAVER && mode != M_HELP) flash_update_last_mode(mode); + if (mode != M_HELP) flash_update_last_mode(mode); } // defined in globals.h void set_last_mode() { if (mode == last_mode) return; - if (mode == M_SCREENSAVER) - set_mode(last_mode); - else if (last_mode == M_LIVE || last_mode == M_EDIT || - last_mode == M_PATTERN) + if (last_mode == M_LIVE || last_mode == M_EDIT || last_mode == M_PATTERN) set_mode(last_mode); else set_mode(M_LIVE); @@ -643,13 +646,11 @@ void clear_delays_and_slews(scene_state_t *ss) { void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key, bool is_release) { // reset inactivity counter - ss_counter = 0; - if (mode == M_SCREENSAVER) { - set_last_mode(); -#if SS_DROP_KEYSTROKE + if (ss_counter >= SS_TIMEOUT) { + exit_screensaver(); return; -#endif } + ss_counter = 0; // release is a special case for live mode if (is_release) { @@ -675,8 +676,6 @@ void process_keypress(uint8_t key, uint8_t mod_key, bool is_held_key, process_preset_r_keys(key, mod_key, is_held_key); break; case M_HELP: process_help_keys(key, mod_key, is_held_key); break; - case M_SCREENSAVER: - break; // impossible } } @@ -787,6 +786,11 @@ void render_init(void) { region_alloc(&line[7]); } +void exit_screensaver(void) { + ss_counter = 0; + set_mode(mode); +} + //////////////////////////////////////////////////////////////////////////////// // teletype_io.h diff --git a/module/screensaver_mode.c b/module/screensaver_mode.c deleted file mode 100644 index d182ce91..00000000 --- a/module/screensaver_mode.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "screensaver_mode.h" -#include "globals.h" -#include "region.h" - -static bool blank; - -void set_screensaver_mode() { - for (int i = 0; i < 8; i++) region_fill(&line[i], 0); - blank = false; -} - -uint8_t screen_refresh_screensaver() { - if (!blank) { - blank = true; - return 0xFF; - } - return 0; -} diff --git a/module/screensaver_mode.h b/module/screensaver_mode.h deleted file mode 100644 index bef715cb..00000000 --- a/module/screensaver_mode.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef SCREENSAVER_H -#define SCREENSAVER_H -#include - -#define SS_TIMEOUT 90 /* minutes */ * 60 * 100 -//#define SS_TIMEOUT 1000 // 10 seconds -#define SS_DROP_KEYSTROKE 1 // drops the keystroke that caused wake-up - -uint8_t screen_refresh_screensaver(void); -void set_screensaver_mode(void); - -#endif From c975266cd63a97c7c7baac1e239a98a7c5a86f46 Mon Sep 17 00:00:00 2001 From: Rylee Lyman Date: Sat, 30 Jun 2018 12:05:52 -0400 Subject: [PATCH 090/117] quickstart.md --- docs/quickstart.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/quickstart.md b/docs/quickstart.md index a793caba..f6933666 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -168,6 +168,24 @@ To facilitate performance without the need for the keyboard, scenes can be recal The *INIT* script (represented as `I`) is executed when a preset is recalled. This is a good place to set initial values of variables if needed, like metro time `M` or time enable `TIME.ACT` for example. +## USB Backup + +Teletype's scenes can be saved and loaded from a USB flash drive. When a flash +drive is inserted, Teletype will recognize it and go into disk mode. First, +all 32 scenes will be written to text files on the drive with names of the form `tt##s.txt`. For example, scene 5 will be saved to `tt05s.txt`. The screen will display `WRITE.......` as this is done. + +Once complete, Teletype will attempt to read any files named `tt##.txt` and save them into +memory. For example, a file named `tt13.txt` would be saved as scene 13 on +Teletype. The screen will display `READ......` Once this process is complete, Teletype will return to LIVE mode and the drive can be safely removed. + +For best results, use an FAT-formatted USB flash drive. If Teletype does not +recognize a disk that is inserted within a few seconds, it may be best to try another. + +An +example of possible scenes to load, as well as the set of factory default scenes, can be +found at the [Teletype +Codex](https://github.com/monome-community/teletype-codex). + ## Commands ### Nomenclature From f15772efc1f57320a46a301ce562376a6ee40094 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 1 Jul 2018 14:25:14 -0700 Subject: [PATCH 091/117] update quickstart --- docs/quickstart.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/quickstart.md b/docs/quickstart.md index f6933666..cd1d0e42 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -174,8 +174,8 @@ Teletype's scenes can be saved and loaded from a USB flash drive. When a flash drive is inserted, Teletype will recognize it and go into disk mode. First, all 32 scenes will be written to text files on the drive with names of the form `tt##s.txt`. For example, scene 5 will be saved to `tt05s.txt`. The screen will display `WRITE.......` as this is done. -Once complete, Teletype will attempt to read any files named `tt##.txt` and save them into -memory. For example, a file named `tt13.txt` would be saved as scene 13 on +Once complete, Teletype will attempt to read any files named `tt##.txt` and load them into +memory. For example, a file named `tt13.txt` would be loaded as scene 13 on Teletype. The screen will display `READ......` Once this process is complete, Teletype will return to LIVE mode and the drive can be safely removed. For best results, use an FAT-formatted USB flash drive. If Teletype does not From 6bfcd405da72e2375dd5954ddae877c09e2b8a96 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 2 Jul 2018 11:07:45 -0700 Subject: [PATCH 092/117] strengthen grid refresh --- module/grid.c | 3 +++ module/main.c | 11 ++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/module/grid.c b/module/grid.c index 0186c505..fed1136f 100644 --- a/module/grid.c +++ b/module/grid.c @@ -1264,6 +1264,9 @@ void grid_refresh(scene_state_t *ss) { size_x = monome_size_x(); size_y = monome_size_y(); + if (size_x == 0) size_x = 16; + if (size_y == 0) size_y = 8; + grid_fill_area(0, 0, size_x, size_y, 0); u16 x, y; diff --git a/module/main.c b/module/main.c index 906ea7bb..85b565d8 100644 --- a/module/main.c +++ b/module/main.c @@ -271,7 +271,7 @@ static void monome_poll_timer_callback(void* obj) { // monome refresh callback static void monome_refresh_timer_callback(void* obj) { - if (scene_state.grid.grid_dirty) { + if (grid_connected && scene_state.grid.grid_dirty) { static event_t e; e.type = kEventMonomeRefresh; event_post(&e); @@ -504,14 +504,14 @@ static void handler_FtdiConnect(s32 data) { ftdi_setup(); } static void handler_FtdiDisconnect(s32 data) { - timers_unset_monome(); grid_connected = 0; + timers_unset_monome(); } static void handler_MonomeConnect(s32 data) { - grid_connected = 1; hold_key = 0; timers_set_monome(); + grid_connected = 1; if (grid_control_mode && mode == M_HELP) set_mode(M_LIVE); grid_set_control_mode(grid_control_mode, mode, &scene_state); @@ -828,10 +828,7 @@ void tele_metro_updated() { } void tele_metro_reset() { - if (metro_timer_enabled) { - timer_reset(&metroTimer); - if (grid_connected && grid_control_mode) scene_state.grid.grid_dirty = 1; - } + if (metro_timer_enabled) timer_reset(&metroTimer); } void tele_tr(uint8_t i, int16_t v) { From 0206a200b6c4acbc9d511aeaa925d13a6de48c67 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 2 Jul 2018 11:27:54 -0700 Subject: [PATCH 093/117] increase SCALE and G.FDR.V precision --- src/ops/grid_ops.c | 8 +++++--- src/ops/maths.c | 7 +++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 2267084e..c11d42c2 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -47,7 +47,7 @@ // clang-format off static void grid_common_init(grid_common_t *gc); -static s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value); +static s32 scale(s32 a, s32 b, s32 x, s32 y, s32 value); static void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fill, u8 border); static void grid_init_button(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, s16 w, s16 h, s16 latch, s16 level, s16 script); static void grid_init_fader(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, s16 w, s16 h, s16 type, s16 level, s16 script); @@ -1408,9 +1408,11 @@ void grid_common_init(grid_common_t *gc) { // helpers -s16 scale(s16 a, s16 b, s16 x, s16 y, s16 value) { +s32 scale(s32 a, s32 b, s32 x, s32 y, s32 value) { if (a == b) return x; - return (value - a) * (y - x) / (b - a) + x; + s32 result = (value - a) * (y - x) * 2 / (b - a); + result = (result / 2) + (result & 1); // rounding + return result + x; } void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fill, diff --git a/src/ops/maths.c b/src/ops/maths.c index 7383a1b8..444357ff 100644 --- a/src/ops/maths.c +++ b/src/ops/maths.c @@ -525,7 +525,7 @@ static void op_JI_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), static void op_SCALE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { - int16_t a, b, x, y, i; + int32_t a, b, x, y, i; a = cs_pop(cs); b = cs_pop(cs); x = cs_pop(cs); @@ -537,7 +537,10 @@ static void op_SCALE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), return; } - cs_push(cs, (i - a) * (y - x) / (b - a) + x); + int32_t result = (i - a) * (y - x) * 2 / (b - a); + result = result / 2 + (result & 1); // rounding + + cs_push(cs, result + x); } static void op_N_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), From 0d40a26c1923d8264e8ffca50377bae31db0e4fb Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 2 Jul 2018 12:08:34 -0700 Subject: [PATCH 094/117] fix w/ link --- docs/ops/wslash.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ops/wslash.md b/docs/ops/wslash.md index b89078b1..8819076c 100644 --- a/docs/ops/wslash.md +++ b/docs/ops/wslash.md @@ -1,4 +1,4 @@ W/ -More extensively covered in the [W/ Documentation](https://www.whimsicalraps.com/pages/withtt). +More extensively covered in the [W/ Documentation](https://www.whimsicalraps.com/pages/w-type). From 5799c16d277da2abd19a5d9ac4fbe5dbc1b96817 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 6 Jul 2018 14:18:46 -0700 Subject: [PATCH 095/117] change tracker shortcut for knob --- module/keyboard_helper.h | 9 +++++++++ module/pattern_mode.c | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/module/keyboard_helper.h b/module/keyboard_helper.h index 35c4d688..aaae4df9 100644 --- a/module/keyboard_helper.h +++ b/module/keyboard_helper.h @@ -49,6 +49,15 @@ static inline bool mod_only_shift_alt(uint8_t mod) { return (mod & either_sh) && (mod & either_alt); } +static inline bool mod_only_ctrl_alt(uint8_t mod) { + const uint8_t either_ctrl = + HID_MODIFIER_LEFT_CTRL | HID_MODIFIER_RIGHT_CTRL; + const uint8_t either_alt = HID_MODIFIER_LEFT_ALT | HID_MODIFIER_RIGHT_ALT; + // first check we only have shift and alt + if (mod & ~(either_ctrl | either_alt)) return false; + return (mod & either_ctrl) && (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); diff --git a/module/pattern_mode.c b/module/pattern_mode.c index b53bc7ed..78ceb21b 100644 --- a/module/pattern_mode.c +++ b/module/pattern_mode.c @@ -410,7 +410,7 @@ void process_pattern_keys(uint8_t k, uint8_t m, bool is_held_key) { } void process_pattern_knob(uint16_t knob, uint8_t m) { - if (mod_only_ctrl(m)) { + if (mod_only_ctrl_alt(m)) { ss_set_pattern_val(&scene_state, pattern, base + offset, knob >> 7); dirty = true; } From fdc77299ea9840ab8dab93b0dec25a05ea83dec1 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Sun, 8 Jul 2018 21:18:32 -0700 Subject: [PATCH 096/117] update documentation --- docs/intro.md | 3 +- docs/keys.md | 37 +++++++++++++++----- docs/ops/controlflow.toml | 3 +- docs/ops/maths.toml | 8 +++++ docs/ops/matrixarchate.md | 3 ++ docs/ops/matrixarchate.toml | 67 +++++++++++++++++++++++++++++++++++ docs/ops/patterns.toml | 41 ++++++++++++++++++++++ docs/ops/variables.toml | 5 ++- docs/quickstart.md | 2 ++ docs/whats_new.md | 70 +++++++++++++++++++++++++++++++++---- 10 files changed, 221 insertions(+), 18 deletions(-) create mode 100644 docs/ops/matrixarchate.md create mode 100644 docs/ops/matrixarchate.toml diff --git a/docs/intro.md b/docs/intro.md index 1a1b3686..3a61db84 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -3,8 +3,7 @@ Teletype is a dynamic, musical event triggering platform. * [Teletype Studies](https://monome.org/docs/modular/teletype/studies-1) - guided series of tutorials -* [PDF command reference chart](https://monome.org/docs/modular/teletype/TT_commands_2.1.pdf) -— [PDF key reference chart](https://monome.org/docs/modular/teletype/TT_keys_card_1.3.pdf) +* [PDF command reference chart](https://monome.org/docs/modular/teletype/TT_commands_2.3.pdf) — [PDF scene recall sheet](https://monome.org/docs/modular/teletype/TT_scene_RECALL_sheet.pdf) — [Default scenes](http://monome.org/docs/modular/teletype/scenes-1.0/) diff --git a/docs/keys.md b/docs/keys.md index eb7e18d3..6ad0e131 100644 --- a/docs/keys.md +++ b/docs/keys.md @@ -10,7 +10,7 @@ These bindings work everywhere. | `` | preset read mode, or return to last mode | | `alt-` | preset write mode | | `win-` | clear delays, stack and slews | -| `shift-alt-?` | help text, or return to last mode | +| `shift-alt-?` / `alt-h` | help text, or return to last mode | | `` to `` | run corresponding script | | `` | run metro script | | `` | run init script | @@ -33,6 +33,8 @@ In most cases, the clipboard is shared between _live_, _edit_ and the 2 _preset_ |--------------------------------|-----------------------------------------| | `` / `ctrl-b` | move cursor left | | `` / `ctrl-f` | move cursor right | +| `ctrl-` | move left by one word | +| `ctrl-` | move right by one word | | `` / `ctrl-a` | move to beginning of line | | `` / `ctrl-e` | move to end of line | | `` / `ctrl-h` | backwards delete one character | @@ -46,16 +48,27 @@ In most cases, the clipboard is shared between _live_, _edit_ and the 2 _preset_ ## Live mode -| Key | Action | -|------------------|---------------------| -| `` / `C-n` | history next | -| `` / `C-p` | history previous | -| `` | execute command | -| `~` | toggle variables | -| `[` / `]` | switch to edit mode | +| Key | Action | +|----------------------|--------------------------| +| `` / `C-n` | history next | +| `` / `C-p` | history previous | +| `` | execute command | +| `~` | toggle variables | +| `[` / `]` | switch to edit mode | +| `alt-g` | toggle grid visualizer | +| `alt-` | move grid cursor | +| `alt-shift-` | select grid area | +| `alt-` | emulate grid press | +| `alt-/` | switch grid pages | +| `alt-\` | toggle grid control view | +| `alt-` | insert grid x/y/w/h | + +In full grid visualizer mode pressing `alt` is not required. ## Edit mode +In _edit_ mode multiple lines can be selected and used with the clipboard. + | Key | Action | |--------------------|---------------------------| | `` / `C-n` | line down | @@ -65,6 +78,12 @@ In most cases, the clipboard is shared between _live_, _edit_ and the 2 _preset_ | `` | enter command | | `shift-` | insert command | | `alt-/` | toggle line comment | +| `shift-` | expand selection up | +| `shift-` | expand selection down | +| `alt-` | delete selection | +| `alt-` | move selection up | +| `alt-` | move selection down | +| `ctrl-z` | undo (3 levels) | ## Tracker mode @@ -100,6 +119,8 @@ The tracker mode clipboard is independent of text and code clipboard. | `` | toggle non-zero to zero, and zero to 1 | | `0` to `9` | numeric entry | | `shift-2` (`@`) | toggle turtle display marker (`<`) | +| `ctrl-alt` | insert knob value scaled to 0..31 | +| `ctrl-shift` | insert knob value scaled to 0..1023 | ## Preset read mode diff --git a/docs/ops/controlflow.toml b/docs/ops/controlflow.toml index ee63268f..c39ac63a 100644 --- a/docs/ops/controlflow.toml +++ b/docs/ops/controlflow.toml @@ -210,7 +210,8 @@ prototype = "INIT.DATA" short = "clears all data held in all variables" description = """ -Clears the following variables and resets them to default values: A, B, C, D, CV slew, Drunk min/max, M, O, Q, R, T, TR, CV input, and the Paramter knob +Clears the following variables and resets them to default values: A, B, C, D, CV slew, Drunk min/max, M, O, Q, R, T, TR. +Does not affect the CV input (IN) or the Parameter knob (PARAM) values. """ ["INIT.P"] diff --git a/docs/ops/maths.toml b/docs/ops/maths.toml index 0d222f49..22d9bbe9 100644 --- a/docs/ops/maths.toml +++ b/docs/ops/maths.toml @@ -26,16 +26,22 @@ short = "find the remainder after division of `x` by `y`" [RAND] prototype = "RAND x" +aliases = ["RND"] short = "generate a random number between `0` and `x` inclusive" [RRAND] prototype = "RRAND x y" +aliases = ["RRND"] short = "generate a random number between `x` and `y` inclusive" [TOSS] prototype = "TOSS" short = "randomly return `0` or `1`" +[RRAND] +prototype = "? x y z" +short = "if condition `x` is true return `y`, otherwise return `z`" + [MIN] prototype = "MIN x y" short = "return the minimum of `x` and `y`" @@ -50,6 +56,7 @@ short = "limit the value `x` to the range `y` to `z` inclusive" [WRAP] prototype = "WRAP x y z" +aliases = ["WRP"] short = "limit the value `x` to the range `y` to `z` inclusive, but with wrapping" [QT] @@ -163,6 +170,7 @@ short = "just intonation helper, precision ratio divider normalised to 1V" [SCALE] prototype = "SCALE a b x y i" +aliases = ["SCL"] short = "scale `i` from range `a` to `b` to range `x` to `y`, i.e. `i * (y - x) / (b - a)`" [ER] diff --git a/docs/ops/matrixarchate.md b/docs/ops/matrixarchate.md new file mode 100644 index 00000000..6f088c55 --- /dev/null +++ b/docs/ops/matrixarchate.md @@ -0,0 +1,3 @@ +## Matrixarchate + +The SSSR Labs SM010 Matrixarchate is a 16x8 IO Sequenceable Matrix Signal Router. \ No newline at end of file diff --git a/docs/ops/matrixarchate.toml b/docs/ops/matrixarchate.toml new file mode 100644 index 00000000..d014a70d --- /dev/null +++ b/docs/ops/matrixarchate.toml @@ -0,0 +1,67 @@ +["MA.SELECT"] +prototype = "MA.SELECT x" +short = "select the default matrixarchate module, default `1`" + +["MA.STEP"] +prototype = "MA.STEP" +short = "advance program sequencer" + +["MA.RESET"] +prototype = "MA.RESET" +short = "reset program sequencer" + +["MA.PGM"] +prototype = "MA.PGM pgm" +short = "select the current program (1-based)" + +["MA.ON"] +prototype = "MA.ON x y" +short = "connect row `x` and column `y` in the current program (rows/columns are 0-based)" + +["MA.PON"] +prototype = "MA.PON pgm x y" +short = "connect row `x` and column `y` in program `pgm`" + +["MA.OFF"] +prototype = "MA.OFF x y" +short = "disconnect row `x` and column `y` in the current program" + +["MA.POFF"] +prototype = "MA.POFF x y pgm" +short = "connect row `x` and column `y` in program `pgm`" + +["MA.SET"] +prototype = "MA.SET x y state" +short = "set the connection at row `x` and column `y` to `state` (1 - on, 0 - off)" + +["MA.PSET"] +prototype = "MA.PSET pgm x y state" +short = "set the connection at row `x` and column `y` in program `pgm` to `state` (1 - on, 0 - off)" + +["MA.COL"] +prototype = "MA.COL col" +prototype_set = "MA.COL col value" +short = "get or set column `col` (as a 16 bit unsigned value where each bit represents a connection)" + +["MA.PCOL"] +prototype = "MA.PCOL pgm col" +prototype_set = "MA.PCOL pgm col value" +short = "get or set column `col` in program `pgm`" + +["MA.ROW"] +prototype = "MA.ROW row" +prototype_set = "MA.ROW row value" +short = "get or set row `row`" + +["MA.PROW"] +prototype = "MA.PROW pgm row" +prototype_set = "MA.PROW pgm row value" +short = "get or set row `row` in program `pgm`" + +["MA.CLR"] +prototype = "MA.CLR" +short = "clear all connections" + +["MA.PCLR"] +prototype = "MA.PCLR pgm" +short = "clear all connections in program `pgm`" diff --git a/docs/ops/patterns.toml b/docs/ops/patterns.toml index 828b57c4..d2377037 100644 --- a/docs/ops/patterns.toml +++ b/docs/ops/patterns.toml @@ -204,5 +204,46 @@ prototype = "PN.MAX x" short = "find the first maximum value in the pattern between the START and END for pattern `x` and return its index" +["P.RND"] +prototype = "P.RND" +short = "return a value randomly selected between the start and the end position" + +["PN.RND"] +prototype = "PN.RND x" +short = "return a value randomly selected between the start and the end position of pattern `x`" + + +["P.+"] +prototype = "P.+ x y" +short = "increase the value of the working pattern at index `x` by `y`" + +["PN.+"] +prototype = "PN.+ x y z" +short = "increase the value of pattern `x` at index `y` by `z`" + +["P.-"] +prototype = "P.- x y" +short = "decrease the value of the working pattern at index `x` by `y`" + +["PN.-"] +prototype = "PN.- x y z" +short = "decrease the value of pattern `x` at index `y` by `z`" + +["P.+W"] +prototype = "P.+W x y a b" +short = "increase the value of the working pattern at index `x` by `y` and wrap it to `a`..`b` range" + +["PN.+W"] +prototype = "PN.+W x y z a b" +short = "increase the value of pattern `x` at index `y` by `z` and wrap it to `a`..`b` range" + +["P.-W"] +prototype = "P.-W x y a b" +short = "decrease the value of the working pattern at index `x` by `y` and wrap it to `a`..`b` range" + +["PN.-W"] +prototype = "PN.-W x y z a b" +short = "decrease the value of pattern `x` at index `y` by `z` and wrap it to `a`..`b` range" + diff --git a/docs/ops/variables.toml b/docs/ops/variables.toml index 7f809802..ff861c2d 100644 --- a/docs/ops/variables.toml +++ b/docs/ops/variables.toml @@ -59,7 +59,10 @@ prototype = "I" prototype_set = "I x" short = """ get / set the variable `I`, this variable is overwritten by `L`, but can be used -freely outside an `L` loop""" +freely outside an `L` loop. Each script gets its own `I` variable, so if you call +a script from another script's loop you can still use and modify `I` without +affecting the calling loop. In this scenario the script getting called will have +its `I` value initialized with the calling loop's current `I` value.""" [O] prototype = "O" diff --git a/docs/quickstart.md b/docs/quickstart.md index cd1d0e42..be9067c8 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -147,6 +147,8 @@ The edit position is indicated by the brightest number. Very dim numbers indicat Use the square bracket keys `[` and `]` to decrease/increase the values. Backspace sets the value to 0. Entering numbers will overwrite a new value. You can cut/copy/paste with ALT-X-C-V. +Check the *Keys* section for a complete list of tracker shortcuts. + ## Scenes diff --git a/docs/whats_new.md b/docs/whats_new.md index 85de05f5..e993e2ad 100644 --- a/docs/whats_new.md +++ b/docs/whats_new.md @@ -2,23 +2,81 @@ ## Version 2.3 -### Grid Integration +### Major new features + +#### Grid Integration TBA -### New Operators + +#### Improved script editing + +You can now select multiple lines when editing scripts by holding `shift`. You can move the current selection up and down with 'alt-` and `alt-`. You can copy/cut/paste a multiline selection as well. To delete selected lines without copying into the clipboard use `alt-`. + +Three level undo is also now available with `ctrl-z` shortcut. + +#### Support for the Orthogonal Devices ER-301 Sound Computer over i2c + +You now can connect up to three ER-301s via i2c and address up to 100 virtual CV channels and 100 virtual TR channels per ER-301. (The outputs range 1-100, 101-200, and 201-300 respectively.) To function, this requires a slight mod to current in-market ER-301s and a specialized i2c cable that reorders two of the pins. Find more information [on the Orthogonal Devices ER-301 Wiki Teletype Integration Page](http://wiki.orthogonaldevices.com/index.php/ER-301/Teletype_Integration). + +#### Support for the 16n Faderbank via i2c + +The 16n Faderbank is an open-source sixteen fader controller with support for USB MIDI, standard MIDI, and i2c communication with the Teletype. It operates just like an IN or PARAM (or the TXi for that matter) in that you read values from the device. You use the operator FADER (or the alias FB) and the number of the slider you wish to poll (1-16). Know that longer cables may require that you use a powered bus board even if you only have one device on your Teletype's i2c bus. (You will know that you have a problem if your Teletype randomly hangs on reads.) + +#### Support for the SSSR Labs SM010 Matrixarchate + +The SSSR Labs SM010 Matrixarchate is a 16x8 IO Sequenceable Matrix Signal Router. Teletype integration allows you to switch programs and control connections. For a complete list of available ops refer to the manual. Information on how to connect the module can be found [in the SM010 manual](https://www.sssrlabs.com/store/sm010/). + +### New operators + +`? x y z` is a ternary "if" operator, it will select between `y` and `z` based on the condition `x`. + +#### New pattern ops: `P.MIN` `PN.MIN` `P.MAX` `PN.MAX` returns the position for the first smallest/largest value in a pattern between the `START` and `END` points. + +####New Telex ops + `TO.CV.CALIB` allows you to lock-in an offset across power cycles to calibrate your TELEX CV output (`TO.CV.RESET` removes the calibration). + `TO.ENV` now accepts gate values (1/0) to trigger the attack and decay. -### Support for the Orthogonal Devices ER-301 Sound Computer over i2c +####New Kria ops -You now can connect up to three ER-301s via i2c and address up to 100 virtual CV channels and 100 virtual TR channels per ER-301. (The outputs range 1-100, 101-200, and 201-300 respectively.) To function, this requires a slight mod to current in-market ER-301s and a specialized i2c cable that reorders two of the pins. Find more information [on the Orthogonal Devices ER-301 Wiki Teletype Integration Page](http://wiki.orthogonaldevices.com/index.php/ER-301/Teletype_Integration). +`KR.CV x` get the current CV value for channel `x` +`KR.MUTE x` `KR.MUTE x y` get/set mute state for channel `x` +`KR.TMUTE x` toggle mute state for channel `x` +`KR.CLK x` advance the clock for channel `x` (channel must have teletype clocking enabled) -### Support for the 16n Faderbank via i2c -The 16n Faderbank is an open-source sixteen fader controller with support for USB MIDI, standard MIDI, and i2c communication with the Teletype. It operates just like an IN or PARAM (or the TXi for that matter) in that you read values from the device. You use the operator FADER (or the alias FB) and the number of the slider you wish to poll (1-16). Know that longer cables may require that you use a powered bus board even if you only have one device on your Teletype's i2c bus. (You will know that you have a problem if your Teletype randomly hangs on reads.) +### New aliases + +`$` for `SCRIPT` +`RND` / `RRND` `RAND` / `RRAND` +`WRP` for `WRAP` +`SCL` for `SCALE` + +### New keybindings + +Hold `shift` while making line selection in script editing to select multiple lines. +Use 'alt-` and `alt-` to move selected lines up and down. +Copy/cut/paste shortcuts work with multiline selection as well. To delete selected lines without copying into the clipboard use `alt-`. + +While editing a line you can now use `ctrl-` / `ctrl-` to move by words. + +`ctrl-z` provides three level undo in script editing. + +Additional `Alt-H` shortcut is available to view the Help screen. + +`Alt-G` in Live mode will turn on the Grid Visualizer, which has its own shortcuts. Refer to the **Keys** section for a complete list. + +### Bug fixes + +### New behavior + +Previously, when pasting the clipboard while in script editing the pasted line would replace the current line. It will now instead push the current line down. This might result in some lines being pushed beyond the script limits - if this happens, use `ctrl-z` to undo the change, delete some lines and then paste again. + +`I` would previously get initialized to 0 when executing a script. If you called a script from another script's loop this meant you had to use a variable to pass the loop's current `I` value to the called script. This is not needed anymore - when a script is called from another script its `I` value will be set to the current `I` value of the calling script. ## Version 2.2 From b516fd4bd5e5e3d2f6a6aeffa0c8995bc5990064 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 12 Jul 2018 19:44:43 -0700 Subject: [PATCH 097/117] update documentation for 3.0 --- docs/intro.md | 2 +- docs/whats_new.md | 43 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/docs/intro.md b/docs/intro.md index 3a61db84..03f7ad7b 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -3,7 +3,7 @@ Teletype is a dynamic, musical event triggering platform. * [Teletype Studies](https://monome.org/docs/modular/teletype/studies-1) - guided series of tutorials -* [PDF command reference chart](https://monome.org/docs/modular/teletype/TT_commands_2.3.pdf) +* [PDF command reference chart](https://monome.org/docs/modular/teletype/TT_commands_3.0.pdf) — [PDF scene recall sheet](https://monome.org/docs/modular/teletype/TT_scene_RECALL_sheet.pdf) — [Default scenes](http://monome.org/docs/modular/teletype/scenes-1.0/) diff --git a/docs/whats_new.md b/docs/whats_new.md index e993e2ad..da5f00b4 100644 --- a/docs/whats_new.md +++ b/docs/whats_new.md @@ -1,13 +1,12 @@ # What's new? -## Version 2.3 +## Version 3.0 ### Major new features #### Grid Integration -TBA - +Grid integration allows you to use grid to visualize, control and execute teletype scripts. You can create your own UIs using grid ops, or control Teletype directly with the Grid Control mode. Built in Grid Visualizer allows designing and using grid scenes without a grid. For more information and examples of grid scenes please see the [Grid Studies](https://github.com/scanner-darkly/teletype/wiki/GRID-INTEGRATION). Important: do NOT plug your grid directly into Teletype! Doing so may damage your module. Grid must be powered externally. #### Improved script editing @@ -23,17 +22,27 @@ You now can connect up to three ER-301s via i2c and address up to 100 virtual CV The 16n Faderbank is an open-source sixteen fader controller with support for USB MIDI, standard MIDI, and i2c communication with the Teletype. It operates just like an IN or PARAM (or the TXi for that matter) in that you read values from the device. You use the operator FADER (or the alias FB) and the number of the slider you wish to poll (1-16). Know that longer cables may require that you use a powered bus board even if you only have one device on your Teletype's i2c bus. (You will know that you have a problem if your Teletype randomly hangs on reads.) -#### Support for the SSSR Labs SM010 Matrixarchate +#### Support for the SSSR Labs SM010 Matrixarchate via i2c The SSSR Labs SM010 Matrixarchate is a 16x8 IO Sequenceable Matrix Signal Router. Teletype integration allows you to switch programs and control connections. For a complete list of available ops refer to the manual. Information on how to connect the module can be found [in the SM010 manual](https://www.sssrlabs.com/store/sm010/). +#### Support for W/ via i2c + +Support for controlling Whimsical Raps W/ module via i2c. See the respective section for a complete list of available ops and refer to https://www.whimsicalraps.com/pages/w-type for more details. + ### New operators `? x y z` is a ternary "if" operator, it will select between `y` and `z` based on the condition `x`. -#### New pattern ops: +#### New pattern ops + +`P.MIN` `PN.MIN` `P.MAX` `PN.MAX` return the position for the first smallest/largest value in a pattern between the `START` and `END` points. + +`P.RND` / `PN.RND` return a randomly selected value in a pattern between the `START` and `END` points. -`P.MIN` `PN.MIN` `P.MAX` `PN.MAX` returns the position for the first smallest/largest value in a pattern between the `START` and `END` points. +`P.+` / `PN.+` / `P.-` / `PN.-` increment/decrement a pattern value by the specified amount. + +`P.+W` / `PN.+W` / `P.-W` / `PN.-W` same as above and wrap to the specified range. ####New Telex ops @@ -46,8 +55,11 @@ The SSSR Labs SM010 Matrixarchate is a 16x8 IO Sequenceable Matrix Signal Router `KR.CV x` get the current CV value for channel `x` `KR.MUTE x` `KR.MUTE x y` get/set mute state for channel `x` `KR.TMUTE x` toggle mute state for channel `x` -`KR.CLK x` advance the clock for channel `x` (channel must have teletype clocking enabled) +`KR.CLK x` advance the clock for channel `x` + +####Ops for ER-301, 16n Faderbank, SM010, W/ +Too many to list, please refer to their respective sections. ### New aliases @@ -70,8 +82,25 @@ Additional `Alt-H` shortcut is available to view the Help screen. `Alt-G` in Live mode will turn on the Grid Visualizer, which has its own shortcuts. Refer to the **Keys** section for a complete list. +The keybindings to insert a scaled knob value in the Tracker mode were changed from `ctrl` to `ctrl-alt` and from `shift` to `ctrl-shift`. + ### Bug fixes +i2c initialization delayed to account for ER-301 bootup +last screen saved to flash +knob jitter when loading/saving scenes reduced +[duplicate commands not added to history](https://github.com/monome/teletype/issues/99) +`SCALE` precision improved +`PARAM` set properly when used in the init script +`PARAM` and `IN` won't reset to 0 after `INIT.DATA` +[`PN.HERE`, `P.POP`, `PN.POP` will update the tracker screen](https://github.com/monome/teletype/issues/151) +[`P.RM` was 1-based, now 0-based](https://github.com/monome/teletype/issues/149) +[`P.RM` / `PN.RM` will not change pattern length if deleting outside of length range](https://github.com/monome/teletype/issues/150) +[`JI` op fixed](https://llllllll.co/t/teletype-the-ji-op/10553) +[`TIME` and `LAST` are now 1ms accurate](https://github.com/monome/teletype/issues/144) +[`RAND` / `RRAND` will properly work with large range values](https://github.com/monome/teletype/issues/143) +[`L .. 32767` won't freeze](https://github.com/monome/teletype/issues/148) + ### New behavior Previously, when pasting the clipboard while in script editing the pasted line would replace the current line. It will now instead push the current line down. This might result in some lines being pushed beyond the script limits - if this happens, use `ctrl-z` to undo the change, delete some lines and then paste again. From c5cfbee20804ae6f5456f38900fbbb1980f2ac9d Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 12 Jul 2018 19:51:05 -0700 Subject: [PATCH 098/117] fix formatting --- docs/whats_new.md | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/docs/whats_new.md b/docs/whats_new.md index da5f00b4..1e38b4b8 100644 --- a/docs/whats_new.md +++ b/docs/whats_new.md @@ -6,11 +6,11 @@ #### Grid Integration -Grid integration allows you to use grid to visualize, control and execute teletype scripts. You can create your own UIs using grid ops, or control Teletype directly with the Grid Control mode. Built in Grid Visualizer allows designing and using grid scenes without a grid. For more information and examples of grid scenes please see the [Grid Studies](https://github.com/scanner-darkly/teletype/wiki/GRID-INTEGRATION). Important: do NOT plug your grid directly into Teletype! Doing so may damage your module. Grid must be powered externally. +Grid integration allows you to use grid to visualize, control and execute teletype scripts. You can create your own UIs using grid ops, or control Teletype directly with the Grid Control mode. Built in Grid Visualizer allows designing and using grid scenes without a grid. For more information and examples of grid scenes please see the [Grid Studies](https://github.com/scanner-darkly/teletype/wiki/GRID-INTEGRATION). **Important**: do NOT plug your grid directly into Teletype! Doing so may damage your module. Grid must be powered externally. #### Improved script editing -You can now select multiple lines when editing scripts by holding `shift`. You can move the current selection up and down with 'alt-` and `alt-`. You can copy/cut/paste a multiline selection as well. To delete selected lines without copying into the clipboard use `alt-`. +You can now select multiple lines when editing scripts by holding `shift`. You can move the current selection up and down with `alt-` and `alt-`. You can copy/cut/paste a multiline selection as well. To delete selected lines without copying into the clipboard use `alt-`. Three level undo is also now available with `ctrl-z` shortcut. @@ -44,35 +44,39 @@ Support for controlling Whimsical Raps W/ module via i2c. See the respective sec `P.+W` / `PN.+W` / `P.-W` / `PN.-W` same as above and wrap to the specified range. -####New Telex ops +#### New Telex ops `TO.CV.CALIB` allows you to lock-in an offset across power cycles to calibrate your TELEX CV output (`TO.CV.RESET` removes the calibration). `TO.ENV` now accepts gate values (1/0) to trigger the attack and decay. -####New Kria ops +#### New Kria ops `KR.CV x` get the current CV value for channel `x` + `KR.MUTE x` `KR.MUTE x y` get/set mute state for channel `x` + `KR.TMUTE x` toggle mute state for channel `x` + `KR.CLK x` advance the clock for channel `x` -####Ops for ER-301, 16n Faderbank, SM010, W/ +#### Ops for ER-301, 16n Faderbank, SM010, W/ Too many to list, please refer to their respective sections. ### New aliases `$` for `SCRIPT` + `RND` / `RRND` `RAND` / `RRAND` + `WRP` for `WRAP` + `SCL` for `SCALE` ### New keybindings -Hold `shift` while making line selection in script editing to select multiple lines. -Use 'alt-` and `alt-` to move selected lines up and down. -Copy/cut/paste shortcuts work with multiline selection as well. To delete selected lines without copying into the clipboard use `alt-`. +Hold `shift` while making line selection in script editing to select multiple lines. Use `alt-` and `alt-` to move selected lines up and down. Copy/cut/paste shortcuts work with multiline selection as well. To delete selected lines without copying into the clipboard use `alt-`. While editing a line you can now use `ctrl-` / `ctrl-` to move by words. @@ -87,18 +91,31 @@ The keybindings to insert a scaled knob value in the Tracker mode were changed f ### Bug fixes i2c initialization delayed to account for ER-301 bootup + last screen saved to flash + knob jitter when loading/saving scenes reduced + [duplicate commands not added to history](https://github.com/monome/teletype/issues/99) + `SCALE` precision improved + `PARAM` set properly when used in the init script + `PARAM` and `IN` won't reset to 0 after `INIT.DATA` + [`PN.HERE`, `P.POP`, `PN.POP` will update the tracker screen](https://github.com/monome/teletype/issues/151) + [`P.RM` was 1-based, now 0-based](https://github.com/monome/teletype/issues/149) + [`P.RM` / `PN.RM` will not change pattern length if deleting outside of length range](https://github.com/monome/teletype/issues/150) + [`JI` op fixed](https://llllllll.co/t/teletype-the-ji-op/10553) + [`TIME` and `LAST` are now 1ms accurate](https://github.com/monome/teletype/issues/144) + [`RAND` / `RRAND` will properly work with large range values](https://github.com/monome/teletype/issues/143) + [`L .. 32767` won't freeze](https://github.com/monome/teletype/issues/148) ### New behavior From 8d87b1a5be84bcdc5960c4347b0e8bd46d726998 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 23 Jul 2018 19:21:53 -0700 Subject: [PATCH 099/117] fix bug in G.GRP.RST --- src/ops/grid_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index c11d42c2..28760fc6 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -335,7 +335,7 @@ static void op_G_GRP_RST_get(const void *NOTUSED(data), scene_state_t *ss, SG.group[group].enabled = true; SG.group[group].script = -1; SG.group[group].fader_min = 0; - SG.group[group].fader_max = 0; + SG.group[group].fader_max = 16383; for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.group == group) { From 05cd8fea9e66821ee4415a701267cf06b62659b0 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 30 Jul 2018 18:14:53 -0700 Subject: [PATCH 100/117] grid docs --- docs/ops/grid.md | 38 +++ docs/ops/grid.toml | 633 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 671 insertions(+) create mode 100644 docs/ops/grid.md create mode 100644 docs/ops/grid.toml diff --git a/docs/ops/grid.md b/docs/ops/grid.md new file mode 100644 index 00000000..4f0e5c02 --- /dev/null +++ b/docs/ops/grid.md @@ -0,0 +1,38 @@ +## Grid +Grid operators allow creating scenes that can interact with grid connected to +teletype (important: grid must be powered externally, do not connect it directly +to teletype!). You can light up individual LEDs, draw shapes and create controls +(such as buttons and faders) that can be used to trigger and control scripts. +You can take advantage of grid operators even without an actual grid by using +the built in Grid Visualizer. + +For more information on grid integration see Advanced section and +[Grid Studies](https://github.com/scanner-darkly/teletype/wiki/GRID-INTEGRATION). + +As there are many operators let's review some naming conventions that apply to +the majority of them. All grid ops start with `G.`. For control related ops this +is followed by 3 letters specifying the control: `G.BTN` for buttons, `G.FDR` +for faders. To define a control you use the main ops `G.BTN` and `G.FDR`. To +define multiple controls replace the last letter with `X`: `G.BTX`, `G.FDX`. + +All ops that initialize controls use the same list of parameters: id, +coordinates, width, height, type, level, script. When creating multiple controls +there are two extra parameters: the number of columns and the number of rows. +Controls are created in the current group (set with `G.GRP`). To specify a +different group use the group versions of the 4 above ops - `G.GBT`, `G.GFD`, +`G.GBX`, `G.GFX` and specify the desired group as the first parameter. + +All controls share some common properties, referenced by adding a `.` and: + +* `EN`: `G.BTN.EN`, `G.FDR.EN` - enables or disables a control +* `V`: `G.BTN.V`, `G.FDR.V` - value, 1/0 for buttons, range value for faders +* `L`: `G.BTN.L`, `G.FDR.L` - level (brightness level for buttons and coarse faders, max value level for fine faders) +* `X`: `G.BTN.X`, `G.FDR.X` - the X coordinate +* `Y`: `G.BTN.Y`, `G.FDR.Y` - the Y coordinate + +To get/set properties for individual controls you normally specify the control +id as the first parameter: `G.FDR.V 5` will return the value of fader 5. Quite +often the actual id is not important, you just want to work with the latest +control pressed. As these are likely the ops to be used most often they are +offered as shortcuts without a `.`: `G.BTNV` returns the value of the last +button pressed, `G.FDRL 4` will set the level of the last fader pressed etc etc. diff --git a/docs/ops/grid.toml b/docs/ops/grid.toml new file mode 100644 index 00000000..6619c957 --- /dev/null +++ b/docs/ops/grid.toml @@ -0,0 +1,633 @@ +["G.RST"] +prototype = "G.RST" +short = "full grid reset" +description = """ +Full grid reset - hide all controls and reset their properties to the default +values, clear all LEDs, reset the dim level and the grid rotation. +""" + +["G.CLR"] +prototype = "G.CLR" +short = "clear all LEDs" +description = """ +Clear all LEDs set with `G.LED`, `G.REC` or `G.RCT`. +""" + +["G.DIM"] +prototype = "G.DIM level" +short = "set dim level" +description = """ +Set the dim level (0..14, higher values dim more). To remove set to 0. +""" + +["G.ROTATE"] +prototype = "G.ROTATE x" +short = "set grid rotation" +description = """ +Set the grid rotation (0 - no rotation, 1 - rotate by 180 degrees). +""" + +["G.KEY"] +prototype = "G.KEY x y action" +short = "emulate grid press" +description = """ +Emulate a grid key press at the specified coordinates (0-based). Set `action` +to 1 to emulate a press, 0 to emulate a release. You can also emulate a button +press with `G.BTN.PR` and a fader press with `G.FDR.PR`. +""" + +["G.GRP"] +prototype = "G.GRP" +prototype_set = "G.GRP id" +short = "get/set current group" +description = """ +Get or set the current group. Grid controls created without specifying a group +will be assigned to the current group. This op doesn't enable/disable groups - +use `G.GRP.EN` for that. The default current group is 0. 64 groups are +available. +""" + +["G.GRP.EN"] +prototype = "G.GRP.EN id" +prototype_set = "G.GRP.EN id x" +short = "enable/disable group or check if enabled" +description = """ +Enable or disable the specified group or check if it's currently enabled. +1 means enabled, 0 means disabled. Enabling or disabling a group enables / +disables all controls assigned to that group (disabled controls are not shown +and receive no input). This allows groups to be used as pages - initialize +controls in different groups, and then simply enable one group at a time. +""" + +["G.GRP.RST"] +prototype = "G.GRP.RST id" +short = "reset all group controls" +description = """ +Reset all controls associated with the specified group. This will disable +the controls and reset their properties to the default values. This will also +reset the fader scale range to 0..16383. +""" + +["G.GRP.SW"] +prototype = "G.GRP.SW id" +short = "switch groups" +description = """ +Switch groups. Enables the specified group, disables all others. +""" + +["G.GRP.SC"] +prototype = "G.GRP.SC id" +prototype_set = "G.GRP.SC id script" +short = "get/set group script" +description = """ +Assign a script to the specified group, or get the currently assigned script. +The script gets executed whenever a control associated with the group receives +input. It is possible to have different scripts assigned to a control and +the group it belongs to. Use 9 for Metro and 10 for Init. To unassign, set it +to 0. +""" + +["G.GRPI"] +prototype = "G.GRPI" +short = "get last group" +description = """ +Get the id of the last group that received input. This is useful when sharing +a script between multiple groups. +""" + +["G.LED"] +prototype = "G.LED x y" +prototype_set = "G.LED x y level" +short = "get/set LED" +description = """ +Set the LED level or get the current level at the specified coordinates. +Possible level range is 0..15 (on non varibright grids anything below 8 is +'off', 8 or above is 'on'). + +Grid controls get rendered first, and LEDs are rendered last. This means you can +use LEDs to accentuate certain areas of the UI. This also means that any LEDs +that are set will block whatever is underneath them, even with the level of 0. +In order to completely clear an LED set its level to -3. There are two other +special values for brightness: -1 will dim, and -2 will brighten what's +underneath. They can be useful to highlight the current sequence step, for +instance. +""" + +["G.LED.C"] +prototype = "G.LED.C x y" +short = "clear LED" +description = """ +Clear the LED at the specified coordinates. This is the same as setting +the brightness level to -3. To clear all LEDs use `G.CLR`. +""" + +["G.REC"] +prototype = "G.REC x y w h fill border" +short = "draw rectangle" +description = """ +Draw a rectangle with the specified width and height. `x` and `y` are +the coordinates of the top left corner. Coordinates are 0-based, with the 0,0 +point located at the top left corner of the grid. You can draw rectangles that +are partially outside of the visible area, and they will be properly cropped. + +`fill` and `border` specify the brightness levels for the inner area and +the one-LED-wide border respectively, 0..15 range. You can use the three special +brightness levels: -1 to dim, -2 to brighten and -3 for transparency (you could +draw just a frame by setting `fill` to -3, for instance). + +To draw lines, set the width or the height to 1. In this case only `border` +brightness level is used. +""" + +["G.RCT"] +prototype = "G.RCT x1 y1 x2 y2 fill border" +short = "draw rectangle" +description = """ +Same as `G.REC` but instead of specifying the width and height you specify +the coordinates of the top left corner and the bottom right corner. +""" + +["G.BTN"] +prototype = "G.BTN id x y w h type level script" +short = "initialize button" +description = """ +Initializes and enables a button with the specified id. 256 buttons are +available (ids are 0-based so the possible id range is 0..255. The button will +be assigned to the current group (set with `G.GRP`). Buttons can be +reinitialized at any point. + +`x` and `y` specify the coordinates of the top left corner, and `w` and `h` +specify width and height respectively. `type` determines whether the button is +latching (1) or momentary (0). `level` sets the "off" brightness level, possible +rand is -3..15 (the brightness level for pressed buttons is fixed at 13). + +`script` specifies the script to be executed when the button is pressed or +released (the latter only for momentary buttons). Use 9 for Metro and 10 for +Init. Use 0 if you don't need a script assigned. +""" + +["G.GBT"] +prototype = "G.GBT group id x y w h type level script" +short = "initialize button in group" +description = """ +Initialize and enable a button. Same as `G.BTN` but you can also choose which +group to assign the button too. +""" + +["G.BTX"] +prototype = "G.BTX id x y w h type level script columns rows" +short = "initialize multiple buttons" +description = """ +Initialize and enable a block of buttons in the current group with the specified +number of columns and rows . Ids are incremented sequentially by columns and +then by rows. +""" + +["G.GBX"] +prototype = "G.GBX group id x y w h type level script columns rows" +short = "initialize multiple buttons in group" +description = """ +Initialize and enable a block of buttons. Same as `G.BTX` but you can also +choose which group to assign the buttons too. +""" + +["G.BTN.EN"] +prototype = "G.BTN.EN id" +prototype_set = "G.BTN.EN id x" +short = "enable/disable button or check if enabled" +description = """ +Enable (set `x` to 1) or disable (set `x` to 0) a button with the specified id, +or check if it's currently enabled. Disabling a button hides it and stops it +from receiving input but keeps all the other properties (size/location etc) +intact. +""" + +["G.BTN.X"] +prototype = "G.BTN.X id" +prototype_set = "G.BTN.X id x" +short = "get/set button x coordinate" +description = """ +Get or set `x` coordinate for the specified button's top left corner. +""" + +["G.BTN.Y"] +prototype = "G.BTN.Y id" +prototype_set = "G.BTN.Y id y" +short = "get/set button y coordinate" +description = """ +Get or set `y` coordinate for the specified button's top left corner. +""" + +["G.BTN.V"] +prototype = "G.BTN.V id" +prototype_set = "G.BTN.V id value" +short = "get/set button value" +description = """ +Get or set the specified button's value. For buttons the value of 1 means +the button is pressed and 0 means it's not. If there is a script assigned +to the button it will not be triggered if you change the value - use +`G.BTN.PR` for that. + +Button values don't change when a button is disabled. Button values are stored +with the scene (both to flash and to USB sticks). +""" + +["G.BTN.L"] +prototype = "G.BTN.L id" +prototype_set = "G.BTN.L id level" +short = "get/set button level" +description = """ +Get or set the specified button's brightness level (-3..15). Please note you +can only set the level for unpressed buttons, the level for pressed buttons is +fixed at 13. +""" + +["G.BTNI"] +prototype = "G.BTNI" +short = "id of last pressed button" +description = """ +Get the id of the last pressed button. This is useful when multiple buttons are +assigned to the same script. +""" + +["G.BTNX"] +prototype = "G.BTNX" +prototype_set = "G.BTNX x" +short = "get/set x of last pressed button" +description = """ +Get or set `x` coordinate of the last pressed button's top left corner. This is +the same as `G.BTN.X G.BTNI`. +""" + +["G.BTNY"] +prototype = "G.BTNY" +prototype_set = "G.BTNY y" +short = "get/set y of last pressed button" +description = """ +Get or set `y` coordinate of the last pressed button's top left corner. This is +the same as `G.BTN.Y G.BTNI`. +""" + +["G.BTNV"] +prototype = "G.BTNV" +prototype_set = "G.BTNV value" +short = "get/set value of last pressed button" +description = """ +Get or set the value of the last pressed button. This is the same as +`G.BTN.V G.BTNI`. This op is especially useful with momentary buttons when you +want to react to presses or releases only - just put `IF EZ G.BTNV: BREAK` in +the beginning of the assigned script (this will ignore releases, to ignore +presses replace `NZ` with `EZ`). +""" + +["G.BTNL"] +prototype = "G.BTNL" +prototype_set = "G.BTNL level" +short = "get/set level of last pressed button" +description = """ +Get or set the brightness level of the last pressed button. This is the same as +`G.BTN.L G.BTNI`. +""" + +["G.BTN.SW"] +prototype = "G.BTN.SW id" +short = "switch button" +description = """ +Set the value of the specified button to 1 (pressed), set it to 0 (not pressed) +for all other buttons within the same group (useful for creating radio buttons). +""" + +["G.BTN.PR"] +prototype = "G.BTN.PR id action" +short = "emulate button press/release" +description = """ +Emulate pressing/releasing the specified button. Set `action` to `1` for press, +`0` for release (`action` is ignored for latching buttons). +""" + +["G.GBTN.V"] +prototype = "G.GBTN.V group value" +short = "set value for group buttons" +description = """ +Set the value for all buttons in the specified group. +""" + +["G.GBTN.L"] +prototype = "G.GBTN.L group odd_level even_level" +short = "set level for group buttons" +description = """ +Set the brightness level (0..15) for all buttons in the specified group. You can +use different values for odd and even buttons (based on their index within the +group, not their id) - this can be a good way to provide some visual guidance. +""" + +["G.GBTN.C"] +prototype = "G.GBTN.C group" +short = "get count of currently pressed" +description = """ +Get the total count of all the buttons in the specified group that are currently +pressed. +""" + +["G.GBTN.I"] +prototype = "G.GBTN.I group index" +short = "get id of pressed button" +description = """ +Get the id of a currently pressed button within the specified group by its index +(0-based). The index should be between 0 and C-1 where C is the total count of +all pressed buttons (you can get it using `G.GBTN.C`). +""" + +["G.GBTN.W"] +prototype = "G.GBTN.W group" +short = "get button block width" +description = """ +Get the width of the rectangle formed by pressed buttons within the specified +group. This is basically the distance between the leftmost and the rightmost +pressed buttons, inclusive. This op is useful for things like setting a loop's +length, for instance. To do so, check if there is more than one button pressed +(using `G.GBTN.C`) and if there is, use `G.GBTN.W` to set the length. +""" + +["G.GBTN.H"] +prototype = "G.GBTN.H group" +short = "get button block height" +description = """ +Get the height of the rectangle formed by pressed buttons within the specified +group (see `G.GBTN.W` for more details). +""" + +["G.GBTN.X1"] +prototype = "G.GBTN.X1 group" +short = "get leftmost pressed x" +description = """ +Get the X coordinate of the leftmost pressed button in the specified group. If +no buttons are currently pressed it will return -1. +""" + +["G.GBTN.X2"] +prototype = "G.GBTN.X2 group" +short = "get rightmost pressed x" +description = """ +Get the X coordinate of the rightmost pressed button in the specified group. If +no buttons are currently pressed it will return -1. +""" + +["G.GBTN.Y1"] +prototype = "G.GBTN.Y1 group" +short = "get highest pressed y" +description = """ +Get the Y coordinate of the highest pressed button in the specified group. If no +buttons are currently pressed it will return -1. +""" + +["G.GBTN.Y2"] +prototype = "G.GBTN.Y2 group" +short = "get lowest pressed y" +description = """ +Get the Y coordinate of the lowest pressed button in the specified group. If no +buttons are currently pressed it will return -1. +""" + +["G.FDR"] +prototype = "G.FDR id x y w h type level script" +short = "initialize fader" +description = """ +Initializes and enables a fader with the specified id. 64 faders are available +(ids are 0-based so the possible id range is 0..63). The fader will be assigned +to the current group (set with `G.GRP`). Faders can be reinitialized at any +point. + +`x` and `y` specify the coordinates of the top left corner, and `w` and `h` +specify width and height respectively. + +`type` determines the fader type and orientation. Possible values are: + +* 0 - coarse, horizontal bar +* 1 - coarse, vertical bar +* 2 - coarse, horizontal dot +* 3 - coarse, vertical dot +* 4 - fine, horizontal bar +* 5 - fine, vertical bar +* 6 - fine, horizontal dot +* 7 - fine, vertical dot + +Coarse faders have the possible range of 0..N-1 where N is width for horizontal +faders or height for vertical faders. Pressing anywhere within the fader area +sets the fader value accordingly. Fine faders allow selecting a bigger range +of values by mapping the range to the fader's height or width and dedicating +the edge buttons for incrementing/decrementing. Fine faders employ +varibrightness to reflect the current value. + +`level` has a different meaning for coarse and fine faders. For coarse faders +it selects the background brightness level (similar to buttons). For fine faders +this is the maximum value level (the minimum level being 0). In order to show +each value distinctly using varibright the maximum level possible is the number +of available buttons multiplied by 16 minus 1 (since range is 0-based). Remember +that 2 buttons are always reserved for increment/decrement. Using a larger +number is allowed - it will be automatically adjusted to what's possible. + +`script` specifies the script to be executed when the fader value is changed. +Use 9 for Metro and 10 for Init. Use 0 if you don't need a script assigned. +""" + +["G.GFD"] +prototype = "G.GFD grp id x y w h type level script" +short = "initialize fader in group" +description = """ +Initialize and enable a fader. Same as `G.FDR` but you can also choose which +group to assign the fader too. +""" + +["G.FDX"] +prototype = "G.FDX id x y w h type level script columns rows" +short = "initialize multiple faders" +description = """ +Initialize and enable a block of faders with the specified number of columns +and rows in the current group. Ids are incremented sequentially by columns and +then by rows. +""" + +["G.GFX"] +prototype = "G.GFX group id x y w h type level script columns rows" +short = "initialize multiple faders in group" +description = """ +Initialize and enable a block of faders. Same as `G.FDX` but you can also +choose which group to assign the faders too. +""" + +["G.FDR.EN"] +prototype = "G.FDR.EN id" +prototype_set = "G.FDR.EN id x" +short = "enable/disable fader or check if enabled" +description = """ +Enable (set `x` to 1) or disable (set `x` to 0) a fader with the specified id, +or check if it's currently enabled. Disabling a fader hides it and stops it +from receiving input but keeps all the other properties (size/location etc) +intact. +""" + +["G.FDR.X"] +prototype = "G.FDR.X id" +prototype_set = "G.FDR.X id x" +short = "get/set fader x coordinate" +description = """ +Get or set `x` coordinate for the specified fader's top left corner. +""" + +["G.FDR.Y"] +prototype = "G.FDR.Y id" +prototype_set = "G.FDR.Y id y" +short = "get/set fader y coordinate" +description = """ +Get or set `y` coordinate for the specified fader's top left corner. +""" + +["G.FDR.N"] +prototype = "G.FDR.N id" +prototype_set = "G.FDR.N id value" +short = "get/set fader value" +description = """ +Get or set the specified fader's value. The possible range for coarse faders is +0..N-1 where N is fader's width (for horizontal faders) or height (for vertical +faders). For fine faders the possible range is 0..N where N is the maximum level +set when the fader was initialized (see `G.FDR` for more details). + +Sometimes it's more convenient to map the possible fader range to a different +range (when using it to control a CV, for instance). Use `G.FDR.V` for that. + +If there is a script assigned to the fader it will not be triggered if you change +the value - use `G.FDR.PR` for that. + +Fader values don't change when a fader is disabled. Fader values are stored +with the scene (both to flash and to USB sticks). +""" + +["G.FDR.V"] +prototype = "G.FDR.V id" +prototype_set = "G.FDR.V id value" +short = "get/set scaled fader value" +description = """ +Get or set the specified fader's value mapped to a range set with `G.GFDR.RN`. +This op is very convenient for using faders to control a known range, such as CV +- simply create a fader and set a range and then assign values directly without +any additional calculations, like this: `CV 1 G.FDR.V 1`. +""" + +["G.FDR.L"] +prototype = "G.FDR.L id" +prototype_set = "G.FDR.L id level" +short = "get/set fader level" +description = """ +Get or set the specified fader's brightness level (for coarse faders), or the +maximum value level (for fine faders). +""" + +["G.FDRI"] +prototype = "G.FDRI" +short = "id of last pressed fader" +description = """ +Get the id of the last pressed fader. This is useful when multiple faders are +assigned to the same script. +""" + +["G.FDRX"] +prototype = "G.FDRX" +prototype_set = "G.FDRX x" +short = "get/set x of last pressed fader" +description = """ +Get or set `x` coordinate of the last pressed fader's top left corner. This is +the same as `G.FDR.X G.FDRI`. +""" + +["G.FDRY"] +prototype = "G.FDRY" +prototype_set = "G.FDRY y" +short = "get/set y of last pressed fader" +description = """ +Get or set `y` coordinate of the last pressed fader's top left corner. This is +the same as `G.BTN.Y G.BTNI`. +""" + +["G.FDRN"] +prototype = "G.FDRN" +prototype_set = "G.FDRN value" +short = "get/set value of last pressed fader" +description = """ +Get or set the value of the last pressed fader. This is the same as +`G.FDR.N G.FDRI`. See `G.FDR.N` for more details. +""" + +["G.FDRV"] +prototype = "G.FDRV" +prototype_set = "G.FDRV value" +short = "get/set scaled value of last pressed fader" +description = """ +Get or set the scaled value of the last pressed fader. This is the same as +`G.FDR.V G.FDRI`. See `G.FDR.V` for more details. +""" + +["G.FDRL"] +prototype = "G.FDRL" +prototype_set = "G.FDRL level" +short = "get/set level of last pressed fader" +description = """ +Get or set the brightness level (for coarse faders), or the maximum value level +(for fine faders) of the last pressed fader. This is the same as +`G.FDR.L G.BTNI`. For more details on levels see `G.FDR`. +""" + +["G.FDR.PR"] +prototype = "G.FDR.PR id value" +short = "emulate fader press" +description = """ +Emulate pressing the specified fader. Fader value will be set to the specified +value, and if there is a script assigned it will be executed. +""" + +["G.GFDR.N"] +prototype = "G.GFDR.N group value" +short = "set value for group faders" +description = """ +Set the value for all faders in the specified group. This can be useful for +resetting all faders in a group. See `G.FDR.N` for more details. +""" + +["G.GFDR.V"] +prototype = "G.GFDR.V group value" +short = "set scaled value for group faders" +description = """ +Set the scaled value for all faders in the specified group. This can be useful +for resetting all faders in a group. See `G.FDR.V` for more details. +""" + +["G.GFDR.L"] +prototype = "G.GFDR.L group odd_level even_level" +short = "set level for group faders" +description = """ +Set the brightness level (0..15) for all faders in the specified group. You can +use different values for odd and even faders (based on their index within the +group, not their id) - this can be a good way to provide some visual guidance. +""" + +["G.GFDR.RN"] +prototype = "G.GFDR.RN group min max" +short = "set range for group faders" +description = """ +Set the range to be used for `V` fader values (`G.FDR.V`, `G.FDRV`, `G.GFDR.V`). +While the `.N` ops provide the actual fader value sometimes it's more convenient +to map it to a different range so it can be used directly for something like +a CV without having to scale it each time. + +An example: let's say you create a coarse fader with the width of 8 which will +be used to control a CV output where the voltage must be in the 2V..5V range. +Using `G.FDR.N` you would need to do this: `CV 1 SCL 0 7 V 2 V 5 G.FDR.N 0`. +Instead you can set the range for scaling once: `G.GFDR.RN 0 V 2 V 5` (assuming +the fader is in group 0) and then simply do `CV 1 G.FDR.V 0`. + +The range is shared by all faders within the same group. If you need to use a +different range use a different group when initializing a fader. + +The default range is 0..16383. `G.RST` and `G.GRP.RST` reset ranges to the +default value. +""" From 2ac96980a3eedcde133e4aa265e0e715b53fc1b0 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 30 Jul 2018 18:15:13 -0700 Subject: [PATCH 101/117] fix telex doc --- docs/ops/telex_o.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/ops/telex_o.toml b/docs/ops/telex_o.toml index e537da0f..52936be4 100644 --- a/docs/ops/telex_o.toml +++ b/docs/ops/telex_o.toml @@ -393,6 +393,7 @@ prototype = "TO.OSC.RECT x y" short = "rectifies the polarity of the oscillator for output `x` to `y`; range for `y` is -2 to 2; default is 0 (no rectification); 1 & -1 are partial rectification - omitting all values on the other side of the sign; 2 & -2 are full rectification - inverting values from the other pole" description = """ The rectification command performs a couple of levels of rectification based on how you have it set. The following values for `y` work as follows: + * `y = 2`: "full-positive" - inverts negative values, making them positive * `y = 1`: "half-positive" - omits all negative values (values below zero are set to zero) * `y = 0`: no rectification (default) From 7f7ffb9d214121f148fcdee60da613047dd07930 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Mon, 30 Jul 2018 18:36:42 -0700 Subject: [PATCH 102/117] grid docs --- docs/advanced.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/advanced.md b/docs/advanced.md index a453926f..f4a8d8db 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -127,3 +127,35 @@ Although happy accidents in the modular world are one of it's many joys, when wr 4. **Avoid using `A`, `B`, `C` and `D` to refer to the trigger outputs, instead use the numerical values directly.** As `A-D` are variables, they may no longer contain the values `1-4`, and while this was the recommend way to name triggers, it is no longer consider ideal. Newer versions of the Teletype hardware have replaced the labels on the trigger outputs, with the numbers `1` to `4`. + +## Grid integration + +Grid integration can be described very simply: it allows you to use grid with +teletype. However, there is more to it than just that. You can create custom +grid interfaces that can be tailored individually for each scene. Since it's +done with scripts you can dynamically change these interfaces at any point - +you could even create a dynamic interface that reacts to the scene itself or +incoming triggers or control voltages. + +It's hard to describe what can be done as there are so many different ways you +can use it. You can simply use grid as an LED display to visualize your scene. +Or make it into an earthsea style keyboard. You can create sequencers, or +control surfaces to control other sequencers. + +There are many grid operators intended to simplify building very complex +interfaces, while something simple like a bank of faders can be done with just +two lines of scripts (and can be just as useful!). + +As you can't have both keyboard and grid connected at the same time, the Grid +Visualizer is provided in Live screen so you can see exactly what it will look +like on the actual grid. You can even use it to emulate grid presses so you can +test your scene too. As a matter of fact, it's entirely possible to use grid +scenes without a grid just by using the Visualizer. + +If you don't feel like creating your own interfaces you can take advantage of +the Grid Control mode. It allows you to use grid to trigger and mute scripts, +edit variables and tracker values, save and load scenes, and more. + +As there are many topics to cover, the best way to start learning Grid +integration is by following +[the Grid Studies](https://github.com/scanner-darkly/teletype/wiki/GRID-INTEGRATION). From b072b0dc6ffcbdc5e723fc6734243240543902fe Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 31 Jul 2018 19:45:50 -0700 Subject: [PATCH 103/117] doc fixes --- docs/ops/maths.toml | 2 +- docs/ops/patterns.md | 2 +- utils/docs.py | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/ops/maths.toml b/docs/ops/maths.toml index 22d9bbe9..08c96483 100644 --- a/docs/ops/maths.toml +++ b/docs/ops/maths.toml @@ -38,7 +38,7 @@ short = "generate a random number between `x` and `y` inclusive" prototype = "TOSS" short = "randomly return `0` or `1`" -[RRAND] +["?"] prototype = "? x y z" short = "if condition `x` is true return `y`, otherwise return `z`" diff --git a/docs/ops/patterns.md b/docs/ops/patterns.md index 04b1617f..17f46070 100644 --- a/docs/ops/patterns.md +++ b/docs/ops/patterns.md @@ -1,4 +1,4 @@ -##Patterns +## Patterns Patterns facilitate musical data manipulation– lists of numbers that can be used as sequences, chord sets, rhythms, or whatever you choose. Pattern memory consists four banks of 64 steps. Functions are provided for a variety of pattern creation, transformation, and playback. New in teletype 2.0, a second version of all Pattern ops have been added. The original `P` ops (`P`, `P.L`, `P.NEXT`, etc.) act upon the ‘working pattern’ as defined by `P.N`. By default the working pattern is assigned to pattern 0 (`P.N 0`), in order to execute a command on pattern 1 using `P` ops you would need to first reassign the working pattern to pattern 1 (`P.N 1`). diff --git a/utils/docs.py b/utils/docs.py index ba01432e..9ad5eddb 100755 --- a/utils/docs.py +++ b/utils/docs.py @@ -43,6 +43,7 @@ "stack", "queue", "turtle", + "grid", "ansible", "whitewhale", "meadowphysics", @@ -50,7 +51,11 @@ "orca", "justfriends", "telex_i", - "telex_o" + "telex_o", + "er301", + "fader", + "wslash", + "matrixarchate" ] From 45cfa776d6d48fc71ced6bf5a3297b7c4bb9c51d Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 31 Jul 2018 20:12:40 -0700 Subject: [PATCH 104/117] more doc fixes --- docs/ops/variables.toml | 8 +++++--- docs/ops/wslash.md | 2 +- utils/cheatsheet.py | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/ops/variables.toml b/docs/ops/variables.toml index ff861c2d..c79468ed 100644 --- a/docs/ops/variables.toml +++ b/docs/ops/variables.toml @@ -57,12 +57,14 @@ short = "returns inverted state (`0` or `1`) on each read (also settable)" [I] prototype = "I" prototype_set = "I x" -short = """ -get / set the variable `I`, this variable is overwritten by `L`, but can be used +short = """get / set the variable `I`""" +description=""" +Get / set the variable `I`, this variable is overwritten by `L`, but can be used freely outside an `L` loop. Each script gets its own `I` variable, so if you call a script from another script's loop you can still use and modify `I` without affecting the calling loop. In this scenario the script getting called will have -its `I` value initialized with the calling loop's current `I` value.""" +its `I` value initialized with the calling loop's current `I` value. +""" [O] prototype = "O" diff --git a/docs/ops/wslash.md b/docs/ops/wslash.md index 8819076c..cdf16764 100644 --- a/docs/ops/wslash.md +++ b/docs/ops/wslash.md @@ -1,4 +1,4 @@ -W/ +## W/ More extensively covered in the [W/ Documentation](https://www.whimsicalraps.com/pages/w-type). diff --git a/utils/cheatsheet.py b/utils/cheatsheet.py index 0d68fd41..f392a09a 100755 --- a/utils/cheatsheet.py +++ b/utils/cheatsheet.py @@ -57,7 +57,8 @@ def inject_latex(value): ("delay", "Delay", False), ("stack", "Stack", False), ("queue", "Queue", False), - ("turtle", "Turtle", True), + ("turtle", "Turtle", False), + ("grid", "Grid", True), ("ansible", "Ansible", False), ("whitewhale", "Whitewhale", False), ("meadowphysics", "Meadowphysics", False), @@ -66,7 +67,8 @@ def inject_latex(value): ("justfriends", "Just Friends", False), ("wslash", "W/", False), ("er301", "ER-301", False), - ("fader", "Fader", True), + ("fader", "Fader", False), + ("matrixarchate", "Matrixarchate", True), ("telex_i", "TELEXi", False), ("telex_o", "TELEXo", False) ] From 85cf63267c306f3cb67b6d1abac3410475e230e1 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 31 Jul 2018 20:27:04 -0700 Subject: [PATCH 105/117] updated changelog --- CHANGELOG.md | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a79d0444..8636e1db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,35 @@ # Changelog -## v2.NEXT +## v3.0 + +- **NEW**: grid integration / grid visualizer / grid control mode +- **NEW**: multiline copy/paste and editing +- **NEW**: new keybindings to move by words +- **NEW**: undo in script editing +- **NEW**: i2c support for ER-301 +- **NEW**: i2c support for 16n Faderbank +- **NEW**: i2c support for Matrixarchate +- **NEW**: i2c support for W/ +- **NEW**: new op: ? +- **NEW**: new ops: P.MIN, PN.MIN, P.MAX, PN.MAX, P.RND, PN.RND, P.+, PN.+, P.-, PN.-. P.+W, PN.+W, P.-W, PN.-W +- **NEW**: new Telex ops: TO.CV.CALIB, TO.ENV +- **NEW**: new Kria ops: KR.CV, KR.MUTE, KR.TMUTE, KR.CLK, ME.CV +- **NEW**: new aliases: $, RND, RRND, WRP, SCL +- **FIX**: i2c initialization delayed to account for ER-301 bootup +- **FIX**: last screen saved to flash +- **FIX**: knob jitter when loading/saving scenes reduced +- **FIX**: [duplicate commands not added to history](https://github.com/monome/teletype/issues/99) +- **FIX**: `SCALE` precision improved +- **FIX**: `PARAM` set properly when used in the init script +- **FIX**: `PARAM` and `IN` won't reset to 0 after `INIT.DATA` +- **FIX**: [`PN.HERE`, `P.POP`, `PN.POP` will update the tracker screen](https://github.com/monome/teletype/issues/151) +- **FIX**: [`P.RM` was 1-based, now 0-based](https://github.com/monome/teletype/issues/149) +- **FIX**: [`P.RM` / `PN.RM` will not change pattern length if deleting outside of length range](https://github.com/monome/teletype/issues/150) +- **FIX**: [`JI` op fixed](https://llllllll.co/t/teletype-the-ji-op/10553) +- **FIX**: [`TIME` and `LAST` are now 1ms accurate](https://github.com/monome/teletype/issues/144) +- **FIX**: [`RAND` / `RRAND` will properly work with large range values](https://github.com/monome/teletype/issues/143) +- **FIX**: [`L .. 32767` won't freeze](https://github.com/monome/teletype/issues/148) - **FIX**: I now accessible to child SCRIPTS -- **NEW**: new ops for Ansible: KR.CV, KR.MUTE, KR.TMUTE, KR.CLK, ME.CV -- **NEW**: new ops for W/: WS.PLAY, WS.REC, WS.LOOP, WS.CUE ## v2.2 - **NEW**: added a cheat sheet PDF From 1c4f0453c74c0f2846e456986020bd667fc7b8e9 Mon Sep 17 00:00:00 2001 From: Mirko Date: Tue, 7 Aug 2018 21:19:52 +0200 Subject: [PATCH 106/117] Added help-pages added help pages for ansible, just friends and w/ --- module/help_mode.c | 205 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 192 insertions(+), 13 deletions(-) diff --git a/module/help_mode.c b/module/help_mode.c index 65d49581..e590430e 100644 --- a/module/help_mode.c +++ b/module/help_mode.c @@ -18,7 +18,7 @@ #define HELP_PAGES 11 #define HELP1_LENGTH 59 -const char* help1[HELP1_LENGTH] = { "1/11 HELP", +const char* help1[HELP1_LENGTH] = { "1/14 HELP", "[ ] NAVIGATE HELP PAGES", "UP/DOWN TO SCROLL", " ", @@ -79,7 +79,7 @@ const char* help1[HELP1_LENGTH] = { "1/11 HELP", "SHIFT-2|SHOW/HIDE TURTLE" }; #define HELP2_LENGTH 13 -const char* help2[HELP2_LENGTH] = { "2/11 VARIABLES", +const char* help2[HELP2_LENGTH] = { "2/14 VARIABLES", " ", "X, Y, Z|GENERAL PURPOSE", "T|USE FOR TIME", @@ -94,7 +94,7 @@ const char* help2[HELP2_LENGTH] = { "2/11 VARIABLES", "Q.AVG|AVERAGE OF ALL Q" }; #define HELP3_LENGTH 26 -const char* help3[HELP3_LENGTH] = { "3/11 PARAMETERS", +const char* help3[HELP3_LENGTH] = { "3/14 PARAMETERS", " ", "TR A-D|SET TR VALUE (0,1)", "TR.TIME A-D|TR PULSE TIME", @@ -122,7 +122,7 @@ const char* help3[HELP3_LENGTH] = { "3/11 PARAMETERS", "LAST N|GET SCRIPT LAST RUN" }; #define HELP4_LENGTH 11 -const char* help4[HELP4_LENGTH] = { "4/11 DATA AND TABLES", +const char* help4[HELP4_LENGTH] = { "4/14 DATA AND TABLES", " ", "ALL PARAMS HAVE 16B RANGE", "-32768 TO 32767", @@ -135,7 +135,7 @@ const char* help4[HELP4_LENGTH] = { "4/11 DATA AND TABLES", "EXP X|EXPO LOOKUP" }; #define HELP5_LENGTH 56 -const char* help5[HELP5_LENGTH] = { "5/11 OPERATORS", +const char* help5[HELP5_LENGTH] = { "5/14 OPERATORS", " ", "RAND A|RANDOM 0 - A", "RRAND A B|RANDOM A - B", @@ -193,7 +193,7 @@ const char* help5[HELP5_LENGTH] = { "5/11 OPERATORS", "TR.PULSE X|PULSE TR X" }; #define HELP6_LENGTH 31 -const char* help6[HELP6_LENGTH] = { "6/11 PRE :", +const char* help6[HELP6_LENGTH] = { "6/14 PRE :", " ", "EACH PRE NEEDS A : FOLLOWED", "BY A COMMAND TO OPERATE ON", @@ -226,7 +226,7 @@ const char* help6[HELP6_LENGTH] = { "6/11 PRE :", "BREAK|STOP EXECUTION" }; #define HELP7_LENGTH 37 -const char* help7[HELP7_LENGTH] = { "7/11 PATTERNS", +const char* help7[HELP7_LENGTH] = { "7/14 PATTERNS", " ", "// DIRECT ACCESS", "P A|GET VAL AT INDEX A", @@ -264,7 +264,7 @@ const char* help7[HELP7_LENGTH] = { "7/11 PATTERNS", "P.-W A B C D", " |DEC AND WRAP TO C..D" }; #define HELP8_LENGTH 135 -const char* help8[HELP8_LENGTH] = { "8/11 GRID", +const char* help8[HELP8_LENGTH] = { "8/14 GRID", " ", "G.RST|RESET EVERYTHING", "G.CLR|CLEAR ALL LEDS", @@ -400,7 +400,7 @@ const char* help8[HELP8_LENGTH] = { "8/11 GRID", "G.GFDR.RN group min max", " SET FADER RANGE FOR .V" }; #define HELP9_LENGTH 17 -const char* help9[HELP9_LENGTH] = { "9/11 TURTLE", +const char* help9[HELP9_LENGTH] = { "9/14 TURTLE", " ", "// CRAWLS TRACKER DATA", "@|GET/SET DATA", @@ -419,7 +419,7 @@ const char* help9[HELP9_LENGTH] = { "9/11 TURTLE", "@SHOW 1/0|DISPLAY < ON TRACKER" }; #define HELP10_LENGTH 36 -const char* help10[HELP10_LENGTH] = { "10/11 TELEX INPUT", +const char* help10[HELP10_LENGTH] = { "10/14 TELEX INPUT", " ", "TI.PARAM X|(TI.PRM)", " GET KNOB VALUE", @@ -458,7 +458,7 @@ const char* help10[HELP10_LENGTH] = { "10/11 TELEX INPUT", #define HELP11_LENGTH 164 const char* help11[HELP11_LENGTH] = { - "11/11 TELEX OUTPUT", + "11/14 TELEX OUTPUT", " ", "TO.TR X Y", " SET TR VALUE (0/1)", @@ -623,17 +623,196 @@ const char* help11[HELP11_LENGTH] = { "TO.CV.RESET X", " RESET CV CALIB"}; +#define HELP12_LENGTH 115 +const char* help12[HELP12_LENGTH] = { + "12/14 ANSIBLE", + " ", + "KR.PRE / KR.PRE X", + " RETURN/LOAD CURRENT PRESET", + "KR.PERIOD / KR.PERIOD X", + " GET/SET INTERNAL PERIOD", + "KR.PAT / KR.PAT X", + " GET/SET CURRENT PATTERN", + "KR.SCALE / KR.SCALE X", + " GET/SET CURRENT SCALE", + "KR.POS X Y / KR.POS X Y Z", + " GET/SET POSITION Z", + " FOR TRACK X PARAM Y", + "KR.L.ST X Y", + " GET LOOP START FOR", + " TRACK X, PARAM Y", + "KR.L.ST X Y Z" + " LOOP START FOR", + " TRACK X, PARAM Y TO Z", + "KR.L.LEN X Y", + " GET LENGTH OF", + " TRACK X, PARAM Y", + "KR.L.LEN X Y Z", + " SET LENGTH OF", + " TRACK X, PARAM Y TO Z", + "KR.RES X Y", + " RESET POSITION", + " FOR TRACK X, PARAM Y", + "KR.CV X", + " GET CV FOR CHANNEL X", + "KR.MUTE X / KR.MUTE X Y", + " GET/SET MUTE STATE", + " FOR CHANNEL X", + "KR.TRMUTE X", + " TOGGLE MUTE STATE", + " FOR CHANNEL X", + "KR.CLK X", + " ADVANCE THE CLOCK", + " FOR CHANNEL X", + " (MUST BE ENABLED!)", + "ME.PRE / ME.PRE X", + " RETURN/LOAD CURRENT PRESET", + "ME.SCALE / ME.SCALE X", + " GET/SET CURRENT SCALE", + "ME.PERIOD / ME.PERIOD X", + " GET/SET CLOCK PERIOD", + "ME.STOP X", + " STOP CHANNEL X (0 = ALL)", + "ME.RES X", + " RESET CHANNEL X (0 = ALL)", + " ALSO USED AS START", + "ME.CV X", + " GET CV FOR CHANNEL X", + "LV.PRE / LV.PRE X", + " RETURN/LOAD CURRENT PRESET", + "LV.RES X", + " RESET (0 ON NEXT CLK, 1 NOW)", + "LV.POS / LV.POS X", + " GET/SET CURRENT POSITION", + "LV.L.ST / LV.L.ST X", + " GET/SET LOOP START", + "LV.L.LEN / LV.L.LEN X", + " GET/SET LOOP LENGTH", + "LV.L.DIR / LV.L.DIR X", + " GET/SET LOOP DIRECTION", + "LV.CV X", + " GET CV FOR CHANNEL X", + "CY.PRE / CY.PRE X", + " RETURN/LOAD CURRENT PRESET", + "CY.RES X", + " RESET CHANNEL X (0 = ALL)", + "CY.POS X / CY.POS X Y", + " GET/SET POSITION OF CHANNEL", + " X = 0 TO SET ALL", + " POSITION BETWEEN 0-255", + "CY.REV X", + " REVERSE CHANNEL X (0 = ALL)", + "MID.SLEW T", + " SET PITCH SLEW TIME", + " TO T IN MS", + "MID.SHIFT X", + " SHIFT PITCH BY TT PITCH X", + " (E.G. N 6, V -1)", + "ARP.HLD X", + " 0 DISABLES KEY HOLD", + " OTHER VALUES ENABLE", + "ARP.STY X", + " SET ARP STYLE (0-7)", + "ARP.GT V G", + " SET GATE LENGTH FOR VOICE V", + " TO G (0-127, SYNCED TO CLK)", + "ARP.SLEW V T", + " SET SLEW TIME FOR VOICE V", + " TO T IN MS", + "ARP.RPT V N S", + " SET VOICE PATTERN REPEAT", + " FOR VOICE V TO N TIMES", + " SHIFTED BY S SEMITONES", + "ARP.DIV V D", + " SET VOICE CLOCK DIVISOR", + " FOR VOICE V TO D (1-32)", + "ARP.FIL V F", + " SET VOICE EUCLIDEAN FILL", + " 1 FOR STRAIGHT CLOCK (1-32)", + "ARP.ROT V R", + " SET VOICE EUCLIDEAN", + " ROTATION (-32, 32)", + "ARP.ER V F D R", + " SET ALL EUCLIDEAN RHYTHM", + "ARP.RES V", + " RESET VOICE CLOCK/PATTERN", + " ON NEXT CLOCK TICK", + "ARP.SHIFT V X", + " SHIFT VOICE CV BY TT PITCH", + " (E.G. N 6, V -1)"}; + +#define HELP13_LENGTH 39 +const char* help13[HELP13_LENGTH] = { + "13/14 JUST FRIENDS", + " ", + "JF.TR X Y", + " TRIGGER CHANNEL X (0 = ALL)", + " WITH STATE Y (1 ON, 0 OFF)", + "JF.RMODE X", + " SET RUN STATE OF JF", + " (0 = OFF, NON-ZERO = ON)", + "JF.RUN X", + " SEND X TO RUN INPUT", + " (V -5 TO V 5)", + "JF.SHIFT X", + " TRANSPOSE JF BY X", + "JF.VTR X Y", + " LIKE JF.TR WITH VOLUME CTRL", + " (V 0 TO V 5)", + "JF.TUNE X Y Z", + " ADJUST TUNING OF CHANNEL X", + " SET NUMERATOR TO Y", + " SET DENOMINATOR TO Z", + "JF.MODE X", + " NON-0 FOR ALTERNATE MODES", + "JF.VOX X Y Z", + " CREATE NOTE AT CHANNEL X", + " Y = PITCH, Z = VELOCITY", + "JF.NOTE X Y", + " ALLOCATED NOTE SEQUENCING", + " X = PITCH, Y = VELOCITY", + "JF.GOD X", + " REDEFINE C3 TO GOD NOTE", + " (0: A=440HZ, 1: A=432HZ)", + "JF.TICK X", + " SET TIMEBASE OF GEODE", + " 1-48 TICKS PER MEASURE", + " 49-255 BEATS PER MINUTE", + "JF.QT X", + " SET QUANTIZATION", + " 0 = NO QUANTIZATION", + " 1-32 SETS SUBDIVISION"}; + +#define HELP14_LENGTH 16 +const char* help14[HELP14_LENGTH] = { + "14/14 W/", + " ", + "WS.PLAY X", + " SET PLAYBACK STATE AND DIR", + " 0 = STOP, 1 = FWD, -1 = REV", + "WS.REC X", + " SET RECORDING MODE", + " 0 PLAYBACK ONLY, 1 OVERDUB", + " -1 OVERWRITE" + "WS.CUE X", + " MOVE TO CUEPOINT (RELATIVE)", + " 0 RETRIGGER CURRENT CUE", + " 1 JUMP TO NEXT CUE", + " -1 JUMP TO PREV CUE", + "WS.LOOP X", + " SET LOOP STATE ON/OFF"}; + //////////////////////////////////////////////////////////////////////////////// // Help mode /////////////////////////////////////////////////////////////////// const char** help_pages[HELP_PAGES] = { help1, help2, help3, help4, help5, help6, help7, help8, help9, help10, - help11 }; + help11, help12, help13, help14 }; const uint8_t help_length[HELP_PAGES] = { HELP1_LENGTH, HELP2_LENGTH, HELP3_LENGTH, HELP4_LENGTH, HELP5_LENGTH, HELP6_LENGTH, HELP7_LENGTH, HELP8_LENGTH, HELP9_LENGTH, HELP10_LENGTH, - HELP11_LENGTH + HELP11_LENGTH, HELP12_LENGTH, HELP13_LENGTH, HELP14_LENGTH }; static uint8_t page_no; From dc8d610bf1b2f9fde8877e637195d32c6b493569 Mon Sep 17 00:00:00 2001 From: Mirko Date: Tue, 7 Aug 2018 21:26:00 +0200 Subject: [PATCH 107/117] Updated number of help-pages Forgot to update the number of help pages above. --- module/help_mode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/help_mode.c b/module/help_mode.c index e590430e..eefd3c91 100644 --- a/module/help_mode.c +++ b/module/help_mode.c @@ -15,7 +15,7 @@ //////////////////////////////////////////////////////////////////////////////// // Help text /////////////////////////////////////////////////////////////////// -#define HELP_PAGES 11 +#define HELP_PAGES 14 #define HELP1_LENGTH 59 const char* help1[HELP1_LENGTH] = { "1/14 HELP", From d75bd53825ba3ce194f19e566049ff4c18617b7c Mon Sep 17 00:00:00 2001 From: Mirko Date: Tue, 7 Aug 2018 21:28:50 +0200 Subject: [PATCH 108/117] added missing commas And another thing I missed on first inspection :) --- module/help_mode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/help_mode.c b/module/help_mode.c index eefd3c91..a5de497e 100644 --- a/module/help_mode.c +++ b/module/help_mode.c @@ -641,7 +641,7 @@ const char* help12[HELP12_LENGTH] = { "KR.L.ST X Y", " GET LOOP START FOR", " TRACK X, PARAM Y", - "KR.L.ST X Y Z" + "KR.L.ST X Y Z", " LOOP START FOR", " TRACK X, PARAM Y TO Z", "KR.L.LEN X Y", @@ -793,7 +793,7 @@ const char* help14[HELP14_LENGTH] = { "WS.REC X", " SET RECORDING MODE", " 0 PLAYBACK ONLY, 1 OVERDUB", - " -1 OVERWRITE" + " -1 OVERWRITE", "WS.CUE X", " MOVE TO CUEPOINT (RELATIVE)", " 0 RETRIGGER CURRENT CUE", From b7b3c681a6ad77369470b410cfb8f57c2252ca92 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Tue, 7 Aug 2018 19:33:59 -0700 Subject: [PATCH 109/117] combine jf and w/ help pages --- module/help_mode.c | 47 +++++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/module/help_mode.c b/module/help_mode.c index a5de497e..d0f8c2df 100644 --- a/module/help_mode.c +++ b/module/help_mode.c @@ -15,10 +15,10 @@ //////////////////////////////////////////////////////////////////////////////// // Help text /////////////////////////////////////////////////////////////////// -#define HELP_PAGES 14 +#define HELP_PAGES 13 #define HELP1_LENGTH 59 -const char* help1[HELP1_LENGTH] = { "1/14 HELP", +const char* help1[HELP1_LENGTH] = { "1/13 HELP", "[ ] NAVIGATE HELP PAGES", "UP/DOWN TO SCROLL", " ", @@ -79,7 +79,7 @@ const char* help1[HELP1_LENGTH] = { "1/14 HELP", "SHIFT-2|SHOW/HIDE TURTLE" }; #define HELP2_LENGTH 13 -const char* help2[HELP2_LENGTH] = { "2/14 VARIABLES", +const char* help2[HELP2_LENGTH] = { "2/13 VARIABLES", " ", "X, Y, Z|GENERAL PURPOSE", "T|USE FOR TIME", @@ -94,7 +94,7 @@ const char* help2[HELP2_LENGTH] = { "2/14 VARIABLES", "Q.AVG|AVERAGE OF ALL Q" }; #define HELP3_LENGTH 26 -const char* help3[HELP3_LENGTH] = { "3/14 PARAMETERS", +const char* help3[HELP3_LENGTH] = { "3/13 PARAMETERS", " ", "TR A-D|SET TR VALUE (0,1)", "TR.TIME A-D|TR PULSE TIME", @@ -122,7 +122,7 @@ const char* help3[HELP3_LENGTH] = { "3/14 PARAMETERS", "LAST N|GET SCRIPT LAST RUN" }; #define HELP4_LENGTH 11 -const char* help4[HELP4_LENGTH] = { "4/14 DATA AND TABLES", +const char* help4[HELP4_LENGTH] = { "4/13 DATA AND TABLES", " ", "ALL PARAMS HAVE 16B RANGE", "-32768 TO 32767", @@ -135,7 +135,7 @@ const char* help4[HELP4_LENGTH] = { "4/14 DATA AND TABLES", "EXP X|EXPO LOOKUP" }; #define HELP5_LENGTH 56 -const char* help5[HELP5_LENGTH] = { "5/14 OPERATORS", +const char* help5[HELP5_LENGTH] = { "5/13 OPERATORS", " ", "RAND A|RANDOM 0 - A", "RRAND A B|RANDOM A - B", @@ -193,7 +193,7 @@ const char* help5[HELP5_LENGTH] = { "5/14 OPERATORS", "TR.PULSE X|PULSE TR X" }; #define HELP6_LENGTH 31 -const char* help6[HELP6_LENGTH] = { "6/14 PRE :", +const char* help6[HELP6_LENGTH] = { "6/13 PRE :", " ", "EACH PRE NEEDS A : FOLLOWED", "BY A COMMAND TO OPERATE ON", @@ -226,7 +226,7 @@ const char* help6[HELP6_LENGTH] = { "6/14 PRE :", "BREAK|STOP EXECUTION" }; #define HELP7_LENGTH 37 -const char* help7[HELP7_LENGTH] = { "7/14 PATTERNS", +const char* help7[HELP7_LENGTH] = { "7/13 PATTERNS", " ", "// DIRECT ACCESS", "P A|GET VAL AT INDEX A", @@ -264,7 +264,7 @@ const char* help7[HELP7_LENGTH] = { "7/14 PATTERNS", "P.-W A B C D", " |DEC AND WRAP TO C..D" }; #define HELP8_LENGTH 135 -const char* help8[HELP8_LENGTH] = { "8/14 GRID", +const char* help8[HELP8_LENGTH] = { "8/13 GRID", " ", "G.RST|RESET EVERYTHING", "G.CLR|CLEAR ALL LEDS", @@ -400,7 +400,7 @@ const char* help8[HELP8_LENGTH] = { "8/14 GRID", "G.GFDR.RN group min max", " SET FADER RANGE FOR .V" }; #define HELP9_LENGTH 17 -const char* help9[HELP9_LENGTH] = { "9/14 TURTLE", +const char* help9[HELP9_LENGTH] = { "9/13 TURTLE", " ", "// CRAWLS TRACKER DATA", "@|GET/SET DATA", @@ -419,7 +419,7 @@ const char* help9[HELP9_LENGTH] = { "9/14 TURTLE", "@SHOW 1/0|DISPLAY < ON TRACKER" }; #define HELP10_LENGTH 36 -const char* help10[HELP10_LENGTH] = { "10/14 TELEX INPUT", +const char* help10[HELP10_LENGTH] = { "10/13 TELEX INPUT", " ", "TI.PARAM X|(TI.PRM)", " GET KNOB VALUE", @@ -458,7 +458,7 @@ const char* help10[HELP10_LENGTH] = { "10/14 TELEX INPUT", #define HELP11_LENGTH 164 const char* help11[HELP11_LENGTH] = { - "11/14 TELEX OUTPUT", + "11/13 TELEX OUTPUT", " ", "TO.TR X Y", " SET TR VALUE (0/1)", @@ -625,7 +625,7 @@ const char* help11[HELP11_LENGTH] = { #define HELP12_LENGTH 115 const char* help12[HELP12_LENGTH] = { - "12/14 ANSIBLE", + "12/13 ANSIBLE", " ", "KR.PRE / KR.PRE X", " RETURN/LOAD CURRENT PRESET", @@ -681,7 +681,7 @@ const char* help12[HELP12_LENGTH] = { "LV.PRE / LV.PRE X", " RETURN/LOAD CURRENT PRESET", "LV.RES X", - " RESET (0 ON NEXT CLK, 1 NOW)", + " RESET (0 ON NEXT CLK,1 NOW)", "LV.POS / LV.POS X", " GET/SET CURRENT POSITION", "LV.L.ST / LV.L.ST X", @@ -697,7 +697,7 @@ const char* help12[HELP12_LENGTH] = { "CY.RES X", " RESET CHANNEL X (0 = ALL)", "CY.POS X / CY.POS X Y", - " GET/SET POSITION OF CHANNEL", + " GET/SET CHANNEL POSITION", " X = 0 TO SET ALL", " POSITION BETWEEN 0-255", "CY.REV X", @@ -741,9 +741,9 @@ const char* help12[HELP12_LENGTH] = { " SHIFT VOICE CV BY TT PITCH", " (E.G. N 6, V -1)"}; -#define HELP13_LENGTH 39 +#define HELP13_LENGTH 53 const char* help13[HELP13_LENGTH] = { - "13/14 JUST FRIENDS", + "13/13 JUST FRIENDS & W/", " ", "JF.TR X Y", " TRIGGER CHANNEL X (0 = ALL)", @@ -757,7 +757,7 @@ const char* help13[HELP13_LENGTH] = { "JF.SHIFT X", " TRANSPOSE JF BY X", "JF.VTR X Y", - " LIKE JF.TR WITH VOLUME CTRL", + " LIKE JF.TR WITH VOLUME CTR", " (V 0 TO V 5)", "JF.TUNE X Y Z", " ADJUST TUNING OF CHANNEL X", @@ -781,12 +781,7 @@ const char* help13[HELP13_LENGTH] = { "JF.QT X", " SET QUANTIZATION", " 0 = NO QUANTIZATION", - " 1-32 SETS SUBDIVISION"}; - -#define HELP14_LENGTH 16 -const char* help14[HELP14_LENGTH] = { - "14/14 W/", - " ", + " 1-32 SETS SUBDIVISION", "WS.PLAY X", " SET PLAYBACK STATE AND DIR", " 0 = STOP, 1 = FWD, -1 = REV", @@ -808,11 +803,11 @@ const char* help14[HELP14_LENGTH] = { const char** help_pages[HELP_PAGES] = { help1, help2, help3, help4, help5, help6, help7, help8, help9, help10, - help11, help12, help13, help14 }; + help11, help12, help13 }; const uint8_t help_length[HELP_PAGES] = { HELP1_LENGTH, HELP2_LENGTH, HELP3_LENGTH, HELP4_LENGTH, HELP5_LENGTH, HELP6_LENGTH, HELP7_LENGTH, HELP8_LENGTH, HELP9_LENGTH, HELP10_LENGTH, - HELP11_LENGTH, HELP12_LENGTH, HELP13_LENGTH, HELP14_LENGTH + HELP11_LENGTH, HELP12_LENGTH, HELP13_LENGTH }; static uint8_t page_no; From f880f75893729bfe1482f87146bfa31508a88ed3 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Wed, 8 Aug 2018 19:37:34 -0700 Subject: [PATCH 110/117] updates for docs --- CHANGELOG.md | 1 + docs/advanced.md | 60 +++++++++++++++++++++++------------- docs/img/gridvisualizer.jpg | Bin 0 -> 163507 bytes docs/ops/hardware.toml | 10 +++++- docs/ops/telex_o.toml | 4 +-- utils/cheatsheet.py | 2 +- 6 files changed, 51 insertions(+), 26 deletions(-) create mode 100644 docs/img/gridvisualizer.jpg diff --git a/CHANGELOG.md b/CHANGELOG.md index 8636e1db..65837680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - **NEW**: new Telex ops: TO.CV.CALIB, TO.ENV - **NEW**: new Kria ops: KR.CV, KR.MUTE, KR.TMUTE, KR.CLK, ME.CV - **NEW**: new aliases: $, RND, RRND, WRP, SCL +- **NEW**: telex, ansible, just friends, w/ added to the help screen - **FIX**: i2c initialization delayed to account for ER-301 bootup - **FIX**: last screen saved to flash - **FIX**: knob jitter when loading/saving scenes reduced diff --git a/docs/advanced.md b/docs/advanced.md index f4a8d8db..0d10ab5b 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -73,7 +73,7 @@ IF X: CV 1 N 60; TR.P 1 IF Y: TR.P 1; TR.P 2; TR.P 3 ``` -Sub commands can also be used with `L`, though due to (current) limitations on how many separate numbers, `OP`s and `MOD`s are allowed in a single command this can be tricky (even if you can fit the text on a line). +Sub commands can also be used with `L`. ## Aliases @@ -110,7 +110,7 @@ Aliases are entirely optional, most `OP`s do not have aliases. Consult the `OP` ## Avoiding non-determinism -Although happy accidents in the modular world are one of it's many joys, when writing computer programs they can be incredibly frustrating. Here are some small tips to help keep things predictable (when you want to them to be): +Although happy accidents in the modular world are one of it's many joys, when writing computer programs they can be incredibly frustrating. Here are some small tips to help keep things predictable (when you want them to be): 1. **Don't use variables unless you need to.** @@ -137,25 +137,41 @@ done with scripts you can dynamically change these interfaces at any point - you could even create a dynamic interface that reacts to the scene itself or incoming triggers or control voltages. -It's hard to describe what can be done as there are so many different ways you -can use it. You can simply use grid as an LED display to visualize your scene. -Or make it into an earthsea style keyboard. You can create sequencers, or -control surfaces to control other sequencers. - -There are many grid operators intended to simplify building very complex +You can simply use grid as an LED display to visualize your scene. Or make it +into an earthsea style keyboard. You can create sequencers, or control surfaces +to control other sequencers. The grid operators simplify building very complex interfaces, while something simple like a bank of faders can be done with just -two lines of scripts (and can be just as useful!). - -As you can't have both keyboard and grid connected at the same time, the Grid -Visualizer is provided in Live screen so you can see exactly what it will look -like on the actual grid. You can even use it to emulate grid presses so you can -test your scene too. As a matter of fact, it's entirely possible to use grid -scenes without a grid just by using the Visualizer. - -If you don't feel like creating your own interfaces you can take advantage of -the Grid Control mode. It allows you to use grid to trigger and mute scripts, -edit variables and tracker values, save and load scenes, and more. +two lines of scripts. + +Grid integration consists of 3 main features: grid operators, Grid Visualizer, +and Grid Control mode. Grid operators allow you to draw on grid or create grid +controls, such as buttons and faders, that can trigger scripts when pressed. +As with any other operators you can execute them in Live screen or use them in +any of your scripts. + +Grid Visualizer provides a virtual grid within the Teletype itself: + +![Teletype command terminology](img/gridvisualizer.jpg) + +It can be very useful while developing a script as you don't have to switch +between the grid and the keyboard as often. To turn it on navigate to Live +screen and press `Alt-G` (press again to switch to Full View / turn it off). +You can also emulate button presses, which means it can even be used as an +alternative to grid if you don't have one, especially in full mode - try it +with one of the many [grid scenes](https://github.com/scanner-darkly/teletype/wiki/CODE-EXCHANGE) +already developed. For more information on how to use it please refer to +[the Grid Visualizer documentation](https://github.com/scanner-darkly/teletype/wiki/GRID-VISUALIZER). + +Grid Control Mode is a built in grid interface that allows you to use grid to +trigger and mute scripts, edit variables and tracker values, save and load +scenes, and more. It's available in addition to whatever grid interface you +develop - simply press the front panel button while the grid is attached. It can +serve as a simple way to use grid to control any scene even without using grid +ops, but it can also be very helpful when used together with a scripted grid +interface. For more information and diagrams please refer to +[the Grid Control documentation](https://github.com/scanner-darkly/teletype/wiki/GRID-CONTROL-MODE), + +If you do want to try and build your own grid interfaces +[the Grid Studies](https://github.com/scanner-darkly/teletype/wiki/GRID-INTEGRATION) +is the best place to start. -As there are many topics to cover, the best way to start learning Grid -integration is by following -[the Grid Studies](https://github.com/scanner-darkly/teletype/wiki/GRID-INTEGRATION). diff --git a/docs/img/gridvisualizer.jpg b/docs/img/gridvisualizer.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b999c7437085931bdd5cf54518096523c82aeaf2 GIT binary patch literal 163507 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 z

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 M`0O+%{NLjL03MkqCjbBd literal 0 HcmV?d00001 diff --git a/docs/ops/hardware.toml b/docs/ops/hardware.toml index 444ecc60..24f73bda 100644 --- a/docs/ops/hardware.toml +++ b/docs/ops/hardware.toml @@ -75,6 +75,10 @@ description = """ 7. Call IN and confirm that the result is 16383 """ +["IN.CAL.RESET"] +prototype = "IN.CAL.RESET" +short = "Reset the input CV calibration" + ["PARAM.CAL.MIN"] prototype = "PARAM.CAL.MIN" short = "Reads the Parameter Knob minimum position and assigns a zero value" @@ -86,13 +90,17 @@ description = """ ["PARAM.CAL.MAX"] prototype = "PARAM.CAL.MAX" -short = "Reads the Paramter Knob maximum position and assigns the maximum point" +short = "Reads the Parameter Knob maximum position and assigns the maximum point" description = """ 4. Turn the knob all the way to the right 5. Execute PARAM.CAL.MAX from the live terminal 6. Call PARAM and verify that the result is 16383 """ +["PARAM.CAL.RESET"] +prototype = "PARAM.CAL.RESET" +short = "Resets the Parameter Knob calibration" + ["TR"] prototype = "TR x" prototype_set = "TR x y" diff --git a/docs/ops/telex_o.toml b/docs/ops/telex_o.toml index 52936be4..18a423f5 100644 --- a/docs/ops/telex_o.toml +++ b/docs/ops/telex_o.toml @@ -325,7 +325,7 @@ prototype = "TO.OSC.FQ x y" short = "targets oscillation for CV output `x` to frequency `y` with the portamento rate determined by the `TO.OSC.SLEW` value; `y` is in Hz; a value of `0` disables oscillation; `CV` amplitude is used as the peak for oscillation and needs to be `> 0` for it to be perceivable" ["TO.OSC.FQ.SET"] -prototype = "TO.OSC.FQ x y" +prototype = "TO.OSC.FQ.SET x y" short = "sets oscillation for CV output `x` to frequency `y` (ignores `CV.OSC.SLEW`); `y` is in Hz; a value of `0` disables oscillation; `CV` amplitude is used as the peak for oscillation and needs to be `> 0` for it to be perceivable" ["TO.OSC.LFO"] @@ -386,7 +386,7 @@ description = """ ["TO.OSC.WAVE"] prototype = "TO.OSC.WAVE x y" -short = "set the waveform for output `x` to `y`; `y` values range `0-4999`; values translate to sine (0), triangle (1000), saw (2000), pulse (3000), or noise (4000); oscillator shape between values is a blend of the pure waveforms" +short = "set the waveform for output `x` to `y`; `y` values range `0-4500`. There are 45 different waveforms, values translate to sine (0), triangle (100), saw (200), pulse (300) all the way to random/noise (4500); oscillator shape between values is a blend of the pure waveforms" ["TO.OSC.RECT"] prototype = "TO.OSC.RECT x y" diff --git a/utils/cheatsheet.py b/utils/cheatsheet.py index f392a09a..af12e13e 100755 --- a/utils/cheatsheet.py +++ b/utils/cheatsheet.py @@ -57,7 +57,7 @@ def inject_latex(value): ("delay", "Delay", False), ("stack", "Stack", False), ("queue", "Queue", False), - ("turtle", "Turtle", False), + ("turtle", "Turtle", True), ("grid", "Grid", True), ("ansible", "Ansible", False), ("whitewhale", "Whitewhale", False), From 8f0629d84b25b54857d391effafa05227320ea9c Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 9 Aug 2018 18:38:07 -0700 Subject: [PATCH 111/117] more fixes for docs --- docs/advanced.md | 2 +- docs/img/gridvisualizer.jpg | Bin 163507 -> 73042 bytes docs/ops/hardware.toml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/advanced.md b/docs/advanced.md index 0d10ab5b..6c360d71 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -151,7 +151,7 @@ any of your scripts. Grid Visualizer provides a virtual grid within the Teletype itself: -![Teletype command terminology](img/gridvisualizer.jpg) +![Grid Visualizer](img/gridvisualizer.jpg) It can be very useful while developing a script as you don't have to switch between the grid and the keyboard as often. To turn it on navigate to Live diff --git a/docs/img/gridvisualizer.jpg b/docs/img/gridvisualizer.jpg index b999c7437085931bdd5cf54518096523c82aeaf2..df49b3a1279575713bec608d96b623123c3bebd8 100644 GIT binary patch literal 73042 zcmbrkWl$X44==n(ahDc%U93QHcelm0#bI$R4yCxWXmMW_cXyZKi(B#H#VHiH&;QQ6 zGw=7C^XW`-emQ3{ndBsSTY38hz*Cl2k_R9lAOIBqTY$H9fXx4P|4;NkkpCxu{~dno z1K^_pCJ??MAl5#ELX)Bpei(!2lIfd7xsQPD7vkl&$TA_D#=ppN&S!2cx# z6eMI6G$eEc#Q(AJQPF4t1l;I^QbcrG#2D}CdCc9Uza@WQU<8ry7S_+rlQMmh(YAo} z%UbU6xrY`vEbRWd`VWs10f2yv^#9WbKtlWv4uF7)hW;O03?G1qh=_pr4iOm{2@Meu z3Gjc_;iC}H0#FHwxap+Oh_%fB)8_WA@XrTc>E!zUxgCZpMj7|e`L{Iy781gLZ$rWd zNB|O|@a(2x3&A>xXpBox&2lq{}i$L=If{dh#e7(ZAAL6O%fA&qOeqHU?a ze8xsUr>pXR&YW~+VFY@yJd&zQYVQ9^*aFa#{<~RL?T&krdUD$8R9hb@FcEPnUUKfN zRCYXh@op5p?EQXoN~|oa6@*adC7&000#N7!^7av*QDr$EGihULo|+(;)N%_WvT$_})wl zig`id!HU#s9cfTE<*$z3#)Mzi7Sn0fPkM33k- zq<&lGiC;OMqMBI5oKIFTRw8usl*i{!K3o~P<;I5_F_Bc?nc3^K z{EOV#ClMJSB^D&5Vu}f*9U;j03q5;%^_il1<_D@?whgo4_K2S6GL)=hata<#guCK$ z%>i*=Y(?Jy0j}u(-ThzwpG3$Afqvg(zkc#Hju6ehmF*Gz)tuh8ZE1Ryqx4F{#gt@s zl}HWcrD3J!uhFK@7438s6)N_=%cVu0Ea#<>nzcLk)nJCeK}z;)ggJ`ANvL;}%zO?VyHRc;Yg?Q!BSB+p4oLamgQa}C0+4uOsi<4O;XZ4U| z#V1ex)DmVhVZ`TXs-a)e@h)V7Qk4+Vi0^Y@=Re2s5f6x223ZrMfO(t>19E{?e23>c zM|Gggg+?&oSdCR|SP~&6^rMCgGsN9h6n}4&xfT+(*NGsB-~XqE7b3o4`z@d5OTew` zSBKyERnJOu#*rqR-C7I&S>K$Li)C^Z3YhAE&OvRbs`6gnIeFd2tev4-7a$&y7#}27 zoWU2M7j=-{)VZgjaHO?iy<^M)Fq)rlJ|?k~`=nD{aB?o~9hAVx?vqTRIZ%iaTDW|( zJaHPJd?frmbI)p5hl`W{(2lXz{@szCmP6Yu^1-AA-bz%>KDko>Yuktu*J!*S568GA z&nV7py3}>wo##v9c3`3lqB)$HrIKWZvg->2L|)_@@;~Z6hTvec@e#B!R)BBc)i}wo zSH)it9t98`Jb3kVIbN`ibN$-8!CpAp!% z#3OEx87bIG|fQ)7v2ph?oaO4#|IMpmanWB#&~;S9d=QDO<@2x!?wlt%e;>uq8$8J~ihE{$e@%Z@ z9-d$2S;kK;?WK~lWp)Dxt3q(MQf+B$aRYe{NUBxG0KobUVJmyhkOd{{Lw#;B*p{&4@g+DA%6 zg|V~UyEGqTr3JT|($ai7&4q!xbU;5-hxJ6V=-b+A_8;HTgi6gwJ-hphcHB?3ousc{ z7)L~YZev|k#%5psU8Mi}qT&~rJULe}5G{c58wc(FulrQ4raWP4yqoojE#IIeu4oS| z8}J>F*Q#o{@&aj486}>vZmS9ngI+P@H$=r78E2w*#DipP-WYCOO95e5JR6fy+*}Mw z7aK!8ug&l2;@NMg3I)kaA%}(dt0OQUjU5T@CHU234jrA-P+WU_8y%yc$)_Kmq27f! zaoxM!9Xi@g$Ggtc-f@g-Dyg|CE2U{X?GxjZ58z1?p^Ci$1oz{`Zk~e7o{2jh{e^Ek zo&5Wsx3)}&QLO8jBIrh)HRd@*3;9~c{5K{-Bw5e@j`iD)biG^`XW0@axFy)eP9B!3 z5R_v47lh{EpnDR(S-N~B;vW$YrNZRP;cI)OU4h=s;IO)7tQc$eT$*+SR2$}YVbssT z3w^t)jKtxDN$BSqq!d(T&=kH!d^CCTWOTyHCU#jWx~5NRLOxYKn2ROb_!Hc)_g$Z3FTc2 zz-dxj_ES6IoII~ozwCBdr@H*^wE=Q!n{!Ij2^#|yezf9Pr8XK=)aESlE^d}BH6hBU zqY0wzDj&0X1B74YEPVKy#8>%A`vY17d$yO#(;vh?K(EnbMdK6l-@?p;#lyVZdJi62 zX>7L)5g?sfm2dN#31cFZO&URO04k&n5n+=O#C0I+A9VSTLi=uG5~ulb9*e9kap@i# z;~MKZFhTK;8puJe8b>qQz!luHzoVNGo9t6Q!TRMb1Dw5Z%|(P$aH*Cb*_SaLlWvZV zRGVDmSm|^EG6b4m<$3CJ-HEI7iLI3FC;ZK$OJKgCO0ul1it_5UM%c8fZ5w}!acW0g zNujw4hLpB71I|KRDC6kIDFys-0qURpq9y0{iEA@NbpRE2E`jd`x=e()X-Zv zLi_50DoCPSk2fWGR2296_wa9ADBoU(!G~(_R*&N|Cr7byxO{4M8XqDwCuh53VG76# zw&z|a!PG7xN=e>a+JoiA2`8G{-<_6&mtNSbWE(mB78m(5REP};trd!ChdYVG{SmOo zg4bzFMZ&N`YT|l)e7#f{KKfE=sMnY}>X+Ycu~`>4+R6Qvo=*CtJnvV3>+}ZLGi~W& zxT>nE%jVYp8mT%UXLqYB0AFJ#2|pH@f9a%d4f)b?4f%+oj#ww9@se|tbCf>~I9XWf z*Hjv3@TI|%BpKa|`}>!f`uonK;~T(wnd+)mq-DD0QpJ11Z?0vtopHL&a?(#U^IX+} zHeoCxoRu@JhvGsHk031|M3^SQk8t~SW5(9aPlfd{Ud44Z_I*9=A{_&vkTn_xhWM^R z;|2&(Kkk=L_Kfe$!6@;>RQSxb-^#ygpVLV(CAO`!qJ;U#ZzX<<)=}&+x~UnD%vN}k z_Qr_^HPS6WxUadzL<4HH3=gHC<}^v#+;d=J2u2wkU0UAlMIM*JHZd+Am1OitOdE^9 z_x$`QEcuZ+k@Sd4K@?#$!@sq=N{{ai;5v8zqS0Y@Kc)M(`4MHeLOz);Gi_Gqn$plb zyya0g(dyY?-!?yGPRwDprsuY7Cw{?RW2wWUl-sCm(p$@0HGGtVN#YdYpgN7=p@6v) z^&KlcrO1As+h5-yPPxSWfEaeK@p8G81VRNy>v+=1Dt<%QLS6F6p%BVuYADp9mJAv) zu^l(52TMk-Mt1=*yn=tHK5cr-kB&Ulp?drRz*6>cX^uifE%(M=LvT+t0C!6EeKgRx zxIZ|Of9XSnP^W`u#6&8K9f{feJuB9pTdg_O)X2hd`rQ9m5RR9kmQFiUpG08f<77@{ zAjNzc$Iw)w`X%vIc8R%2BoTh%nep(sOp9rLUpeO1UPp5%@&iQ!9^ODrsxZ+TpgTRu z7`WH;6@n`_?c3WYIAqZ7VR!(gvZVOo=%!36A|K$Hi@@;?rfx}LHTJ#CIf7CKEFQqr zg30VvrhKPb))m3303-7p6S#eG?i5QLbsp^v!6-2|-8h;Sq@f7Xpck6Cdjp7fabO5e zC;|}0QE;TDHAXzfB*eKF<~K*+*5{VSn{z(|!iDc38$hgnSMB3V?VZ}Ymf2l$Rec*Z z5ANp>L)@1~WaOhz=j9?|Dn9;b@uSV@Tw@5EX9b5Y(Ni~pC^~kd0rceyi|Tp{Fc&Pu zm?j)C@V+N#;r{MNtx!Ps-paH@#)NI0j*u$BTEE(R0cQKlHwSDzfzdvAa>xmRvLTdB!Qo!5`y24f%+ARdBrPgYDWtEl<(gmf`SamAyOlf zq|~U1V*bkN%I<}E@)~OjBOdvqdnv!%{pi;ZRzkh)UUOQhwe7Qhe9-)TQ!xhx{XQuh zi5U{ewnl&kYr_Qi2oML$eVa>Z1!<}%ZqGdZ=lLgkn?%(4AU7L#&1GjN932(=Mr!?X zk=Pus$lPKVqo8rif~E8sLX)V6!81{ z(M@Vf-okrtCXGb4sjVy9KuG#Eqlx57XY2Izo!9xy;)D3ds|{$k;ErkF%J+>lURgY8 zKMljAIyJk?r`DRM<&ZyR$^ZZ&+RWIsFA@!bL0O>~{F)+~G{YzV_&?N&0 zhS9u`;b~ES>oX8c`Gen z0#XDd$B*(vyLY36iw&2r8A#?a#U~5E10@eoHDoSr&m@A8h^_7VG#(Rhf<^zn_Tjj_ zXiSTGSF!>D<$pyJB|;Qta$JR8yA>yLe?K=r_h3&P<~hG)zcxB+u`P}h`J1IlRw_Gl z0C{VgZp#WxcqlAHBel*yq;A^@u>xsuinsNlW!YN!=*Tc`CJ7Rb01opEomn6W4Xcz8 z>$DV*^pEN&<_&Mm%_>jQ)w+IZHtu=gKLNL8w}t^u_IQJ+i(#Y=McSlFVDfF=(;tci zf_siH4i0$62rol>(&eKt6r_q||Y4DWgat*~}yJ&L_{l zG%d8mO}=zLdF37>2HirTPl8&Ue&^ePmmH<~&^t|m2F3H6S8C|?07)heGK)701bu`@ z;SC@V%Hwt|L`t1dwG{?Jld%7b1gXkHLoh^*!x4P#R#`R>0~D=gOEiLoErn0J1=4Wx zru>aQc|q;wGrr6%!J%oiC!+kirezI=PQ4a#Qhh(<6q=X;ULT_2toPRE?+~VNtqlmCLx^K99ge9!aQr}hYJdoJ}U>JS|~0(dw&s6sd>e- z-4pItHnF!?qTF`Jz-YV=$NewXN-Y2FC2GLaSc3p)hzZB_N2DGfe2wT^DWLdkgA&UqTNSG1!LxV{n8BvOy>|mBMPc}{_TzvfcRgv#!E~k8y*?8 zeBk@IGdOZ57t3ef`}re*#aXm^>4a>5ay>6g0&=+_G%d`H)g1vVvz?p{4&+t$8z@O6 zUtXDI++?^UD5t4U3Mp=yln9lx#~=mqPTj^G0mSv!ChZK*N{I;FK3kZ@L6VRu($ zNea(C3MKlsP&7eOz)_wC2`bvBIp!$}vnI#Mz{l3Rq{>K2D9n@8siH!|0|=AP*~W4cSHZ_nFI=$E%ChH^6`P zlzjsno?et&Q(r^h0Oi5^rx#FBzCTCh%_+pbm_|Bzpc3kw10f0IKRh3Ur1oHnTMt`* zE;b9#rcpMy)YPA1gEb5VDA=4Ys@5C_%pDsRKPd*To$-S?9vEp$8p2URCJ0jVilQlp znM2(2$Hypw-9`d}xD!Mp-^px@{QB)VMnv|$863_OsS*JvA<8nnahHNhhE0o=*X=5l z7e-ypg@6`Vlu>wukZOnzBQx5?jVon4*9PnJ40Y zD0kx8ZPzP7#UaSv4HiFP)0zSrMbo2n$~Vv&BHiI?;-N1^Bl$64dtWh~7j1X$)Th)E zV-K1crKuIp%&j+Y5G`Iz#Ltnb*_TmhPqmU}-AQSg+=nK@@A=~hM5Yz-qu_xuRVK}T z*(nD=mC7`Rj+=0~Wsy8XMldL~l;y9G5XFH4#N&=*&KakaQj2=&Trc^(4DLwQWb5Y7 z76v{>pltfK^oauj-V;U&Es#wGCTKvPkbN7u6}YQcbHFMKa}YaWQ~)xnj5FFYRE7rk zYQCEMwG56s^8G+F)k9$Xqd#8p%YaT^vr%kfsG^3dH|5Hw7x4M47hGU{u&c+JJgriv zyoG>840I_%3z4BkMqvTa0)YG?Nb5(<`_`zGPAmhdP)&g1M5_P1+xI>#tr5}u1ixeY zW|fo4@RlizNX=YELi%H>9}UkIOXl;Dk4*pG&Ok?2ii3fe2G;va^_$ZCHCWXu>xR?IQ9#AssTOF~RdL6KiFi;lFzC*)O;`4^*uC=x-~T}p~$KIoP28}XRf;4zp(HWn`s+1 zlegG%SfUH`Lc>|KER-l0P$Ps+IT6T!HM%rYIh3w-L|ufjTQ0R?pVjS_#Y2sScR&k5 zGdgp!X?FS*v%fKd=quGU2V$uzNmDs6RYIj?%vCfQzQ^ThXI^6_n*I~HO608in?GD( z=_Xn~&z_nlFqPmrQE@u&V32M?@z%KI0XFe3Yu7!yU3Os07h0CgM=Wg{ zuRs54$tC}UtNsRnUZ8GJ6a2VK>pC}@?(=fbRt@^RD5AA+gqOjhMbGf;vBMfTPX=@& zp+dX)K2FJw0i`Ze&^7WWH(jrW@40O8^$HzrWes(X@s^%sR55`gCul%fMgPsw|%0owlQ_q;xE? zHWJ}NsK?T3ve`7-EL^Qprb9c_W>!~8OlBny=F!}Rh5FHGgl|2C5|L4#U3&Bb!g#-^@u=2mWHRr-Nurf=0c^jwR7HHrJgSz z^g!o2AF^p!R5FL5TB3R)lh8~l!giON>%APk=q#gIjqV?`G*&g117)yxE^OIydh#QH zz8?xnIG~*`iQBu7c1KZ1L9rP8P3@^w-Mzd$vq){sK0ZHj!(v1;k`uV?b9FXh1h}Ah zpp}L8(OBKCUAz?fRcSfJEE*j&e?^ORe#Zpk@3Gz_UM^}@iroNDKqe|NW$HmIT1k*_ zMtfvdjD61;{_QgVxJB}%V(0UL4BthrGJ66WHJkB#rXTupl%a%t4ngdh2`|FvR8Jys zG-`Ln;~*2?cf*g%DX&hhPd)Z-aa$r8a;l$a;Ejf`FM7mcT)um)bX;an88rsqkoNyQ z{%mDz^$-c`cr;EsEcv`pO;-n*(bsq`&~%K)K34Dj>1l7Pd$zP?T@U=~o2)9fyAI7M z)yV)UzI&Z@2OJ3r(qF-8yeAEzl6L{EY&_Bn___V2Txn(W>VjnMawfPB0z@Pep%KQw zb0twK-sP~f&c#hdCyq7pcvqNeDXZL$3FbSeH16=AHXapLEyu_6z3-zk*Wpm3DTAdk z{&!HEE4_|R55GQXZyr1{Dud%x51qT0`1vwlQ(GzAJG% z?P1^2k#=SG8b(gKv&Z986)FOhm^JbTF*XlR$)dq}PRn-|^tDHZW9^KSH|BYcd>uBq z!+D=lKRRG9lKa`WjV`V@Jayu)JRT!<>o&#W29qhFM~fmnH)>#zR2G`x`rx2WD^jH7 zM}hnr^jH_Uv`-UivBBKBuE&-A!!pifeX`0DUp@6wTOd-(of@t)X;f}Y2qK(!o(MB9 zx*PUXlLu1zfdNVBX7}6Ud<_7c{d;^ebYLs4-@T-KTFB#rXpGu72H|FT6At3Y0Qt~3!btq zjptS*pw974*y_z%%7rORnwl2T7s%_Mu1mif+iO7nknUR>j-y}Y+`ZRWL$B3#b~0Sw zkNMnoLb{;zv)WnPQhUtEfpRk(3npcmB$DdRy&mT|!)nZVXW<)_Am7r8b!Od+KQ`Ps z@(T?_8Alnrf^Ukh;i>w*D;Vv*Bm~h<`Yywzv#`EKL@&FYO!rx%Qunwp(+20VlLZYf6)RuW_~+m zKz90ehnsR$&l@b0^_?(Kq$%Fc4VjOB-zubJhq0qLtW@+-Nka6t+OJuB&@BHs+HKTW z8sD~BS?j<5qmnJ@&CTP{6&&}z;}Vur&7H{X z^8S?`x$d^{9@2Kfz=BwdRBN9o;B(s**wysV#xOpm)^^=^tt|b!QQ$f$$iU(~SrCi} zDRHEndT=Ry_GfsVg<<##%(CMp>u!nUD z-D#(-HtQ|Z^NzgvcUpy!j- zV{*;Ab>cg%Oy__)VsxIAr&2L4(Wd0{@`qHU5UIWDqK7ry@_4$Hw#ru1+6uL`+blk1 zsGA7?BacO^Y*=_r*;!lJe{J%(HPCTj(b~&Twlh6R(TfMn@^-BI_b%Lm;ykUi`+^kR z|McWpW@sXo1g={mng}UM{!8EN2DFTdAr1E@EAWQ>(vQozZUP73yDAxqD_(yar9kyE zFZ?=MzvAN_8-N{XgaXQ=PgHLFM!^flR-ByU|e6n@dToY$88{Va!C}~9dMfRtQ<)X*I`#CF<9#T52^|k!cPgZ8&Y)J; zTYc7!OPS@K&1GH=)NW&gccVZz(l8FlqV9}(II?DbHy9QP(59QZtA@>lKn+wQNiobh zYk{nwr#eX#J`UtTWM^X zUPD_=Zr3a6q?PRk2IDj~hJffvPyB7w;-kGF{?F>*eLsDeoOngSlcDo2+`9d&8GU(7 zyBTRM{Q#dR2PuhoP2#~S30DJE@!r0zg7aa|S&>)jrO#6DWm$T1T z5lcfyn;e<_K0XdhAN~d)3U@DD*mhaCgja}Q^ARkI5Ho^=&_Mx4Dqk=j{l-a(E}wg|Z%Ie?ZzsJXf!({t!2F$*5xiso7(O zH7SJbR!=PMeV%YxCvE_lCKyfY%2v_8YQF(k9~Nf$`O&sVM`JRq``UvlcU$@9p}ogk zYQBrl+~h{7ivwc=>k7}AVlc{ajC+h8SC2V_jl&VI8-0O7gXMLjz+8giv;fTul=XbC zk+Q`!_11lDUC}HPyP9E~oeU(k51pnXL?uTB^qTY4hT+vR$|qW2#U*0Xsr3l*G#$>; z=lR=`x`=plp48PqP%1aqNvCv_*4G)0(>H(uE{t%hvS+(P;Y+HH8GH-|Q0PzTuc_<> zgcL~Rk6lo*rSEdLIf%;8YyYgF9I>hF`w%lC^v=ggCT+M;$GbN%?ttZ%7JNK=vH+}f zu=<^=SlD@Ns+96jeQuh(lj?=5EORU<0awAs4fWc1?74HVXa;Q)>=zD;F6fQq z^KO+6>FEv0gPIBPp_b>VEeW*9XY-9E;?yAjzY=0{Mol|)F#%$iXN++|HZO)bd`jXQaPFxEIk@>4lpv|zIt{4a7s!`g#8IWGu??6^K(K9zirt0WOa2@)CQHld&F)b!0C<-WSQkV&81 zZI_E_E*rAG++W~KuUxKr*o(_tdZ|f$&%k0X)=6ox-pH>3tc`4DZPY_!f|7SkA-nle z;>@G1Mm&9J*TmIa{qy`a+I(h?OHGY!wleRur7{D%wjzy`$E3v>O;_2WxBN#+rZ$VR zab`o9c+&2Mv}W2nW}7r?lO2X|mD>uucj$sP6n_pj6?F_KJ-7X*)Y4_iz z{WSh;lT(?N)*q&$2xk1WIh4sL6|RnUd^Yj7iGp6nk@Ixos;)50l+gYuZFjlxmWpUF zthb1);~WTf#Mg%N5S^SAe4TxL7Krjui~+CS&CCcO3Y2bZVZsN-_bw^sH$r*FdhvEF77ZlJ1OC8k zxQYv=SI}oQVbw8%sRrD5zRG%QZhI;+A2mP7a;?&#H^k1G;3^Z&|T;A1-7EqSd^7+T7~q;l=reBtr@&)(rf;`Ytr~>)xPHxcO>hD zBYCw;l+sB}LRy)-XtYwM^OPVRBGG-@iz88wX<-gNTm{MvJ{-qZXY7w&ZQNi;Nnz|2 z$OIcyMCv|j>6(hpBIs!KmFt`VCyYZKGqrtzMv+zfPrg@VjJ&4adW`ghI^h-%L`sk$ z0GHCNtMEInrNHFPVnF}s&CeD+b_P;b?#JKU#@V%wWgM&Mwv?&=(UJ<0I9A!)}x1vOkH2zm>FOd?NUx%PTH*Eip$Bw8w3iqg} z2Sl7l*jGe*BW<(gT)V#6W;iID?5vJ0*%^bPVu)K4S`;8z>u_TJ92bq1v>UqqKrYme zL2~kZ$PYYpiLtrz969Wb?^GAd1>CcBDI2_g%L#}N-eM+YcU@Ho>NgO!CJDu6L z{`pyU?r=Nt1iOMrFukQ^(~F$e$-p8S@24G~EZE6@#g0SHEwNa~pn~>Kb62UyChl{^ zU)=-W@pevVZaHV8nXYn2830%1slD_mvMF`1d0Dd+$()gfLkSSVyPOe>{i=T*L?{4k z%?tG@Y9;#QFlr(GgYiB>o(oGZ%7;X0Hf~rZjn=bQD}T~7R5n8JfIz~CTTJ%%JIt~# zN}6a-iVL0(G*nv@J+H;!Pl1vRx$y2mkN}}!ius&Lv{~^)G-Iq^j;5@G*RU+m38!C* z6+{$P6&&R;xUi~KGjY4Hjf`Psc&WXft>9NwMwOQdV{M&4^*NOq`}F2 zeR5b=sWLV4zMpR@1~oM-#ae(eJ1xO7E{#0B-lY;(7~LE^z-DV;)>CJ9DWluG#~|ww zdCkbzrRr|7goKmgJ8;iJGpG~8tlPl5nKSEr#%tdGD#tp?GpngxlTmwv?cV=2tC+Bx z^|Qx!X0gv=p+9W{N(P3bhLo4Deuz@JnxD_XqS_fqDBy;qCsOevVp$)z(=nz~9Tb-Px+d#m#%f0iE(+3`9pWw9(~65OlF22v5z~ zqv)4JQhHR1Yf-91fr`=cAh^KiViB*o?%GwOYFlF?ibbf0dgn$IFEN*OZShq~`v{O$rdnT=Ay6wqqIX4u}_xhQk)=~r9 z7-w((&rMIPTNoDfH%i;g8+zbGA&FO>m}I~KNkzaP?mkf;i6clr;%J-~U9D2}#CfaU z9h>qeg@E^qJLUSiD0>Z6FBLP*6p0R6XGY)WlYU0lWQ7B(rA(G^tt=u>k}HP7SQrr$ zfH&LuR~wO$GwHPn`-UtZXRSC5zsFiTTV7uwX)SeUI_Rc1SeaJ~sNNSgf=PC(DIgAWISemY$GKI*C$k|p z@6uu+9&N?Cf<-v>J!iYJk8w3sKi+3UZeXh zfj2b?eMImtD(SIGGYS0j6W?!O{II;et)l0c;N-HJ8V)~};HvTpCPFFF{e1~CLrKXO ztOWP_@P<2iRqt#k70^-=qA^elC`g5RL$QZ!mGkA>H+W=I&H0^mw574lgq=JM1Va_&$ad-HyX$=oZaW8^?6VqlGZb#M1u^?X7DIVu zn*6v64N5PqJF`J^3>dc0H2)P3W*1o(-_iZ+g0~bb?(3MKe_S0*XnKODmgIyq0d(`` z13a$-N$BS_p!cajU5gZiD{oEda0;ZwsU2{%SiFIqJj;kSXyH;Rnvz~a}@dMm>2BQ@b?9Wllo{OKWwAf-DAaNj{c(V zEXVm8e@?wBcYjnj6t@@w4X^Hws9;ScnHhV>Ce+w5N{f409JB1Ld3ggVW)Y*vg~--jx1B>>mp$#&R94pCS|mV=u^i!o7!L$CCnLs^DxSva;DjI*#| zi-D%v0F@>LG}Yvc`L%;vqrK3nqT7G&*sC4>_XDqYb4S)Gms;!vQyvVc%UNXECbEQ= z3adL38Y4NeMS67FZwkiAshxoR{roL%`vkXq84rr0+la#<;y@>^-E5oCXrz_PfPzM0is zz&~8py)f>J&((r$hd}3vzhP^oXUEGyrG_T++({CflTtm2Gkp_m+z1?%^l-5kw1BCc zaaj&~R}axiS@^i#Q{hagRJ;0>a|^sI#`GMN!jIf~4%Rp&TvSYc1GF%@X5hFZp(gF+ z^`Z6AD(#i{T0VmJyJRLL1O@q~jfZQEkBGr?8uXys2F;O7I-k|rvDwNI^q^9f+UC_W zuN_inU84&J^dRA{_$;6DO5BGC^s)5+^T)5X8zJHdSMyG+&8aQHyGxfYa4o?XP)$zo zpl*IU+QsV@?u@40?8px9DX}z8FOl>cpd@V|-`AaiiN$ULc3(A)P7qk!cX^IEnxu4! z_I3PZz+Z&R$w5gbIW?_lz?N3ENsCfSq7!+aZv*e6dtT5lKWey|)KXSZt2`V`sl4N2 zq~$qQJqjCwGU{G=iSETDJ+Z=~wC^U26NyKkco2Y-zQ0_?GzLG@TrZFwda3;DjXhY; za6@-Z%O>`=hr}fk4?lds9HfSRegh+k?G zXH>1YPXcSrUs?h@VaDEVPQw_vt%;>I2DN%Ev66{@)z)M*-MF06_pODUbhC9 zuMZFRHN$s}D;Hz_v!wT|vMvOTIk7ba$7cjp>*TH?R^CCM|JNDnaqXu{y7EY5As%af z42LK!oC>AOcQW6;hw|RcD9P2U+-1HnplWk=C%u$qO!tchE_t7fwXbT;G02TaWfSRr) zh&%{KR60RajT?kN!wx?9+91AsY_|)nR^sG{42a{A!$SdI4Q+Cs)-j+OBbER5NuRtX z;o5zv@?vKrM0#;}9}=C~(&s+tcZPU+H!Id5;%M#E-T2Zjm`cm4mtuILC@EGzrb2?$ z$xI@_Tv+=oRsQ8nPdX3n9Q;~PdD(}=ZOa^Y^(!ZbIw|1pLmx!_Qf)?tg)`???4jIaCOANcdd%$qOW zwu-;DWSP7_Y}w3OK6fn~*yszWuXGOCmt0M;e4Z z>g{X$o@)P;ntDvt$;evRmq=Ce?wk1Z(KOV%oQ61y*M1QL=ojME68rUPHak-?^TWt9 z`Ag97>C*tqPlO+6*vrd3A?oADE0iJUJ3pVibU34)rM5CI7$&L$C9&tQQ!9O+*7Zfw z76%dOIBr3DY3-V9)O{LUtO2bl^Jz^_d8fs8E!Xl#BuhegTeIswytA{qT*4G&!({So zvj|Sc@Ow&47_T;xbWq!TMx|zC_;9`W!^L|EUGCHrqt)_-^O<&>$4gaVqo(p)Z-B-O zF|A*!G8(PPXQczHMp6U133}P}lvWeQ@O zqb@r&lpu;p!bbL_W9h&DvUueOK|u9*J2llLUrzIn;(edCE4FC; zN{ynD0=|?)iwYZE7vrART4G_}sQGI3a(DkqJs)8UIdG$2UfGZPUr9X$fZJSR>h?do zVifd^0$LBel;x-HW!+s{(oqqMqRP6a?iNvqxW~gh#DWv|DWuHjTtr`p?{81Kg^!;% zV{0GCjpJ<1$mZe4clR5z;PM_~FkMR~784{ryZoyHF?HcXP!x=DU|L$k23NAvC1ZNm z(ILGRw4NsY@0;gzp%_M6CqXt4s%`qt-Oz3Srwu!4g)=q0Wgz_|TUw@2!dr2&C9QU= zl84L}$D}h|TUn({o&&rhPmH_fSydE~g#P{C{;vq}v-|x!#zU@*)wpSgAEl}p8Ob^a zZC!l$%uMZ{e1G!poqj?IaA)+@W6Bita&Bgy;0OG5i5(j>Yew;LFD;)mAA^x)Eg{#C zu;*)@9KU?x>m_F{OA5&c8S(Ove^JmKE+0epYUdIN0gHvv#*G1TymP)H{9B>9z4dfo z+|ClXRH`uj>2TA5I8qBYO@4w`4o`{kn^(=ePRH>$){YOAD$k2-mWyzgOO0zph z5MD%OCk(ljf`L!IgG@{M^G{GxjKMoPg%_>y$sYiS`sbTh%#_ZYu}xU|_3Ni;SFnkZ z;$Q0@dIy9^Rx(ys-FS7B7MHUJ-?%VRR=!fPF=OaQlVN4r@qkQGAc@M7BV7AGm6k2C zXmBGWT4O8!4Zi{AR~eOLtz^lwp*u|@zTC0$`?fUlnonU(2>td7U2%^Lp05uMW!b0I zF5p_zc^|)NPn|9P=PIVfTn}x>V)=Nw9A{i`X3Tf)A@QN^yQxx0MxUmpp4;rZswJhG)@!k*24{RS|LNgxIJ^$4b=7;kof z8rj-VT<|2K5KGfix!1pkn2k|(WD)AyI>RRMTM@P5SFa>z$>%mfW}tECnEP< zrsVa7OT=GhD%L$0%uFS^n6wpPa;nka66UQ?7E|$(Y7>fYYIy~4HQ^dn8=|>VDKO6d zvS4z}cS-_01)uWPG%sL`1h2WQ$a24+NN3{0emY=irAO+CVG;bnhBaS7g($H&+n0{V zJPM}9$Q{@!jfBXmG4CI2XBP?p7t2 zy?WsyS7m#4E+2O(QS1#4)gLceYP3-P!NWC!)u#h643WK%R$94DKSg>2oCLj6%v2F! zG!v@x>#MdGwPTz^k3l;o@v4!uu#@Uhy!G;+VxUY7>4I#*Q7;XLoC8oxi&>1bBe~=` zeDP8}K3%(IN3nz1L??^U#&q^Pmr1Rc0hH^7UDv*d0+k~)#tp?w*gLNxw%kV!oNVvx zg|&R>u)TBF`A!9PB0dSr8Y(T5=t&X!A2K0=nUkc5jNOJ^6^wR$@a2#K z%V>8an>SB2!Z1snD>a3QR~cUM&4S;nhDTLP45YIxa@KM6ou$F*x(d!C$FUIF9)Yt= zi}xHTl9vutifvyGD!!*dB<;-ppmRGp4^=r=bNZ(L9p*V@S`KW<4p-Nyv~Jf>3Hq?4 zZ<@vm;w5%^R(pBe)& zYsz%2m&hDc3zN(5CJv;d*d}e+Q{~Im zlg4rkpN&1%FVRUZNJe$MH*H)l_8UtiT5S1xA84~qtHeKD?^n+KF6uD62yTzk6=Vnc zet84n4}>;szcbTbnnB8V$$RJQ)VJ5vW1Zmkx1Qr4T}%9eqXlu`FN<8+5xNK34zHr1 z07q-|$vZ3?wWM8nL45$`a3G(CTTi@8y_l)6$crdRHP7r+-)~!}&7FOARPnOKQVp40 zw`QxptA+r3*aB(lIu9oC2WGX8WKRj0G{x<*1j3TtWH2w_OIo)Icq{rYgVIB}{C16= zL*B_<0+f1ZAu3zX>ij7a$OWUmr2SIx>j7uu_UE03@{5MKfq>|X4tcCzu2cz~+!Ck% zL^IF#C!kdrKUj1Bzp<#t=#+$|rO9#}?{a!U+FqxG$<5p=P)DJYD;Nxw`Tp*?%YHM+ z3wyiJBr*lCND;0DjmC-`+!`=3&P{ligran;ls*a+_AEiWZFB5$ge%DIFRwH@A~__hu zdnF{vN^%AhlZ*(tUg}D&tAS|;AFR}pGMsRUj}ih#K+ZV8AOb!*Db)?Udbk*~gx2>c zsA*<-oQYbIT`dOMjo(l&p;swN(qfFhl>!`Z2{|1Js9H@ibdcJu@hn5aU%()%TU&DDV+|^tKDJ$^U+A4VHaVd2nYZ1NM ztR=E69Wi7L>9GS|A~W_2RH0R9->V&YEl4E3OFX7y86jJt0SVFp0Cw2@d*e`e2ec9j ze2`BkkOn?{XMvtaC#&XPTVn}Qhy2OTJRdm#ayasSIU~akIL;4%Pv^zFYLk(sN1E76j>eG8ga<(_scblxQXB^vLX-z^ z1vy4=M+)oopcI^^ARaOYj2w}VjGT^s2ji<^+HyuQl1WcKdBDH~V3XirXM#tQwXIyK zQmPfknMfLCASoUH08!Zg0CC|Ras#owf)4b4-yc2x!2ZA6!$wK7#>ZTj--R$IY|I;40`4~KPaHa@3N$vO~ z<0%~Y0~i=M8UCLhX@rn_R!;}P9Dhu3apRA-z&Jiglo6lU4*@4f^Bg z0L*{T{{ZCc?zidw{{ZFx0KXdWueP4^D-K)Cywj+C=3H$- zNp+>Ew-BV~wP{j26on*!0Sd_c^VSh0XC#FA0Aunv&)uIsbA#g?4zF8SN=isU$o_1O zNGAjj9tVsc#>U@hqrOfGXPz2m}yxI!Gf#5x&QJ{@xCRfCwZJ+z@m|yA2WX@#AH7 zp!}yxk|jMQZXV|xediu^#bX4xrxdjn3;+t1$QjAU8CqUmc>{n3K+aTrkbXhI$Bh2~ zKt2Yc9Hfv>10Fdb5DCFJK5zyP#z6j?4L(P<;s{sUk)OB{f14zLt}&0n@OjTYLt21G z5lGck0i_6`K-Rkj01n;28rS%Ea}yGJn379(EJ;5D?oa*4_a8nVE`UL0>zah8659J} z5RYPlNXOJR3HH^Ik@1jxX9JG9>F6X#<3x0jhFjxKtlkS~ImH48p48(!{{Vym^Y|l< z-k4sZfm5f=&O;I#cOAtiEUYaVJe*_;yD<)!XOLB`q zZffrO^J|>lA_EXUvBpzQQW{i%$XP;GQiT!$DZ%TORLE1~oSz|+%)w%Mc5(35u3@Ow z%FP{rsXWpi&+{j_Cj*QS2^{=%%Kav2$U7^r#B@HEMa!tbw#yVXv;t;G z7z>t#J}|Giq^tS9dvTFx>J95>ckic7XqsnL(mPJgg+Z(?;QdC2an!1kWjgdvrbJ?i zQJQHDp)2lifLGu4keqbdw(Y;&VbOgeqv_p`r?$m%Eh42`nAD2oTGOw~71vyK^`=xQ zOt7D&E9~~meahg4;~;qJ@kzupereFkrxNt*!E=#evK4*&(c@7o)5ASm1(sKgBO45Q zSLKJ)J9ixqhFOaakS*;q#RZjbNlk;fCk~^j18?aXAbf0t@z~+|$WhciKJ}qwJW3a* zziW(964=F32>Xmign_{vwx9_dlAZ|Y{hcau6{q`?C<_X1>##qOG~UtNnWSg+1e25b zY~$rX@zW{YM*cSku9`b^XpwQ{OhKY_^|z(d;`)&$wB=C(>#aCEU$VQ_)_dmrDtVAxw@vw*#NV?@Ig( zV0A*`9!K-pe+}Hf%T%$ApOR(yRcxgp9#*^86ylQ-?dn=dN+W8lqoJ4+v7x3OBrfOi z%gSiw3e2^lrtrv23>Z5J0+5G9gVsBa-@fH{{XW+QQzdpI4_kFo~`ARh8FjydaF zy!~!>6?Iz``&M3?>2!Ek4H~;fmh5;{^7C7)d_&m=Z~*|wDb00~f(-f7j?U5s1mmu7jV>yB`!too8CqC%_R|Jy+-{}_gs+UA50$l zpQJ~6$8W#h6OX)OA%~E^hu<+gtH=4KIZXJ?a;_gH8yainBeIEX#c@HMf&Nrv&mP~n z?A`kfmyq&IW?FnZQdyhX-$~^S10g61AE$ciZpX0E@2=klsjh ze=hlUQ!kmliJrZVJ$oF9M<^~!?xnLT| zQPSe>WIEVULLF=>62e?ccyR$>C?!Ej1O;Owrddb*r(MBQX;5j$Nwk&kpoJO=97=9v zsnH#f(p~LUO9@iafO}2?RCphORq9*n?W!C3rP_ak; zzej!d*K#=)KOJU;!*0XGA`3F~tesAMRA8E3oqUnL{{Y*5B(v%MVV#s{3(J#H9hzpz zDQ>4jX(=D8tmQ2_(RnT8U?uOo1CyL|Gyec+3gM;B+HIhyNT`t3x;-1-nKqLpuYIa4 z&vYfYNkii!x3Ox=WOob`i~~I`^4REy~TkE?lL<64fi+ zmg{rdOR`ep$V-K^B`NIzJ_ttlaq2U!o4K?07(ZV0qv<*%cRC|m?IzzsOMZ=7 z*;T(&n&nVTfvT74qlmRiJXq*jsm%WXGZR=_>nlka`-*t`K*2pN{<3jlH|goFZZhP@ z6x=%mk9ws=kkBTeK+7>(OUffYS|9_AjAy8xZGY6Ca$8cLn$iw&QrdOPq0<#?szf0nx07QKVk-=IuwD@Ifj`~IDsmeJ7rcw9X+ zFYA|0Hj%v>($19hE4JBcfn1?VLojAE)cC9+Oeu8Ptvn|HzCEO&X*nIqI6W>qPuI(H5gwlUF(49i9$UzgGjTQ}DqnfJ?I!M;- z#%or!6tv@kni~xEGG%2u@dTP|r;9X}Rj_f%#gZ98t# zL8{YX$AwODRj71G4=f0(Qbc1Qw)j5hwzJPb!)^PW)ZMM!)yvaO5pO+LuTUi0lTmWg zS6GIcbg3*#aI(TA#4X7WM{lvxwFIZVKH1MtI!~-V?^cHph}vGzc`gSEY;~0a>`$X5 zDm7Ev{45lLKbQ>X=2OhSD)}EH&+`kEc)t_OrzOH-F}U2$Zz`2CJaWwlC5BrxA^fWB zjLy=lt4C(BEg0@Q6$U3WUaeXyCA+oFN#~YY@W5UxDis}KjJv6-3sO?b64OZ)FRk~TI4gNw+=C4%*KI-3?Outk7J{i_ z^@UNYRT(upa%WPEn!nV2XM6(dVQrBm&uzbOb{u27x2NI%0HxD;C@r{$wDFGAup20_ zVF0AZkf{yeszUO8)ewGEFq4ovlJf)0Zb6*QUAt3_@h(Rd{s&i!*PoDNR;`RCMi;(c zC68CeUo5~{jg{kS?phTcK!8B8Sz53_i1zMPXtGanmb^ulc$h>4QjsEbgVJ_1$^##r z_{QrJ;k zab3{#jf;}rjEHo*ZWVT#m=!@!{du)q3Zcn)ZK*E1?>c2>DoG(t_JPnNx%JCXZcS`^ zU8*iqk*HFx==YM{k4|a2dMlCTwJoIzSPEcAFSL&6svV^{P5>ly_aF6a-s;riMPAKH zlw~POZ%$}r=3)XLIaFl~lmG`mX&~b`Jrj`mZOAOo!mTa`i1LKN`G5Q=a+f8@dN4td zVMqS}$kQ*4z9x8$X;Ee9h04jkpb1i%nM%=%@taqviSmB(IV#80?HK9;CjwaX7_i!s zem|#u{B7Q`(ioS#>QmACKwXQcuDGPs4Bq!lV5gV$3PK80Rt{PT0i(dc>GJx5ZX0#l zUscdLR@tjpy)xgZXuX$EuCr>={{VWJU2&)hX|=y4beY05k7EHbiqHZ;At!^-2G{L> z)h)v63Uwz{CBd0>rkhTuHtjx*4vif#DPX1|Qvw@Jwce6RTb-qA@}hCW%AxwF@1m1Q zrBdlt>M9`8p;DnhAMEPgd1;GEj3U4bd33e7=}Ra`Qq-j_)0HnOB!yk_w>Fp`DC@Q> zhVnT$Mh_>A%3`?<=UhFh@)c;o6xF1Bb>U#wYRt&bT?*`IsXez2YN5B9aV7eq{fK3P zYO#-97AA7R*VRJ3d+(+o{rov^S1R>V>C!EfR<4DvW^=d$Z^ySTn zrdUlrLZq!~axxo8Lb99=+;p_xda1Y#I`rY$jGeVqZrWwjIwg7?(Djzf)#-0i8+lGJ znY8gwnurloBP2M0JDdb}5HLdSIRhuLL)Am$s^3 z-jtS2Z(S8%ovM;Gl2NTxE|o}uTwGQjmfbxvD65MRsO=^i8%r(*l2nW<2fL~}FT6D( z*7UU2Il3lm(Y0DWuEI9#n_uc>Tu2VC3MHlmF_vF#{`jhOE-1F8CBE~Iw>=E~!tYmh z+WBJ(Ls{!jPqf8qJzO$u%54cIryZp-!v3x;Iy0TYvPZIA0RI3nPDXmR+m7&eX`t4O zt4l(wlIgbOs@s*R5u;h~YvEOeM+~XYs+Uffw%6={0|CUOe=tEfJqUSMo<3ephG;li z-G4Iw0F6@)E=+iu(-)TD!x?`s>JWtfSE4A0g7)drBf$=8vCGF`eqqqKk6>mosJPBh zC$G>X1E?LbJ!F&njrcEmGkoqk?bt^66}ktndDXTpdIMH-ntstPp+F3RKFw$yYPCLz`@pDJWlT6Cv>coC*$Hfuln!&$Xm8fkyVB<<0SNtir~*== zQjztq00BIZ065MG8Og^T66s!`KBiNekjn1c;D_0inH`#OOF>d)G3-k2CfyyN#vQ64 zWhwiIY3HGq;Ga>c$al^im&dAq>8N1Nhr$VGc z{Dui^$kSe4mypls=~VT(Axh|Mj>LYxETGa{mynb!sDM(G00~g?4{**1=YW5kCTnDtsFDl2?~4 z%9fxtQKZj#mRK<=5LV21?}lA>x83(kB?UOhHr}S25z^PaQ{UT0h|n#~DYNezp2oIm zQ0eAc=yWL;8x-ajDRGwb(v;F3khv~2hr5q)N)(KhbtQMs94%f`V~zC7*H)dYc5XN+ z3|`Su<%}U7tfQcfNPwYzpglmJ3}M4GkcZlt2v#xtkgPxiw)L`fdO-e@-2J>p73+FX zVLj27k&)QvX$kEh092q)f_PCN0mq)TsZ{r3JVL<8$jAo=1e}rw+!TIEBk`X-bZnpK zU$Wu$4mTQmbgAw|Q>-CnP9+ber70kir1uU<8R)zZ z&P*>hy^*CtIpUU!%tB40?kmG0MAISOkck{4M&vS`9kQK)-NU_Qjr!E9gxLf7dcY`7 zx3y*4DeQIfqgwFMjzKvD9ukp{Bpz@Iete!kJf8-dfmlc&5_6mauLB&F06YS5pNwZ6 z5e@U-J9)gRx*m-P+QrAWAJMe_6bs6I!2IXVq+Bhbu_EfHs$_{cjUhowN3^sj3;tA` z0P_7Rv^#7XwYN?5OxBBQPb>PBZ)w~|v}oOzBh;IbtCB=2iEXPkl+5VLtyJES+aN`0 ziB2tk+5%5@1*0$KlpJ@2CpF37Gf_kDsZy5_8KG+>553GqhmORCt-0!Y5gC@`%$8ZA zsu;S772^Ph3f8hMkBZC;-kVA%)Qb}ZgiKTiReq+?McVg&+rNN1>P7}JgUQAL{@BSr zen>tz{F@%s_mka>k;wxC1LWt=9|w*}$Achk>S#vT^wZMgYBx>4Xlc!_xyrT2REw%9 zk6L(YlaWv*{W@-oW%*`ZHICG>rv1n<)5~j4bDpE{>Vi&2Q;#JiVEE?)$@m20AM4eR zg7dn3?-_S1MvdAK)XnAap)aZ{Sd$TLsmXG?M(&SJ%O|T^P~XgqhU`wfGs)v*#!iq) zEON8K4CKeXFRYznHUt74J{*0Uw~LIo`A7Pvuez}JmHz_b2}VKlSir{*nGa;orskYw`&I zq=Iwuc_4Tn*Cd`v$?=1hVdaMbAIbpWjAZf#PxLv*kHGLmsMQA$ zv;^RQpp|EnjO65ye?CWn`5km3+aA!iyOCE|h}lO(BL^T6TKO7nsTTu$l*>dRbxUl+8HPOD4jXR=w`1RS9;zuBr>u<42Cl zn29Cgk@XC;r72CJMD`PrjGW0A(hESeQn#>u4y@Mnr%&qjsdT!!=GAI8ts-SYW2Uh+ zwL2nYn2x;il!PT6#cKN!l#C<+)FJn=>WxL-eZ62%Y4$bOX#VD0b*kHsSMGKz?8;45 zq&9}xVGX0$b*|8*xULirXh^{5=K6Yi{{U!S*>Uddc99} z`JxdvJ+9K=X+?ogoetcL{5jCAN<3+iA8x4y33fDy@f&%U0!oq=g{1b9GlF`HFQiW2 zbbnFf?kHbcac5o&q}*0hG_~CJi#Hj9)RoQphT=H#6e1zul%>=K0Ox8+7zYoNdY`l- zp?dwc?Ml(>OGq^ams`E5Oj6=iDpi^RhY4-Xi!Ik4Oh;Uh;Ot>Z32h_0xN-)148ETm z&#h>s(|6glD++zvQq~)a-Aysn-H5ed)8*3DAhy*)T$t`g_T(+lgud&Iw#h$sLE=C0 zF-rdcD8ce?_GV$!9u=N^LNm2B+8*j&x z3IvlHLvj+rOACy!lFR+sYx$CJIE!DR=9bvHi@e$P_4#Q~F8Vk7KfL9llV6}Qansv= zD`8ALnse>A*m0AeZNNL4;~C?kX{?^Emm(;a<%w6&Tbcz*Z6@!vB`E3=X0;AQUAH1U zulH(mj7UUvsH-S+q2z(uu$5#3U7YTP-I?o*jaq)xn{|gR+U*3<;no#GkUv*IPrdcY zVfA*gfTc801BX63;=WGsFE;4;Mdtn!HDf0)A>`QV@o`foeQi(bik1Ot_g3tyS8_aG zU#k#14Y8s`{(B>aY}OKZQWdRQS2p!upam?S)}EN^9go(C^01sgreQ2}m4Mn%VcPMC}L)R;=12hFunQD;K z7NFN#VjFaKQe(8jN>WoDO_aCVoFwBtW8;3%1{`Sr0I+)ZdK{)Wp8ZLDkN9(IYZ(;J z4h7^7@b=@MmNmBB`NGm|>C*RGGSZb(VU0(rUove()w^Xs9;Dpn+^34Gj3{@sW+h@m zn8J&AQb1A0ejdE6^NWP!`3;XTBg#oalnD&TBtv^#FCLWT|^rzHS03r3R{{X4%e02CaH>9aYXwyp&1g8Lg>QOKU z;18nkPsfg+{rf~#eWh-0>W0O?Y|$t&-L>7;>bdGeMc*d2LDf5Y z$(Lh6r%~xN#_03v%~fQ+s%K$Tg-BtD?V&FzI7?x?pmUOW>)hP-?;PY*@l`mD2rJ%) zCFH*7jDTVDo!;dV!tdCOw_Di5gOTbG$@1XwNL!2V)6-+x5nKD!b_P zh8IXeXSJ%5uY;8TcHs*^i*SD>7)$IG3brf6Hq-$L=mc?O|w&a%M9@%aoDkw{;AxKVA zI5{*aUcYt9B`T3jPJ^yWsS#+g5g}TQR&2bQJRhORLShskJU;&1<-SwM`??u>`Sk^; zZ&s_P6Q$Tf${Kq}s#4I|xTaT)OZ7RZn5Vm@G}(>qly-I_xho%jaxvF~{EG5F&t5C$ zwgcT+gZM=d0X^ixnn{pH(>S%1G*H^h7&T^&Ncp=)9MZU@l=Lt3~5BThP#2 z?2Yug7y8U=`Y=8F{kP&+9-e!1(R-U^8+o{^I%#56YZJ816D8E@dSgnf&X*)rRG+Ak zRC!^^j`rkx>-&cZ835&udiH4EoN4~mttz#jWZHJb_cgTBot;6j>9)+5Vmn2sx><6e z5yJD#m9~`_#1_J^vB>3sZF|;s=F%+})9o39qfo0Y*mlqE;wui{6_^I1ku1vkh1282 zafsL|?DpGHNe8$nbJ9!d3FAi6y&}`Q>t;x; zT~=kUaMV$&mxKjQtJpN_nrG87NQUBB{Yql}(9#s5q(|%sY?4PR>A?D`Xf~HnHVLj( znhlR<((16S`z`3xX_{$Bq0D36sxpO^sh}1VCCL}nIv)X{bSa__dWke|;08ak^x=&g=!*IG6 zeCV9*6SwWCSDiYK0qXQ?#r(hkzfZI_7b#W_vP;k z4{A$##xejBdSn7yTW$XUay$6J`f0sx**kmP?xoMN?OVdFr*w)P$w!BEThQxJ-g*-* zyka{dLRS0;@_PbbQwO<8Cq4#T2HbZ+3wL^Jx_Uj!q1sJle&OhK-(985v~1{)$$Cuq zvXWBlnYmO^6d^xNA~-IgT=9SipW43nDjQ^@>J13#jkT#%jYC~4^;&JsIz(tlk4-Bo ziu6X{&0=hMfqjoPC9=>@1q&G+I4YN_iyyjI&97)}OGoTgUsk<-)~Ho2ht*1y+)Cpv zvX@Aw(BXYyr~8UrR-bd*?%?*0N1^#=mfX83$+>OVIHcJr^4Z=wdjZMEC9P2~)M!PC zT!bSVCCKD|RMoZ$h!0qoYw|Z+rruqIY?x2SCN#iXWD<{UauBa^w$`A6GoGJ5 z%QwAP+|J?O(Yv!mbZXkS(?z?g?bPkdF_-HfQ9*{x80>*jc~Jd_kiT{H0p5p3TObk$ zMA}a2YkO7H8vXA{vnZFlw-u{WwItE&(J3?*Rv!%}Jg(@tVQ@y9*{UnCIt_&zo`%aRV-a=eTTy-P8C(llN z((?0?XE_fq$W-D#p8jvgu@rdjZ}^6;IPu%{BC?ikEjg{k@)IPmNz@}?-jM_6xUkt; zb*j>h?waNs6TO%{vq~&R?1dMpRP>Dk4x8lf;PF|qjOqhzN zM3~A@fmsc9!H`5nr5H*>Y9T1VDL-iFgxXu{y()Xmr|rgGl4(?XI!>*-r>m^Pw9=c4 z^oSP(#+#g!IVbe*)E0y%y(%8S$;JjTsQPv6FL@f*UYWez1=4B_?M}4sYQknyY8MPD zWG8DCIObf6b1X@n5~BMt*s38(akm0^PFA%A4vg{HU#TQImA_nPV>^FMYO?DRS*jv^ z7}cQ7`nAk6=Fb(R%4SQBI782+)jU!M__LaCnryc@9RBByFC!y?<8W18OsiwY8#O)4 zb!+6%F$-W#Zp1a9kpW5U#vqN_O)rP|c8VH-MbxCjAoe6qgpki%EN)^Tw$tcR#5Rhl z1-?P?7Y)GMbojohHCT;BZMtH289;3e2yod*Vat-9l_0`tMjBL7PFn5_9|Za6hi?OZ z`jeoWrK;#8TT(8Fl>Y#)TdIRQ=)0qb)?$!=l#mqaahz(~ z{Mataj`D3j^)>lF2(v|++(H2D*iPeNjLNmI`-_iFzD zhP5eQYj?T*TW`l|Zq%w9Y}@TZs#PPtr7nS2nK@i+mlZ7}vafWhwG1Qx z0P4ps7RNM;h1jphaop+-HN$LiT)hh!=&`GhXvGcTEsGrl2zP;uH(Z< ztwT`X2Go>2)%CXovBB&5wMmod8rTZmORoO_A7kM(^^S>6i@TZ=uwteoQnb%c<+yjZbG&uA6S%wkk2Gbea=Xn`OD} z(#&c{cxB$ojJa|HtM4ITJ?)YQYDa?hsot;}p%#g4(WhuGgV&q3sPqaXDRsMktx=Y^ zv?$1o$#KawHTIbyu;hd^5YcdzAqnFatG-!sNw~k1bg%K8e=Tk$h{)5=;V$PRrCM7S zsnv$OiE)+I!L2Mz!=(s1@2%{$hb>RuX5Kqe)AzGN_3R~fk%A+$I4Hf>tTwcCPv78a zQT1iG6@6%q%JmANPmKb-dRUc;?Qxh?>U}<*iPOIOr?8>PZ=jY zF5mQ!y>_+frL^nQODIys5Pwx<-9*3$@2 zW;?P;=#qI~$^QV^&j7(q$8oud`0p*tW-@$g&Tcp;O^UfDX{ys128u+KRT&C}SJU~2 zS{m)8%u^X`m5A+20JB0G@Z4JD$de-14=1I)j-wlQ@7Vlz@c4I2tXCf5{VSq;rI;?StDX!NGyQ=OL%GMbD6ry;`15~m83P_>e=k32 zQ03n?rm9lhp|?|}Q>xVEiHN1deYfF047c*j?)D|66s18b;Dgfx+^?x7sP0QkU(&0C zPPEd{w_Ug)SJv&FN1siSnNS*AO`)*t*CVB;Le#f_WUWf)xP0L@tLi1Hn^v%^T772O z8hLe5D>ox|ETec)=2YGK#-q0x3?&UqWsj!qZ7T^|Wnp8uFM-xa<$o&w0A_g(K6vIP zI}>@3oT9%L{O&W2OcLL%XY!WGEIkUQ2;_sLLDSNECXT#s^O}E~M`zv5(wLU0_dU51 zn4uxP$8QC(*wCA5kSy#n54#%DbuM3qVp zBkE-+EtCW)g$~h>c|5i6MXIATTE^_FC`!#rlcO!wDB&oGw0(U&`m~7Zd8uhW<6+b{ zmYYdigDCk2q(f4@S~bg2H0JZuX&P;$Gzul}Z!X=d$)MYFVa{$NuLsohcau;k5>lW- zTy+adQb-B%OHtZ}@3kLj_3OU7r<6NZyEgTq$Dq|C-Big{D9u8TA?XNIW}?fAQ0km@ zVQO%=g(M_)^oo8~^0(l=YT_c}_?|yEF3RF=VEE-c%yx10tI@59ip&prYs8Qxxv5#2 zPvj5`&9LN?<7YEWWU%%Pn-)blWl8M4c3EAWr6}D6o2a05-j2I{zS0NSj`g*>aN4h0 zvh`X`JM@3u8^WrXbjvy&xhLyl!CMV4^#_{lQ+~)wl)wopC%Aa(F&c;y8&K~CTT*~- z<*T6`#AgYpKfxpI&wxnapB!{k2dv)ZSzGcU>8^=Dee_C7osVVI7CMGE$jH2wbZ=|XF{A;(*gO%uGR+8VScGjaNL+!Nwpp-g* z=?HKN4Q~O#+&h6d?d}-Q0|%arFQ`RgpGx)7wOx?=F~yewQb_wpQ5?t0%+_bjv&dswu;J$6_pq~D4yJXzX3MezUr5Y?Ck$M_ z+o!i;1yd&kG}bm|GOVgX4fa(kN#EFSeYSpoe;rv|+;xEdt5q~twz8VcTN&HM>#5k0 z(PI9d@JwL^yP(MWB~?P53NW~EAuCZQw;ghi--Sjzz0qrMr$}Z)CsMAJF(tPed6yEZ z%%YVc=D}@k=ln<|By*pRop|+J-F3&a2%8{{2HKTkLa94g7hEVeBK1B_YA@9l8S3b- zJi?-(`310s>8MbSlr~r7s7TjUE$Pm?R#cR{r;4R}>T}=aMNSt3xpUkZQ6XTQ+ zZ%vt-dg}nG(a;(pz5&|)r1$Xex7i0@Shn{2D_b=ePVcC4^zJ&WICe54B2Bk%4`j1V zuZZxX6;x23-u1d(R#KtvdCfmhZ4a+r*Yy2zjaj3_wKmx{g{c>nCFw6muh!_)$u3Nj z0@^@|>^EvoGZEyrCdi7(acBk15=X7+{{YY(n;$@q&?;J~R=pgtqbprTp|drrbbHjX zAL<&m45%=Ws(K`SK|y3X(Md)YbHjVk&D84F-|f9nwDjaqmr2!X0k>}BSE3rEq*BXL z8$YMM9&AB(vP+qKp<}ot8yw6fpP;wcdd6_dQ9p z@y%CDd+xJlu?tG|p5QdQa?q~HQ@8ao%4~H@HKKCqV3+5k8z&u>jF#HCJQN-5=BsW=>fae_D*@;J#n{!Qo0d@f^-@yPI*XR67J zw{D&sR+P?D171NEB0EzRR+8dW2)13e%^)S2j?akv?V9&48#RN2G*QW9I4ip>p{6me z$Pt$$s2#Q34fwbIC**&lU-uo5->>-({CI-!riFJ54Eg7j=NTNF z^XKFecpQ$ZsbJucIR0)4_~YmL6OZqoAoXm8066Z>PDm#OSRiD9fDS$fAPo8I^pc=( zl0Hr{2jd){87Il)oQ!0Sn=#oxr`!F0{u~a#57Wi!7NgogIPwqunEwDQ;1iEL_#I># zIlw$*jFG@N;D20?>5fJ`5C$ofs02gW!DU`tzKVM3I1gK^g8N=Q!YY zgUR^ulgvvXI$KgoG@uDegc@gMm#i{0byss1kcg z2RP4DdE2+7R>UtY4$_OlxurE}_4}VqtV@EiH5!>#hQz9^ayt%G9}!xV0||L+S8GTK zLwUkLAOQ!MPO{4Kph-LcpC29B!f-wY0Xgz>^EEvH^_JPShoU-DW!JSDbXw)7r#2RH0a>I+g z<(aGdTHfE?`z@bO)ans+_Uh`;-u!f~0{C$?^~`%OPtt@yE(pqo>pfi_r)~7>diWac zuMC^j?_)b|+E$ur6~m%7Ov_rSbl#Uu9itU7ysnDfO_%KHR?=97RF2b897FONLS&Z|f(s#C z$nsJNB)G3lUsT<J88taH{n$(Bgf}~WCpqB!}jg=$2 zE%@!=^}=}$Gta9(hORP@CpbQ0o?Bq#x?3ap`NewqK96!h7L8v_*60uXy?T24c(PTW zjwda)7~}r{EcQ|QK#0v@Fc9?>?qduN_xIkx`}lbK@bviFmW*v@QS~QI^x+gsx`1rY z((0!6t5ww))hEMZY5Ey5TxHnR5wY6;`)eApd?|Ig>a^brv zHA*CS_Wf3_%%}}h6&=@o>U$5Nr6KGkNOYj!g(p1qbNn%5xt&a83FkZ+QyX$y&1ODc zlh4(TIH*NoBHRv5Z*|qsG*i_l?oWvRV=XyeLx3^$n$Ywb1yzK;x7HWZ(dseiw!T;A zW5kK|3)0(Rjac_|p|?93FGRMhvYB}?<)!AHW}PMG-9w^KSX*u-DnTbHAYhDO!Ov&= zRnjeP-et+AH?^ZqxGgrVE7qY7lToQmq{V7{27!Sj%827{W-5+DedH_;xGTp~Ak-gQ zzfWiE+qRn*RjV?m&9wt;cQgo3rD1CpfxGt@9Pk-O^y zLicT1);qD<;}*obcI>3G|Kx8TUN^h?z)Wpa67yLvevHoj*SHnSJC0d+w*yT`XiE zNKezfY<{P|-@(_VdPrvP(5CQv#BmyvFPWHQ6)SdUWxd+^< zD$Q$JoYVz8-7$sMmq%Sq$$jajIN*)-p3;&`WjY%Q81MN$Vf;K%^TA>BH96$Gwn?pU z`Qzh@mcMewvgSKMKQ9x^;u{5;5E?#~8d4j#i+3iM0!}N~ihU`04Ua()N29a^$O4U~ zf!@#D_WO92^PZSHAxm!$_8ny>v8wXE>$bY$K!*DWV5j}*S?xlU5`2v3obeW~RqY(p zeGcALS536O-KARAV>BBcQ#3kM`7_|RBB@G*{MDvRwJqGpb=9fRRfH(^j{p;AGuN|g zZK3qG?yao2)oGv;Vq2&q^#|Bn3k6j&2WV`SjyqI%3LQsZ)LV8IX6rXeP}Vya_l;KT z^qWea$+;=esdYl_4xJJ#uIP{-ksU4jjFhmia4BiR)(0Rt{4a42KQWyC^`9}K<;#R_ zHQ8<@eTqLVgYb+2tF+%f}XFZptw zdIyl)Kk*xn^N$;UogQr5K_tyA<13Z7XBY&PEUiAcCA9IM=K5ZjQa4KwQ%B=D9quzO z23Y8t2I~s_0vMHL>JFV_s36hl*dPUoqb1ckZYgn_}~xa|J`*2hBj`?kF#(TkFYtkUb2 z6`dm9sK~cz7K_xC%5tEYXj~`f*J8*@`%NIM66@c6wPc2~ANf7-P|_0?@7(<|EU8nJQFlUch3L-khaQK=B0 zjS&JWgF-t_xVM`Gg?ANaAY-M+)Qe#|MAH3_Yo+yK=&q7mSFO8i+OsIN+kKjdt;3Th ztqF-Q#9W1zir;C)rP6XcN$mjn6~3EZu6j|k4F;8^SDm%1Rcf@2K&#!NO_Lthc9bB` zrbmQ^oLyqzrb!ch#!8$CWU>%aL#0EvrAvAqwwg7#{jq9(h}*Vaw85<3G%6h`6zh$f zH54|UrPQL#b;^h7_aw=_(vZOodl8*kbGO_|LCAfX;6I58{{Rs!nx_viK3$G|kGO^$ z#EFU+IPKJV&$Rc-4PQ-UEf1hnfWx5gzM;wSb>kj{jYsnnjd=P@D${!YnFH$)f4nE8 zhU)nrJ{b3=#g(G6w3l@{m#dmnXzG~KtA34f(&;xdCD{%&9Wx)94w(10<8hsumQdTS zIE5qtliPrLbb1SQ?DKXOcH-dMn>y1yGO20aj^4L?3dErvrzp%^SwE(Vcd<{7V@szx zfa4MrwFHm?dwvH-$#;3BJAJgZw#wCeHub$N-CL&8DHCayo7AQlew!6?lTnRQa(!Bu z`V%3C`x#s{7XrJov>XuSEuH-AgGuduQKo3F-nBxn?&COc@kE2?? zC311tqM545!Q_hRaB=g7E>4L*O=ll^l2oFPXB`}A1)+8s;8(LOtkRf@xrK<(DgOZM zUyk2z2`8mKo9VWqZUa!M+M8zDH?qm0I7Vv6G2mgQ*k6jEYk zdaV6bY=#QoBx$vTxlRhS(X7#kCA$rBIpA3(nigpNFpObx2m!#;ugE{zPo9V^CV{ja z*)d4Hzjb5K_X%-Frc$6d>{jW`L#I+v8az1hmY11gN>GMUmYVME!bV6Vrq>_Vi&no*-VjgvFw1gzYan&p!VNQ~fhXeaOwYwKu zcFVb%E5S6%t>3QoN%5r2s4|JM+NxXhY4JY9$V%LP8E}H*Nm5qgP6_fJ6JCzna&G?s zxHUz(jik->M60Ug7cyo~RYALmRGpZ*w4wUIVV9Olkf2)j!9B@HBL~i0*N6|!vZEBBeo1vZjZ`^f?sLPa@N)6Nf|al)p^d-%&a9@!;bNWa%1bsaC+K7dzU)M!=e zZH26KdGAsnOpffj>o8f7CAQ-{ryVV-D>0lxTwiz!bp((=>M9zw>JPHrMZI6XH4AB% z1>tzQvDFTEwSE}D%- zeX|CSDXEPz+fti#OQXtE_a-bCB+2&@R-?#Qo`h!lw^>2mR;to3%Wl=J+EmI#okg|< zGQCr7tu0HWhf*GDOC+Tc)P*4pwy(JzrzDav^($VZ`%u5_Z9Amv4%DjplUA^7%W~3% zP_5jNA4@FJ*h(gdDRE%28gqaxED@BF0=VO@-)n^O`FNLSlX3%urIL@7;qjT# zLn3CHl1E9cU5_tE+@dgbLLa=g z*>O#zBzKUM=cTIBzBF@fKAf9$);fmXw3}A0i_WWcTQy(ai)JD!Evc!~oMNFOw77B? zG3Hxo4Kmrswu69D0qA>gYkGDLD1ZvrfM)-r_?@~FyPap zvBXB9qCa3pa6wKyW2J9LeM0ma+uL59Xcn{W(sr*!uwAaoj=GI@Afl>$R%6m*&5KTa zE7^WCE~%9q0%zJa~yiUc_GX<8k)v+sMMDzGO+rh z7_8$%0g-1t02XeNJZW+?KQ_NITB{1nj)pibJ#x?sK`V(QSp6bYmRS$`zq#MrZa;Dt z4wh^8rj1Wu=sG8+I!SUptF-%hx^i5SWraH-*M>usYyR>2?X`8 zdVI;#JvrE};x*di(w#rl%ZpC0+B1-8ca5&aO;X{?k4}p0Pt~1_`r*a~Ql9pbdsMV? zlahLGdyMq~(Opd2ZCh^IJD?Kuf{QxqrClsB61NrVBv}y(mp#EwVX&X6oas}Gba+uD z4{npy)Ya;~Zxly)N1WP|rQeUafu zA&&gwyx!`uQHf|Jwkxr(?@UYtzKMu-57K|#>*Hg=Bhme0(w*Mzhj*2UTXWI9Fstc? znQ}cK7M1Fzo@oZu4wt*C z7KFQIr%<5RV8x94&aLG^ol=V#lo^SFht}Iosa@QhE0fbY*xv8ydq}-+yOO_SO}{CZ zrJ&`e?J5;n6ood2pHq&l_g349eV1BsO)Zk1LdhqSgjL}j$+$n8SnPis&)}Ooa}hTc zz~9cpZzUaQDq|A*Lx1yIX$QEm1*ZZ_%b_XPNFWW%lE?mMgpuvnoK}i)a@2LqarHAv z>6VMpjJHa%52iEm_xbQ;_Eo!WINg@My`%O0s^~S5O#Kq*t%}_$%Yjyz?$N1=ZK$b; z?KiO~eP`TKhCQ|9kBmmkSYfkF)a&vTM%!j2YofNyc9>`B+i9li4}`Yc2}t%(5&%PK z03cx?0gM_e6V)?o8eemM`03ur==O!e8?NDwAGpg^0{qJduP;9Myr`h#0SB?cz5-a=i4Z z#+P8bW-07ElS2bSJttWGHEyV4*#%e*$LGem8ERJ_{KFjh@scxuapdO&D1Vnu&udyw zNY*W1(@O%sQk_es-dDx3ZBL&~ZKox~g<7k{fcxwv@TQBcwEBx-z@&G9+z1%yqDNZN z3E%)oJ`dyP9(X=+{cHKaPDU|)_>%~iWT@3(Gc(^B}1xyYkcBGeZZ5)_96 zOMNVRX>hi*p-KuVAP{>WD_i3Wko>d}d)inPiWCkf^qbP?E;<#u`ZUZy8t!$nE7VMW zykbxcePgU1{{T+L{@>Df-^BLzQR$hWyBPI0UX)rtU8y$hYi(6qkV({v1-(|24yN@& zp3}ci?9&>G-cW^hI2uccO4QkLK;*)o)L!3*LfzirA=6<-g%&QS-Hk_!5;7r0Wu#SP zgfzrf(w5n1C+$mVN>Y$85(YY-SEkRahLHM+?kUS+iMFw)dVv>CsIahd9PC|nI z@4t-a?X-+1cNV zW?0uWqY(rOJr+G3I@wnQj+3F(N5{^`ap57}JzH7ox_h@&>TZcy+Es7Gu-Rh8t=o~J zu{!#sCAj^yy4#VTaJwmJ4Jk$Dki4x&13WrEN=ts$uIc{uKX@tdCrE*!a%9sLF5HP* zb%`Q1XAVbxN=l#-P@ngPe*A=4@#xG=IMH3KT@CKWUf^Zk+J4PV`xZ>sr6WfW zreZBN%yd0fsHQp)rwc{4*@T=k%R>MqyzJKKys3KgrdEx)b=RmAEk@KkCepmA)XDRi zrd)I?mBS7ks!hR8hVyOKDUUHF)}DbS4m9&lEwZ1zU3aT=Mx*iw zT&*aR@=Wtzw;I>V4}KnXrz{NaOj5jtNC~b`7HKJ|o`L6$ozrw+V?Wj)`@EJ<8HhB}ggkP8nMJ zQjkYD?dTK8IVvZDPDlfcapRohKZAmC!5jm5>uGFNbU$@>Hi26exs=T;qEhY3{Tjfc z{dK)#)2bCZQ&J^Or&-8-G>CE}JnPQAC77+c>y9|3lBKBh5S;+1l0XB2f%rJ^J8}Mg zMtC?GwRs=^0L$SJ@)Wlvy1c^u{#`+4>N3-#otbV|qa!h3&s87OB{YPMr~|}*Cv_PH ztf;8eA&QiRHPZ4|Q5#6Q_z$i3@A~+o*nj6A>Ob=J_g;H{{KfwO^rQa(4!-NL_^kL+ z8XzQva23jaJ0$+6ehQ$FHhvDqwej)a{Qm&w z-^Jg!cq9Xyat9=M1cS#PfH=Y96f+*Podj0`07&nC;L25H9JeR?@}M#JJh9LR!yUKno=~L zY_m-_J8d{%nP0rSyVLudygEf9)Ow2&}zJ9rrLj1mw1r{g$2GtuX3 zJFU{12H$r3Yg8^uBU4(@O)yNC2?zT-{HRYi)6D0MQ6M5!um1+1K?k;}jJ?bbVD`qAwfjY+%h`;qASr+&+7 zJu3KvbiD=ym@&fv$gvOmq7}gR+{kn!B`U}uJikV5#c8dDu+22KYxi}pO{+$^^&R(O zRCNZKLYCTP&6>6fsdAK;nn?-)DxyT5-t(@f;g5}TTGy{l&#v<8clcP$Fwnf2cQiZhbya}}K)u)qfs&j18?UdXos{X#I0d6hNtcoHA6CEWe z!phX6$N&zFhpPtV^s4aKp0(Qa8`jdPR_C>+sErO5q0*}|-ZASm_g@j|k=$F-N)nUb z*pOO4D^@Ui9$tZ3^QZb%XYM_#*5|fu_bS!hKXRUm_2UZIar8x8@cN@OEyOBXQQivF zjE0hMqLizO?i2p3W2V0dx~YRSp3%89Ik`T`y4Hj=}r7yMxf~)3dFMuIZhx z_kDcZmeu80O)cvW=-HU7dK0d)gDI+_*3Z18gWLjw2>w;4AT%FH-%tHL-+s2-dVi=@ z+SRp2x9sYT!ikh7Sbl7&EYui^(+`=1u-XD1C%FhxyOV>@Js+J{-iCwC(``b5A5%2# z>2qv-MPe&0YLzADUwTvr+K$_7Hz1dsd2R%<)(W0c?MOM#Lxc8mbrVl*&COm?D)&V) zg2c@ys)yy=Q|a`WW}uqXRjM>8G9)(KgswObr6;k`hZESK*;#w|T;%>?^EonW=6sn4 zulz~J=_6dGm}E*8S^ek|RDzeM8-N4M7&>Ta*JHqWja+^{B{-FZW)-YSqO%?`!`!pd7q|Mr0Pmq3My?WW`-0AND2yBib)3pf_V7no}zEK{fJps zhWr`YwHDy4i&Ac?MX`}_I}SXW+c0FvWuL4>M0;_bl9akTS_KWQLmYFCk}hr=LC~-l zta@mbBxI!CbPV8(kN*H4_!;NpKaQXyyj^S4R{dKe-cWAZ47*a1ue92wM&w0dv{0Lg z8dP;TAl2AXm`qd@lH``$QWM&&s{=iH=gq8UGm2v%o6ETwat(>(vdSssY~|z@E8|4e z9ip*j;71ln5e|XsvFSZy>G4ItS+ja)T(|q7El{4UDFEqt<5>VIk@hLD+b2M8w#o3n zPyL-88Ff#{cUm=Mj@r|Oxb{^UtbUr~4YCpo>+BDEg=;;ho)U4B)Oxlf6WCw92Kc z{kLfb7R}6(6{+f336Ul-jsil~GU`%F0OdesBk>TwSZ!jlHIIB%d*;Hqt=q2LUA17w zOHl)0P{{U9Bke?lR-|(;I58@M(`GW;Oz?RuAMR9$X07J}OhJzS>!bbx@kt5Vr% zUt>xuO1n}@yNLt{&sI-PT{GBBof?Z_+?S=uH6D|3)T(b@5n)7fE0l@s#E#855Lsmo zG*aPO%bn{B?fZgHQis#;Qq7}MEZaT}Ph7NeEAXgxJb6tn_?_;u#@2W8r(HUZw~2A`Dfm#wrDqN6`^U>rB($w>9vUOMs9NCAO=?J zNK)HM2Pg!qLumV3^eW+$ClNN#8XoM z>=%7Swc&h^8OCeiW}1X_1=SV$3^TLIws`vVzOxRkZ>#Af4g7cT;x<$0YoHs5+V+rZ zjn8`P97^_~S#oYlj5-WT59rb4wNXq!%oR(gyz-bRB}Gm+;)=%y0|5#3PV|S-O^|Kw z2CV7j%c?c1u^fib`r94h2_ZeBIT^=IQ`W0| z`*hqM)*#t>QL9>cd|V7`1v0j}RjE3qCUR+P+w&NHVuZz%2+h3e8!G@PxU3EjI^sOr z@h@-j8($BWv&@^z!R8KHoQXCTNU;rpiv856t#|VDQ&-!p9WwgiU3yPh-p;M#xYBW% zCy6oQ{{ZFC$Qfn^aXTbMw7#!rEJL!^gff_S2l8SlujAckcZ8-&MSSk47$9jo+mhBr>_E)Z2ZDs3@ zn%tL_&tzNF+8qv&9^+j~qcR<8ESIB1a!P)g4z$~4)hW_Z*a-8_MdZAv@i!OZLe?)C zW1NpJSIi7;XydJlwD@6wdvyh*7Lt=jX^5I`xqW_>POZ1ozX_>JjUF(v%DBOh{JGqg zl?49aBM^E_yDkU-0=w$hZFrAor}okGOK^6M;P3r#s9%)JQ$=Vrdxli&CRH_;B2wQ} z_0^?Ii8377GmBB;10FmE*7;w5*sOumu+x2)`f6?pfvkV*4)@n2^`C?pSW&rQSAe_3=!%+u}B>DIJrRToYv`nzgT zZJ2ZFP^uFoxWne8#ZB63AvEhkOg1E?-}jt0qEmsK^y#!3xv&kVQT5`fVs6eY_gvJS zAik_f)SBg|US*`aDioj6RRP!(loZRJ`jFBV`@X|rK}#vZk6w@GSw3eEDCV(L%=wQ_ z)qIy596KL^#oeEcTc;&FQ)NBnh_O~-{{VdVeNt}M3PITI-nWg4gH*>ChZN}W+V|4g zmNc~-it>6snlz|>Ju(1BI_>rVFfUF0t?BOSHw$vA~CHc*wn=(y0 zkr=l`r^$M>KT(@*GYl3bv_n1467xXzWDuY}{V?_4Omru5S2f?NcYP|(wd(p~dRvIB zRp}La)Md@9Or$C#WJ9CHmn|>6(=RQzR>@%jrJ>aVpbPHX%|p{qZkp`}T<9CasMqU} zWYt!xEq_mLhp28dazK)5KH_0oNR(9yQ;BXk4&;DJlHzi{m*$m@U^zD~j;2@4s!_qj z@bd8byi*;Jw}-c$WXK!Il9IMEW38lS7%$&T#_W6 zVB8@+5b`4(gC@S01b{X03rX7Dpv_Z!bbY=xTD)m?wB1y%+0LecT}3j!Y4oYJD6ACJ zkVGLgHwCclk7Tr>71#nwM@1rF*n|yndv4F_PUuFcPP@~m@+rTrtrXc8TI*k?7|+&B zG%)N!g(!VjxTcEFcnVGjK}SKg&cL$$Kqz|4UAZAswBjbR+*cd78`PSlxG14ds8!yL zJM?(bU8*gIS(M34WW+L1l_V_*DOLzoO0nseKXGSrj_%Ij{p&h{okGehEiA07b=sGL`@aGd|0bW3d9L%{!M;9iJGL(Q_n0lmL{aXq^VZQtA*|hHd zh`TFz6ZX!{Zt#_1(zOQJwwQxhxK~lBHwv*foXn2tz28UmWx1}UxeYRo&{7l#1Q%Dh zExGzwZOcLN)9-`V?5#1_jQBvcDKVntf zoRPiATwa)an$;t$7nbR+DjmkSbV_pRcHM_@$E2Z(6)~hmbRtcwA<*OUk?lTx%n_9( zAtyaax}=ioUvIE7+S@~Tj<8hO?g!2~d>W0lPfdNd>Bfau_W?-N_G_BG zrxwlU5zAuWeyb7pWU$KXYg;iLL8qjxGe&=+rZ*+}e z+y!#exHPLwExTGpKG(D>h)|eg#YJI>@+8ovwISGQWczQ&SZ!w|3UD5z?OEqv!M;yE zZr_;|#L;B`0F9^P6*4W!i!CP@!+scRO+0(Fv3i17b^TulxCC+ITOphfCMCK|9>HzA ze$)dZdcrc!7hOF>FmIh`{P=91p*v37c9Li|-Sx+BRExF+y{#|Y6Bv_p*VR&!E|C!t zou-x3U3J$f&!rBp-U{tmzy~}Il}#MluEnh#jOkYBw=Y1{c`sjA70YbDI?lM?SG!e( zI%`zKB8eJHF2!Xr;ix?FliH<#q7Fw%&!|Sc?V{@2rrY#KZ~Bb={{Rz6W!!Kac74B6 zq}1D^KFnt6@@Gn!3L6sKf7?(ZIucRal^|pelx-H)eUWNb!?d?;+lSUF&4pOAuKTL# zlM>vus&eX#Np@vHbf(^^id{k*(WNspy-lDMp!Ow27&%*7=fCX7hRb%(nF#01Jd|0> z80xtu=7)!iIl)2fLY3a)v92+N%U9{&PtrCuikQF6@2Vy!D&pcb(pQhzd(gGZ>AICQ z)MXu?di$RHp|~BV?3TN+i`R8qVYl@HBQzW8g=a&kUKb3HbrM{4hN|dtg(gGJIF&8z zF(U+HBow4zXda)tPum`*ZKq$i2e`Tg)mEZt)x|(=bN0Q&PivYQWK7xvmV`>d6#?x9+~C>MP;CBtjf;nd!csW9ED_SDTX z6h@=R_MG;cT2i%Ogq3GKCVrnAf!jT;w*ALwKH>ESb&pNe%GI)jJ4>KcD%D3RP*R1> zkpf&;Q)5GQr&w$h$VnYD=TO%va^SDk(}S?)^g`U=%0GP#rQK zORcMER_L{dQLQ~$qf~12D@ROg7mQf+>hh>BqFpjeVNNOZmj0{wC22%*Pjc~`4nyD5 z4Pf-%+a8tf8i%90^>^Hr-CWa3#kceqRi#yN4%8wyRc?zO8|={Gw-m|x;$C_66a&~w z+rb?%&rD6p=^lVcqjw=R7%uUhfviY&_Nmo}v9A-L_ugC0YzsZ9HeZRMmk zl>m}+j<;4`c>F8QGlHMYiG+WY9u+?%tCNqDfYmCTn4uKV!(we(7CkWpTj|%&&y18~ ze=@-Pg~TB~xV*JmBTSC6BK1gOqv;Ax&(8MR--rFTUA}rv?t59IXqKAT8pfN#YAUkW zMSkU%Or@$V3YNJQEY34rPq>)~QkhN&aX0{_C#d)9Wvx%L^+Niz>1`>BeZ6#6X)xM# z(E8ht3Tv_2O5gtg-l+*d9^oHx!n~fO6SoaO^rqWBvq9F&BXIhKHspXRahr)=v?}vy zUrk=6xXney$7b1K;HIB(O~(my?ZQb5A9qpu*Bg$Jck0HVT$CwBbr!RBR_b)wWv3WZ z@g>fA=qY-NCFWd(T7NMo<15E-ja2j4GEmH!&v$ra zg(HxL6481d(|rN8q6s77JCKUQA5%jXw+*`;f0ndGO@4^IGa!te5Zyz*zqf>)3Lx^5 zLFdjgaCrI2@%>InIRmZIfS1;@JRq~_9tK8 z!|K@{?e|l$Yq{-v(5U|aM=hEiLfM~Iu3CS*R0LBhrH`p)->7UxZcnxP5B7_1jeMT~xnkMxS+F^~!~Qxh5PY>G9pDPkC=XreU-a(+E87D5Co%! zl(b;=&Z_2)w9R=9_64QIqyvBnN|Zr4yj@N^8XaN(QQs#!UpeX^$#9ZmEZwb(cFzTtPul zB)fX{F7fEQW7*}yxGP6bs5(bmvVycev1(1DNv~HZCL9+%`;~|lN%C2g7*u5x%#96Y zN>*Dc1P3L%jWoMq`Z?^1`k77*&?;5Bq#h20KZ? zny1b&nEY1{$3L{qROUR(F~r(eO@|6? zN|kL=sViMBlFDO8{{V&CwCFIJZZjb%TcRlLJh-BwNo%zzt;c=;``4L=SM4)XE!HRI~)8 zu%~i+k^(^>E^8Gz>TaiM1Q(E$y$=z!jQYr>GU`p9xY(-icFvO8mhOnv@FHDti+6cWm@fCiQi;u08 znr4v2L%p?bG-0llCkB0EVCc0Ga;)k6(3hmHt)!r~d%%b@yFI zzwQ43Fa7@jfAl-Rc;A~(X!G;-pE$?lkaOUlk@(2#(NH-!Cz1{ilkx!YdH5s%Gv}VD zf~*jbGIBZLL;;+BNZ^sk2m0WF=mH0D;DR!Lr#~d}PaNQ6cpT@UxB&M50N3sR0KW$x z1N#pZf{$-F;~o!;c^nc+K78l#j(WRq;W_vO=K)G1pU2!sj{}3?bJd=50rSRqAd`%a zGC#IP0sLTfbiq#}CnN3WCkMgsGyU>>419yrNl*1_zVtu${{Vyf>%xK2*!y_QMF1d^ z+;N3tJQ6X;@HpcD<0l|z2cwCm{)YSL)XN^r)G7;FWG&my*Pz`rMbFeo(d9QsxLa*> z^C~i;DN&sP#Qj8Z+@{ILa){s`Q?e8n-cklJgoOe|PBD&8&PN_k<2^ezb5XNVwQakm zNtPcv9i-)B_fe%KPW>bf+tgLs_d|8*BB4oXx26d!qBABtKHAb6 zbP^YwZ~^I6+Q+1p>9;?n7XGy9oZUBzYuD!1;M0>|yc?%gL)0a@+|cwP7Du!SnOSct zCCrSWB#;e{?HbRZzoD7{#XLzaBULZ*zjBVvF|H}`Fr>QDQnzwOLI@-0IUscJy$)*B z2%etWR@CD+>Qi^>lHB%aaOE?f)T#v|>Ru^vN+~%b{0D%0M_gAk_>=Q8r{SZH`K=8s zIORD`Sz`}o1BiB^?4z-fi41hw!E}>VVl3?`-rKO>iTHS~A^BCTQELXIRML3c)*@e1 zQ4{rr8&X*4boTAs_>ETNJs@{aw*4f!wYO4hT5SEPX(o#0QMw)4s-02K*Cn$K5Q_vs zX)boU`(fn!i4CK;f_r&Lc2())t^3-AeN^fgQf$7t?6<$K-`*9{1X zB))`u3J+wbw<8Hxam2knV{5ka-kw_a#B(#=c0QW+hiMQYv@>6&5~V)U{nU(q$`#yx z+!2$|%Ke;ry(SHlx>Zk9zHU7+_Cpl-lM~tQR6>fCDMNNA z0EVt@=B2v0i1}U%lhwpyqKgp8OWI2=9ytt@no`n8R`lP@>Huj-A3@n{@q9d7qJ||6 zgHn2pG=$21Q6h;5)0G-i&^7=k_21o-*8K{1XK35?%c7xsXv(15v|EO|Etr=@LHFH_ zZLs8t&9IS22vg1k6vs(Y615N%Q^!pEWtth}te z0?5jf_h6EK;5vwhp$%e{1AR_Ub@x=l^s@f|3T7)YBs_<`rblay&LO0sV0R>fR1|*S zoI?3)=g*k@_sTyxIgcZ$i#dK7kB)o_SHpT0nntH$bL-bKKe+}-&;UyIBz^bbnNB^6 z$7b-9>$K|y*&S!x#J-i30I#jD&bQxPzDV%wPov)QosNbX)*T~`+_gYu)SH61qOa5t zwX&Y$NyY#{4uS!}0|ays>Ut}A-20qsY);%1Z{Ha@ki9kiamOU8-%VIga-6xv-)S;e z06N)NSFjxR$UT7YIwCWBTS;;WF4V~{TO?*3wvYb+3nYQaX z3R|W+H*F?BS_DscH~Y~m!CHQVFB~WohI5_(1EybwuQ`0f=J5HSV>?e91l(hW&zi%v zOgdBQ$Sii5eMS1caHbgb8y@4f$vun8aCq7$5S8A+7Ox~TES4HVVs3y!?4FV~KqI){ z&u;En-`VoqDpK)xTl8@WK&mN4DY#t1sZJrcaDI&h7Yl%+o&Y`lxfl{V!rEoqv>j`e zqE}thLAq;j>69A6>lWf=qL!v>(Ak?El!<6V-Rz<8hmUV*P{`opu8i_E7TQWA1ym;> zDXYc6mn2$^l1!Mr#{ntEG62s9kV(J>6P~&C`gLp6LbEy?mB?fFM@-PQy!}1r31)!- zB_8ECh^ZV92MPcJ<`tf#{{RdB0Ek~Ve9Q9^-UFI@Q;CC&Yruul7YACbQb<+=Mkn$L02 zXtkAY6H1~Yw+4whESg2Y;@L&P1kR3!7M{eC!bfYWPYPEF%11-De;%E8Uc=qfbX{7P zYTwJ$SQVMkO|eg?!A&VNS&c+-sb8oqW!1=2p>38x2?-%Y=K_41X{(lmdm_Yb>xJ|w zng*VsO}SsQ+9)Zvh+Yu4lIZr-Fnh^R1O;H^h{b-<#q~wHFI5`jDOaA}{LR5N;@)PkL=Wjamrx(NdQK~rAne%C3W5B~r%2T0s zdZXP0S5fN25!i360vmhqPDjP?R4`K8rmnVQ5H{MuaD7Q4R{9Cp`6ITq+vmeh+Yh1j z_qgo~)7@`_ua+&bPSh)EUB?!KQMT*TDipS&&JfILQX@Ww9eHJ5;8RHn?HE6IAu`{0 zq$SU?9Uf;^>srxlY7AL7tP3PjXqMe#l_f9Er@c`V)h>LOS@u%f1+vgVaFqoD6V#)9 zEwy&cp?ZF8nwe0!Aw-oIODc@WitXELz)~Gea3~>BraqZ0pOA-uQinMC>7)M87OYwq zUd$j5jPgLP~&B*bShNl6#2jTu<>C=XO)^ z8(V>2m@f{0FfzCnMZi^!jv}S|kXIh`R`qx3Lm%_~K+oNa?4Js`#;_4_rpP2;{Lzkv zz;>|bQ#5h2A5W+cmLo(RYvaH#*gvFA#lC$Zm#XkJo`fUfd-n=tiE~RO^k~az36_>8@1K zI-rVqh?<+#rz6eKk1<;JU6$NhrR7Gq z+*2-EkdhwydV%-U*KjHK0QT0ew0-Fqc%G;l>8BSa!M7ztrrwsE%B4q3sBOf97g4Bn z88RP5!iA}(DbbW2nCe1uSwQbfe&PTbDdk^?KRz+Pi0fP%8ESOlQFHuW6;XKo8I$sR z7imRdP1d6G6=-FbbNan&y@wjuOPLt*aFMDx>LLGLcuRRVsGl)#z)5QF>EyB*=NX#T~kAdUH`$`|rqg z*3{V}>;R~{XkL@LQFhXAYKEO}g2vP;os($Yw_NHqt7NxVl(=@pH>EVGMjihEA#kGA zR?--5W2~(a%E2jj1uDAqpLT;<(>>~G5WyWifuA}xUEu*;+WyA z7TxadK?1aWC-&{A7ff3c%-`jWbzZXMrYknR0>X(=u9Dn0WYm4QG4(OmoK-Exmdv5; zg&?6yUt#-7Rp|wMTQ-LBt{SD!U!hy{soGbl)b!M@3z|KtO;m}KXkt5Gsz{R=qUzFz z6x?v?z2qTFN>8>(efv+@-Ho?R)zG&MRNb!LE7aOdRuh!+npJtGQ;frm;kcZy8O74$lyZ<~bCwq-ZB&}v z_?y#2rb^VKDwD#fvutSh0>b0z&q}0?kA~Yxc6cqzEtw%T>!FA%gjrBGW_ARF{XePj z5A^$OLigRhGi&Z$&r=gGQ)=3HtGyH#CO+TkvuDH=MBAdE(%fycwi8-ak(&GF+jjkxfb3Y(7b#5=Ikop@BdE zj-LD0GKC3Xoy98mBuuMUe_GSRVx|I~r0JG0;1YCCQ785A6t^9=L7+REs_o%7Oq+qa zZOLy@QF6$lJ4%r2b@K-gs*L29+(Oty(nCs;uW+LXa|#ORkl)^xJ7Cg^>sFqp?~adT zT@oU~nr-`r#r-m*m{kgDr$U$`KXDg5iB94>4r8^#N|LU7OK$ZYz3qFS)K2ESZM%+z zU!Xa4Y4o;h^jndOf{wIAVu~a@EAiw=Wz?`*U%u#gh{{5eNbKO4Z+~mrO}rgzg{&0a z;^-Ba(k)v)*)&?6^+&GEF3_lc^OF}h_11z~dC%Y_qMzZqdk@@tS0LtmvMPR4%aY}J z&L>NdaI4uaNt4C#>e)*YXQ6`#)oWO-CLbay37*yF=|~_^>6Ppd0hKZInoP>WQnkme zeIl(CwoFR3i%cDngsIii6*aQoZ=bkv-%idcdp^Bvi(Z|6R4?jn?_t5cVb&$vYqzl6 z`BG!B!x7guS$;Cxj)##fEg?b72F5yfu>CN0`$5wUDby`x-L!2idsVEe72QXs*R1t4 z%jv2&8FM1jWxG;BXE#i4N)+UTp&>)=zzWA$-&tGM%(?XwZ|qt3jjek#Z0L0c+No4+ zTc$nH5KX1en!?i|)?~^0Czh0@^utnulG4(kJ6DqMb&E%IpLtto+08M{(CD_9)ike0 z=oIRl3ySoCQK-Exr4o@9=+8i1PBWB=6!k|_l431A$ONRNAq4aryyKcD3-XI0k>r`Y z3i1m%Xt`c`j~;^U^@^=akB@0_?TNOPMT-zuM(Cvw0&RUGL?#S%1CY)|6-X=^$pNQc zOAQ=s&hd#z*VCIwH7jd&&gHdpaWClY2H?2vJ8edzX{ucr znvEh%sL{S&kR3j;wlB492(@){PxV%r>Z8k1|rJv79RQ+jo%Sk$|Fl-gfJ2>5k()EUaC>SM~EuG@9UttG8v; z;;##~BNJGS27O`1TXx-kd{-J1M3kyLkOEdPKu}*rpPqAc^23ehUym^_~( zi;l%ERB;Hc<>RlBY(d33#_w9a83|l^owvX&c0|Qv{{T0)Tve>8!x4CB;2a zs7U&jK8d)6DM%#_2RrgeBa$Pib~cu6lhYqx^d_6QjVslP<;i$j*Nr_Eoz)NP9{P#2 zR^&rsh|KwJOnNAWryg-7U8y9gDC{{#y)0`QcW`ZodD<^{>XnnGaiU0 zPBCKc0xQ>35HV1!jRY4m4YNUy^7_7_y|gj7;h3Qd)~^Vk88p+?7IzQ3RG7yZn99X^ znIr!I_72D74#vur>1(!~LbJ6hy`uZPdsC{Kb7j}=+PyB{vfFtPSf({G*a)adH6UX( zR50BLf3;nmi^30R%MjRR&#C*s)(ZZaRPNfPr5=f9R_>!yrO^{yeZ^6oVFi~WE?h9v zN<+mNI*oNeq|T2jlNzvCLJ%s_ zME5Etpp?arfJsl-72S|Ky&N?r&C{*d-L*@$?YHe3Jxfb3dQ(+flDf^m0m(BJ7wO}f z&b-nbeZZ2WFqIPE3he}ri9??AHsT(1TEg;t?lp@^S|XD{*8$K)P+6un#N6%mT2 zwhejJqflzeu%l$`?Gj_C3)mRvsaC7nl61RTJ3g#HBY_`Of>-J4O&{wW_J6X)V0v6^ z?^JI_H0w{dxU0hXobuzuwy3s3WK~@;AvrFrq()s?AgZ10x|hLHQk1r%obk{@)>{;5 zo~B<`3M4x@7LCbNpr&ig2+zw!I#ZFu??(%8Fyn;*OK2@!q>vP>b0uA-?LR{{*ScB; z;pFdgLhcqRbqeFI+mUWcbt+4UyD1eI>+Px{y0V18T%>!-ED-5OYKl9$k3Q{c)au6L zb(*6|s6?vMXKEG6E)_-$u{tE!&(z;>nGvQTMK7}INKzi}T3kjIlb&t9Px8#xZ<}WE zt;(~!uK@=Z#9vF9ya>X*T-^7q#gL~Cu~^StQoMDaeG(1G#4tMnmm;HHwm!6?ooZH^ z+|jgk?0Vu#>XDe;w=BBb7T0mu54VQx9OII&xknk!0T|;1QBR?4gjAxFL#17(<=eHTgK1ezL01zDKKPQv@dfqLne5tRYETwA7 z(oz8*Z*F-!kL)~ggXgbAWh0JClB|RQ&~{JT{b>IH>wYSgn28rdXQ&W6_wG0G`e=Ba z?$#=9JNq}=hYDp5C92)pl&Gaj1RIu!O2X1GRFbpKKGgyV$T@+iGr{3Fbr>C;er8+B}D1 zxMc_`l*<)HP#i7ywvw_4fv-0yQ(pJe+Txs1PzeAWp9x7NBN!YEe2?gOmz8{WY%W`x z&o*Bhl1!F3B07G;)8L?8P`(>1O{RdF%9y5 zJO2QG4wqfirz~i`g1>9-R`S)$mC7p3)23C~)p=BXER>cb5lo^pHRZ#N9ZD`W+Yv3c zQpyq%LUYlU)9qlDx&4D|$8I`9Z(Dkacf2%PNj2-!sF6v zw9yc#ONmT!OqnfZv`1MuB4cuJ>q*-_+MkoNYOaP;)kctry6rNFQK!S#VpxhrQXN8F zDim6R85nomi!N$AUl?-)D5QH^w)cfzu3pS-E}N?r3e$FU={Ng2Qq5ucNU=~#YAd)u zNkfWiij@_8LZxA%Nd$qOft}(sIbRUQvvUlsS)NHQ!Fis)fo~Sb*5eZBTX$1 z4{eu6dQw1G$WZCS*64f1kGF^BRiSGNHq71SDm$;qjaWKe`|u<_WwusZ{T$Z5phyl9 zp!axlxa6LhypWKr5!>>i&zz8aj!*cGc=#h3>Tk*KEirs9&RZu}EmJRP>0XQ!{y&{6Hd zQR)39zpHHCEV8fp)BdCX01m$E*J1wv;(z^Jeb;#DAHUoDwf_M5ALrty{sa8~0Q3H~ ze{FB7Ad$&G2PYqI$m5Ug@yW`$>+yL~fakPh`d|P@#xeczfuAP_uP2Q1PuvN}_#l9M zeDm5qbIHy}RaAR%jC`D*oaEqtbIHK`V;u*<{C>7FqLJhdc|2no1IZ&GoRB}SR|raf z00K@DJ7#%41}_Q*jq>iJqVa#D+MHu z(~+E<{lks|j~w~&k0A5cPTiS)kT#RHq$0gXLy6E$Ar3aX=2I&|ggSR}RLWLT!u#@) z!f+cPwv&W{JZ<>6^OkQXFdR!I2NS^Zx6I{l(lBRWX=A1!s}#a&{V4q}A!3i%Z9qHi z?8E{l8P<1iPBj&G*@s^}SNvl{;Liw)DES zN;RsjSE$#fz;?9S5W2D{X{yYW(q{(BOrnIL;)0&@;EmgF+9&EseQCWix3^jj;i?)~ z^y<4*Nfs4qy9(G`=*~PVXokc(oLIr+I+ujiG|*bsm3OH`l4KS8N2`Rb0o&?gPlGv0 z)tmgSF>CTFt|JtHN|EL37nfIjEM zR&~#B9;Ozan%oyAy<3}viKX=9(j2*@-uDG=b+*D~NoA@*s70GskjsfwrLvga%rDz@ zXebFdAuQVFi0?;M;NA}HUWuyJdR-D#C9BC=cUzxHip05P(?qr{^o40~ zwot5gWRo-RSm$WU^zGNAN2pR>kRs`VklcFQxo;~s6&(Gnx&j;>qq$w=_TZ45;B+$o z0A~IALM)xsCVaYkDpkv+;k3+~G8&c^YCZniBPB_3DHzI%K^Y(n6M%8=#HLd#_;Kc5 zX@3K8O1E%anzkw)KMhHLC$y5yhl#A&gQ;DoQGJTIBc#I~`wbkk#i5UsQN?~^b>p#7 zrZ!8DT^R(LMPsqhdPi>C*&YOa!Lu(_=v2D<)$31is-x0qwOXBd$@h(Ea8XB$(%h`B zNqV{MyvkZ>&#Y(%JAfg?E4X(u&A90{;B|vhT(Y+3OS&q$gZed2qU>u*tg1Cv^msjn zq~fL~bP{8vDIW7>@)j}nub#RuYn-cCXx6NROQR{nrh38>l+}=eLn-lo$)yH`;;gDqSR;hxjvf7!=SOtjvF z=d9&0E!b{BM((GDy0ZGB`$p%Pg()dNP+A}Z+7=waJ;ywNejh&)+?UL{zGlsl;v7#8 z{3XOD&QwfBI@NJ@%Ex8a3#MCAdbPI*+D1``bEh9{6RkUa)frlEuC&>dokouWlR8XEwWcfblNPBNx9Lh%Nr`hCSX^gXA+Y%^Cketa zj=ERLooEImpL*U=_Ag%0nANueh@BXC_esG%Ip7cz!8nA6uC$7KzM|FdqA=GTHjbDd z_eLLKj^S_9y}%lhRPo6Ny-Fl3f>D9ce+>TsiT-2e*O)hW&TowId`%ksZz+~pu^8J` zY? z+U(nM+e|i7TZ5&uOkM37sW#Y4cSK8(Z%3v`Wr^i$jUq{i68p`BrNTYTl>vd*MBO;5 z+NrW^VeQb)XgYX;Rc=)rQ7N}_Ny=0lRzc)pAP@D6{{ZbFPozC7YKESeEvQ>}=u%yiXn35@LvsOcwQyn~2i@t8UC5ZJc!BG)Lg%&e!>k|khQq;Fkaj`j#0 zk8c9oLj5Q=*RDEKYwEV0(5=^OJK}{Rvu{YBs1&Mfhbb|peLKrlJ@qFgNrdI8?nWn93mbTOFn6{JmJS$D7X;-~I;+Oiw_;1gQlMXRkft5#L&glmU zO41uv3F>6NmGvuauTM>|qFWTRH5yS^4wr2?l^0Y+dz7w95F33*IVuO96M>FeKkW)n zqCc`I&B2Ear^de8;5i!CdXln%YSm9~)x4|$pXOyLC0GOj+D}8`--{11b3cem{#jVS z@t81kbL^KJdywL-CPUa$ziPB|Etj^@dxwq$XOKnESg{DZ*M;2TSlD>eWY%kj%H!j+ zrkPA#Z5&KNPK}iXj)zdt{fBtQZ8y^wbvww@>AI1l5bWnISQk^)bI)8?oI83^u10{> zLF6|L)TwKZBD~*hf&x^pundkA?QQgE-d=}kJ>{%7^nE!+qhnj~?n>IJm*hH?MKtLW z{)xY(gox=>hr_@U%2bRug?DEF$Ora!YLu2XYjQU=h>j7sTEmG`*5j2mkgG}n8JL&Q zFcsVbU8O*RPmzb)>V;pVIqCPgrrD1WI`)gwmW4NHt{-pyu((MwS1o@|ql_h8hqUAn zbH@2!;gUd(A*mYXKTiA)Ab+w;Ho!C<;HJa1)jUO>+bh`Cga$CNn zJt1-JxQ1->w1%ilN}O9rA}Un02UUQjpq`e0NZNf;)pFkr(3n%1Jp}) zmhDQn0_;lbjkL^{n?zJqW_=2TbUIAV&IS+(D#u=j=bmhGoCbTIRHe$emL)i}{CzQ8 zb0>?Ae9s_El?-*OW~}d$uOaA?%&3Mcll1h3U|13>c+5R3H8JK&mnSzC!J5o7m4>m3 zM??;SHeTUDJxrjV*Wm1KHXEt@yytt^mAQaaJc=>?KS5jZ1GN$M&OPtSl&MBAn5UEC}^wnC`eslR03 z(zNVUB+r)Ju$tsavLL+bsz|3hH}us=jI!LX(+jFXkfRwTMIeX0=%Kmh-CIuTE`c=o z`oyXczpG*Y0CE)Hp?R>zpbzA@laf_fX z@Tw#K0AgNa_YUqEAhwhC1mhTfdfl--*InEBs_VtIZl*?;oouCFEzff0p+I$3)e7jQ z$*Q_-(>WM*w&S`)0T_Gv?e^9bL3PbM$mFy#*a}ec{xidCUGnN4S2c|0DjUC;<=$Z# z$5b<9C@dwTJz*85a0bL|J_U`%)Rqep8dh%@vWA$B35pn??YSSOIXb#d!6!rKzkp+} zTW-F#@2s^Q4!x(_ldi}TD2zEe-k&CQ44UgvortF8%7Fq(lG-IUm(-|;>{3(^768c> zW6^tZ(S&0sQ#1}D=3`TUmEZ9w=N`QJeuZ+D~$o7A9CnC_TKApg~{A=!W`|Y>RW-q1MYoP_$x%nYP0k zVPe~oU7c{zEr%6ZiAj26iA)5`U@f1fb)_a(Z*z+7NhGI%<$TWM@?$)sdHGiz;fc(+ zenUB$&1La0+ok!1I=D$|)vpxyX-5aRY=xec6O;U~0-YTa96d2UX%?lc=8f2^!vqqt zNMm-Fso9kus4qhAw!U|-0M~cBK-8V3Ty~8QQLENEo063Ep;VbuhRhK)*kP$I z&8Jh;)869>Qc~I+L2XG;aCi=bPCX;F?@)B+$JD4AiKEnN4fkx)?y5{`{nb#X)KLPe zrc)icEG~?uQz4@AOoTM^$x23h&Ie29t%Q1n2|Gij)*`AkR*#?*$}LR_Vhc(7>STh% zq^0On4GJ-uGsn+_XEA;+t&27G-K}RrF7U!lb(Ep7lB;f22|nQkM|&lw2h} zrx_W&wR&l52IaJ>7O&d3#+lnz+}iDGfYUc^eq}ClCef7Wc)Htk=i{NbOC-l4LYC%J zmca+22fvLqzw~p{18llmsj&W%@3OT{l(wpq8M|H=hW;>0LT*^Tu zIUS&NncFUsYF^^KAeW??O&t>N2^#lVslxZ=)2Q+OmY*%zb3&^QI*BP-T5#clkcF!u zIZvG*HThrrGsWkJB)~&%*P1psb)Hz*n41hR5!}euk2JJB*@aeEt3fa(;ZB!7%ql~8 z#lq4#iR*i74vU9N;+UAM#>+<&7zDi~whOX>)4liC*f4!=^t0Bz7Sc<%SL-+am0ULE zn--HUs}k6_r&OvcMOs@h*h2^u_SyGZc0v^EZ#>^>JCq4H9U}Wi*w&+N>K*%0v2J@d z-H%`@ii*p(bw*7!3l+t_h|b4b5al*nXvbN7$5hZyazM!^qZLNm&a-Ww(#LrAKDJYt ziCDO*cAe8nR9clf;b~N*)MzmhrzfTLN{YXzjIdZ~D)?9U&q$}E^&Y=^?f(FNdV6ZN zr>;A~#I`7ubT85sSJXq)At-;bXfe@^rpBdRGp9;1s7xv8 zJ*_iKSW2Gl?T)7k5VdEyNf_ybZF_5Xw(7N2%_*|0mhA?*)f%r{T+5O9F)5! zDGV261Wkma?(j-#*`zPeGg>2v>h_g#eFk*e za@}$SnH1;L!>+_z&9vf}Sw>n~+igVzWh3HByG7V0>~wp3_HMe~5Gc**-8${LDznud z?xs~G8guXpcGUx>Wqg>2ab*(|yYTslI_m{ffWobGQYBfTOARM{;{xZ@2y+ z>BnnCwvs_0geasO_MCCmtIBSFoa9{FBggG>-aX8*u<;CLd2$#mZF)Y-C2suHY~w5# zE!z(8MHFsHbU)1mpzKRNL5r_X9Tk}AS)(Ifmbr?=tuLt*aVspzwNs~Jb=&?DHg&HI z`LzsyPB2rS<{%uLocJ7r#(3a^kTT&kTDwT3-E;>l)Wp>&&D7w%R)w59G7D0gT&5aX zQVJIH0d2SZM19In+>@T0s#F07#~|bp##B4L-bv0g^W>8TfHpg5 z{{Yip`0>)RUa0LOQhg9NKUdlYnpZT#OQT!Wnr%kctuowMrtN7~`K(P-Vy#;XYEqqG zrNqk$bR>|{GBeH6^9(gsk=T0>9B^lx09K$6kVpjlbNL4Yskdw{@S~&lcsGqP*?#*d zxbEnLG^Sos9+oWDm_bU`96_Q5SD=;eBG1)r$u|@_kKQf2To(GJGg|!>FvUht zkM)wC`dKCDtQP~%H-xLTzT~SU;8yD-U9LybJr;9E+SF$Cf!Htq0JcBghL)RK^)k~Q z%58@XcA8Tj_r6F&jt;_tNzX(#(K4wfE&I91@K!_fHsy9O;P)T_?5MaE#PuX8IU|Nb zo(Bau0QC3FoMm?MC!11-9%{us+stb=77Q6LCnkbMoYAOEQU`PEi-h&$0TyKerX$15 zM1XQ!dov@2i8{ZYYy+xvAh!p17pm zmYvS+M%8(W)AbsYaTqc_b{7 zpfZ1$jxY)2lg0u359yCN=EeAN#m|kw^J>z|uWb}R9?rO74wZSP}Tx(Fq zStHR^Ctexz84^o4_lbHUd|gu-b(i$V)OtFOi7TydKp&poJoc~u0GIt2{{WY-y0-UM z{{Sif08jq_$FI8dZ>Re&`G2qekL|i|g$*EM8SNYsfC1w^PBc2WRQOu>)A?DQVAfdkOz~;9FHC`o;k-O&sBm+{C4B|k_hqrF^mr0GCn?f zXy-%w_;KUpr#-xclw$xNlg>%VKb#B_0ngkCBIqR~fIc}TB%kHU9H<;*agopYf!Btb zIpFXzPD#K69x_SK&QBx#F?Q2fBoH%_agmXX{{Ui1cefXP*b2i*1MNGrk=>v#om)+r8~5mgSpm z(Cu0rN31Fomzt#8!L(BudP}JHUU{^#(0TQrapIHT!BFT;M`)|J10xQp%D7(==8)B`%J}vtkikkvnyfi$P+pF_ zvM5KAB%K{nM?eEO0F?l5?c!37M)ozG=-QsEN&?7Xk&~Bnf*L6|rR7+N|Q?F7Y((Q^}2(whIHil<9>#$o6JcYJ^mfKqU5rRh~<9X0u zQ~lZPyGQRJRA&1#KkNA&LRj+G%js}c__Uly zk3Su&VXfD~J~E?YAhgWv)+46TdJ8i&vJ)UqveG#u?D#t7vdd+zi`IS9ppEQ$jp{ND z0ENK^S^#T*Vc?2uf2uz4_X(#J{VUYXL8VnJi<|V3Sf;|YD0IhUri}YjDdxS+v40-)G7BxGej?jEl78yx>VbRrzmuqs^-5%_YFNra;FwT z*h@b8)rORWxKH1ZG1EZ|tFa{KAP~HFXFLIekI5gClfm*j^oA5pdGc}Ho^TEZ00W#8 zkDs^C2c%Z=+kjHR+2b|1mmY(UU9c_N!pDoKxXU(2qD1r45qc6z3^5Syg@>kuAE0Yz zF_n_STYI)z#B1rLgDd*ThhVD7zMwv%us+1^=Y9$Gd)4QE7iA`|LaJ*=yGgCm>r|SP zD7G!g7jN)8&hAS|Nxm&2FUr>e+1!vuwI~U7V)?W<3+I- zu*alOS|M=SQ&Eb0Y1jdzIHB>7pjDok9BpvantrPdZ;f=$YgAEmxq2q-LSu>I<#I~p zxl;%YeK>hi9aEjY&_+~8Xc!$Np`rqFf-%AQ=bW769C7_fAJ?jDX@Tp>2BSK(H|S|MC5v~Z}rll{{TrFpJ#f|CZP}}jOOBYd_IsOc zw$j{Y8*Qe-Qk-CtN#LY@+J^@zBLI_tIV0s+{2%L#{PEZ4uvMG^fs%L}<0W4o9P{Mx zamGn7{1b%n+bwei#klq!0qqH0zSkJ-)|4apHt2DL5T_^P0Z?qXwX@R#CBP%HriQc6DB-H z+e#yj(H*R|&>W>013xYISa&_HTY`Fo{ykhP7jWMm(K^zLC$)%?IB&NBxK_!!N-%2&Q;Dc zz&HotcXne>e^EvDJM+uK$3#$%&({VgAl-id~RHxMri#R zuG*G9z{e!gGUyOMD$GIA0F92vxbNZHS-a`oww_wlYbM6r7O7g+jlBWNT@u}*-4mcw zDYWNY4?7MNSneeZGPi+Rke&*LNgVa4>Za~DDXmmL-K|*H9ZS?JZ8bKlEl}>Owy9U8 zqN>9#MrNV(QlvP?)-=P5X}8N|NNr0AI47p`PzH0{l>}$TQgBa@ag&^Xd|+cBb>u~H zVMhdv{Bm$H-N%uR?p68zycbpYcM^i|$-~C5Fyz*DurJ4npqG8a9;Tn%tO9RYn6nu} z`h}T^ZIj_AA$_7S8?hx@+p)sM?o) z;&rO!wrfzEr&VqG)}>vQIxSM3+rIm7XVYa>orx|Y9sVL?$YsX6@}QjLme#f%X@1(U z2*yak1aLvf=jT5KCyeK>D`>Wio^j*t03I>H8Q^i?XBp*QdOVyS~%GA3oP z*Pj9?SYsT?q zYR0B%o3$r&^H6VF8QQ~bGgMulbXG0J)LM?R4gnuOKa-4)&O8za1E+Q{I6HHjHn7;MHdv`PY*4E- zQpMX(@H54m=zjixYIqE9jPz09qe?Vdx2*iD5rC~hbcfh?W~Fk z4TP0yUF4#lVL{(;{z51%%FD|9}xOmSK z*7}t4rHLOOpVM+v$vx1;V z;UiOJ!cGPV3LhgQ8OM>w_T=CX!JzDNQ~f~W!2}*oIOKjw1OEWGMVk|ewou!~(6i{G z#}BxtUT;n{_(=Uo+o1>9S3rG-ZyH(WP5N_7A5q(MNXyiFY_^EmI_^(@pBYPn?76PG z)0Z95a8|A=2_S#TlCfy9s`#JZlhXUIO|bb z+K8%y@>Ih`SX$a>r7BqNBR+OYR=4Wy5}6W_NYwp8rcz+WL|9bXb>m-$0vty0q(+Ms zii2_Eu#z$wX|%QuFp+_j;Vldv;p094Cj^fG4hSUt;Dhjbr|grEKE(GN51ez3F^rMP z$N3*UEwOmHAd0k@`fpwmS{m(E0}Mp`v~d(Dhw5#WQL=lU=f(-949+E#JAYFN8>zqk zO}(G-C&uS=YNn-L(3_`SxAp0B(^-;cu>#?_s}+ch%TiQ>DG{m@Bs7@?wJAREY%jE_ zJ;V|PJ9AcbGR%ScO{b`LwXsVQ9GCia0_m+%prT9333ftaL7N^pebnVEd)p2yaHSmQ ztw6_DX+7P?9~c7|{{T`(MtlRF4;)$jGQlCh55Wp2kPjID05U-%Jn_#;Ty8C^iiV9Z zY_IAH-qrzKUwi8i^m<{pzpJD%+3}$?!TmujqD=+s^&hXKd=9PeL-gLhKTirZTU#}H z;HAoQk{A&IoQrQcqiPngS2d#y7n9I5U{d8XV6aR_y_r49h%Ku`y)HLa;v z#fX`L&AYCPQ}qzgsGD-&s!>%?L}H~zM9`M}2n`~rPE(oQ=NaF9E)Lb5?UxBy^$WD}kbBZ5>hn6!oJr3z_YRu3d8 zS`h=f>rC;4=w=-&re!2(ckSaEY1xCBr7pkH<=n9SgBIA|$6`Dy4(=~p-$RVQtJ;?H zZ>B?Thi|Kq)VhbjOYOLo)QDSeBPn$%1UQ_ef)6R>3h}xvdZ?}2Hyv)>tAxDTYLqIh z%2h!v$OK4l>mfYEl(z6VdB1bD)PNKeJnO1Lv*WY`;Bky&;NX9k=a4XY>%l^gXh=A~ z$7sOgKX*K50RDLx`$s(zwksE1C5jwI;Jaf-f7nP$4BN+KO&IuUj2PFIh{#fIuwDI`bM7=sR>N_t( zJ$mrM%%FqPS~OBuU>=fm2>9@cCZ12GS!Iv|y*!M-9cy}GM)mjm__G)VM2^xi+k?pS z&puU*em}A5vvL&Lkgp^Al0SKJR*tr}(1 zT7hiV-%nsewK@c8%~I+MNM)=$CL4+&wvRo7wKaCC`qW+yDGO3?SI%;KiSjY$;O9IN z4*L03JymN6+H`@-dwA8v=~aXilrXkvNX zNjpaxBTV204=Gg!M+ySxmW3)rJI3}xpvH!&H)NHqO~{Z$R-SQe;VO`|xI(*<0|=*F z70MIRUZPei)M*l!Tv=|?>QgDoek+IXit^#S(%p{YN8ZbdQ)Qe2$voxXu>^Moexlgmvjna^3lBGf80{ z-a^A$w<-4zG5&R#9zuYK(6*yhP@ryWb4w_eM`o2#5IE8hsG(E>pnt>IooxRApN#YO z1#QR*r8!xuu9{?-PE(aWVyWtr=ie~PzfNAtioN2`xN=I5&szJ7D^Xra$nr7==kCWG z{{WtUsq^VX6Osuh%Ek!;k2%H(!5A1GIO>U4alp<_GH?JOk~|W8fN(sVXXmN-VU7^q zoNE|jScFwT%yqV40NWjRC%Nt1_-fA2uBI)ap|iaK_8a&gx4`>&r`*5!lm7s3{!YH? zz6a!g+y4NEUvz&7@T4~00X*d7l0nEB9&yM76X*JqjOVMAGUEG47)U3QIm&xTC!C)I z0or-|5!O}}J;@8~Zy=L__T>GifCm{TBR`IDf&lAxg=th?NN?%Z3W8MMYhaaka%A2F#iC&aG>wGZFVGleuMS>ygx`;k6>G0pgQ|}pZ>gPNnuF?jO6mK z1SFo)Nb`}&P&mjrz{eRzBKH*b4ppAsIRtQ%`2MFk7|B18vOPe4I)e_hw#rXpkfesx zm1h}JQ~kUgagIPB^|xDgl!}AxGL-fyYe;Ok4i%8B9_0_TcMwm&91+?{5tHR0NQ}K> zq<0Pf01mr%-|jy`-{;`zU5fw*$pHNCzJSm_sX8Cw{u*pbTdM#iCje)RcpuCMgU(1K z0&&3^JY>;FabN(_k~lg3Vh9|JdBOM`fsX+ADI0I}&)o*(ZOK<&k!bbjdRvfcFVdw~ zXtae%q_tFx#Ay;Bu4yH+DW)byd2A%9z|*K!0#q}pYUa`|{T8|<+1i0gk#Aj8w|r}H^%VUH9ZFblL~TLX2kqOx#`b%UnA8VUJ5t(~2b>U}fH^1mjxultPmnsl z{oHjb?JX;`qz*|SVMEEmA93UHjQsgFnltGmyPa9Js29zxp|{Oi(755ZI*(b4NKZ zJyBH^#i?jzueg#zbAV6t9^8@$`%VYpTzrm<&b@kU>rUREp~BT$KBH(ERJR_I8l;{XbUO0Q+4LHcbbuEk&aW~R;b=2C8i%hHN<AMa^j_bFB z%tS=jMHsOmO-MpvI^557N@gMlvj6WQ~+EIgo@3 z$_qK^17rh@hMa3i7&7%KRze%3buk1T5TG$6Yy}5?0z34#8!AyrNhE>~^8!W)PmE_g zXE^x;^<*i|kVKX4}<{!aRTn3$h7KkR1sD zT}vwtr6g@g2V=ox$IBdkqbUPne_b)@JuRczh#-J;ba$@)8){)FW-XJn(t^ zWAc7H+?q?hxh<2yw+$uKK>ql6!p*wd(AUT7@;C5%{C7cBMqh6!z`*;Ilga+L9x?}mgU)#C801Hp$OTv@xFsb(jFE%+ z9D;M_K1W9%Q++766{OpCv9}R;*+wp(YARtnX;kA@DKlM~%}So_N-MG{(PueRf`_5U zb>u2kMseHPu!X59B9i5@mr0oHcUvtfr&8OAAY^^mPznkOJ-8qOcpwjeI%kXKR5EhQ z1X7bELNdxjEBbQAvPCaLfW|3fWq9P#NfCpgU`K+_kCp{ef25MVK!TvD3d&0M46U$K zoq{w#J`ncdt-=Wk#W8QFBquoMkVyjv2MN!?Jf9=_oRtDqzELE$8|}lL zxgeaL(}D(aI41=BV%qR-`B% zg$#>vEzS1SFiVaANJs@^03HYfCnG05dG0v@raP6^$VWLwktMGq#XK@b(N6@ikgpWb z$f8K(R@h`^*!d&DCZJ(u-$_V6p*9+m`s#=$%ApGBcK`f?g19ym!+!5<(2 z+nkP0al!l!sK0K?LRH+!NJ!2~a0*5T+73IFpCAm5PmG?ApQeYTZmxQSQZMSBm`k-H zN7K2KDAna$Rgcn?rB@k}^i;%cFs1!KNQU`!UG0Q`gn`_l+Tb_u=uNNNG12BVhW3?Z zRBaaPkZt+qfn76a#HdtRn)D}^9q6$XsOwBOP`4UdgKjAaQUXaSg`b-|6Gn8oQUa714XH>H()JjF!QnIHe5am+%$bcx4T62dCm}qL;Q)ej&(1mU zeDTq-ysoZBueyp=WKctXs#Nr{up?^9%F4>xA+`^3;S$k!WHGP@<3t_pPKYW-!Pq^u zvHBCg32Rg*R**s$gUBHO44>(bfIbFK&m8q-CX(Ysp=dcsB;cljfHNi`?7c{4#QD)NO%7qQs=#t7^CSiV~93ipcvb7V0s}P@|V~yBe}Oh?OGI-XU|dfIrcWi zi7`^gA6ACKqq=MtMUZ_3*X08h zZ4<5ii23k3euOE&kdg@gWdWXibAV6aWAmJ!JzxHW>xn1ZBe)W;x6dDfG7fS{{{X+G za^JGvs#amsS#PA(iehSv*1ua6;YE2Yx|vQXR2j&7xTUl#w1q5p5|_DNV^bXQM5?gf0oCD zF?2W7gs8Tn6afSz1A&eY!O6(a13VL-IN4N5al(|S&II6qeX;_G1o8O;jDdnN@N
xTc34Btr;qZC6BH5lLnXU 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 z

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 M`0O+%{NLjL03MkqCjbBd diff --git a/docs/ops/hardware.toml b/docs/ops/hardware.toml index 24f73bda..2c575264 100644 --- a/docs/ops/hardware.toml +++ b/docs/ops/hardware.toml @@ -77,7 +77,7 @@ description = """ ["IN.CAL.RESET"] prototype = "IN.CAL.RESET" -short = "Reset the input CV calibration" +short = "Resets the input CV calibration" ["PARAM.CAL.MIN"] prototype = "PARAM.CAL.MIN" From 13bbc2eee4b05d1612fb2982f83af8a850eeca3c Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Thu, 9 Aug 2018 20:49:40 -0700 Subject: [PATCH 112/117] update grid control mode --- module/grid.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/module/grid.c b/module/grid.c index fed1136f..02f0ed12 100644 --- a/module/grid.c +++ b/module/grid.c @@ -178,6 +178,7 @@ static grid_control_mode_t tt_mode = G_LIVE_V, tt_last_mode = G_LIVE_V; static u8 control_mode_on, tt_script, variable_edit, variable_changed; static u8 preset_write, tracker_pressed, tracker_x, tracker_y; static u8 tracker_changed, tracker_select, tracker_selected; +static u8 tracker_set_start, tracker_set_end; static s16 tracker_last, variable_last; static u16 size_x = 16, size_y = 8; static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION/2]; @@ -523,6 +524,9 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ if (tt_mode == G_TRACKER) { u8 offset = get_pattern_offset(); + if (x == 7 && y == 4) tracker_set_start = z; + if (x == 7 && y == 5) tracker_set_end = z; + if (tracker_pressed) { s16 value = ss_get_pattern_val(ss, tracker_x-2, tracker_y+offset); @@ -600,7 +604,7 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ return 1; } - if (tracker_select) { + if (tracker_select || tracker_set_start || tracker_set_end) { if (x == 7 && y == tracker_select && !z) { if (y == 3 && !tracker_selected) { turtle_set_shown(&ss->turtle, !turtle_get_shown(&ss->turtle)); @@ -623,17 +627,19 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ turtle_set_shown(&ss->turtle, 1); tele_pattern_updated(); ss->grid.grid_dirty = 1; - } else if (tracker_select == 4) { + } + if (tracker_set_start) { // set start - tracker_selected = 1; ss_set_pattern_start(ss, x - 2, y + offset); + tracker_selected = 1; tele_pattern_updated(); ss->grid.grid_dirty = 1; - } else if (tracker_select == 5) { + } + if (tracker_set_end) { // set end - tracker_selected = 1; ss_set_pattern_end(ss, x - 2, y + offset); ss_set_pattern_len(ss, x - 2, y + offset + 1); + tracker_selected = 1; tele_pattern_updated(); ss->grid.grid_dirty = 1; } @@ -667,7 +673,7 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ u8 offset = get_pattern_offset(); if (offset < 56) set_pattern_offset(offset + 1); ss->grid.grid_dirty = 1; - } else if (x == 7 && y > 1 && z) { + } else if (x == 7 && y > 1 && y != 4 && y != 5 && z) { tracker_select = y; tracker_selected = 0; } From a6a43b03f4ac689524e191363e3feb222668e060 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 10 Aug 2018 08:36:41 -0700 Subject: [PATCH 113/117] make cursor brighter --- libavr32 | 2 +- module/line_editor.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libavr32 b/libavr32 index b49b2bfd..cde5d4fc 160000 --- a/libavr32 +++ b/libavr32 @@ -1 +1 @@ -Subproject commit b49b2bfda708ea1e05d5db8f3444dd01831b3850 +Subproject commit cde5d4fc86e7684ff512e4be6d9ddca787f8bbba diff --git a/module/line_editor.c b/module/line_editor.c index c468b814..c0e65f70 100644 --- a/module/line_editor.c +++ b/module/line_editor.c @@ -178,5 +178,5 @@ void line_editor_draw(line_editor_t *le, char prefix, region *reg) { strcat(s, " "); region_fill(reg, 0); - font_string_region_clip_hi(reg, s, 0, 0, 0xf, 0, le->cursor + 2); + font_string_region_clip_hid(reg, s, 0, 0, 0xf, 0, le->cursor + 2, 3); } From b2c8d167d0bc0eaf581d8db3317dda3f07d7fb22 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 10 Aug 2018 08:43:12 -0700 Subject: [PATCH 114/117] clangify --- module/edit_mode.c | 28 +- module/flash.c | 4 +- module/grid.c | 808 +++++++++++++++++++++++++----------------- module/grid.h | 5 +- module/help_mode.c | 745 +++++++++++++++++++------------------- module/live_mode.c | 31 +- module/live_mode.h | 3 +- module/main.c | 22 +- module/pattern_mode.c | 4 +- module/profile.h | 4 +- 10 files changed, 908 insertions(+), 746 deletions(-) diff --git a/module/edit_mode.c b/module/edit_mode.c index 863c6193..f362d67f 100644 --- a/module/edit_mode.c +++ b/module/edit_mode.c @@ -65,25 +65,25 @@ static void save_undo(void) { undo_line_no2[undo_pos] = line_no2; undo_length[undo_pos] = ss_get_script_len(&scene_state, script); for (u8 l = 0; l < undo_length[undo_pos]; l++) { - undo_comments[undo_pos][l] = ss_get_script_comment(&scene_state, - script, l); - ss_copy_script_command(&undo_buffer[undo_pos][l], - &scene_state, script, l); + undo_comments[undo_pos][l] = + ss_get_script_comment(&scene_state, script, l); + ss_copy_script_command(&undo_buffer[undo_pos][l], &scene_state, script, + l); } } static void undo(void) { if (undo_count == 0) return; undo_count--; - + ss_clear_script(&scene_state, script); for (u8 l = 0; l < undo_length[undo_pos]; l++) { ss_insert_script_command(&scene_state, script, l, - &undo_buffer[undo_pos][l]); + &undo_buffer[undo_pos][l]); ss_set_script_comment(&scene_state, script, l, - undo_comments[undo_pos][l]); + undo_comments[undo_pos][l]); } - + line_no1 = undo_line_no1[undo_pos]; line_no2 = undo_line_no2[undo_pos]; @@ -100,9 +100,7 @@ void edit_mode_refresh() { void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { // C-z: undo - if (match_ctrl(m, k, HID_Z)) { - undo(); - } + if (match_ctrl(m, k, HID_Z)) { undo(); } // or C-n: line down else if (match_no_mod(m, k, HID_DOWN) || match_ctrl(m, k, HID_N)) { if (line_no1 < (SCRIPT_MAX_COMMANDS - 1) && @@ -150,7 +148,8 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { &le, ss_get_script_command(&scene_state, script, line_no1)); dirty |= D_LIST | D_INPUT; } - } else if (line_no2) { + } + else if (line_no2) { line_no2--; dirty |= D_LIST | D_INPUT; } @@ -223,7 +222,7 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { save_undo(); strcpy(copy_buffer[0], line_editor_get(&le)); copy_buffer_len = 1; - ss_delete_script_command(&scene_state, script, line_no1); + ss_delete_script_command(&scene_state, script, line_no1); } } else { @@ -257,7 +256,8 @@ void process_edit_keys(uint8_t k, uint8_t m, bool is_held_key) { else { save_undo(); copy_buffer_len = 0; - for (u8 l = min(line_no1, line_no2); l <= max(line_no1, line_no2); l++) + for (u8 l = min(line_no1, line_no2); l <= max(line_no1, line_no2); + l++) print_command(ss_get_script_command(&scene_state, script, l), copy_buffer[copy_buffer_len++]); } diff --git a/module/flash.c b/module/flash.c index 74440336..ad7e5233 100644 --- a/module/flash.c +++ b/module/flash.c @@ -4,8 +4,8 @@ // asf #include "flashc.h" -#include "print_funcs.h" #include "init_teletype.h" +#include "print_funcs.h" // this #include "teletype.h" @@ -21,7 +21,7 @@ static grid_data_t grid_data; // NVRAM data structure located in the flash array. typedef const struct { - scene_script_t scripts[SCRIPT_COUNT - 1]; // Exclude TEMP script + scene_script_t scripts[SCRIPT_COUNT - 1]; // Exclude TEMP script scene_pattern_t patterns[PATTERN_COUNT]; grid_data_t grid_data; char text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS]; diff --git a/module/grid.c b/module/grid.c index 02f0ed12..bde39a21 100644 --- a/module/grid.c +++ b/module/grid.c @@ -1,16 +1,16 @@ #include "grid.h" +#include "edit_mode.h" +#include "flash.h" #include "font.h" #include "globals.h" +#include "live_mode.h" +#include "pattern_mode.h" +#include "preset_r_mode.h" #include "state.h" #include "teletype.h" #include "teletype_io.h" #include "timers.h" #include "util.h" -#include "edit_mode.h" -#include "live_mode.h" -#include "pattern_mode.h" -#include "preset_r_mode.h" -#include "flash.h" #define GRID_MAX_KEY_PRESSED 10 #define GRID_KEY_HOLD_DELAY 700 @@ -28,6 +28,8 @@ typedef enum { G_PRESET } grid_control_mode_t; +// clang-format off + static const u8 glyph[16][6] = { { 0b000000, @@ -159,6 +161,8 @@ static const u8 glyph[16][6] = { } }; +// clang-format on + typedef struct { u8 used; u8 key; @@ -181,18 +185,22 @@ static u8 tracker_changed, tracker_select, tracker_selected; static u8 tracker_set_start, tracker_set_end; static s16 tracker_last, variable_last; static u16 size_x = 16, size_y = 8; -static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION/2]; +static u8 screen[GRID_MAX_DIMENSION][GRID_MAX_DIMENSION / 2]; static hold_repeat_info held_keys[GRID_MAX_KEY_PRESSED]; static u8 timers_uninitialized = 1; static script_trigger_info script_triggers[11]; static void grid_control_refresh(scene_state_t *ss); -static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_held); -static void hold_repeat_timer_callback(void* o); +static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, + u8 from_held); +static void hold_repeat_timer_callback(void *o); static void grid_process_key_hold_repeat(scene_state_t *ss, u8 x, u8 y); -static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); -static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); -static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2); +static void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, + u8 x2, u8 y2); +static void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, + u8 x1, u8 y1, u8 x2, u8 y2); +static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, + u8 x2, u8 y2); static bool grid_within_area(u8 x, u8 y, grid_common_t *gc); static void grid_fill_area(u8 x, u8 y, u8 w, u8 h, s8 level); static void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, s8 level, u8 page); @@ -205,12 +213,15 @@ void grid_set_control_mode(u8 control, u8 mode, scene_state_t *ss) { tt_mode = G_LIVE_GF; else tt_mode = G_LIVE_V; - } else if (mode == M_EDIT) { + } + else if (mode == M_EDIT) { tt_mode = G_EDIT; tt_script = get_edit_script(); - } else if (mode == M_PATTERN) { + } + else if (mode == M_PATTERN) { tt_mode = G_TRACKER; - } else if (mode == M_PRESET_W || mode == M_PRESET_R) { + } + else if (mode == M_PRESET_W || mode == M_PRESET_R) { tt_mode = G_PRESET; } control_mode_on = control; @@ -221,7 +232,7 @@ void grid_set_control_mode(u8 control, u8 mode, scene_state_t *ss) { void grid_control_refresh(scene_state_t *ss) { size_x = monome_size_x(); size_y = monome_size_y(); - + u16 d = size_y == 16 ? 128 : 0; if (size_x == 16) d += 8; @@ -256,7 +267,7 @@ void grid_control_refresh(scene_state_t *ss) { u8 line_on = 8; u8 line_off = 4; u8 script_control = 8; - + if (!monome_is_vari()) { mode_on = 15; mode_off = 15; @@ -291,174 +302,185 @@ void grid_control_refresh(scene_state_t *ss) { } for (u16 i = 0; i < 8; i++) - for (u16 j = 0; j < 8; j++) - monomeLedBuffer[d+i+(j<<4)] = 0; - + for (u16 j = 0; j < 8; j++) monomeLedBuffer[d + i + (j << 4)] = 0; + if (tt_mode == G_TRACKER) { - monomeLedBuffer[d+7] = mode_on; + monomeLedBuffer[d + 7] = mode_on; u8 offset = get_pattern_offset(), in, off, rem; for (u16 j = 0; j < 8; j++) { for (u16 i = 0; i < 4; i++) { in = offset + j >= ss_get_pattern_start(ss, i) && - offset + j <= ss_get_pattern_end(ss, i); - monomeLedBuffer[d+i+2+(j<<4)] = - ss_get_pattern_val(ss, i, j + offset) ? - tracker_on : (in ? tracker_in : tracker_out); + offset + j <= ss_get_pattern_end(ss, i); + monomeLedBuffer[d + i + 2 + (j << 4)] = + ss_get_pattern_val(ss, i, j + offset) + ? tracker_on + : (in ? tracker_in : tracker_out); } off = offset >> 3; rem = (offset & 7) >> 1; - monomeLedBuffer[d+(j<<4)] = - j == off ? tracker_page_on - rem : - (j == off + 1 ? tracker_page_off + rem : tracker_page_off); + monomeLedBuffer[d + (j << 4)] = + j == off ? tracker_page_on - rem + : (j == off + 1 ? tracker_page_off + rem + : tracker_page_off); } for (u16 i = 0; i < 4; i++) { u8 index = ss_get_pattern_idx(ss, i); if (index >= offset && index <= offset + 7) { - monomeLedBuffer[d+i+2+(index<<4)] += tracker_pos; + monomeLedBuffer[d + i + 2 + (index << 4)] += tracker_pos; } } d += 32; - monomeLedBuffer[d+7] = tracker_control; + monomeLedBuffer[d + 7] = tracker_control; d += 16; - monomeLedBuffer[d+7] = + monomeLedBuffer[d + 7] = turtle_get_shown(&ss->turtle) ? tracker_control : tracker_loop; d += 16; - monomeLedBuffer[d+7] = tracker_loop; + monomeLedBuffer[d + 7] = tracker_loop; d += 16; - monomeLedBuffer[d+7] = tracker_loop; + monomeLedBuffer[d + 7] = tracker_loop; d += 16; - monomeLedBuffer[d+7] = tracker_control; + monomeLedBuffer[d + 7] = tracker_control; d += 16; - monomeLedBuffer[d+7] = tracker_control; + monomeLedBuffer[d + 7] = tracker_control; return; } - + // mode selection - monomeLedBuffer[d] = + monomeLedBuffer[d] = tt_mode == G_EDIT && tt_script == 8 ? mode_on : mode_off; - monomeLedBuffer[d+1] = + monomeLedBuffer[d + 1] = tt_mode == G_EDIT && tt_script == 9 ? mode_on : mode_off; - monomeLedBuffer[d+3] = tt_mode == G_LIVE_V ? mode_on : mode_off; - monomeLedBuffer[d+4] = + monomeLedBuffer[d + 3] = tt_mode == G_LIVE_V ? mode_on : mode_off; + monomeLedBuffer[d + 4] = tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF ? mode_on : mode_off; - monomeLedBuffer[d+6] = tt_mode == G_PRESET ? mode_on : mode_off; - monomeLedBuffer[d+7] = mode_off; + monomeLedBuffer[d + 6] = tt_mode == G_PRESET ? mode_on : mode_off; + monomeLedBuffer[d + 7] = mode_off; d += 16; for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = + monomeLedBuffer[d + i] = tt_mode == G_EDIT && tt_script == i ? mode_on : mode_off; d += 16; - + if (tt_mode == G_PRESET) { for (u8 j = 0; j < 25; j += 8) { for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = i + j == - preset_select ? preset_selected : preset_unselected; + monomeLedBuffer[d + i] = i + j == preset_select + ? preset_selected + : preset_unselected; d += 16; } - - monomeLedBuffer[d+7] = preset_scroll; + + monomeLedBuffer[d + 7] = preset_scroll; d += 16; - monomeLedBuffer[d+2] = preset_load; - monomeLedBuffer[d+4] = preset_save; - monomeLedBuffer[d+7] = preset_scroll; + monomeLedBuffer[d + 2] = preset_load; + monomeLedBuffer[d + 4] = preset_save; + monomeLedBuffer[d + 7] = preset_scroll; return; } - monomeLedBuffer[d+16] = ss->variables.m_act ? mute_off : mute_on; - monomeLedBuffer[d+17] = script_triggers[10].on ? exec : kill; - monomeLedBuffer[d+32] = script_triggers[8].on ? exec : trig; - monomeLedBuffer[d+33] = script_triggers[9].on ? exec : trig; - + monomeLedBuffer[d + 16] = ss->variables.m_act ? mute_off : mute_on; + monomeLedBuffer[d + 17] = script_triggers[10].on ? exec : kill; + monomeLedBuffer[d + 32] = script_triggers[8].on ? exec : trig; + monomeLedBuffer[d + 33] = script_triggers[9].on ? exec : trig; + if (tt_mode == G_LIVE_V) { - monomeLedBuffer[d+3] = variable_edit == 1 ? var_edit_on : var_edit_off; - monomeLedBuffer[d+4] = variable_edit == 2 ? var_edit_on : var_edit_off; + monomeLedBuffer[d + 3] = + variable_edit == 1 ? var_edit_on : var_edit_off; + monomeLedBuffer[d + 4] = + variable_edit == 2 ? var_edit_on : var_edit_off; d += 16; - monomeLedBuffer[d+3] = variable_edit == 3 ? var_edit_on : var_edit_off; - monomeLedBuffer[d+4] = variable_edit == 4 ? var_edit_on : var_edit_off; - monomeLedBuffer[d+6] = live_hist; + monomeLedBuffer[d + 3] = + variable_edit == 3 ? var_edit_on : var_edit_off; + monomeLedBuffer[d + 4] = + variable_edit == 4 ? var_edit_on : var_edit_off; + monomeLedBuffer[d + 6] = live_hist; d += 16; - monomeLedBuffer[d+3] = variable_edit == 5 ? var_edit_on : var_edit_off; - monomeLedBuffer[d+4] = variable_edit == 6 ? var_edit_on : var_edit_off; - monomeLedBuffer[d+6] = live_hist; - monomeLedBuffer[d+7] = live_exec; + monomeLedBuffer[d + 3] = + variable_edit == 5 ? var_edit_on : var_edit_off; + monomeLedBuffer[d + 4] = + variable_edit == 6 ? var_edit_on : var_edit_off; + monomeLedBuffer[d + 6] = live_hist; + monomeLedBuffer[d + 7] = live_exec; d += 16; - monomeLedBuffer[d+3] = variable_edit == 7 ? var_edit_on : var_edit_off; - monomeLedBuffer[d+4] = variable_edit == 8 ? var_edit_on : var_edit_off; - - } else if (tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF) { + monomeLedBuffer[d + 3] = + variable_edit == 7 ? var_edit_on : var_edit_off; + monomeLedBuffer[d + 4] = + variable_edit == 8 ? var_edit_on : var_edit_off; + } + else if (tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF) { d += 16; - monomeLedBuffer[d+7] = grid_page == 0 ? grid_page_on : grid_page_off; + monomeLedBuffer[d + 7] = grid_page == 0 ? grid_page_on : grid_page_off; d += 16; - monomeLedBuffer[d+3] = ss->grid.rotate ? grid_page_on : grid_page_off; - monomeLedBuffer[d+5] = + monomeLedBuffer[d + 3] = ss->grid.rotate ? grid_page_on : grid_page_off; + monomeLedBuffer[d + 5] = grid_show_controls ? grid_page_on : grid_page_off; - monomeLedBuffer[d+7] = grid_page == 1 ? grid_page_on : grid_page_off; + monomeLedBuffer[d + 7] = grid_page == 1 ? grid_page_on : grid_page_off; d += 16; - - } else if (tt_mode == G_EDIT) { + } + else if (tt_mode == G_EDIT) { d += 16; - monomeLedBuffer[d+3] = + monomeLedBuffer[d + 3] = ss_get_script_comment(ss, tt_script, 0) ? line_off : line_on; - monomeLedBuffer[d+4] = + monomeLedBuffer[d + 4] = ss_get_script_comment(ss, tt_script, 3) ? line_off : line_on; - monomeLedBuffer[d+7] = script_control; + monomeLedBuffer[d + 7] = script_control; d += 16; - monomeLedBuffer[d+3] = + monomeLedBuffer[d + 3] = ss_get_script_comment(ss, tt_script, 1) ? line_off : line_on; - monomeLedBuffer[d+4] = + monomeLedBuffer[d + 4] = ss_get_script_comment(ss, tt_script, 4) ? line_off : line_on; - monomeLedBuffer[d+7] = script_control; + monomeLedBuffer[d + 7] = script_control; d += 16; - monomeLedBuffer[d+3] = + monomeLedBuffer[d + 3] = ss_get_script_comment(ss, tt_script, 2) ? line_off : line_on; - monomeLedBuffer[d+4] = + monomeLedBuffer[d + 4] = ss_get_script_comment(ss, tt_script, 5) ? line_off : line_on; - } + } d += 16; - + // script mutes - for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = ss_get_mute(ss, i) ? mute_on : mute_off; + for (u16 i = 0; i < 8; i++) + monomeLedBuffer[d + i] = ss_get_mute(ss, i) ? mute_on : mute_off; d += 16; - + // triggered scripts for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = script_triggers[i].on ? exec : trig; - + monomeLedBuffer[d + i] = script_triggers[i].on ? exec : trig; + if (variable_edit) { u8 ve = variable_edit - 1; int16_t *v = &(ss->variables.a); if (size_x == 8) { if (v[ve] < 0) for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = var_value_off; + monomeLedBuffer[d + i] = var_value_off; else if (v[ve] > 8) for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = var_value_on; + monomeLedBuffer[d + i] = var_value_on; else for (u16 i = 0; i < 8; i++) - monomeLedBuffer[d+i] = + monomeLedBuffer[d + i] = i < v[ve] ? var_value_on : var_value_off; - } else { + } + else { d -= 8; if (v[ve] < 0) for (u16 i = 0; i < 16; i++) - monomeLedBuffer[d+i] = var_value_off; + monomeLedBuffer[d + i] = var_value_off; else if (v[ve] > 16) for (u16 i = 0; i < 16; i++) - monomeLedBuffer[d+i] = var_value_on; + monomeLedBuffer[d + i] = var_value_on; else for (u16 i = 0; i < 16; i++) - monomeLedBuffer[d+i] = + monomeLedBuffer[d + i] = i < v[ve] ? var_value_on : var_value_off; } } } -static void script_triggers_callback(void* o) { - script_trigger_info* st = o; +static void script_triggers_callback(void *o) { + script_trigger_info *st = o; timer_remove(&st->timer); st->on = 0; st->ss->grid.grid_dirty = 1; @@ -468,9 +490,9 @@ void grid_metro_triggered(scene_state_t *ss) { script_triggers[8].on = 1; script_triggers[8].ss = ss; timer_remove(&script_triggers[8].timer); - timer_add(&script_triggers[8].timer, - min(GRID_SCRIPT_TRIGGER, ss->variables.m >> 1), - &script_triggers_callback, (void *)&script_triggers[8]); + timer_add(&script_triggers[8].timer, + min(GRID_SCRIPT_TRIGGER, ss->variables.m >> 1), + &script_triggers_callback, (void *)&script_triggers[8]); ss->grid.grid_dirty = 1; } @@ -479,18 +501,23 @@ static void restore_last_mode(scene_state_t *ss) { if (tt_mode == G_EDIT) { set_edit_mode_script(tt_script); set_mode(M_EDIT); - } else if (tt_mode == G_PRESET) { + } + else if (tt_mode == G_PRESET) { set_mode(M_PRESET_R); - } else if (tt_mode == G_LIVE_V) { + } + else if (tt_mode == G_LIVE_V) { set_mode(M_LIVE); set_live_submode(1); - } else if (tt_mode == G_LIVE_G) { + } + else if (tt_mode == G_LIVE_G) { set_mode(M_LIVE); set_live_submode(2); - } else if (tt_mode == G_LIVE_GF) { + } + else if (tt_mode == G_LIVE_GF) { set_mode(M_LIVE); set_live_submode(3); - } else if (tt_mode == G_TRACKER) { + } + else if (tt_mode == G_TRACKER) { tt_mode = G_TRACKER; set_mode(M_PATTERN); } @@ -498,7 +525,8 @@ static void restore_last_mode(scene_state_t *ss) { ss->grid.grid_dirty = 1; } -static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_held) { +static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, + u8 from_held) { if (size_y == 16) { if (y < 8) return 0; y -= 8; @@ -519,83 +547,93 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ if (x < 8) return 0; x -= 8; } - + // tracker if (tt_mode == G_TRACKER) { u8 offset = get_pattern_offset(); - + if (x == 7 && y == 4) tracker_set_start = z; if (x == 7 && y == 5) tracker_set_end = z; - + if (tracker_pressed) { - s16 value = ss_get_pattern_val(ss, tracker_x-2, tracker_y+offset); - + s16 value = + ss_get_pattern_val(ss, tracker_x - 2, tracker_y + offset); + if (x == tracker_x && y == tracker_y && !z) { if (!tracker_changed) { - s16 value = ss_get_pattern_val(ss, tracker_x-2, - tracker_y+get_pattern_offset()); + s16 value = ss_get_pattern_val( + ss, tracker_x - 2, tracker_y + get_pattern_offset()); if (value) { tracker_last = value; value = 0; - } else { + } + else { value = tracker_last ? tracker_last : 1; } - ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, value); + ss_set_pattern_val(ss, tracker_x - 2, tracker_y + offset, + value); } tracker_pressed = 0; tele_pattern_updated(); ss->grid.grid_dirty = 1; return 1; } - + if (!z) return 1; - + u8 updated = 0; if (y == tracker_y) { if (x == tracker_x + 1) { if (value < 32767) { - ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, - value + 1); + ss_set_pattern_val(ss, tracker_x - 2, + tracker_y + offset, value + 1); updated = 1; } - } else if (x == tracker_x + 2) { + } + else if (x == tracker_x + 2) { if (value < 32758) { - ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, - value + 10); + ss_set_pattern_val(ss, tracker_x - 2, + tracker_y + offset, value + 10); updated = 1; - } else if (value < 32767) { - ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, - 32767); + } + else if (value < 32767) { + ss_set_pattern_val(ss, tracker_x - 2, + tracker_y + offset, 32767); updated = 1; } - } else if (x == tracker_x - 1) { + } + else if (x == tracker_x - 1) { if (value > -32768) { - ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, - value - 1); + ss_set_pattern_val(ss, tracker_x - 2, + tracker_y + offset, value - 1); updated = 1; } - } else if (x == tracker_x - 2) { + } + else if (x == tracker_x - 2) { if (value > -32759) { - ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, - value - 10); + ss_set_pattern_val(ss, tracker_x - 2, + tracker_y + offset, value - 10); updated = 1; - } else if (value > -32768) { - ss_set_pattern_val(ss, tracker_x-2, tracker_y+offset, - -32768); + } + else if (value > -32768) { + ss_set_pattern_val(ss, tracker_x - 2, + tracker_y + offset, -32768); updated = 1; } } - } else if (x > 1 && x < 6) { + } + else if (x > 1 && x < 6) { // set loop if (from_held) return 1; for (u8 i = min(tracker_x, x); i <= max(tracker_x, x); i++) { - ss_set_pattern_start(ss, i - 2, min(y, tracker_y)+offset); - ss_set_pattern_end(ss, i - 2, max(y, tracker_y)+offset); - ss_set_pattern_len(ss, i - 2, max(y, tracker_y)+offset+1); + ss_set_pattern_start(ss, i - 2, min(y, tracker_y) + offset); + ss_set_pattern_end(ss, i - 2, max(y, tracker_y) + offset); + ss_set_pattern_len(ss, i - 2, + max(y, tracker_y) + offset + 1); } updated = 1; } - + if (updated) { tracker_changed = 1; tele_pattern_updated(); @@ -603,23 +641,26 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ } return 1; } - + if (tracker_select || tracker_set_start || tracker_set_end) { if (x == 7 && y == tracker_select && !z) { if (y == 3 && !tracker_selected) { - turtle_set_shown(&ss->turtle, !turtle_get_shown(&ss->turtle)); + turtle_set_shown(&ss->turtle, + !turtle_get_shown(&ss->turtle)); tele_pattern_updated(); ss->grid.grid_dirty = 1; } tracker_select = 0; - } else if (x > 1 && x < 6 && z && !from_held) { + } + else if (x > 1 && x < 6 && z && !from_held) { if (tracker_select == 2) { // set current position tracker_selected = 1; ss_set_pattern_idx(ss, x - 2, offset + y); tele_pattern_updated(); ss->grid.grid_dirty = 1; - } else if (tracker_select == 3) { + } + else if (tracker_select == 3) { // set turtle position tracker_selected = 1; turtle_set_x(&ss->turtle, x - 2); @@ -646,7 +687,7 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ } return 1; } - + if (x > 1 && x < 6 && z) { // pattern value selected if (x != tracker_x || y != tracker_y) tracker_last = 0; @@ -657,33 +698,38 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ set_pattern_selected_value(x - 2, y); tele_pattern_updated(); ss->grid.grid_dirty = 1; - } else if (x == 7 && y == 0 && !from_held && z) { + } + else if (x == 7 && y == 0 && !from_held && z) { // exit tracker restore_last_mode(ss); ss->grid.grid_dirty = 1; - } else if (x == 0 && !from_held && z) { + } + else if (x == 0 && !from_held && z) { // select page set_pattern_offset(y << 3); ss->grid.grid_dirty = 1; - } else if (x == 7 && y == 6 && z) { + } + else if (x == 7 && y == 6 && z) { u8 offset = get_pattern_offset(); if (offset) set_pattern_offset(offset - 1); ss->grid.grid_dirty = 1; - } else if (x == 7 && y == 7 && z) { + } + else if (x == 7 && y == 7 && z) { u8 offset = get_pattern_offset(); if (offset < 56) set_pattern_offset(offset + 1); ss->grid.grid_dirty = 1; - } else if (x == 7 && y > 1 && y != 4 && y != 5 && z) { + } + else if (x == 7 && y > 1 && y != 4 && y != 5 && z) { tracker_select = y; tracker_selected = 0; } return 1; } - + // select page if (y == 0) { if (!z || from_held) return 1; - + switch (x) { case 0: case 1: @@ -719,8 +765,7 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ set_mode(M_PATTERN); ss->grid.grid_dirty = 1; break; - default: - break; + default: break; } grid_clear_held_keys(); return 1; @@ -747,48 +792,55 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ } process_preset_r_preset(x + ((y - 2) << 3)); ss->grid.grid_dirty = 1; - } else if (y == 6 && x == 7) { + } + else if (y == 6 && x == 7) { if (preset_write) { preset_write = 0; set_mode(M_PRESET_R); } preset_line_up(); ss->grid.grid_dirty = 1; - } else if (y == 7 && x == 7) { + } + else if (y == 7 && x == 7) { if (preset_write) { preset_write = 0; set_mode(M_PRESET_R); } preset_line_down(); ss->grid.grid_dirty = 1; - } else if (y == 7 && x == 2 && !from_held) { + } + else if (y == 7 && x == 2 && !from_held) { if (preset_write) { preset_write = 0; set_mode(M_PRESET_R); - } else { + } + else { process_preset_r_load(); set_mode(M_PRESET_R); restore_last_mode(ss); } ss->grid.grid_dirty = 1; - } else if (y == 7 && x == 4 && !from_held) { + } + else if (y == 7 && x == 4 && !from_held) { if (preset_write) { flash_write(preset_select, ss, &scene_text); flash_update_last_saved_scene(preset_select); preset_write = 0; restore_last_mode(ss); - } else { + } + else { set_mode(M_PRESET_W); preset_write = 1; } ss->grid.grid_dirty = 1; - } else { + } + else { preset_write = 0; set_mode(M_PRESET_R); } return 1; } - + // mutes if (y == 6) { if (!z || from_held) return 1; @@ -806,22 +858,23 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ script_triggers[x].ss = ss; timer_remove(&script_triggers[x].timer); timer_add(&script_triggers[x].timer, GRID_SCRIPT_TRIGGER, - &script_triggers_callback, (void *)&script_triggers[x]); + &script_triggers_callback, (void *)&script_triggers[x]); ss->grid.grid_dirty = 1; run_script(ss, x); return 1; } - + if (variable_edit && y > 1 && y < 6) { int16_t *v = &(ss->variables.a); u8 ve = variable_edit - 1; - + if (!z && x > 2 && x < 5 && variable_edit == x - 2 + ((y - 2) << 1)) { if (!variable_changed) { if (v[ve]) { variable_last = v[ve]; v[ve] = 0; - } else { + } + else { v[ve] = variable_last ? variable_last : 1; } } @@ -831,26 +884,33 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ return 1; } if (!z) return 1; - + u8 v_x = 3 + (ve & 1); if (x == v_x + 1) { if (v[ve] < 32767) v[ve]++; - } else if (x == v_x + 2) { - if (v[ve] < 32758) v[ve] += 10; - else v[ve] = 32767; - } else if (x == v_x - 1) { + } + else if (x == v_x + 2) { + if (v[ve] < 32758) + v[ve] += 10; + else + v[ve] = 32767; + } + else if (x == v_x - 1) { if (v[ve] > -32768) v[ve]--; - } else if (x == v_x - 2) { - if (v[ve] > -32759) v[ve] -= 10; - else v[ve] = -32768; } - + else if (x == v_x - 2) { + if (v[ve] > -32759) + v[ve] -= 10; + else + v[ve] = -32768; + } + variable_changed = 1; set_vars_updated(); ss->grid.grid_dirty = 1; return 1; } - + // metro on/off if (y == 3 && x == 0 && !from_held && !z) { ss->variables.m_act = !ss->variables.m_act; @@ -859,19 +919,19 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ ss->grid.grid_dirty = 1; return 1; } - + // kill slews/delays if (y == 3 && x == 1 && !from_held && z) { script_triggers[10].on = 1; script_triggers[10].ss = ss; timer_remove(&script_triggers[x].timer); timer_add(&script_triggers[10].timer, GRID_SCRIPT_TRIGGER, - &script_triggers_callback, (void *)&script_triggers[10]); + &script_triggers_callback, (void *)&script_triggers[10]); clear_delays_and_slews(ss); ss->grid.grid_dirty = 1; return 1; - } - + } + // trigger metro/init if (y == 4 && x < 2 && z) { x += 8; @@ -879,12 +939,12 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ script_triggers[x].ss = ss; timer_remove(&script_triggers[x].timer); timer_add(&script_triggers[x].timer, GRID_SCRIPT_TRIGGER, - &script_triggers_callback, (void *)&script_triggers[x]); + &script_triggers_callback, (void *)&script_triggers[x]); ss->grid.grid_dirty = 1; run_script(ss, x); return 1; } - + // live variables if (tt_mode == G_LIVE_V) { if (y > 1 && y < 6 && x > 2 && x < 5 && !from_held) { @@ -893,61 +953,66 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ ss->grid.grid_dirty = 1; return 1; } - + if (!z) return 1; - - if (y == 3 && x == 6) { - history_prev(); - } else if (y == 4 && x == 6) { + + if (y == 3 && x == 6) { history_prev(); } + else if (y == 4 && x == 6) { history_next(); - } else if (y == 4 && x == 7 && !from_held) { + } + else if (y == 4 && x == 7 && !from_held) { execute_line(); } - + return 1; } - + // live grid preview if (tt_mode == G_LIVE_G || tt_mode == G_LIVE_GF) { if (!z || from_held) return 1; - + if (y == 3 && x == 7) { grid_page = 0; set_grid_updated(); ss->grid.grid_dirty = 1; - } else if (y == 4 && x == 3) { + } + else if (y == 4 && x == 3) { ss->grid.rotate = ss->grid.rotate == 0; set_grid_updated(); ss->grid.grid_dirty = 1; - } else if (y == 4 && x == 5) { + } + else if (y == 4 && x == 5) { grid_show_controls = !grid_show_controls; set_grid_updated(); ss->grid.grid_dirty = 1; - } else if (y == 4 && x == 7) { + } + else if (y == 4 && x == 7) { grid_page = 1; set_grid_updated(); ss->grid.grid_dirty = 1; } - + return 1; } // edit scripts if (tt_mode == G_EDIT) { if (!z || from_held) return 1; - + if (y > 2 && y < 6 && x > 2 && x < 5) { u8 i = (x - 3) * 3 + y - 3; if (i >= ss_get_script_len(ss, tt_script)) return 1; ss_toggle_script_comment(ss, tt_script, i); edit_mode_refresh(); ss->grid.grid_dirty = 1; - } else if (y == 3 && x == 7) { + } + else if (y == 3 && x == 7) { for (u8 i = 0; i < ss_get_script_len(ss, tt_script); i++) ss_set_script_comment(ss, tt_script, i, 1); edit_mode_refresh(); ss->grid.grid_dirty = 1; - } else if (y == 4 && x == 7) { + } + else if (y == 4 && x == 7) { for (u8 i = 0; i < ss_get_script_len(ss, tt_script); i++) ss_set_script_comment(ss, tt_script, i, 0); edit_mode_refresh(); @@ -955,17 +1020,16 @@ static u8 grid_control_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 from_ } return 1; } - + return 1; } void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { if (timers_uninitialized) { timers_uninitialized = 0; - for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) - held_keys[i].used = 0; + for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) held_keys[i].used = 0; } - + size_x = monome_size_x(); size_y = monome_size_y(); u8 x = SG.rotate && !emulated ? size_x - _x - 1 : _x; @@ -975,7 +1039,7 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { grid_clear_held_keys(); SG.clear_held = 0; } - + if (control_mode_on ? !emulated : true) { u8 key = (y << 4) | x; if (z) { @@ -987,10 +1051,12 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { held_keys[i].y = y; held_keys[i].ss = ss; timer_add(&held_keys[i].timer, GRID_KEY_HOLD_DELAY, - &hold_repeat_timer_callback, (void *)&held_keys[i]); + &hold_repeat_timer_callback, + (void *)&held_keys[i]); break; } - } else { + } + else { for (u8 i = 0; i < GRID_MAX_KEY_PRESSED; i++) if (held_keys[i].key == key) { timer_remove(&held_keys[i].timer); @@ -1001,18 +1067,20 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { if (control_mode_on && !emulated) if (grid_control_process_key(ss, x, y, z, 0)) return; - + u8 refresh = 0; u8 scripts[SCRIPT_COUNT]; for (u8 i = 0; i < SCRIPT_COUNT; i++) scripts[i] = 0; - + for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { - if (z && GXYC.enabled && SG.group[GXYC.group].enabled && grid_within_area(x, y, &GXYC)) { + if (z && GXYC.enabled && SG.group[GXYC.group].enabled && + grid_within_area(x, y, &GXYC)) { GXY.value_x = x - GXYC.x; GXY.value_y = y - GXYC.y; if (GXYC.script != -1) scripts[GXYC.script] = 1; SG.latest_group = GXYC.group; - if (SG.group[GXYC.group].script != -1) scripts[SG.group[GXYC.group].script] = 1; + if (SG.group[GXYC.group].script != -1) + scripts[SG.group[GXYC.group].script] = 1; refresh = 1; } } @@ -1021,31 +1089,36 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { s8 held; if (z) { for (u8 i = 0; i < GRID_FADER_COUNT; i++) { - if (GFC.enabled && SG.group[GFC.group].enabled && grid_within_area(x, y, &GFC)) { + if (GFC.enabled && SG.group[GFC.group].enabled && + grid_within_area(x, y, &GFC)) { held = -1; if (GF.type & 1) { for (u8 j = 0; j < GRID_MAX_KEY_PRESSED; j++) - if (held_keys[j].used && (held_keys[j].y != y) && - grid_within_area(held_keys[j].x, held_keys[j].y, &GFC)) { + if (held_keys[j].used && (held_keys[j].y != y) && + grid_within_area(held_keys[j].x, held_keys[j].y, + &GFC)) { held = j; break; } - } else { + } + else { for (u8 j = 0; j < GRID_MAX_KEY_PRESSED; j++) if (held_keys[j].used && (held_keys[j].x != x) && - grid_within_area(held_keys[j].x, held_keys[j].y, &GFC)) { + grid_within_area(held_keys[j].x, held_keys[j].y, + &GFC)) { held = j; break; } } - + switch (GF.type) { case FADER_CH_BAR: case FADER_CH_DOT: if (held == -1) { GF.slide = 0; GF.value = x - GFC.x; - } else { + } + else { GF.slide = 1; GF.slide_acc = 0; GF.slide_end = x - GFC.x; @@ -1058,7 +1131,8 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { if (held == -1) { GF.slide = 0; GF.value = GFC.h + GFC.y - y - 1; - } else { + } + else { GF.slide = 1; GF.slide_acc = 0; GF.slide_end = GFC.h + GFC.y - y - 1; @@ -1068,19 +1142,26 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { break; case FADER_FH_BAR: case FADER_FH_DOT: - if (held != -1 && (held_keys[held].x == GFC.x || held_keys[held].x == (GFC.x + GFC.w - 1))) + if (held != -1 && + (held_keys[held].x == GFC.x || + held_keys[held].x == (GFC.x + GFC.w - 1))) held = -1; if (held == -1) { GF.slide = 0; if (x == GFC.x) { if (GF.value) GF.value--; - } else if (x == GFC.x + GFC.w - 1) { + } + else if (x == GFC.x + GFC.w - 1) { if (GF.value < GFC.level) GF.value++; - } else { - value = ((((x - GFC.x - 1) << 1) + 1) * GFC.level) / (GFC.w - 2); + } + else { + value = + ((((x - GFC.x - 1) << 1) + 1) * GFC.level) / + (GFC.w - 2); GF.value = (value >> 1) + (value & 1); } - } else { + } + else { GF.slide = 1; GF.slide_acc = 0; if (x == GFC.x) @@ -1088,7 +1169,9 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { else if (x == (GFC.x + GFC.w - 1)) value = GFC.level; else { - value = ((((x - GFC.x - 1) << 1) + 1) * GFC.level) / (GFC.w - 2); + value = + ((((x - GFC.x - 1) << 1) + 1) * GFC.level) / + (GFC.w - 2); value = (value >> 1) + (value & 1); } GF.slide_end = value; @@ -1100,19 +1183,26 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { break; case FADER_FV_BAR: case FADER_FV_DOT: - if (held != -1 && (held_keys[held].y == GFC.y || held_keys[held].y == (GFC.y + GFC.h - 1))) + if (held != -1 && + (held_keys[held].y == GFC.y || + held_keys[held].y == (GFC.y + GFC.h - 1))) held = -1; if (held == -1) { GF.slide = 0; if (y == GFC.y) { if (GF.value < GFC.level) GF.value++; - } else if (y == GFC.y + GFC.h - 1) { + } + else if (y == GFC.y + GFC.h - 1) { if (GF.value) GF.value--; - } else { - value = ((((GFC.h + GFC.y - y - 2) << 1) + 1) * GFC.level) / (GFC.h - 2); + } + else { + value = ((((GFC.h + GFC.y - y - 2) << 1) + 1) * + GFC.level) / + (GFC.h - 2); GF.value = (value >> 1) + (value & 1); } - } else { + } + else { GF.slide = 1; GF.slide_acc = 0; if (y == GFC.y) @@ -1120,7 +1210,9 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { else if (y == (GFC.y + GFC.h - 1)) value = 0; else { - value = ((((GFC.h + GFC.y - y - 2) << 1) + 1) * GFC.level) / (GFC.h - 2); + value = ((((GFC.h + GFC.y - y - 2) << 1) + 1) * + GFC.level) / + (GFC.h - 2); value = (value >> 1) + (value & 1); } GF.slide_end = value; @@ -1131,34 +1223,38 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { } break; } - + if (GFC.script != -1) scripts[GFC.script] = 1; SG.latest_fader = i; SG.latest_group = GFC.group; - if (SG.group[GFC.group].script != -1) scripts[SG.group[GFC.group].script] = 1; + if (SG.group[GFC.group].script != -1) + scripts[SG.group[GFC.group].script] = 1; refresh = 1; } } } for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { - if (GBC.enabled && SG.group[GBC.group].enabled && grid_within_area(x, y, &GBC)) { + if (GBC.enabled && SG.group[GBC.group].enabled && + grid_within_area(x, y, &GBC)) { if (GB.latch) { if (z) { GB.state = !GB.state; if (GBC.script != -1) scripts[GBC.script] = 1; } - } else { + } + else { GB.state = z; if (GBC.script != -1) scripts[GBC.script] = 1; } SG.latest_button = i; SG.latest_group = GBC.group; - if (SG.group[GBC.group].script != -1) scripts[SG.group[GBC.group].script] = 1; + if (SG.group[GBC.group].script != -1) + scripts[SG.group[GBC.group].script] = 1; refresh = 1; } } - + for (u8 i = 0; i < SCRIPT_COUNT; i++) if (scripts[i]) run_script(ss, i); @@ -1168,55 +1264,61 @@ void grid_process_key(scene_state_t *ss, u8 _x, u8 _y, u8 z, u8 emulated) { void grid_process_key_hold_repeat(scene_state_t *ss, u8 x, u8 y) { if (control_mode_on) if (grid_control_process_key(ss, x, y, 1, 1)) return; - + u8 refresh = 0; u8 scripts[SCRIPT_COUNT]; for (u8 i = 0; i < SCRIPT_COUNT; i++) scripts[i] = 0; - + u8 update = 0; for (u8 i = 0; i < GRID_FADER_COUNT; i++) { - if (GFC.enabled && SG.group[GFC.group].enabled && grid_within_area(x, y, &GFC)) { + if (GFC.enabled && SG.group[GFC.group].enabled && + grid_within_area(x, y, &GFC)) { update = 0; if (GF.type == FADER_FH_BAR || GF.type == FADER_FH_DOT) { if (x == GFC.x) { if (GF.value) GF.value--; update = 1; - } else if (x == GFC.x + GFC.w - 1) { + } + else if (x == GFC.x + GFC.w - 1) { if (GF.value < GFC.level) GF.value++; update = 1; } - } else if (GF.type == FADER_FV_BAR || GF.type == FADER_FV_DOT) { + } + else if (GF.type == FADER_FV_BAR || GF.type == FADER_FV_DOT) { if (y == GFC.y) { if (GF.value < GFC.level) GF.value++; update = 1; - } else if (y == GFC.y + GFC.h - 1) { + } + else if (y == GFC.y + GFC.h - 1) { if (GF.value) GF.value--; update = 1; } } - + if (update) { if (GFC.script != -1) scripts[GFC.script] = 1; SG.latest_fader = i; SG.latest_group = GFC.group; - if (SG.group[GFC.group].script != -1) scripts[SG.group[GFC.group].script] = 1; + if (SG.group[GFC.group].script != -1) + scripts[SG.group[GFC.group].script] = 1; refresh = 1; } } } - + for (u8 i = 0; i < SCRIPT_COUNT; i++) if (scripts[i]) run_script(ss, i); if (refresh) SG.grid_dirty = SG.scr_dirty = 1; } -void hold_repeat_timer_callback(void* o) { - hold_repeat_info* hr = o; +void hold_repeat_timer_callback(void *o) { + hold_repeat_info *hr = o; u8 is_hold = hr->used == 1; if (is_hold) { - timer_reset_set(&hr->timer, - control_mode_on && hr->x > 7 ? GRID_KEY_REPEAT_RATE_CTL : GRID_KEY_REPEAT_RATE); + timer_reset_set(&hr->timer, control_mode_on && hr->x > 7 + ? GRID_KEY_REPEAT_RATE_CTL + : GRID_KEY_REPEAT_RATE); hr->used = 2; } grid_process_key_hold_repeat(hr->ss, hr->x, hr->y); @@ -1226,7 +1328,7 @@ void grid_process_fader_slew(scene_state_t *ss) { u8 refresh = 0; u8 scripts[SCRIPT_COUNT]; for (u8 i = 0; i < SCRIPT_COUNT; i++) scripts[i] = 0; - + for (u8 i = 0; i < GRID_FADER_COUNT; i++) { if (!GF.slide) continue; GF.slide_acc++; @@ -1244,7 +1346,8 @@ void grid_process_fader_slew(scene_state_t *ss) { SG.latest_fader = i; SG.latest_group = GFC.group; if (GFC.script != -1) run_script(ss, GFC.script); - if (SG.group[GFC.group].script != -1) scripts[SG.group[GFC.group].script] = 1; + if (SG.group[GFC.group].script != -1) + scripts[SG.group[GFC.group].script] = 1; refresh = 1; } } @@ -1263,7 +1366,8 @@ void grid_clear_held_keys() { } bool grid_within_area(u8 x, u8 y, grid_common_t *gc) { - return x >= gc->x && x < (gc->x + gc->w) && y >= gc->y && y < (gc->y + gc->h); + return x >= gc->x && x < (gc->x + gc->w) && y >= gc->y && + y < (gc->y + gc->h); } void grid_refresh(scene_state_t *ss) { @@ -1272,9 +1376,9 @@ void grid_refresh(scene_state_t *ss) { if (size_x == 0) size_x = 16; if (size_y == 0) size_y = 8; - + grid_fill_area(0, 0, size_x, size_y, 0); - + u16 x, y; for (u8 i = 0; i < GRID_XYPAD_COUNT; i++) { if (GXYC.enabled && SG.group[GXYC.group].enabled) { @@ -1293,58 +1397,74 @@ void grid_refresh(scene_state_t *ss) { if (GFC.enabled && SG.group[GFC.group].enabled) { switch (GF.type) { case FADER_CH_BAR: - grid_fill_area(GFC.x, GFC.y, GF.value + 1, GFC.h, GRID_ON_BRIGHTNESS); - grid_fill_area(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.level); + grid_fill_area(GFC.x, GFC.y, GF.value + 1, GFC.h, + GRID_ON_BRIGHTNESS); + grid_fill_area(GFC.x + GF.value + 1, GFC.y, + GFC.w - GF.value - 1, GFC.h, GFC.level); break; case FADER_CV_BAR: - grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.level); - grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, GRID_ON_BRIGHTNESS); + grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, + GFC.level); + grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, + GF.value + 1, GRID_ON_BRIGHTNESS); break; case FADER_CH_DOT: grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h, GFC.level); - grid_fill_area(GFC.x + GF.value, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS); + grid_fill_area(GFC.x + GF.value, GFC.y, 1, GFC.h, + GRID_ON_BRIGHTNESS); break; case FADER_CV_DOT: grid_fill_area(GFC.x, GFC.y, GFC.w, GFC.h, GFC.level); - grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, GRID_ON_BRIGHTNESS); + grid_fill_area(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, + 1, GRID_ON_BRIGHTNESS); break; case FADER_FH_BAR: fv = (((GFC.w - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; - grid_fill_area(GFC.x, GFC.y, ff + 1, GFC.h, GRID_ON_BRIGHTNESS); + grid_fill_area(GFC.x, GFC.y, ff + 1, GFC.h, + GRID_ON_BRIGHTNESS); if (fp) grid_fill_area(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp); - grid_fill_area(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS); + grid_fill_area(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, + GRID_ON_BRIGHTNESS); break; case FADER_FV_BAR: fv = (((GFC.h - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; - grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff + 1, GRID_ON_BRIGHTNESS); - if (fp) grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, fp); + grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff + 1, + GRID_ON_BRIGHTNESS); + if (fp) + grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, + fp); grid_fill_area(GFC.x, GFC.y, GFC.w, 1, GRID_ON_BRIGHTNESS); break; case FADER_FH_DOT: grid_fill_area(GFC.x, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS); - grid_fill_area(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS); + grid_fill_area(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, + GRID_ON_BRIGHTNESS); fv = (((GFC.w - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; if (fp) grid_fill_area(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp); else if (ff) - grid_fill_area(GFC.x + ff, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS); + grid_fill_area(GFC.x + ff, GFC.y, 1, GFC.h, + GRID_ON_BRIGHTNESS); break; case FADER_FV_DOT: - grid_fill_area(GFC.x, GFC.y + GFC.h - 1, GFC.w, 1, GRID_ON_BRIGHTNESS); + grid_fill_area(GFC.x, GFC.y + GFC.h - 1, GFC.w, 1, + GRID_ON_BRIGHTNESS); grid_fill_area(GFC.x, GFC.y, GFC.w, 1, GRID_ON_BRIGHTNESS); fv = (((GFC.h - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; if (fp) - grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, fp); + grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, + fp); else if (ff) - grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, 1, GRID_ON_BRIGHTNESS); + grid_fill_area(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, 1, + GRID_ON_BRIGHTNESS); break; } } @@ -1352,8 +1472,9 @@ void grid_refresh(scene_state_t *ss) { for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.enabled && SG.group[GBC.group].enabled) - grid_fill_area(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? GRID_ON_BRIGHTNESS : GBC.level); - + grid_fill_area(GBC.x, GBC.y, GBC.w, GBC.h, + GB.state ? GRID_ON_BRIGHTNESS : GBC.level); + u16 led; for (u16 i = 0; i < size_x; i++) for (u16 j = 0; j < size_y; j++) { @@ -1395,7 +1516,8 @@ void grid_refresh(scene_state_t *ss) { monomeLedBuffer[a] = monomeLedBuffer[b]; monomeLedBuffer[b] = temp; } - } else { + } + else { u16 total = size_x * size_y; if (total > MONOME_MAX_LED_BYTES) total = MONOME_MAX_LED_BYTES; for (u16 i = 0; i < (total >> 1); i++) { @@ -1452,7 +1574,8 @@ void grid_fill_area(u8 x, u8 y, u8 w, u8 h, s8 level) { ///////////////////////////////////////// screen functions -void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 ctrl, u8 x1, u8 y1, u8 x2, u8 y2) { +void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, + u8 ctrl, u8 x1, u8 y1, u8 x2, u8 y2) { switch (mode) { case GRID_MODE_EDIT: grid_screen_refresh_led(ss, 0, page, x1, y1, x2, y2); @@ -1471,24 +1594,27 @@ void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, u8 page, u8 c void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { grid_fill_area_scr(0, 0, GRID_MAX_DIMENSION, GRID_MAX_DIMENSION, 0, 0); - + u8 last_x, last_y; - + for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { if (!SG.group[GBC.group].enabled || !GBC.enabled) continue; last_x = GBC.x + GBC.w - 1; last_y = GBC.y + GBC.h - 1; if (GBC.w == 1 && GBC.h == 1) { grid_fill_area_scr(GBC.x, GBC.y, 1, 1, 1, page); - } else if (GBC.w == 1 && GBC.h > 1) { + } + else if (GBC.w == 1 && GBC.h > 1) { grid_fill_area_scr(GBC.x, GBC.y, 1, 1, 2, page); grid_fill_area_scr(GBC.x, GBC.y + 1, 1, GBC.h - 2, 3, page); grid_fill_area_scr(GBC.x, last_y, 1, 1, 4, page); - } else if (GBC.w > 1 && GBC.h == 1) { + } + else if (GBC.w > 1 && GBC.h == 1) { grid_fill_area_scr(GBC.x, GBC.y, 1, 1, 5, page); grid_fill_area_scr(GBC.x + 1, GBC.y, GBC.w - 2, 1, 6, page); grid_fill_area_scr(last_x, GBC.y, 1, 1, 7, page); - } else { + } + else { grid_fill_area_scr(GBC.x, GBC.y, 1, 1, 8, page); grid_fill_area_scr(GBC.x + 1, GBC.y, GBC.w - 2, 1, 9, page); grid_fill_area_scr(last_x, GBC.y, 1, 1, 10, page); @@ -1506,15 +1632,18 @@ void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, last_y = GFC.y + GFC.h - 1; if (GFC.w == 1 && GFC.h == 1) { grid_fill_area_scr(GFC.x, GFC.y, 1, 1, 1, page); - } else if (GFC.w == 1 && GFC.h > 1) { + } + else if (GFC.w == 1 && GFC.h > 1) { grid_fill_area_scr(GFC.x, GFC.y, 1, 1, 2, page); grid_fill_area_scr(GFC.x, GFC.y + 1, 1, GFC.h - 2, 3, page); grid_fill_area_scr(GFC.x, last_y, 1, 1, 4, page); - } else if (GFC.w > 1 && GFC.h == 1) { + } + else if (GFC.w > 1 && GFC.h == 1) { grid_fill_area_scr(GFC.x, GFC.y, 1, 1, 5, page); grid_fill_area_scr(GFC.x + 1, GFC.y, GFC.w - 2, 1, 6, page); grid_fill_area_scr(last_x, GFC.y, 1, 1, 7, page); - } else { + } + else { grid_fill_area_scr(GFC.x, GFC.y, 1, 1, 8, page); grid_fill_area_scr(GFC.x + 1, GFC.y, GFC.w - 2, 1, 9, page); grid_fill_area_scr(last_x, GFC.y, 1, 1, 10, page); @@ -1534,7 +1663,8 @@ void grid_screen_refresh_ctrl(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, _y = y / 6; __y = y % 6; for (u16 x = 0; x < 96; x++) - if ((1 << (5 - (x%6))) & glyph[screen[x/6][_y]][__y]) line[l].data[x + d] = 10; + if ((1 << (5 - (x % 6))) & glyph[screen[x / 6][_y]][__y]) + line[l].data[x + d] = 10; } return; @@ -1562,58 +1692,84 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, if (GFC.enabled && SG.group[GFC.group].enabled) { switch (GF.type) { case FADER_CH_BAR: - grid_fill_area_scr(GFC.x, GFC.y, GF.value + 1, GFC.h, GRID_ON_BRIGHTNESS, page); - grid_fill_area_scr(GFC.x + GF.value + 1, GFC.y, GFC.w - GF.value - 1, GFC.h, GFC.level, page); + grid_fill_area_scr(GFC.x, GFC.y, GF.value + 1, GFC.h, + GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x + GF.value + 1, GFC.y, + GFC.w - GF.value - 1, GFC.h, GFC.level, + page); break; case FADER_CV_BAR: - grid_fill_area_scr(GFC.x, GFC.y, GFC.w, GFC.h - GF.value - 1, GFC.level, page); - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, GF.value + 1, GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, + GFC.h - GF.value - 1, GFC.level, page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, + GFC.w, GF.value + 1, GRID_ON_BRIGHTNESS, + page); break; case FADER_CH_DOT: - grid_fill_area_scr(GFC.x, GFC.y, GFC.w, GFC.h, GFC.level, page); - grid_fill_area_scr(GFC.x + GF.value, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, GFC.h, GFC.level, + page); + grid_fill_area_scr(GFC.x + GF.value, GFC.y, 1, GFC.h, + GRID_ON_BRIGHTNESS, page); break; case FADER_CV_DOT: - grid_fill_area_scr(GFC.x, GFC.y, GFC.w, GFC.h, GFC.level, page); - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, GFC.w, 1, GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, GFC.h, GFC.level, + page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - GF.value - 1, + GFC.w, 1, GRID_ON_BRIGHTNESS, page); break; case FADER_FH_BAR: fv = (((GFC.w - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; - grid_fill_area_scr(GFC.x, GFC.y, ff + 1, GFC.h, GRID_ON_BRIGHTNESS, page); - if (fp) grid_fill_area_scr(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp, page); - grid_fill_area_scr(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x, GFC.y, ff + 1, GFC.h, + GRID_ON_BRIGHTNESS, page); + if (fp) + grid_fill_area_scr(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp, + page); + grid_fill_area_scr(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, + GRID_ON_BRIGHTNESS, page); break; case FADER_FV_BAR: fv = (((GFC.h - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, ff + 1, GRID_ON_BRIGHTNESS, page); - if (fp) grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, fp, page); - grid_fill_area_scr(GFC.x, GFC.y, GFC.w, 1, GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, + ff + 1, GRID_ON_BRIGHTNESS, page); + if (fp) + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, + 1, fp, page); + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, 1, + GRID_ON_BRIGHTNESS, page); break; case FADER_FH_DOT: - grid_fill_area_scr(GFC.x, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS, page); - grid_fill_area_scr(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x, GFC.y, 1, GFC.h, + GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x + GFC.w - 1, GFC.y, 1, GFC.h, + GRID_ON_BRIGHTNESS, page); fv = (((GFC.w - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; if (fp) - grid_fill_area_scr(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp, page); + grid_fill_area_scr(GFC.x + ff + 1, GFC.y, 1, GFC.h, fp, + page); else if (ff) - grid_fill_area_scr(GFC.x + ff, GFC.y, 1, GFC.h, GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x + ff, GFC.y, 1, GFC.h, + GRID_ON_BRIGHTNESS, page); break; case FADER_FV_DOT: - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - 1, GFC.w, 1, GRID_ON_BRIGHTNESS, page); - grid_fill_area_scr(GFC.x, GFC.y, GFC.w, 1, GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - 1, GFC.w, 1, + GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x, GFC.y, GFC.w, 1, + GRID_ON_BRIGHTNESS, page); fv = (((GFC.h - 2) << 4) * GF.value) / GFC.level; ff = fv >> 4; fp = fv & 15; if (fp) - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, 1, fp, page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 2, GFC.w, + 1, fp, page); else if (ff) - grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, 1, GRID_ON_BRIGHTNESS, page); + grid_fill_area_scr(GFC.x, GFC.y + GFC.h - ff - 1, GFC.w, + 1, GRID_ON_BRIGHTNESS, page); break; } } @@ -1621,12 +1777,13 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.enabled && SG.group[GBC.group].enabled) - grid_fill_area_scr(GBC.x, GBC.y, GBC.w, GBC.h, GB.state ? GRID_ON_BRIGHTNESS : GBC.level, page); - + grid_fill_area_scr(GBC.x, GBC.y, GBC.w, GBC.h, + GB.state ? GRID_ON_BRIGHTNESS : GBC.level, page); + u16 pd = page ? 8 : 0; s8 l; for (u16 i = 0; i < GRID_MAX_DIMENSION; i++) - for (u16 j = 0; j < GRID_MAX_DIMENSION/2; j++) { + for (u16 j = 0; j < GRID_MAX_DIMENSION / 2; j++) { l = SG.leds[i][j + pd]; if (l >= 0) screen[i][j] = l; @@ -1661,7 +1818,7 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, u8 _line; u16 _data; for (u16 x = 0; x < GRID_MAX_DIMENSION; x++) - for (u16 y = 0; y < GRID_MAX_DIMENSION/2; y++) + for (u16 y = 0; y < GRID_MAX_DIMENSION / 2; y++) for (u16 j = 0; j < size; j++) { _y = y * cell + j + 1; _line = _y >> 3; @@ -1686,14 +1843,15 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, if (full_grid) { _x2 = (max(x1, x2) + 1) * cell - 2; _y2 = (max(y1, y2) + 1) * cell - 2; - } else { + } + else { _x2 = (max(x1, x2) + 1) * cell - 1; _y2 = (max(y1, y2) + 1) * cell - 1; } - + u8 show_y1, show_y2; show_y1 = show_y2 = true; - + u16 p = cell << 3; if (page) { if (_y2 < p) return; @@ -1703,14 +1861,15 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, }; _y1 -= p; _y2 -= p; - } else { + } + else { if (_y1 >= p) return; if (_y2 >= p) { show_y2 = false; _y2 = p - 1; } } - + if (show_y1) { _line = _y1 >> 3; _data = left + ((_y1 & 7) << 7); @@ -1727,7 +1886,7 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, for (u16 x = _x1 + 1; x <= _x2; x++) line[_line].data[_data + x] = x & 1 ? 15 : 4; } - + if (full_grid) for (u16 y = _y1; y <= _y2; y++) { line[y >> 3].data[left + ((y & 7) << 7) + _x1] = @@ -1738,7 +1897,7 @@ void grid_screen_refresh_led(scene_state_t *ss, u8 full_grid, u8 page, u8 x1, line[y >> 3].data[left + ((y & 7) << 7) + _x1] = y & 1 ? 4 : 15; line[y >> 3].data[left + ((y & 7) << 7) + _x2] = y & 1 ? 15 : 4; } -} +} static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, u8 x2, u8 y2) { @@ -1790,21 +1949,24 @@ static void grid_screen_refresh_info(scene_state_t *ss, u8 page, u8 x1, u8 y1, line[j >> 3].data[119 + ((j & 7) << 7)] = 1; // icons - + if (page == 0) { - for (u16 i = 0; i < 5; i++) line[0].data[i] = line[0].data[i + 128] = 10; + for (u16 i = 0; i < 5; i++) + line[0].data[i] = line[0].data[i + 128] = 10; line[0].data[0 + 256] = 1; line[0].data[4 + 256] = 1; line[0].data[0 + 384] = 1; line[0].data[4 + 384] = 1; for (u16 i = 512; i < 517; i++) line[0].data[i] = 1; - } else { + } + else { for (u16 i = 0; i < 5; i++) line[0].data[i] = 1; line[0].data[0 + 128] = 1; line[0].data[4 + 128] = 1; line[0].data[0 + 256] = 1; line[0].data[4 + 256] = 1; - for (u16 i = 384; i < 389; i++) line[0].data[i] = line[0].data[i + 128] = 10; + for (u16 i = 384; i < 389; i++) + line[0].data[i] = line[0].data[i + 128] = 10; } u8 l = ss->grid.rotate ? 10 : 1; @@ -1828,17 +1990,18 @@ void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, s8 level, u8 page) { u16 y1, y2; y1 = y; y2 = min(GRID_MAX_DIMENSION, y + h) - 1; - + if (page) { if (y2 < 8) return; if (y1 < 8) y1 = 8; y1 -= 8; y2 -= 8; - } else { + } + else { if (y1 >= 8) return; if (y2 >= 8) y2 = 7; } - + if (level == LED_DIM) { for (u16 _x = x; _x < x_end; _x++) for (u16 _y = y1; _y <= y2; _y++) @@ -1857,7 +2020,6 @@ void grid_fill_area_scr(u8 x, u8 y, u8 w, u8 h, s8 level, u8 page) { } else { for (u16 _x = x; _x < x_end; _x++) - for (u16 _y = y1; _y <= y2; _y++) - screen[_x][_y] = level; + for (u16 _y = y1; _y <= y2; _y++) screen[_x][_y] = level; } } diff --git a/module/grid.h b/module/grid.h index 97af3ea3..302121be 100644 --- a/module/grid.h +++ b/module/grid.h @@ -23,9 +23,8 @@ extern void grid_set_control_mode(u8 control, u8 mode, scene_state_t *ss); extern void grid_metro_triggered(scene_state_t *ss); extern void grid_refresh(scene_state_t *ss); extern void grid_screen_refresh(scene_state_t *ss, screen_grid_mode mode, - u8 page, u8 ctrl, u8 x1, u8 y1, u8 x2, u8 y2); -extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, - u8 emulated); + u8 page, u8 ctrl, u8 x1, u8 y1, u8 x2, u8 y2); +extern void grid_process_key(scene_state_t *ss, u8 x, u8 y, u8 z, u8 emulated); extern void grid_process_fader_slew(scene_state_t *ss); extern void grid_clear_held_keys(void); diff --git a/module/help_mode.c b/module/help_mode.c index d0f8c2df..05f60f45 100644 --- a/module/help_mode.c +++ b/module/help_mode.c @@ -420,393 +420,390 @@ const char* help9[HELP9_LENGTH] = { "9/13 TURTLE", #define HELP10_LENGTH 36 const char* help10[HELP10_LENGTH] = { "10/13 TELEX INPUT", - " ", - "TI.PARAM X|(TI.PRM)", - " GET KNOB VALUE", - "TI.PARAM.QT X", - " KNOB VALUE QUANTIZED", - "TI.PARAM.N X", - " KNOB AS SCALE NOTE", - "TI.PARAM.SCALE X", - " SELECT KNOB QUANT SCALE", - "TI.PARAM.MAP X Y Z", - " MAP KNOB VALUE TO Y..Z", - "TI.IN X", - " GET INPUT VAL", - "TI.IN.QT X", - " IN VALUE QUANTIZED", - "TI.IN.N X", - " IN AS SCALE NOTE", - "TI.IN.SCALE X", - " SELECT IN QUANT SCALE", - "TI.IN.MAP X Y Z", - " MAP IN VALUE TO Y..Z", - "TI.PARAM.INIT X", - " RESET KNOB X", - "TI.IN.INIT X", - " RESET IN X", - "TI.INIT D", - " RESET DEVICE D", - "TI.PARAM.CALIB X Y", - " CALIBRATE KNOB X", - "TI.IN.CALIB X Y", - " CALIBRATE IN X", - "TI.STORE D", - " STORE CALIB FOR DEVICE D", - "TI.RESET D", - " RESET CALIB FOR DEVICE D" }; + " ", + "TI.PARAM X|(TI.PRM)", + " GET KNOB VALUE", + "TI.PARAM.QT X", + " KNOB VALUE QUANTIZED", + "TI.PARAM.N X", + " KNOB AS SCALE NOTE", + "TI.PARAM.SCALE X", + " SELECT KNOB QUANT SCALE", + "TI.PARAM.MAP X Y Z", + " MAP KNOB VALUE TO Y..Z", + "TI.IN X", + " GET INPUT VAL", + "TI.IN.QT X", + " IN VALUE QUANTIZED", + "TI.IN.N X", + " IN AS SCALE NOTE", + "TI.IN.SCALE X", + " SELECT IN QUANT SCALE", + "TI.IN.MAP X Y Z", + " MAP IN VALUE TO Y..Z", + "TI.PARAM.INIT X", + " RESET KNOB X", + "TI.IN.INIT X", + " RESET IN X", + "TI.INIT D", + " RESET DEVICE D", + "TI.PARAM.CALIB X Y", + " CALIBRATE KNOB X", + "TI.IN.CALIB X Y", + " CALIBRATE IN X", + "TI.STORE D", + " STORE CALIB FOR DEVICE D", + "TI.RESET D", + " RESET CALIB FOR DEVICE D" }; #define HELP11_LENGTH 164 -const char* help11[HELP11_LENGTH] = { - "11/13 TELEX OUTPUT", - " ", - "TO.TR X Y", - " SET TR VALUE (0/1)", - "TO.TR.TOG X", - " TOGGLE TR", - "TO.TR.P X", - " PULSE TR", - "TO.TR.P.DIV X Y", - " SET TR X CLOCK DIV TO Y", - "TO.TR.P.MUTE X Y", - " MUTE TR X (0/1)", - "TO.TR.TIME X Y", - " SET TR PULSE TIME (MS)", - "TO.TR.TIME.S X Y", - " SET TR PULSE TIME (SEC)", - "TO.TR.TIME.M", - " SET TR PULSE TIME (MIN)", - "TO.TR.WIDTH X Y", - " SET TR DUTY (%)", - "TO.TR.POL X Y", - " SET TR POLARITY", - "TO.TR.M.ACT X Y", - " ENABLE METRO (0/1)", - "TO.TR.M X Y", - " SET METRO RATE (MS)", - "TO.TR.M.S X Y", - " SET METRO RATE (SEC)", - "TO.TR.M.M X Y", - " SET METRO RATE (MIN)", - "TO.TR.M.BPM X Y", - " SET METRO RATE (BPM)", - "TO.TR.M.COUNT X Y", - " SET METRO REPEAT", - "TO.TR.M.MUL X Y", - " SET METRO MULT", - "TO.TR.M.SYNC X", - " SYNC METRO", - "TO.M.ACT D Y", - " ENABLE DEVICE METRO (0/1)", - "TO.M D Y", - " SET DEVICE METRO RATE (MS)", - "TO.M.S D Y", - " AS ABOVE IN SECONDS", - "TO.M.M D Y", - " AS ABOVE IN MINUTES", - "TO.M.BPM D Y", - " AS ABOVE IN BPM", - "TO.M.COUNT D Y", - " SET DEVICE METRO REPEAT", - "TO.M.SYNC D", - " SYNC DEVICE METRO", - "TO.CV X Y", - " SET CV WITH SLEW", - "TO.CV.SLEW X Y", - " SET CV SLEW (MS)", - "TO.CV.SLEW.S X Y", - " SET CV SLEW (SEC)", - "TO.CV.SLEW.M", - " SET CV SLEW (MIN)", - "TO.CV.SET X Y", - " SET CV WITH NO SLEW", - "TO.CV.OFF X Y", - " SET CV OFFSET", - "TO.CV.QT X Y", - " SET CV QUANTIZED", - "TO.CV.QT.SET X Y", - " AS ABOVE NO SLEW", - "TO.CV.N X Y", - " SET CV TO SCALE NOTE", - "TO.CV.N.SET X Y", - " AS ABOVE NO SLEW", - "TO.CV.LOG X Y", - " SET CV LOG MODE", - "TO.OSC X Y", - " SET CV OSC FREQ", - "TO.OSC.SET X Y", - " AS ABOVE NO SLEW", - "TO.OSC.QT X Y", - " SET CV OSC QUANTIZED", - "TO.OSC.QT.SET X Y", - " AS ABOVE NO SLEW", - "TO.OSC.N X Y", - " SET CV OSC TO SCALE NOTE", - "TO.OSC.N.SET X Y", - " AS ABOVE NO SLEW", - "TO.OSC.FQ X Y", - " SET CV OSC (HZ)", - "TO.OSC.LFO X Y", - " SET CV LFO RATE (MILLIHZ)", - "TO.OSC.LFO.SET X Y", - " AS ABOVE NO SLEW", - "TO.OSC.CYC X Y", - " SET CV OSC CYCLE (MS)", - "TO.OSC.CYC.SET X Y", - " AS ABOVE NO SLEW", - "TO.OSC.CYC.S X Y", - " SET CV OSC CYCLE (SEC)", - "TO.OSC.CYC.S.SET X Y", - " AS ABOVE NO SLEW", - "TO.OSC.CYC.M X Y", - " SET CV OSC CYCLE (MIN)", - "TO.OSC.CYC.M.SET X Y", - " AS ABOVE NO SLEW", - "TO.OSC.SCALE X Y", - " CV X QT SCALE Y", - "TO.OSC.WAVE X Y", - " SELECT CV OSC WAVEFORM", - "TO.OSC.RECT X Y", - " SET OSC RECTIFY (-2..2)", - "TO.OSC.WIDTH X Y", - " SET OSC PULSEWIDTH", - "TO.OSC.SYNC X", - " RESET OSC PHASE", - "TO.OSC.PHASE X Y", - " SET OSC PHASE", - "TO.OSC.SLEW X Y", - " SET OSC SLEW (MS)", - "TO.OSC.SLEW.S X Y", - " SET OSC SLEW (SEC)", - "TO.OSC.SLEW.M X Y", - " SET OSC SLEW (MIN)", - "TO.OSC.CTR X Y", - " SET OSC CENTER", - "TO.ENV.ACT X Y", - " ENABLE ENV (1/0)", - "TO.ENV X Y", - " SET ENV GATE (1/0)", - "TO.ENV.TRIG X Y", - " TRIGGER ENV", - "TO.ENV.ATT X Y", - " SET ENV ATTACK (MS)", - "TO.ENV.ATT.S X Y", - " SET ENV ATTACK (SEC)", - "TO.ENV.ATT.M X Y", - " SET ENV ATTACK (MIN)", - "TO.ENV.DEC X Y", - " SET ENV DECAY (MS)", - "TO.ENV.DEC.S X Y", - " SET ENV DECAY (SEC)", - "TO.ENV.DEC.M X Y", - " SET ENV DECAY (MIN)", - "TO.ENV.EOR X N", - " PULSE TR N AT END OF RISE", - " TR ON SAME DEVICE", - "TO.ENV.EOC X N", - " AS ABOVE FOR END OF CYCLE", - "TO.ENV.LOOP X Y", - " LOOP ENV Y TIMES", - " 0 TO LOOP INDEFINITELY", - "TO.TR.INIT X", - " RESET TR", - "TO.CV.INIT X", - " RESET CV", - "TO.INIT D", - " RESET DEVICE", - "TO.KILL D", - " CANCEL DEVICE TR PULSES", - " AND CV SLEW", - "TO.CV.CALIB X", - " SAVE TO.CV.OFF X", - " AS CALIB VALUE", - "TO.CV.RESET X", - " RESET CV CALIB"}; +const char* help11[HELP11_LENGTH] = { "11/13 TELEX OUTPUT", + " ", + "TO.TR X Y", + " SET TR VALUE (0/1)", + "TO.TR.TOG X", + " TOGGLE TR", + "TO.TR.P X", + " PULSE TR", + "TO.TR.P.DIV X Y", + " SET TR X CLOCK DIV TO Y", + "TO.TR.P.MUTE X Y", + " MUTE TR X (0/1)", + "TO.TR.TIME X Y", + " SET TR PULSE TIME (MS)", + "TO.TR.TIME.S X Y", + " SET TR PULSE TIME (SEC)", + "TO.TR.TIME.M", + " SET TR PULSE TIME (MIN)", + "TO.TR.WIDTH X Y", + " SET TR DUTY (%)", + "TO.TR.POL X Y", + " SET TR POLARITY", + "TO.TR.M.ACT X Y", + " ENABLE METRO (0/1)", + "TO.TR.M X Y", + " SET METRO RATE (MS)", + "TO.TR.M.S X Y", + " SET METRO RATE (SEC)", + "TO.TR.M.M X Y", + " SET METRO RATE (MIN)", + "TO.TR.M.BPM X Y", + " SET METRO RATE (BPM)", + "TO.TR.M.COUNT X Y", + " SET METRO REPEAT", + "TO.TR.M.MUL X Y", + " SET METRO MULT", + "TO.TR.M.SYNC X", + " SYNC METRO", + "TO.M.ACT D Y", + " ENABLE DEVICE METRO (0/1)", + "TO.M D Y", + " SET DEVICE METRO RATE (MS)", + "TO.M.S D Y", + " AS ABOVE IN SECONDS", + "TO.M.M D Y", + " AS ABOVE IN MINUTES", + "TO.M.BPM D Y", + " AS ABOVE IN BPM", + "TO.M.COUNT D Y", + " SET DEVICE METRO REPEAT", + "TO.M.SYNC D", + " SYNC DEVICE METRO", + "TO.CV X Y", + " SET CV WITH SLEW", + "TO.CV.SLEW X Y", + " SET CV SLEW (MS)", + "TO.CV.SLEW.S X Y", + " SET CV SLEW (SEC)", + "TO.CV.SLEW.M", + " SET CV SLEW (MIN)", + "TO.CV.SET X Y", + " SET CV WITH NO SLEW", + "TO.CV.OFF X Y", + " SET CV OFFSET", + "TO.CV.QT X Y", + " SET CV QUANTIZED", + "TO.CV.QT.SET X Y", + " AS ABOVE NO SLEW", + "TO.CV.N X Y", + " SET CV TO SCALE NOTE", + "TO.CV.N.SET X Y", + " AS ABOVE NO SLEW", + "TO.CV.LOG X Y", + " SET CV LOG MODE", + "TO.OSC X Y", + " SET CV OSC FREQ", + "TO.OSC.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.QT X Y", + " SET CV OSC QUANTIZED", + "TO.OSC.QT.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.N X Y", + " SET CV OSC TO SCALE NOTE", + "TO.OSC.N.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.FQ X Y", + " SET CV OSC (HZ)", + "TO.OSC.LFO X Y", + " SET CV LFO RATE (MILLIHZ)", + "TO.OSC.LFO.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.CYC X Y", + " SET CV OSC CYCLE (MS)", + "TO.OSC.CYC.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.CYC.S X Y", + " SET CV OSC CYCLE (SEC)", + "TO.OSC.CYC.S.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.CYC.M X Y", + " SET CV OSC CYCLE (MIN)", + "TO.OSC.CYC.M.SET X Y", + " AS ABOVE NO SLEW", + "TO.OSC.SCALE X Y", + " CV X QT SCALE Y", + "TO.OSC.WAVE X Y", + " SELECT CV OSC WAVEFORM", + "TO.OSC.RECT X Y", + " SET OSC RECTIFY (-2..2)", + "TO.OSC.WIDTH X Y", + " SET OSC PULSEWIDTH", + "TO.OSC.SYNC X", + " RESET OSC PHASE", + "TO.OSC.PHASE X Y", + " SET OSC PHASE", + "TO.OSC.SLEW X Y", + " SET OSC SLEW (MS)", + "TO.OSC.SLEW.S X Y", + " SET OSC SLEW (SEC)", + "TO.OSC.SLEW.M X Y", + " SET OSC SLEW (MIN)", + "TO.OSC.CTR X Y", + " SET OSC CENTER", + "TO.ENV.ACT X Y", + " ENABLE ENV (1/0)", + "TO.ENV X Y", + " SET ENV GATE (1/0)", + "TO.ENV.TRIG X Y", + " TRIGGER ENV", + "TO.ENV.ATT X Y", + " SET ENV ATTACK (MS)", + "TO.ENV.ATT.S X Y", + " SET ENV ATTACK (SEC)", + "TO.ENV.ATT.M X Y", + " SET ENV ATTACK (MIN)", + "TO.ENV.DEC X Y", + " SET ENV DECAY (MS)", + "TO.ENV.DEC.S X Y", + " SET ENV DECAY (SEC)", + "TO.ENV.DEC.M X Y", + " SET ENV DECAY (MIN)", + "TO.ENV.EOR X N", + " PULSE TR N AT END OF RISE", + " TR ON SAME DEVICE", + "TO.ENV.EOC X N", + " AS ABOVE FOR END OF CYCLE", + "TO.ENV.LOOP X Y", + " LOOP ENV Y TIMES", + " 0 TO LOOP INDEFINITELY", + "TO.TR.INIT X", + " RESET TR", + "TO.CV.INIT X", + " RESET CV", + "TO.INIT D", + " RESET DEVICE", + "TO.KILL D", + " CANCEL DEVICE TR PULSES", + " AND CV SLEW", + "TO.CV.CALIB X", + " SAVE TO.CV.OFF X", + " AS CALIB VALUE", + "TO.CV.RESET X", + " RESET CV CALIB" }; #define HELP12_LENGTH 115 -const char* help12[HELP12_LENGTH] = { - "12/13 ANSIBLE", - " ", - "KR.PRE / KR.PRE X", - " RETURN/LOAD CURRENT PRESET", - "KR.PERIOD / KR.PERIOD X", - " GET/SET INTERNAL PERIOD", - "KR.PAT / KR.PAT X", - " GET/SET CURRENT PATTERN", - "KR.SCALE / KR.SCALE X", - " GET/SET CURRENT SCALE", - "KR.POS X Y / KR.POS X Y Z", - " GET/SET POSITION Z", - " FOR TRACK X PARAM Y", - "KR.L.ST X Y", - " GET LOOP START FOR", - " TRACK X, PARAM Y", - "KR.L.ST X Y Z", - " LOOP START FOR", - " TRACK X, PARAM Y TO Z", - "KR.L.LEN X Y", - " GET LENGTH OF", - " TRACK X, PARAM Y", - "KR.L.LEN X Y Z", - " SET LENGTH OF", - " TRACK X, PARAM Y TO Z", - "KR.RES X Y", - " RESET POSITION", - " FOR TRACK X, PARAM Y", - "KR.CV X", - " GET CV FOR CHANNEL X", - "KR.MUTE X / KR.MUTE X Y", - " GET/SET MUTE STATE", - " FOR CHANNEL X", - "KR.TRMUTE X", - " TOGGLE MUTE STATE", - " FOR CHANNEL X", - "KR.CLK X", - " ADVANCE THE CLOCK", - " FOR CHANNEL X", - " (MUST BE ENABLED!)", - "ME.PRE / ME.PRE X", - " RETURN/LOAD CURRENT PRESET", - "ME.SCALE / ME.SCALE X", - " GET/SET CURRENT SCALE", - "ME.PERIOD / ME.PERIOD X", - " GET/SET CLOCK PERIOD", - "ME.STOP X", - " STOP CHANNEL X (0 = ALL)", - "ME.RES X", - " RESET CHANNEL X (0 = ALL)", - " ALSO USED AS START", - "ME.CV X", - " GET CV FOR CHANNEL X", - "LV.PRE / LV.PRE X", - " RETURN/LOAD CURRENT PRESET", - "LV.RES X", - " RESET (0 ON NEXT CLK,1 NOW)", - "LV.POS / LV.POS X", - " GET/SET CURRENT POSITION", - "LV.L.ST / LV.L.ST X", - " GET/SET LOOP START", - "LV.L.LEN / LV.L.LEN X", - " GET/SET LOOP LENGTH", - "LV.L.DIR / LV.L.DIR X", - " GET/SET LOOP DIRECTION", - "LV.CV X", - " GET CV FOR CHANNEL X", - "CY.PRE / CY.PRE X", - " RETURN/LOAD CURRENT PRESET", - "CY.RES X", - " RESET CHANNEL X (0 = ALL)", - "CY.POS X / CY.POS X Y", - " GET/SET CHANNEL POSITION", - " X = 0 TO SET ALL", - " POSITION BETWEEN 0-255", - "CY.REV X", - " REVERSE CHANNEL X (0 = ALL)", - "MID.SLEW T", - " SET PITCH SLEW TIME", - " TO T IN MS", - "MID.SHIFT X", - " SHIFT PITCH BY TT PITCH X", - " (E.G. N 6, V -1)", - "ARP.HLD X", - " 0 DISABLES KEY HOLD", - " OTHER VALUES ENABLE", - "ARP.STY X", - " SET ARP STYLE (0-7)", - "ARP.GT V G", - " SET GATE LENGTH FOR VOICE V", - " TO G (0-127, SYNCED TO CLK)", - "ARP.SLEW V T", - " SET SLEW TIME FOR VOICE V", - " TO T IN MS", - "ARP.RPT V N S", - " SET VOICE PATTERN REPEAT", - " FOR VOICE V TO N TIMES", - " SHIFTED BY S SEMITONES", - "ARP.DIV V D", - " SET VOICE CLOCK DIVISOR", - " FOR VOICE V TO D (1-32)", - "ARP.FIL V F", - " SET VOICE EUCLIDEAN FILL", - " 1 FOR STRAIGHT CLOCK (1-32)", - "ARP.ROT V R", - " SET VOICE EUCLIDEAN", - " ROTATION (-32, 32)", - "ARP.ER V F D R", - " SET ALL EUCLIDEAN RHYTHM", - "ARP.RES V", - " RESET VOICE CLOCK/PATTERN", - " ON NEXT CLOCK TICK", - "ARP.SHIFT V X", - " SHIFT VOICE CV BY TT PITCH", - " (E.G. N 6, V -1)"}; +const char* help12[HELP12_LENGTH] = { "12/13 ANSIBLE", + " ", + "KR.PRE / KR.PRE X", + " RETURN/LOAD CURRENT PRESET", + "KR.PERIOD / KR.PERIOD X", + " GET/SET INTERNAL PERIOD", + "KR.PAT / KR.PAT X", + " GET/SET CURRENT PATTERN", + "KR.SCALE / KR.SCALE X", + " GET/SET CURRENT SCALE", + "KR.POS X Y / KR.POS X Y Z", + " GET/SET POSITION Z", + " FOR TRACK X PARAM Y", + "KR.L.ST X Y", + " GET LOOP START FOR", + " TRACK X, PARAM Y", + "KR.L.ST X Y Z", + " LOOP START FOR", + " TRACK X, PARAM Y TO Z", + "KR.L.LEN X Y", + " GET LENGTH OF", + " TRACK X, PARAM Y", + "KR.L.LEN X Y Z", + " SET LENGTH OF", + " TRACK X, PARAM Y TO Z", + "KR.RES X Y", + " RESET POSITION", + " FOR TRACK X, PARAM Y", + "KR.CV X", + " GET CV FOR CHANNEL X", + "KR.MUTE X / KR.MUTE X Y", + " GET/SET MUTE STATE", + " FOR CHANNEL X", + "KR.TRMUTE X", + " TOGGLE MUTE STATE", + " FOR CHANNEL X", + "KR.CLK X", + " ADVANCE THE CLOCK", + " FOR CHANNEL X", + " (MUST BE ENABLED!)", + "ME.PRE / ME.PRE X", + " RETURN/LOAD CURRENT PRESET", + "ME.SCALE / ME.SCALE X", + " GET/SET CURRENT SCALE", + "ME.PERIOD / ME.PERIOD X", + " GET/SET CLOCK PERIOD", + "ME.STOP X", + " STOP CHANNEL X (0 = ALL)", + "ME.RES X", + " RESET CHANNEL X (0 = ALL)", + " ALSO USED AS START", + "ME.CV X", + " GET CV FOR CHANNEL X", + "LV.PRE / LV.PRE X", + " RETURN/LOAD CURRENT PRESET", + "LV.RES X", + " RESET (0 ON NEXT CLK,1 NOW)", + "LV.POS / LV.POS X", + " GET/SET CURRENT POSITION", + "LV.L.ST / LV.L.ST X", + " GET/SET LOOP START", + "LV.L.LEN / LV.L.LEN X", + " GET/SET LOOP LENGTH", + "LV.L.DIR / LV.L.DIR X", + " GET/SET LOOP DIRECTION", + "LV.CV X", + " GET CV FOR CHANNEL X", + "CY.PRE / CY.PRE X", + " RETURN/LOAD CURRENT PRESET", + "CY.RES X", + " RESET CHANNEL X (0 = ALL)", + "CY.POS X / CY.POS X Y", + " GET/SET CHANNEL POSITION", + " X = 0 TO SET ALL", + " POSITION BETWEEN 0-255", + "CY.REV X", + " REVERSE CHANNEL X (0 = ALL)", + "MID.SLEW T", + " SET PITCH SLEW TIME", + " TO T IN MS", + "MID.SHIFT X", + " SHIFT PITCH BY TT PITCH X", + " (E.G. N 6, V -1)", + "ARP.HLD X", + " 0 DISABLES KEY HOLD", + " OTHER VALUES ENABLE", + "ARP.STY X", + " SET ARP STYLE (0-7)", + "ARP.GT V G", + " SET GATE LENGTH FOR VOICE V", + " TO G (0-127, SYNCED TO CLK)", + "ARP.SLEW V T", + " SET SLEW TIME FOR VOICE V", + " TO T IN MS", + "ARP.RPT V N S", + " SET VOICE PATTERN REPEAT", + " FOR VOICE V TO N TIMES", + " SHIFTED BY S SEMITONES", + "ARP.DIV V D", + " SET VOICE CLOCK DIVISOR", + " FOR VOICE V TO D (1-32)", + "ARP.FIL V F", + " SET VOICE EUCLIDEAN FILL", + " 1 FOR STRAIGHT CLOCK (1-32)", + "ARP.ROT V R", + " SET VOICE EUCLIDEAN", + " ROTATION (-32, 32)", + "ARP.ER V F D R", + " SET ALL EUCLIDEAN RHYTHM", + "ARP.RES V", + " RESET VOICE CLOCK/PATTERN", + " ON NEXT CLOCK TICK", + "ARP.SHIFT V X", + " SHIFT VOICE CV BY TT PITCH", + " (E.G. N 6, V -1)" }; #define HELP13_LENGTH 53 -const char* help13[HELP13_LENGTH] = { - "13/13 JUST FRIENDS & W/", - " ", - "JF.TR X Y", - " TRIGGER CHANNEL X (0 = ALL)", - " WITH STATE Y (1 ON, 0 OFF)", - "JF.RMODE X", - " SET RUN STATE OF JF", - " (0 = OFF, NON-ZERO = ON)", - "JF.RUN X", - " SEND X TO RUN INPUT", - " (V -5 TO V 5)", - "JF.SHIFT X", - " TRANSPOSE JF BY X", - "JF.VTR X Y", - " LIKE JF.TR WITH VOLUME CTR", - " (V 0 TO V 5)", - "JF.TUNE X Y Z", - " ADJUST TUNING OF CHANNEL X", - " SET NUMERATOR TO Y", - " SET DENOMINATOR TO Z", - "JF.MODE X", - " NON-0 FOR ALTERNATE MODES", - "JF.VOX X Y Z", - " CREATE NOTE AT CHANNEL X", - " Y = PITCH, Z = VELOCITY", - "JF.NOTE X Y", - " ALLOCATED NOTE SEQUENCING", - " X = PITCH, Y = VELOCITY", - "JF.GOD X", - " REDEFINE C3 TO GOD NOTE", - " (0: A=440HZ, 1: A=432HZ)", - "JF.TICK X", - " SET TIMEBASE OF GEODE", - " 1-48 TICKS PER MEASURE", - " 49-255 BEATS PER MINUTE", - "JF.QT X", - " SET QUANTIZATION", - " 0 = NO QUANTIZATION", - " 1-32 SETS SUBDIVISION", - "WS.PLAY X", - " SET PLAYBACK STATE AND DIR", - " 0 = STOP, 1 = FWD, -1 = REV", - "WS.REC X", - " SET RECORDING MODE", - " 0 PLAYBACK ONLY, 1 OVERDUB", - " -1 OVERWRITE", - "WS.CUE X", - " MOVE TO CUEPOINT (RELATIVE)", - " 0 RETRIGGER CURRENT CUE", - " 1 JUMP TO NEXT CUE", - " -1 JUMP TO PREV CUE", - "WS.LOOP X", - " SET LOOP STATE ON/OFF"}; +const char* help13[HELP13_LENGTH] = { "13/13 JUST FRIENDS & W/", + " ", + "JF.TR X Y", + " TRIGGER CHANNEL X (0 = ALL)", + " WITH STATE Y (1 ON, 0 OFF)", + "JF.RMODE X", + " SET RUN STATE OF JF", + " (0 = OFF, NON-ZERO = ON)", + "JF.RUN X", + " SEND X TO RUN INPUT", + " (V -5 TO V 5)", + "JF.SHIFT X", + " TRANSPOSE JF BY X", + "JF.VTR X Y", + " LIKE JF.TR WITH VOLUME CTR", + " (V 0 TO V 5)", + "JF.TUNE X Y Z", + " ADJUST TUNING OF CHANNEL X", + " SET NUMERATOR TO Y", + " SET DENOMINATOR TO Z", + "JF.MODE X", + " NON-0 FOR ALTERNATE MODES", + "JF.VOX X Y Z", + " CREATE NOTE AT CHANNEL X", + " Y = PITCH, Z = VELOCITY", + "JF.NOTE X Y", + " ALLOCATED NOTE SEQUENCING", + " X = PITCH, Y = VELOCITY", + "JF.GOD X", + " REDEFINE C3 TO GOD NOTE", + " (0: A=440HZ, 1: A=432HZ)", + "JF.TICK X", + " SET TIMEBASE OF GEODE", + " 1-48 TICKS PER MEASURE", + " 49-255 BEATS PER MINUTE", + "JF.QT X", + " SET QUANTIZATION", + " 0 = NO QUANTIZATION", + " 1-32 SETS SUBDIVISION", + "WS.PLAY X", + " SET PLAYBACK STATE AND DIR", + " 0 = STOP, 1 = FWD, -1 = REV", + "WS.REC X", + " SET RECORDING MODE", + " 0 PLAYBACK ONLY, 1 OVERDUB", + " -1 OVERWRITE", + "WS.CUE X", + " MOVE TO CUEPOINT (RELATIVE)", + " 0 RETRIGGER CURRENT CUE", + " 1 JUMP TO NEXT CUE", + " -1 JUMP TO PREV CUE", + "WS.LOOP X", + " SET LOOP STATE ON/OFF" }; //////////////////////////////////////////////////////////////////////////////// // Help mode /////////////////////////////////////////////////////////////////// -const char** help_pages[HELP_PAGES] = { help1, help2, help3, help4, help5, - help6, help7, help8, help9, help10, +const char** help_pages[HELP_PAGES] = { help1, help2, help3, help4, help5, + help6, help7, help8, help9, help10, help11, help12, help13 }; const uint8_t help_length[HELP_PAGES] = { - HELP1_LENGTH, HELP2_LENGTH, HELP3_LENGTH, HELP4_LENGTH, HELP5_LENGTH, - HELP6_LENGTH, HELP7_LENGTH, HELP8_LENGTH, HELP9_LENGTH, HELP10_LENGTH, + HELP1_LENGTH, HELP2_LENGTH, HELP3_LENGTH, HELP4_LENGTH, HELP5_LENGTH, + HELP6_LENGTH, HELP7_LENGTH, HELP8_LENGTH, HELP9_LENGTH, HELP10_LENGTH, HELP11_LENGTH, HELP12_LENGTH, HELP13_LENGTH }; diff --git a/module/live_mode.c b/module/live_mode.c index d6cffdf7..2ac6805c 100644 --- a/module/live_mode.c +++ b/module/live_mode.c @@ -125,16 +125,21 @@ void set_live_submode(u8 submode) { if (submode == 0) { show_vars = 0; grid_mode = GRID_MODE_OFF; - } else if (submode == 1) { + } + else if (submode == 1) { show_vars = 1; grid_mode = GRID_MODE_OFF; - } else if (submode == 2) { + } + else if (submode == 2) { show_vars = 0; grid_mode = GRID_MODE_EDIT; - } else if (submode == 3) { + } + else if (submode == 3) { show_vars = 0; grid_mode = GRID_MODE_FULL; - } else return; + } + else + return; dirty = D_ALL; activity_prev = 0xFF; grid_view_changed = true; @@ -179,14 +184,14 @@ void execute_line() { s16 found = -1; for (s16 i = history_top; i >= 0; i--) if (command.length == history[i].length && - memcmp(&(command.data), &(history[i].data), - command.length * sizeof(tele_data_t)) == 0) { - found = i; - break; - } - + memcmp(&(command.data), &(history[i].data), + command.length * sizeof(tele_data_t)) == 0) { + found = i; + break; + } + if (found == -1) { - // increase history_size up to a maximum + // increase history_size up to a maximum if (history_top < MAX_HISTORY_SIZE - 1) history_top++; found = history_top; } @@ -427,8 +432,8 @@ uint8_t screen_refresh_live(scene_state_t *ss) { (grid_view_changed || ss->grid.scr_dirty)) { grid_view_changed = 0; screen_dirty = 0b111111; - grid_screen_refresh(ss, grid_mode, grid_page, grid_show_controls, grid_x1, - grid_y1, grid_x2, grid_y2); + grid_screen_refresh(ss, grid_mode, grid_page, grid_show_controls, + grid_x1, grid_y1, grid_x2, grid_y2); } if (grid_mode == GRID_MODE_FULL) return 0b11111111; diff --git a/module/live_mode.h b/module/live_mode.h index ae5a4b60..bb8e6f1b 100644 --- a/module/live_mode.h +++ b/module/live_mode.h @@ -15,7 +15,8 @@ void set_grid_updated(void); void history_next(void); void history_prev(void); void execute_line(void); -void process_live_keys(uint8_t key, uint8_t mod_key, bool is_held_key, bool is_release, scene_state_t *ss); +void process_live_keys(uint8_t key, uint8_t mod_key, bool is_held_key, + bool is_release, scene_state_t *ss); uint8_t screen_refresh_live(scene_state_t *ss); void set_vars_updated(void); extern uint8_t grid_mode; diff --git a/module/main.c b/module/main.c index 85b565d8..b79ef504 100644 --- a/module/main.c +++ b/module/main.c @@ -305,7 +305,7 @@ void handler_Front(int32_t data) { return; } ss_counter = 0; - + if (data == 0) { if (grid_connected) { grid_control_mode = !grid_control_mode; @@ -313,7 +313,7 @@ void handler_Front(int32_t data) { grid_set_control_mode(grid_control_mode, mode, &scene_state); return; } - + if (mode != M_PRESET_R) { front_timer = 0; set_preset_r_mode(adc[1] >> 7); @@ -450,7 +450,7 @@ void handler_ScreenRefresh(int32_t data) { profile_update(&prof_ScreenRefresh); #endif uint8_t screen_dirty = 0; - + switch (mode) { case M_PATTERN: screen_dirty = screen_refresh_pattern(); break; case M_PRESET_W: screen_dirty = screen_refresh_preset_w(); break; @@ -463,11 +463,11 @@ void handler_ScreenRefresh(int32_t data) { u8 grid = 0; for (size_t i = 0; i < 8; i++) if (screen_dirty & (1 << i)) { - grid = 1; - if (ss_counter < SS_TIMEOUT) region_draw(&line[i]); + grid = 1; + if (ss_counter < SS_TIMEOUT) region_draw(&line[i]); } if (grid_control_mode && grid) scene_state.grid.grid_dirty = 1; - + #ifdef TELETYPE_PROFILE profile_update(&prof_ScreenRefresh); #endif @@ -475,7 +475,7 @@ void handler_ScreenRefresh(int32_t data) { void handler_EventTimer(int32_t data) { tele_tick(&scene_state, RATE_CLOCK); - + if (ss_counter < SS_TIMEOUT) { ss_counter++; if (ss_counter == SS_TIMEOUT) { @@ -512,10 +512,10 @@ static void handler_MonomeConnect(s32 data) { hold_key = 0; timers_set_monome(); grid_connected = 1; - + if (grid_control_mode && mode == M_HELP) set_mode(M_LIVE); grid_set_control_mode(grid_control_mode, mode, &scene_state); - + scene_state.grid.grid_dirty = 1; grid_clear_held_keys(); } @@ -635,7 +635,7 @@ void set_last_mode() { } // defined in globals.h -void clear_delays_and_slews(scene_state_t *ss) { +void clear_delays_and_slews(scene_state_t* ss) { clear_delays(ss); for (int i = 0; i < 4; i++) { aout[i].step = 1; } } @@ -823,7 +823,7 @@ void tele_metro_updated() { set_metro_icon(true); else set_metro_icon(false); - + if (grid_connected && grid_control_mode) scene_state.grid.grid_dirty = 1; } diff --git a/module/pattern_mode.c b/module/pattern_mode.c index 78ceb21b..72f24a83 100644 --- a/module/pattern_mode.c +++ b/module/pattern_mode.c @@ -76,9 +76,7 @@ void pattern_down() { void process_pattern_keys(uint8_t k, uint8_t m, bool is_held_key) { // : move down - if (match_no_mod(m, k, HID_DOWN)) { - pattern_down(); - } + if (match_no_mod(m, k, HID_DOWN)) { pattern_down(); } // alt-: move a page down else if (match_alt(m, k, HID_DOWN)) { editing_number = false; diff --git a/module/profile.h b/module/profile.h index f3c05a4c..9b0b3c1c 100644 --- a/module/profile.h +++ b/module/profile.h @@ -1,5 +1,5 @@ -#include "sysclk.h" #include "stdbool.h" +#include "sysclk.h" typedef struct { uint32_t last; @@ -11,7 +11,7 @@ static inline void profile_update(profile_t *p) { uint32_t count = Get_system_register(AVR32_COUNT); if (count < p->last) - p->delta = INT32_MAX - p->last + count; + p->delta = INT32_MAX - p->last + count; else p->delta = count - p->last; From dc71c463e9cde02ba10b3accbfba418617bc3b51 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 10 Aug 2018 08:47:00 -0700 Subject: [PATCH 115/117] clangify 2 --- src/ops/ansible.c | 29 ++++--- src/ops/controlflow.c | 8 +- src/ops/er301.c | 3 +- src/ops/grid_ops.c | 186 ++++++++++++++++++++++------------------ src/ops/init.c | 2 +- src/ops/maths.c | 23 ++--- src/ops/maths.h | 2 +- src/ops/matrixarchate.c | 158 ++++++++++++++++++++++------------ src/ops/op.c | 28 +++--- src/ops/patterns.c | 24 +++--- src/ops/telex.c | 3 +- src/ops/variables.c | 25 +++--- src/ops/wslash.c | 32 +++---- src/state.c | 5 +- src/teletype.c | 2 +- 15 files changed, 300 insertions(+), 230 deletions(-) diff --git a/src/ops/ansible.c b/src/ops/ansible.c index 25a83c0e..a2c4fbf9 100644 --- a/src/ops/ansible.c +++ b/src/ops/ansible.c @@ -37,14 +37,14 @@ static void op_KR_RES_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_KR_CV_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_KR_MUTE_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_KR_MUTE_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_KR_TMUTE_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); +static void op_KR_MUTE_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_MUTE_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_KR_TMUTE_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); static void op_KR_CLK_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); + command_state_t *cs); static void op_ME_PRE_get(const void *data, scene_state_t *ss, exec_state_t *es, @@ -348,16 +348,18 @@ static void op_KR_CV_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), cs_push(cs, (d[0] << 8) + d[1]); } -static void op_KR_MUTE_set(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_KR_MUTE_set(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); uint8_t d[] = { II_KR_MUTE, a, b }; tele_ii_tx(II_KR_ADDR, d, 3); } -static void op_KR_MUTE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_KR_MUTE_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); uint8_t d[] = { II_KR_MUTE | II_GET, a }; uint8_t addr = II_KR_ADDR; @@ -367,8 +369,9 @@ static void op_KR_MUTE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss) cs_push(cs, d[0]); } -static void op_KR_TMUTE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_KR_TMUTE_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); uint8_t d[] = { II_KR_TMUTE, a }; tele_ii_tx(II_KR_ADDR, d, 2); diff --git a/src/ops/controlflow.c b/src/ops/controlflow.c index 37f9c0a9..ced11e4e 100644 --- a/src/ops/controlflow.c +++ b/src/ops/controlflow.c @@ -60,8 +60,8 @@ const tele_mod_t mod_OTHER = MAKE_MOD(OTHER, mod_OTHER_func, 0); const tele_op_t op_SCRIPT = MAKE_GET_SET_OP(SCRIPT, op_SCRIPT_get, op_SCRIPT_set, 0, true); -const tele_op_t op_SYM_DOLLAR = MAKE_ALIAS_OP($, op_SCRIPT_get, op_SCRIPT_set, 0, - true); +const tele_op_t op_SYM_DOLLAR = + MAKE_ALIAS_OP($, op_SCRIPT_get, op_SCRIPT_set, 0, true); const tele_op_t op_KILL = MAKE_GET_OP(KILL, op_KILL_get, 0, false); const tele_op_t op_SCENE = MAKE_GET_SET_OP(SCENE, op_SCENE_get, op_SCENE_set, 0, true); @@ -121,12 +121,12 @@ static void mod_L_func(scene_state_t *ss, exec_state_t *es, command_state_t *cs, // iterator, allowing users to roll back a loop or advance it faster int16_t *i = &es_variables(es)->i; *i = a; - + // Forward loop if (a < b) { // continue the loop whenever the _pointed-to_ I meets the condition // this means that I can be interacted with inside the loop command - + // iterate with higher precision to account for b == 32767 for (int32_t l = a; l <= b; l++) { process_command(ss, es, post_command); diff --git a/src/ops/er301.c b/src/ops/er301.c index 4e898666..b24bf80e 100644 --- a/src/ops/er301.c +++ b/src/ops/er301.c @@ -52,8 +52,7 @@ void ERSend(uint8_t command, uint16_t output, int16_t value, bool set) { // zero-index the output output -= 1; // return if out of range - if (output < 0 || output > 299) - return; + if (output < 0 || output > 299) return; // convert the output to the device and the port uint8_t port = output % 100; uint8_t device = output / 100; diff --git a/src/ops/grid_ops.c b/src/ops/grid_ops.c index 28760fc6..a8c37b27 100644 --- a/src/ops/grid_ops.c +++ b/src/ops/grid_ops.c @@ -498,12 +498,12 @@ static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); - + if (count_x <= (s16)0) return; if (count_x > (s16)GRID_MAX_DIMENSION) count_x = GRID_MAX_DIMENSION; if (count_y <= (s16)0) return; if (count_y > (s16)GRID_MAX_DIMENSION) count_y = GRID_MAX_DIMENSION; - + u16 i; s16 x, y, w, h; for (s16 cy = 0; cy < count_y; cy++) @@ -513,7 +513,8 @@ static void op_G_BTX_get(const void *NOTUSED(data), scene_state_t *ss, w = _w; y = _y + _h * cy; h = _h; - grid_init_button(ss, SG.current_group, i, x, y, w, h, latch, level, script); + grid_init_button(ss, SG.current_group, i, x, y, w, h, latch, level, + script); } SG.scr_dirty = SG.grid_dirty = 1; @@ -532,12 +533,12 @@ static void op_G_GBX_get(const void *NOTUSED(data), scene_state_t *ss, s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); - + if (count_x <= (s16)0) return; if (count_x > (s16)GRID_MAX_DIMENSION) count_x = GRID_MAX_DIMENSION; if (count_y <= (s16)0) return; if (count_y > (s16)GRID_MAX_DIMENSION) count_y = GRID_MAX_DIMENSION; - + u16 i; s16 x, y, w, h; for (s16 cy = 0; cy < count_y; cy++) @@ -664,7 +665,8 @@ static void op_G_BTNV_set(const void *NOTUSED(data), scene_state_t *ss, SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_BTNL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_BTNL_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.button[SG.latest_button].common.level); } @@ -795,7 +797,7 @@ static void op_G_GBTN_C_get(const void *NOTUSED(data), scene_state_t *ss, cs_push(cs, 0); return; } - + s16 count = 0; for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) if (GBC.group == group && GB.state) count++; @@ -810,7 +812,7 @@ static void op_G_GBTN_I_get(const void *NOTUSED(data), scene_state_t *ss, cs_push(cs, -1); return; } - + s16 id = -1; s16 count = -1; for (u16 i = 0; i < GRID_BUTTON_COUNT; i++) { @@ -841,7 +843,7 @@ static void op_G_GBTN_W_get(const void *NOTUSED(data), scene_state_t *ss, atleastone = 1; } } - + cs_push(cs, atleastone ? x2 - x1 + 1 : 0); } @@ -862,12 +864,12 @@ static void op_G_GBTN_H_get(const void *NOTUSED(data), scene_state_t *ss, atleastone = 1; } } - + cs_push(cs, atleastone ? y2 - y1 + 1 : 0); } static void op_G_GBTN_X1_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) { cs_push(cs, -1); @@ -882,12 +884,12 @@ static void op_G_GBTN_X1_get(const void *NOTUSED(data), scene_state_t *ss, atleastone = 1; } } - + cs_push(cs, atleastone ? x1 : -1); } static void op_G_GBTN_X2_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) { cs_push(cs, -1); @@ -902,12 +904,12 @@ static void op_G_GBTN_X2_get(const void *NOTUSED(data), scene_state_t *ss, atleastone = 1; } } - + cs_push(cs, atleastone ? x2 : -1); } static void op_G_GBTN_Y1_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) { cs_push(cs, -1); @@ -922,12 +924,12 @@ static void op_G_GBTN_Y1_get(const void *NOTUSED(data), scene_state_t *ss, atleastone = 1; } } - + cs_push(cs, atleastone ? y1 : -1); } static void op_G_GBTN_Y2_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) { cs_push(cs, -1); @@ -942,7 +944,7 @@ static void op_G_GBTN_Y2_get(const void *NOTUSED(data), scene_state_t *ss, atleastone = 1; } } - + cs_push(cs, atleastone ? y2 : -1); } @@ -987,17 +989,17 @@ static void op_G_FDX_get(const void *NOTUSED(data), scene_state_t *ss, s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); - + if (count_x <= (s16)0) return; if (count_x > (s16)GRID_MAX_DIMENSION) count_x = GRID_MAX_DIMENSION; if (count_y <= (s16)0) return; if (count_y > (s16)GRID_MAX_DIMENSION) count_y = GRID_MAX_DIMENSION; - + for (u16 cy = 0; cy < count_y; cy++) for (u16 cx = 0; cx < count_x; cx++) grid_init_fader(ss, SG.current_group, id + cy * count_x + cx, - x + w * cx, y + h * cy, w, h, type, level, script); - + x + w * cx, y + h * cy, w, h, type, level, script); + SG.scr_dirty = SG.grid_dirty = 1; } @@ -1014,17 +1016,17 @@ static void op_G_GFX_get(const void *NOTUSED(data), scene_state_t *ss, s16 script = cs_pop(cs) - 1; s16 count_x = cs_pop(cs); s16 count_y = cs_pop(cs); - + if (count_x <= (s16)0) return; if (count_x > (s16)GRID_MAX_DIMENSION) count_x = GRID_MAX_DIMENSION; if (count_y <= (s16)0) return; if (count_y > (s16)GRID_MAX_DIMENSION) count_y = GRID_MAX_DIMENSION; - + for (u16 cy = 0; cy < count_y; cy++) for (u16 cx = 0; cx < count_x; cx++) grid_init_fader(ss, group, id + cy * count_x + cx, x + w * cx, - y + h * cy, w, h, type, level, script); - + y + h * cy, w, h, type, level, script); + SG.scr_dirty = SG.grid_dirty = 1; } @@ -1051,9 +1053,10 @@ static void op_G_FDR_V_get(const void *NOTUSED(data), scene_state_t *ss, cs_push(cs, 0); return; } - - s16 value = scale(0, grid_fader_max_value(ss, i), - SG.group[GFC.group].fader_min, SG.group[GFC.group].fader_max, GF.value); + + s16 value = + scale(0, grid_fader_max_value(ss, i), SG.group[GFC.group].fader_min, + SG.group[GFC.group].fader_max, GF.value); cs_push(cs, value); } @@ -1063,11 +1066,14 @@ static void op_G_FDR_V_set(const void *NOTUSED(data), scene_state_t *ss, s16 value = cs_pop(cs); if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; - if (value < SG.group[GFC.group].fader_min) value = SG.group[GFC.group].fader_min; - else if (value > SG.group[GFC.group].fader_max) value = SG.group[GFC.group].fader_max; - - GF.value = scale(SG.group[GFC.group].fader_min, - SG.group[GFC.group].fader_max, 0, grid_fader_max_value(ss, i), value); + if (value < SG.group[GFC.group].fader_min) + value = SG.group[GFC.group].fader_min; + else if (value > SG.group[GFC.group].fader_max) + value = SG.group[GFC.group].fader_max; + + GF.value = + scale(SG.group[GFC.group].fader_min, SG.group[GFC.group].fader_max, 0, + grid_fader_max_value(ss, i), value); SG.scr_dirty = SG.grid_dirty = 1; } @@ -1081,13 +1087,15 @@ static void op_G_FDR_N_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs); s16 value = cs_pop(cs); - + if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; s16 maxvalue = grid_fader_max_value(ss, i); - if (value < (s16)0) value = 0; - else if (value > maxvalue) value = maxvalue; - + if (value < (s16)0) + value = 0; + else if (value > maxvalue) + value = maxvalue; + GF.value = value; SG.scr_dirty = SG.grid_dirty = 1; } @@ -1103,7 +1111,7 @@ static void op_G_FDR_L_set(const void *NOTUSED(data), scene_state_t *ss, s16 i = cs_pop(cs); s16 level = cs_pop(cs); if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; - + level = grid_fader_clamp_level(level, GF.type, GFC.w, GFC.h); if (GF.type > FADER_COARSE) GF.value = scale(0, GFC.level, 0, level, GF.value); @@ -1167,8 +1175,9 @@ static void op_G_FDRI_get(const void *NOTUSED(data), scene_state_t *ss, static void op_G_FDRV_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { u8 i = SG.latest_fader; - s16 value = scale(0, grid_fader_max_value(ss, i), - SG.group[GFC.group].fader_min, SG.group[GFC.group].fader_max, GF.value); + s16 value = + scale(0, grid_fader_max_value(ss, i), SG.group[GFC.group].fader_min, + SG.group[GFC.group].fader_max, GF.value); cs_push(cs, value); } @@ -1176,44 +1185,53 @@ static void op_G_FDRV_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 value = cs_pop(cs); s16 i = SG.latest_fader; - - if (value < SG.group[GFC.group].fader_min) value = SG.group[GFC.group].fader_min; - else if (value > SG.group[GFC.group].fader_max) value = SG.group[GFC.group].fader_max; - - GF.value = scale(SG.group[GFC.group].fader_min, - SG.group[GFC.group].fader_max, 0, grid_fader_max_value(ss, i), value); + + if (value < SG.group[GFC.group].fader_min) + value = SG.group[GFC.group].fader_min; + else if (value > SG.group[GFC.group].fader_max) + value = SG.group[GFC.group].fader_max; + + GF.value = + scale(SG.group[GFC.group].fader_min, SG.group[GFC.group].fader_max, 0, + grid_fader_max_value(ss, i), value); SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDRN_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDRN_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.fader[SG.latest_fader].value); } -static void op_G_FDRN_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDRN_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 value = cs_pop(cs); s16 i = SG.latest_fader; - + s16 maxvalue = grid_fader_max_value(ss, i); - if (value < (s16)0) value = 0; - else if (value > maxvalue) value = maxvalue; - + if (value < (s16)0) + value = 0; + else if (value > maxvalue) + value = maxvalue; + GF.value = value; SG.scr_dirty = SG.grid_dirty = 1; } -static void op_G_FDRL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDRL_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, SG.fader[SG.latest_fader].common.level); } -static void op_G_FDRL_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_G_FDRL_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 level = cs_pop(cs); u16 i = SG.latest_fader; - + level = grid_fader_clamp_level(level, GF.type, GFC.w, GFC.h); if (GF.type > FADER_COARSE) GF.value = scale(0, GFC.level, 0, level, GF.value); GFC.level = level; - + SG.scr_dirty = SG.grid_dirty = 1; } @@ -1269,9 +1287,11 @@ static void op_G_FDR_PR_get(const void *NOTUSED(data), scene_state_t *ss, if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; s16 maxvalue = grid_fader_max_value(ss, i); - if (value < (s16)0) value = 0; - else if (value > maxvalue) value = maxvalue; - + if (value < (s16)0) + value = 0; + else if (value > maxvalue) + value = maxvalue; + GF.value = value; SG.latest_fader = i; SG.latest_group = GFC.group; @@ -1305,9 +1325,10 @@ static void op_G_GFDR_V_get(const void *NOTUSED(data), scene_state_t *ss, for (u16 i = 0; i < GRID_FADER_COUNT; i++) if (GFC.group == group) - GF.value = scale(SG.group[group].fader_min, - SG.group[group].fader_max, 0, grid_fader_max_value(ss, i), value); - + GF.value = + scale(SG.group[group].fader_min, SG.group[group].fader_max, 0, + grid_fader_max_value(ss, i), value); + SG.scr_dirty = SG.grid_dirty = 1; } @@ -1315,7 +1336,7 @@ static void op_G_GFDR_N_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { s16 group = cs_pop(cs); s16 value = cs_pop(cs); - + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; if (value < (s16)0) value = 0; @@ -1330,14 +1351,15 @@ static void op_G_GFDR_L_get(const void *NOTUSED(data), scene_state_t *ss, s16 group = cs_pop(cs); s16 odd = cs_pop(cs); s16 even = cs_pop(cs); - + if (group < (s16)0 || group > (s16)GRID_GROUP_COUNT) return; u8 is_odd = 0; s16 level; for (u16 i = 0; i < GRID_FADER_COUNT; i++) if (GFC.group == group) { - level = grid_fader_clamp_level(is_odd ? odd : even, GF.type, GFC.w, GFC.h); + level = grid_fader_clamp_level(is_odd ? odd : even, GF.type, GFC.w, + GFC.h); if (GF.type > FADER_COARSE) GF.value = scale(0, GFC.level, 0, level, GF.value); GFC.level = level; @@ -1411,7 +1433,7 @@ void grid_common_init(grid_common_t *gc) { s32 scale(s32 a, s32 b, s32 x, s32 y, s32 value) { if (a == b) return x; s32 result = (value - a) * (y - x) * 2 / (b - a); - result = (result / 2) + (result & 1); // rounding + result = (result / 2) + (result & 1); // rounding return result + x; } @@ -1449,11 +1471,10 @@ void grid_rectangle(scene_state_t *ss, s16 x, s16 y, s16 w, s16 h, u8 fill, } static void grid_init_button(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, - s16 w, s16 h, s16 latch, s16 level, s16 script) { - + s16 w, s16 h, s16 latch, s16 level, s16 script) { if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; if (i < (s16)0 || i >= (s16)GRID_BUTTON_COUNT) return; - + if (x >= (s16)GRID_MAX_DIMENSION || y >= (s16)GRID_MAX_DIMENSION) return; if (x < (s16)0) { w += x; @@ -1466,20 +1487,20 @@ static void grid_init_button(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, } if (h + y > (s16)GRID_MAX_DIMENSION) h = GRID_MAX_DIMENSION - y; if (w == 0 || h == 0) return; - + if (level < (s16)LED_OFF) level = LED_OFF; else if (level > (s16)15) level = 15; - + if (script < 0 || script > INIT_SCRIPT) script = -1; - + GBC.enabled = true; GBC.group = group; GBC.x = x; GBC.y = y; GBC.w = w; - + GBC.h = h; GBC.level = level; GBC.script = script; @@ -1488,8 +1509,7 @@ static void grid_init_button(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, } static void grid_init_fader(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, - s16 w, s16 h, s16 type, s16 level, s16 script) { - + s16 w, s16 h, s16 type, s16 level, s16 script) { if (group < (s16)0 || group >= (s16)GRID_GROUP_COUNT) return; if (i < (s16)0 || i >= (s16)GRID_FADER_COUNT) return; @@ -1505,7 +1525,7 @@ static void grid_init_fader(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, } if (h + y > (s16)GRID_MAX_DIMENSION) h = GRID_MAX_DIMENSION - y; if (w == 0 || h == 0) return; - + if (type < FADER_CH_BAR || type > FADER_FV_DOT) type = FADER_CH_BAR; level = grid_fader_clamp_level(level, type, w, h); @@ -1526,16 +1546,13 @@ static void grid_init_fader(scene_state_t *ss, s16 group, s16 i, s16 x, s16 y, static s16 grid_fader_max_value(scene_state_t *ss, u16 i) { switch (GF.type) { case FADER_CH_BAR: - case FADER_CH_DOT: - return GFC.w - 1; + case FADER_CH_DOT: return GFC.w - 1; case FADER_CV_BAR: - case FADER_CV_DOT: - return GFC.h - 1; + case FADER_CV_DOT: return GFC.h - 1; case FADER_FH_BAR: case FADER_FV_BAR: case FADER_FH_DOT: - case FADER_FV_DOT: - return GFC.level; + case FADER_FV_DOT: return GFC.level; } return 0; } @@ -1546,7 +1563,8 @@ static s16 grid_fader_clamp_level(s16 level, s16 type, s16 w, s16 h) { s16 maxlevel = ((size - 2) << 4) - 1; if (level < 0 || size < 3) return 0; if (level > maxlevel) return maxlevel; - } else { + } + else { if (level < (s16)LED_OFF) return LED_OFF; if (level > (s16)15) return 15; } diff --git a/src/ops/init.c b/src/ops/init.c index 09d675ee..38ae1c02 100644 --- a/src/ops/init.c +++ b/src/ops/init.c @@ -62,7 +62,7 @@ static void op_INIT_get(const void *NOTUSED(data), scene_state_t *ss, // At boot, all data is zeroed memset(ss, 0, sizeof(scene_state_t)); ss_init(ss); - + ss->cal = caldata; // Once calibration data is loaded, the scales need to be reset ss_update_param_scale(ss); diff --git a/src/ops/maths.c b/src/ops/maths.c index 444357ff..e368ad4a 100644 --- a/src/ops/maths.c +++ b/src/ops/maths.c @@ -22,7 +22,7 @@ static void op_RAND_get(const void *data, scene_state_t *ss, exec_state_t *es, static void op_RRAND_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_R_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); + command_state_t *cs); static void op_R_MIN_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_R_MIN_set(const void *data, scene_state_t *ss, exec_state_t *es, @@ -266,7 +266,7 @@ static void op_RRAND_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), static void op_R_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, push_random(ss->variables.r_min, ss->variables.r_max)); } @@ -473,26 +473,27 @@ static void op_OR_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), static void op_JI_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { - const uint8_t prime[6] = {2, 3, 5, 7, 11, 13 }; + const uint8_t prime[6] = { 2, 3, 5, 7, 11, 13 }; const int16_t ji_const[6] = { 6554, 10388, 15218, 18399, 22673, 24253 }; int32_t result = 0; int16_t n = abs(cs_pop(cs)); int16_t d = abs(cs_pop(cs)); - + /* code for generation of ji_const - + int16_t ji_find_prime_constant( uint16_t prime ) { float r = 1638.0 * logf( (float)prime ) / log( 2.0 ); - r *= 4.0; // this corresponds to the inverse of the bitshift applied at rounding & scaling + r *= 4.0; // this corresponds to the inverse of + the bitshift applied at rounding & scaling return( (int16_t)( r + 0.5 ) ); } */ - + if (n == 0 || d == 0) { // early return if zeroes cs_push(cs, 0); return; } - + for (uint8_t p = 0; p <= 6; p++) { // find num factors if (n == 1) { break; } // succeed if all primes found if (p == 6) { // failed to find solution @@ -519,7 +520,7 @@ static void op_JI_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), quotient = d / prime[p]; } } - result = ( result + 2 ) >> 2; // round & scale + result = (result + 2) >> 2; // round & scale cs_push(cs, result); } @@ -538,8 +539,8 @@ static void op_SCALE_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), } int32_t result = (i - a) * (y - x) * 2 / (b - a); - result = result / 2 + (result & 1); // rounding - + result = result / 2 + (result & 1); // rounding + cs_push(cs, result + x); } diff --git a/src/ops/maths.h b/src/ops/maths.h index bdac59da..c595f7bc 100644 --- a/src/ops/maths.h +++ b/src/ops/maths.h @@ -55,7 +55,7 @@ extern const tele_op_t op_BCLR; extern const tele_op_t op_CHAOS; extern const tele_op_t op_CHAOS_R; extern const tele_op_t op_CHAOS_ALG; -extern const tele_op_t op_TIF; // ternary if +extern const tele_op_t op_TIF; // ternary if extern const tele_op_t op_XOR; // XOR alias NE diff --git a/src/ops/matrixarchate.c b/src/ops/matrixarchate.c index 97fcbd99..b510c7c5 100644 --- a/src/ops/matrixarchate.c +++ b/src/ops/matrixarchate.c @@ -5,33 +5,55 @@ #include "teletype.h" #include "teletype_io.h" -static void op_MA_SELECT_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_SELECT_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); - -static void op_MA_STEP_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_RESET_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_PGM_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); - -static void op_MA_ON_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_PON_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_OFF_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_POFF_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_SET_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_PSET_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); - -static void op_MA_COL_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_COL_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_PCOL_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_PCOL_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_ROW_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_ROW_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_PROW_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_PROW_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); - -static void op_MA_CLR_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); -static void op_MA_PCLR_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); - -const tele_op_t op_MA_SELECT = MAKE_GET_SET_OP(MA.SELECT, op_MA_SELECT_get, op_MA_SELECT_set, 0, true); +static void op_MA_SELECT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MA_SELECT_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); + +static void op_MA_STEP_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MA_RESET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MA_PGM_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); + +static void op_MA_ON_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_MA_PON_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_MA_OFF_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_MA_POFF_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MA_SET_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_MA_PSET_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); + +static void op_MA_COL_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_MA_COL_set(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_MA_PCOL_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MA_PCOL_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MA_ROW_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_MA_ROW_set(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_MA_PROW_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_MA_PROW_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); + +static void op_MA_CLR_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_MA_PCLR_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); + +const tele_op_t op_MA_SELECT = + MAKE_GET_SET_OP(MA.SELECT, op_MA_SELECT_get, op_MA_SELECT_set, 0, true); const tele_op_t op_MA_STEP = MAKE_GET_OP(MA.STEP, op_MA_STEP_get, 0, false); const tele_op_t op_MA_RESET = MAKE_GET_OP(MA.RESET, op_MA_RESET_get, 0, false); @@ -44,10 +66,14 @@ const tele_op_t op_MA_POFF = MAKE_GET_OP(MA.POFF, op_MA_POFF_get, 3, false); const tele_op_t op_MA_SET = MAKE_GET_OP(MA.SET, op_MA_SET_get, 3, false); const tele_op_t op_MA_PSET = MAKE_GET_OP(MA.PSET, op_MA_PSET_get, 4, false); -const tele_op_t op_MA_COL = MAKE_GET_SET_OP(MA.COL, op_MA_COL_get, op_MA_COL_set, 1, true); -const tele_op_t op_MA_PCOL = MAKE_GET_SET_OP(MA.PCOL, op_MA_PCOL_get, op_MA_PCOL_set, 2, true); -const tele_op_t op_MA_ROW = MAKE_GET_SET_OP(MA.ROW, op_MA_ROW_get, op_MA_ROW_set, 1, true); -const tele_op_t op_MA_PROW = MAKE_GET_SET_OP(MA.PROW, op_MA_PROW_get, op_MA_PROW_set, 2, true); +const tele_op_t op_MA_COL = + MAKE_GET_SET_OP(MA.COL, op_MA_COL_get, op_MA_COL_set, 1, true); +const tele_op_t op_MA_PCOL = + MAKE_GET_SET_OP(MA.PCOL, op_MA_PCOL_get, op_MA_PCOL_set, 2, true); +const tele_op_t op_MA_ROW = + MAKE_GET_SET_OP(MA.ROW, op_MA_ROW_get, op_MA_ROW_set, 1, true); +const tele_op_t op_MA_PROW = + MAKE_GET_SET_OP(MA.PROW, op_MA_PROW_get, op_MA_PROW_set, 2, true); const tele_op_t op_MA_CLR = MAKE_GET_OP(MA.CLR, op_MA_CLR_get, 0, false); const tele_op_t op_MA_PCLR = MAKE_GET_OP(MA.PCLR, op_MA_PCLR_get, 1, false); @@ -61,8 +87,11 @@ static void ma_set(s16 row, s16 column, s16 value) { } static void ma_set_pgm(s16 program, s16 row, s16 column, s16 value) { - if (program < 0 || program > 59 || row < 0 || row > 15 || column < 0 || column > 7) return; - uint8_t d[] = { value ? 0b10010000 : 0b10000000, (row << 3) + column, program }; + if (program < 0 || program > 59 || row < 0 || row > 15 || column < 0 || + column > 7) + return; + uint8_t d[] = { value ? 0b10010000 : 0b10000000, (row << 3) + column, + program }; tele_ii_tx(MATRIXARCHATE + selected_ma, d, 3); } @@ -90,67 +119,78 @@ static void ma_set_row_pgm(s16 program, s16 row, u16 value) { tele_ii_tx(MATRIXARCHATE + selected_ma, d, 5); } -static void op_MA_SELECT_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_SELECT_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, selected_ma + 1); } -static void op_MA_SELECT_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_SELECT_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 i = cs_pop(cs) - 1; if (i < 0 || i > 2) return; selected_ma = i; } -static void op_MA_STEP_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_STEP_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { uint8_t d[] = { 0b11111000 }; tele_ii_tx(MATRIXARCHATE + selected_ma, d, 1); } -static void op_MA_RESET_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_RESET_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { uint8_t d[] = { 0b11111101 }; tele_ii_tx(MATRIXARCHATE + selected_ma, d, 1); } -static void op_MA_PGM_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_PGM_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 program = cs_pop(cs) - 1; if (program < 0 || program > 59) return; uint8_t d[] = { 0b11000000, program }; tele_ii_tx(MATRIXARCHATE + selected_ma, d, 2); } -static void op_MA_ON_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_ON_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 row = cs_pop(cs); s16 column = cs_pop(cs); ma_set(row, column, 1); } -static void op_MA_PON_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_PON_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 program = cs_pop(cs) - 1; s16 row = cs_pop(cs); s16 column = cs_pop(cs); ma_set_pgm(program, row, column, 1); } -static void op_MA_OFF_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_OFF_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 row = cs_pop(cs); s16 column = cs_pop(cs); ma_set(row, column, 0); } -static void op_MA_POFF_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_POFF_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 program = cs_pop(cs) - 1; s16 row = cs_pop(cs); s16 column = cs_pop(cs); ma_set_pgm(program, row, column, 0); } -static void op_MA_SET_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_SET_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 row = cs_pop(cs); s16 column = cs_pop(cs); s16 value = cs_pop(cs); ma_set(row, column, value); } -static void op_MA_PSET_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_PSET_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 program = cs_pop(cs) - 1; s16 row = cs_pop(cs); s16 column = cs_pop(cs); @@ -158,7 +198,8 @@ static void op_MA_PSET_get(const void *NOTUSED(data), scene_state_t *ss, exec_st ma_set_pgm(program, row, column, value); } -static void op_MA_COL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_COL_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 column = cs_pop(cs); u16 value = 0; if (column >= 0 && column <= 7) { @@ -172,13 +213,15 @@ static void op_MA_COL_get(const void *NOTUSED(data), scene_state_t *ss, exec_sta cs_push(cs, value); } -static void op_MA_COL_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_COL_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 column = cs_pop(cs); u16 value = cs_pop(cs); ma_set_col(column, value); } -static void op_MA_PCOL_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_PCOL_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 program = cs_pop(cs) - 1; s16 column = cs_pop(cs); u16 value = 0; @@ -193,14 +236,16 @@ static void op_MA_PCOL_get(const void *NOTUSED(data), scene_state_t *ss, exec_st cs_push(cs, value); } -static void op_MA_PCOL_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_PCOL_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 program = cs_pop(cs) - 1; s16 column = cs_pop(cs); u16 value = cs_pop(cs); ma_set_col_pgm(program, column, value); } -static void op_MA_ROW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_ROW_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 row = cs_pop(cs); u16 value = 0; if (row >= 0 && row <= 15) { @@ -214,13 +259,15 @@ static void op_MA_ROW_get(const void *NOTUSED(data), scene_state_t *ss, exec_sta cs_push(cs, value); } -static void op_MA_ROW_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_ROW_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 row = cs_pop(cs); u16 value = cs_pop(cs); ma_set_row(row, value); } -static void op_MA_PROW_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_PROW_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 program = cs_pop(cs) - 1; s16 row = cs_pop(cs); u16 value = 0; @@ -235,18 +282,21 @@ static void op_MA_PROW_get(const void *NOTUSED(data), scene_state_t *ss, exec_st cs_push(cs, value); } -static void op_MA_PROW_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_PROW_set(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 program = cs_pop(cs) - 1; s16 row = cs_pop(cs); u16 value = cs_pop(cs); ma_set_row_pgm(program, row, value); } -static void op_MA_CLR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_CLR_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { for (u8 i = 0; i < 8; i++) ma_set_col(i, 0); } -static void op_MA_PCLR_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_MA_PCLR_get(const void *NOTUSED(data), scene_state_t *ss, + exec_state_t *NOTUSED(es), command_state_t *cs) { s16 program = cs_pop(cs) - 1; for (u8 i = 0; i < 8; i++) ma_set_col_pgm(program, i, 0); } diff --git a/src/ops/op.c b/src/ops/op.c index 6d7d05d2..70ec2cb2 100644 --- a/src/ops/op.c +++ b/src/ops/op.c @@ -15,8 +15,8 @@ #include "ops/hardware.h" #include "ops/init.h" #include "ops/justfriends.h" -#include "ops/matrixarchate.h" #include "ops/maths.h" +#include "ops/matrixarchate.h" #include "ops/meadowphysics.h" #include "ops/metronome.h" #include "ops/orca.h" @@ -78,14 +78,14 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_ADD, &op_SUB, &op_MUL, &op_DIV, &op_MOD, &op_RAND, &op_RND, &op_RRAND, &op_RRND, &op_R, &op_R_MIN, &op_R_MAX, &op_TOSS, &op_MIN, &op_MAX, &op_LIM, &op_WRAP, &op_WRP, &op_QT, &op_AVG, &op_EQ, &op_NE, &op_LT, &op_GT, &op_LTE, - &op_GTE, &op_NZ, &op_EZ, &op_RSH, &op_LSH, &op_EXP, &op_ABS, &op_AND, + &op_GTE, &op_NZ, &op_EZ, &op_RSH, &op_LSH, &op_EXP, &op_ABS, &op_AND, &op_OR, &op_JI, &op_SCALE, &op_SCL, &op_N, &op_V, &op_VV, &op_ER, &op_BPM, - &op_BIT_OR, &op_BIT_AND, &op_BIT_NOT, &op_BIT_XOR, &op_BSET, &op_BGET, - &op_BCLR, &op_XOR, &op_CHAOS, &op_CHAOS_R, &op_CHAOS_ALG, &op_SYM_PLUS, - &op_SYM_DASH, &op_SYM_STAR, &op_SYM_FORWARD_SLASH, &op_SYM_PERCENTAGE, - &op_SYM_EQUAL_x2, &op_SYM_EXCLAMATION_EQUAL, &op_SYM_LEFT_ANGLED, + &op_BIT_OR, &op_BIT_AND, &op_BIT_NOT, &op_BIT_XOR, &op_BSET, &op_BGET, + &op_BCLR, &op_XOR, &op_CHAOS, &op_CHAOS_R, &op_CHAOS_ALG, &op_SYM_PLUS, + &op_SYM_DASH, &op_SYM_STAR, &op_SYM_FORWARD_SLASH, &op_SYM_PERCENTAGE, + &op_SYM_EQUAL_x2, &op_SYM_EXCLAMATION_EQUAL, &op_SYM_LEFT_ANGLED, &op_SYM_RIGHT_ANGLED, &op_SYM_LEFT_ANGLED_EQUAL, &op_SYM_RIGHT_ANGLED_EQUAL, - &op_SYM_EXCLAMATION, &op_SYM_LEFT_ANGLED_x2, &op_SYM_RIGHT_ANGLED_x2, + &op_SYM_EXCLAMATION, &op_SYM_LEFT_ANGLED_x2, &op_SYM_RIGHT_ANGLED_x2, &op_SYM_AMPERSAND_x2, &op_SYM_PIPE_x2, &op_TIF, // stack @@ -117,11 +117,11 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { // ansible &op_KR_PRE, &op_KR_PAT, &op_KR_SCALE, &op_KR_PERIOD, &op_KR_POS, - &op_KR_L_ST, &op_KR_L_LEN, &op_KR_RES, &op_KR_CV, &op_KR_MUTE, &op_KR_TMUTE, &op_KR_CLK, - &op_ME_PRE, &op_ME_RES, &op_ME_STOP, - &op_ME_SCALE, &op_ME_PERIOD, &op_ME_CV, &op_LV_PRE, &op_LV_RES, &op_LV_POS, - &op_LV_L_ST, &op_LV_L_LEN, &op_LV_L_DIR, &op_LV_CV, &op_CY_PRE, &op_CY_RES, - &op_CY_POS, &op_CY_REV, &op_CY_CV, &op_MID_SHIFT, &op_MID_SLEW, &op_ARP_STY, + &op_KR_L_ST, &op_KR_L_LEN, &op_KR_RES, &op_KR_CV, &op_KR_MUTE, &op_KR_TMUTE, + &op_KR_CLK, &op_ME_PRE, &op_ME_RES, &op_ME_STOP, &op_ME_SCALE, + &op_ME_PERIOD, &op_ME_CV, &op_LV_PRE, &op_LV_RES, &op_LV_POS, &op_LV_L_ST, + &op_LV_L_LEN, &op_LV_L_DIR, &op_LV_CV, &op_CY_PRE, &op_CY_RES, &op_CY_POS, + &op_CY_REV, &op_CY_CV, &op_MID_SHIFT, &op_MID_SLEW, &op_ARP_STY, &op_ARP_HLD, &op_ARP_RPT, &op_ARP_GT, &op_ARP_DIV, &op_ARP_RES, &op_ARP_SHIFT, &op_ARP_SLEW, &op_ARP_FIL, &op_ARP_ROT, &op_ARP_ER, @@ -196,11 +196,11 @@ const tele_op_t *tele_ops[E_OP__LENGTH] = { &op_G_GFDR_N, &op_G_GFDR_L, &op_G_GFDR_RN, &op_G_XYP, &op_G_XYP_X, &op_G_XYP_Y, &op_G_GBTN_C, &op_G_GBTN_I, &op_G_GBTN_W, &op_G_GBTN_H, &op_G_GBTN_X1, &op_G_GBTN_X2, &op_G_GBTN_Y1, &op_G_GBTN_Y2, - + // matrixarchate &op_MA_SELECT, &op_MA_STEP, &op_MA_RESET, &op_MA_PGM, &op_MA_ON, &op_MA_PON, &op_MA_OFF, &op_MA_POFF, &op_MA_SET, &op_MA_PSET, &op_MA_COL, &op_MA_PCOL, - &op_MA_ROW, &op_MA_PROW, &op_MA_CLR, &op_MA_PCLR + &op_MA_ROW, &op_MA_PROW, &op_MA_CLR, &op_MA_PCLR }; ///////////////////////////////////////////////////////////////// diff --git a/src/ops/patterns.c b/src/ops/patterns.c index 6d17ad0f..aa24b4f4 100644 --- a/src/ops/patterns.c +++ b/src/ops/patterns.c @@ -787,8 +787,8 @@ const tele_op_t op_PN_RND = MAKE_GET_OP(PN.RND, op_PN_RND_get, 1, true); //////////////////////////////////////////////////////////////////////////////// // P.+ P.+W //////////////////////////////////////////////////////////////////// -static void p_add_get(scene_state_t *ss, int16_t pn, int16_t idx, - int16_t delta, uint8_t wrap_value, int16_t min, int16_t max) { +static void p_add_get(scene_state_t *ss, int16_t pn, int16_t idx, int16_t delta, + uint8_t wrap_value, int16_t min, int16_t max) { pn = normalise_pn(pn); idx = normalise_idx(ss, pn, idx); int16_t value = ss_get_pattern_val(ss, pn, idx) + delta; @@ -814,7 +814,7 @@ static void op_PN_ADD_get(const void *NOTUSED(data), scene_state_t *ss, } static void op_P_ADDW_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { + exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t idx = cs_pop(cs); int16_t delta = cs_pop(cs); int16_t min = cs_pop(cs); @@ -824,7 +824,7 @@ static void op_P_ADDW_get(const void *NOTUSED(data), scene_state_t *ss, } static void op_PN_ADDW_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { + exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t pn = cs_pop(cs); int16_t idx = cs_pop(cs); int16_t delta = cs_pop(cs); @@ -837,14 +837,14 @@ static void op_PN_ADDW_get(const void *NOTUSED(data), scene_state_t *ss, // Make ops const tele_op_t op_P_ADD = MAKE_GET_OP(P.+, op_P_ADD_get, 2, false); const tele_op_t op_PN_ADD = MAKE_GET_OP(PN.+, op_PN_ADD_get, 3, false); -const tele_op_t op_P_ADDW = MAKE_GET_OP(P.+W, op_P_ADDW_get, 4, false); -const tele_op_t op_PN_ADDW = MAKE_GET_OP(PN.+W, op_PN_ADDW_get, 5, false); +const tele_op_t op_P_ADDW = MAKE_GET_OP(P.+ W, op_P_ADDW_get, 4, false); +const tele_op_t op_PN_ADDW = MAKE_GET_OP(PN.+ W, op_PN_ADDW_get, 5, false); //////////////////////////////////////////////////////////////////////////////// // P.- P.-W //////////////////////////////////////////////////////////////////// -static void p_sub_get(scene_state_t *ss, int16_t pn, int16_t idx, - int16_t delta, uint8_t wrap_value, int16_t min, int16_t max) { +static void p_sub_get(scene_state_t *ss, int16_t pn, int16_t idx, int16_t delta, + uint8_t wrap_value, int16_t min, int16_t max) { pn = normalise_pn(pn); idx = normalise_idx(ss, pn, idx); int16_t value = ss_get_pattern_val(ss, pn, idx) - delta; @@ -870,7 +870,7 @@ static void op_PN_SUB_get(const void *NOTUSED(data), scene_state_t *ss, } static void op_P_SUBW_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { + exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t idx = cs_pop(cs); int16_t delta = cs_pop(cs); int16_t min = cs_pop(cs); @@ -880,7 +880,7 @@ static void op_P_SUBW_get(const void *NOTUSED(data), scene_state_t *ss, } static void op_PN_SUBW_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { + exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t pn = cs_pop(cs); int16_t idx = cs_pop(cs); int16_t delta = cs_pop(cs); @@ -893,5 +893,5 @@ static void op_PN_SUBW_get(const void *NOTUSED(data), scene_state_t *ss, // Make ops const tele_op_t op_P_SUB = MAKE_GET_OP(P.-, op_P_SUB_get, 2, false); const tele_op_t op_PN_SUB = MAKE_GET_OP(PN.-, op_PN_SUB_get, 3, false); -const tele_op_t op_P_SUBW = MAKE_GET_OP(P.-W, op_P_SUBW_get, 4, false); -const tele_op_t op_PN_SUBW = MAKE_GET_OP(PN.-W, op_PN_SUBW_get, 5, false); +const tele_op_t op_P_SUBW = MAKE_GET_OP(P.- W, op_P_SUBW_get, 4, false); +const tele_op_t op_PN_SUBW = MAKE_GET_OP(PN.- W, op_PN_SUBW_get, 5, false); diff --git a/src/ops/telex.c b/src/ops/telex.c index cbeed160..ec4b239b 100644 --- a/src/ops/telex.c +++ b/src/ops/telex.c @@ -374,8 +374,7 @@ void TXSend(uint8_t model, uint8_t command, uint8_t output, int16_t value, // zero-index the output output -= 1; // return if out of range - if (output < 0 || output > 31) - return; + if (output < 0 || output > 31) return; // convert the output to the device and the port uint8_t port = output & 3; uint8_t device = output >> 2; diff --git a/src/ops/variables.c b/src/ops/variables.c index 62c288fe..9f899a78 100644 --- a/src/ops/variables.c +++ b/src/ops/variables.c @@ -27,13 +27,13 @@ static void op_I_get(const void *data, scene_state_t *ss, exec_state_t *es, static void op_I_set(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_TIME_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); + command_state_t *cs); static void op_TIME_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_TIME_ACT_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_TIME_ACT_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); + command_state_t *cs); +static void op_TIME_ACT_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_TIME_ACT_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); // clang-format off const tele_op_t op_A = MAKE_SIMPLE_VARIABLE_OP(A , variables.a ); @@ -63,25 +63,26 @@ const tele_op_t op_I = MAKE_GET_SET_OP(I , op_I_get, op_I_set, 0, true); static void op_TIME_get(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { - int64_t delta = ss->variables.time_act ? - tele_get_ticks() - ss->variables.time : ss->variables.time; + int64_t delta = ss->variables.time_act + ? tele_get_ticks() - ss->variables.time + : ss->variables.time; cs_push(cs, delta & 0x7fff); } static void op_TIME_set(const void *NOTUSED(data), scene_state_t *ss, exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t new_time = cs_pop(cs); - ss->variables.time = ss->variables.time_act ? - tele_get_ticks() - new_time : new_time; + ss->variables.time = + ss->variables.time_act ? tele_get_ticks() - new_time : new_time; } static void op_TIME_ACT_get(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { + exec_state_t *NOTUSED(es), command_state_t *cs) { cs_push(cs, ss->variables.time_act ? 1 : 0); } static void op_TIME_ACT_set(const void *NOTUSED(data), scene_state_t *ss, - exec_state_t *NOTUSED(es), command_state_t *cs) { + exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t act = cs_pop(cs); if (act && ss->variables.time_act) return; if (!act && !ss->variables.time_act) return; diff --git a/src/ops/wslash.c b/src/ops/wslash.c index 2f3cfbcf..e1311e94 100644 --- a/src/ops/wslash.c +++ b/src/ops/wslash.c @@ -4,14 +4,14 @@ #include "ii.h" #include "teletype_io.h" -static void op_WS_REC_get(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_WS_REC_set(const void *data, scene_state_t *ss, - exec_state_t *es, command_state_t *cs); -static void op_WS_PLAY_get(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); -static void op_WS_PLAY_set(const void *data, scene_state_t *ss, exec_state_t *es, - command_state_t *cs); +static void op_WS_REC_get(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_WS_REC_set(const void *data, scene_state_t *ss, exec_state_t *es, + command_state_t *cs); +static void op_WS_PLAY_get(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); +static void op_WS_PLAY_set(const void *data, scene_state_t *ss, + exec_state_t *es, command_state_t *cs); static void op_WS_LOOP_get(const void *data, scene_state_t *ss, exec_state_t *es, command_state_t *cs); static void op_WS_LOOP_set(const void *data, scene_state_t *ss, @@ -29,8 +29,7 @@ const tele_op_t op_WS_CUE = MAKE_GET_SET_OP(WS.CUE , op_WS_CUE_get , op_WS_CUE_ // clang-format on -static void op_WS_REC_set(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), +static void op_WS_REC_set(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); uint8_t d[] = { WS_REC, a }; @@ -53,8 +52,9 @@ static void op_WS_PLAY_set(const void *NOTUSED(data), uint8_t d[] = { WS_PLAY, a }; tele_ii_tx(WS_ADDR, d, 2); } -static void op_WS_PLAY_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_WS_PLAY_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { uint8_t d[] = { WS_PLAY | II_GET }; uint8_t addr = WS_ADDR; tele_ii_tx(addr, d, 1); @@ -70,8 +70,9 @@ static void op_WS_LOOP_set(const void *NOTUSED(data), uint8_t d[] = { WS_LOOP, a }; tele_ii_tx(WS_ADDR, d, 2); } -static void op_WS_LOOP_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), - exec_state_t *NOTUSED(es), command_state_t *cs) { +static void op_WS_LOOP_get(const void *NOTUSED(data), + scene_state_t *NOTUSED(ss), + exec_state_t *NOTUSED(es), command_state_t *cs) { uint8_t d[] = { WS_LOOP | II_GET }; uint8_t addr = WS_ADDR; tele_ii_tx(addr, d, 1); @@ -80,8 +81,7 @@ static void op_WS_LOOP_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss) cs_push(cs, d[0]); } -static void op_WS_CUE_set(const void *NOTUSED(data), - scene_state_t *NOTUSED(ss), +static void op_WS_CUE_set(const void *NOTUSED(data), scene_state_t *NOTUSED(ss), exec_state_t *NOTUSED(es), command_state_t *cs) { int16_t a = cs_pop(cs); uint8_t d[] = { WS_CUE, a }; diff --git a/src/state.c b/src/state.c index 20f865e5..0106e9b3 100644 --- a/src/state.c +++ b/src/state.c @@ -18,8 +18,7 @@ void ss_init(scene_state_t *ss) { memset(&ss->scripts, 0, ss_scripts_size()); turtle_init(&ss->turtle); uint32_t ticks = tele_get_ticks(); - for (size_t i = 0; i < TEMP_SCRIPT; i++) - ss->scripts[i].last_time = ticks; + for (size_t i = 0; i < TEMP_SCRIPT; i++) ss->scripts[i].last_time = ticks; ss->variables.time = 0; ss->variables.time_act = 1; } @@ -505,7 +504,7 @@ size_t es_push(exec_state_t *es) { if (es->exec_depth > 0) { es->variables[es->exec_depth].if_else_condition = es->variables[es->exec_depth - 1].if_else_condition; - es->variables[es->exec_depth].i = + es->variables[es->exec_depth].i = es->variables[es->exec_depth - 1].i; } else { diff --git a/src/teletype.c b/src/teletype.c index 8bc642f3..d52ca3be 100644 --- a/src/teletype.c +++ b/src/teletype.c @@ -147,7 +147,7 @@ process_result_t run_script_with_exec_state(scene_state_t *ss, exec_state_t *es, #ifdef TELETYPE_PROFILE tele_profile_script(script_no); #endif - process_result_t result = { .has_value = false, .value = 0 }; + process_result_t result = {.has_value = false, .value = 0 }; es_set_script_number(es, script_no); From b089e3805b9e1976583875203ec101044e7b5508 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 10 Aug 2018 10:43:02 -0700 Subject: [PATCH 116/117] fix clang formatting --- src/ops/patterns.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ops/patterns.c b/src/ops/patterns.c index aa24b4f4..92d0eaf2 100644 --- a/src/ops/patterns.c +++ b/src/ops/patterns.c @@ -835,10 +835,12 @@ static void op_PN_ADDW_get(const void *NOTUSED(data), scene_state_t *ss, } // Make ops +// clang-format off const tele_op_t op_P_ADD = MAKE_GET_OP(P.+, op_P_ADD_get, 2, false); const tele_op_t op_PN_ADD = MAKE_GET_OP(PN.+, op_PN_ADD_get, 3, false); -const tele_op_t op_P_ADDW = MAKE_GET_OP(P.+ W, op_P_ADDW_get, 4, false); -const tele_op_t op_PN_ADDW = MAKE_GET_OP(PN.+ W, op_PN_ADDW_get, 5, false); +const tele_op_t op_P_ADDW = MAKE_GET_OP(P.+W, op_P_ADDW_get, 4, false); +const tele_op_t op_PN_ADDW = MAKE_GET_OP(PN.+W, op_PN_ADDW_get, 5, false); +// clang-format on //////////////////////////////////////////////////////////////////////////////// // P.- P.-W //////////////////////////////////////////////////////////////////// @@ -891,7 +893,9 @@ static void op_PN_SUBW_get(const void *NOTUSED(data), scene_state_t *ss, } // Make ops +// clang-format off const tele_op_t op_P_SUB = MAKE_GET_OP(P.-, op_P_SUB_get, 2, false); const tele_op_t op_PN_SUB = MAKE_GET_OP(PN.-, op_PN_SUB_get, 3, false); -const tele_op_t op_P_SUBW = MAKE_GET_OP(P.- W, op_P_SUBW_get, 4, false); -const tele_op_t op_PN_SUBW = MAKE_GET_OP(PN.- W, op_PN_SUBW_get, 5, false); +const tele_op_t op_P_SUBW = MAKE_GET_OP(P.-W, op_P_SUBW_get, 4, false); +const tele_op_t op_PN_SUBW = MAKE_GET_OP(PN.-W, op_PN_SUBW_get, 5, false); +// clang-format on From 07a369876b8d8a919d9b1cc2d9772f1d5065ef65 Mon Sep 17 00:00:00 2001 From: scanner-darkly Date: Fri, 10 Aug 2018 15:01:39 -0700 Subject: [PATCH 117/117] remove warning --- docs/whats_new.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/whats_new.md b/docs/whats_new.md index 1e38b4b8..ad127078 100644 --- a/docs/whats_new.md +++ b/docs/whats_new.md @@ -6,7 +6,7 @@ #### Grid Integration -Grid integration allows you to use grid to visualize, control and execute teletype scripts. You can create your own UIs using grid ops, or control Teletype directly with the Grid Control mode. Built in Grid Visualizer allows designing and using grid scenes without a grid. For more information and examples of grid scenes please see the [Grid Studies](https://github.com/scanner-darkly/teletype/wiki/GRID-INTEGRATION). **Important**: do NOT plug your grid directly into Teletype! Doing so may damage your module. Grid must be powered externally. +Grid integration allows you to use grid to visualize, control and execute teletype scripts. You can create your own UIs using grid ops, or control Teletype directly with the Grid Control mode. Built in Grid Visualizer allows designing and using grid scenes without a grid. For more information and examples of grid scenes please see the [Grid Studies](https://github.com/scanner-darkly/teletype/wiki/GRID-INTEGRATION). #### Improved script editing