Skip to content
Permalink
main
Go to file
 
 
Cannot retrieve contributors at this time
2923 lines (2626 sloc) 103 KB
// -----------------------------------------------------------------------------
// controller - the glue between the engine and the hardware
//
// reacts to events (grid press, clock etc) and translates them into appropriate
// engine actions. reacts to engine updates and translates them into user
// interface and hardware updates (grid LEDs, CV outputs etc)
//
// should talk to hardware via what's defined in interface.h only
// should talk to the engine via what's defined in engine.h only
// ----------------------------------------------------------------------------
#include "compiler.h"
#include "string.h"
#include "control.h"
#include "interface.h"
#include "engine.h"
// ----------------------------------------------------------------------------
// firmware dependent stuff starts here
#define I2C_ADDRESS 0x50
#define TXOWAVF 15
#define MAX_HELD_KEYS 32
#define GRID_KEY_HOLD_TIME 15
#define ES_CHORD_THRESHOLD 30
#define ES_EDGE_PATTERN 0
#define ES_EDGE_FIXED 1
#define ES_EDGE_DRONE 2
#define ES_BLINKER_TIMER (VOICE_COUNT + 1)
#define ES_PLAY_POS_TIMER (VOICE_COUNT + 2)
#define ES_PLAY_TIMER (VOICE_COUNT + 3) // 16 of these for each pattern
#define ES_PSTART_TIMER (VOICE_COUNT + 3 + 16) // 16 of these for each pattern
#define ES_KNOB_TIMER (VOICE_COUNT + 3 + 32)
typedef enum {
es_stopped,
es_armed,
es_recording,
es_playing
} es_mode_t;
typedef enum {
es_main,
es_patterns_held,
es_patterns,
es_voices,
es_voices_held,
es_devices,
es_devices_held
} es_view_t;
u8 key_count = 0;
u8 held_keys[MAX_HELD_KEYS];
u8 key_times[128];
u8 playing[16];
u8 preset_mode;
u8 preset, selected_preset, selected_voice;
u8 sel_device, sel_param, sel_mapping, sel_pattern_start;
u8 prev_param_x, prev_param_y;
u8 sel_mod = 255;
preset_meta_t meta;
preset_data_t e;
shared_data_t shared;
es_mode_t es_mode;
es_view_t es_view;
u8 es_blinker;
u8 es_runes, es_edge, es_voices_changed, es_devices_changed;
u32 es_tick;
u16 es_pos[16];
es_note_t es_notes[VOICE_COUNT];
u32 es_p_start, es_p_total;
u8 es_ignore_arm_release;
u8 help_on, help_sel, pattern_leader, pattern_held = 255;
static u8 midi_notes[VOICE_COUNT];
static u8 midi_cc_ind;
static u8 wtf_update_devices = 0;
static void read_knobs(void);
static void save_to_preset(u8 p);
static void update_devices(void);
static void remap_voices(void);
static void pattern_start(u8 pattern, u8 on);
static void update_mod(u8 voice, u8 x, u8 y, u8 index);
static void update_mod_off(u8 voice);
static void update_mod_arc(u8 enc, s8 delta);
static void update_i2c(void);
static void event_main_clock(u8 external, u8 phase);
static void event_front_button(u8 pressed);
static void load_preset(void);
static void load_preset(void);
static void external_clock_received(void);
static void external_clock_switched(u8 external);
static void handler_ESGridKey(u8 x, u8 y, u8 z);
static void es_blinker_callback(void);
static void es_play_callback(u8 pattern);
static void es_play_pos_callback(void);
static void es_note_off_callback(u8 index);
static void es_reset_all_playing(void);
static void process_timed_event(u8 index);
static void ii_es(uint8_t *data, uint8_t l);
static void grid_key_held(u8 x, u8 y);
static void copy_pattern(u8 src, u8 dest);
static void es_start_playback(u8 pattern, u8 pos);
static void es_stop_playback(u8 pattern);
static void es_prev_pattern(void);
static void es_next_pattern(void);
static u8 es_note_on(s8 x, s8 y, u8 from_pattern, u16 timer, u8 voices);
static u8 es_note_off(s8 x, s8 y);
static void update_dest(u8 mod);
static void clock_next_note(u8 is_leader);
static void es_start_recording(void);
static void es_record_pattern_note(u8 x, u8 y, u8 z);
static void es_kill_pattern_notes(u8 pattern);
// ----------------------------------------------------------------------------
// functions for main.c
void init_control(void) {
load_shared_data_from_flash(&shared);
update_i2c();
preset = selected_preset = get_preset_index();
load_preset();
es_mode = es_stopped;
es_view = es_main;
preset_mode = 0;
selected_voice = 0;
for (u8 i = 0; i < 16; i++) playing[i] = 0;
add_timed_event(ES_BLINKER_TIMER, 288, 1);
add_timed_event(ES_KNOB_TIMER, 100, 1);
clear_all_grid_leds();
refresh_grid();
update_devices();
}
void process_event(u8 event, u8 *data, u8 length) {
u8 found;
u8 voice;
u8 index;
switch (event) {
case MAIN_CLOCK_RECEIVED:
event_main_clock(data[0], data[1]);
break;
case MAIN_CLOCK_SWITCHED:
external_clock_switched(data[0]);
break;
case GATE_RECEIVED:
if (data[0] == 7) event_main_clock(1, data[1]);
else if (data[1]) es_start_playback(e.p_select, 0);
break;
case GRID_CONNECTED:
es_view = es_main;
break;
case GRID_KEY_PRESSED:
handler_ESGridKey(data[0], data[1], data[2]);
break;
case GRID_KEY_HELD:
grid_key_held(data[0], data[1]);
break;
case ARC_ENCODER_COARSE:
update_mod_arc(data[0], data[1]);
break;
case FRONT_BUTTON_PRESSED:
event_front_button(data[0]);
break;
case FRONT_BUTTON_HELD:
save_to_preset(preset);
break;
case BUTTON_PRESSED:
if (data[1]) {
if (data[0] == 0)
es_prev_pattern();
else if (data[0] == 1)
es_next_pattern();
}
break;
case I2C_RECEIVED:
ii_es(data, length);
break;
case TIMED_EVENT:
process_timed_event(data[0]);
break;
case MIDI_CONNECTED:
break;
case MIDI_NOTE:
found = 0;
data[1] -= 24;
for (u8 x = 1; x < 16; x++) {
for (u8 y = 0; y < 7; y++) {
u16 note_index = x + (7 - y) * 5 - 1;
if (note_index == data[1]) {
found = 1;
if (data[0] == 0) {
if (es_mode == es_armed) es_start_recording(); // will change es_mode to es_recording
if (es_mode == es_recording) es_record_pattern_note(x, y, data[3]);
}
if (data[3]) {
index = data[0] ? data[0] : e.p_select;
voice = es_note_on(x, y, 255, 0, e.p[index].voices);
if (voice != 255) midi_notes[voice] = data[1];
} else {
voice = es_note_off(x, y);
if (voice != 255) midi_notes[voice] = 255;
}
break;
}
}
if (found) break;
}
break;
case MIDI_CC:
found = MOD_COUNT;
for (u8 i = 0; i < MOD_COUNT; i++) {
if (e.midi_cc[i] == data[1]) {
found = i;
break;
}
}
if (es_mode == es_armed && found == MOD_COUNT && midi_cc_ind < MOD_COUNT) {
e.midi_cc[midi_cc_ind] = data[1];
found = midi_cc_ind;
midi_cc_ind++;
}
if (found < MOD_COUNT) {
index = get_knob_count() + found;
if (index < MOD_COUNT) {
e.mod_value[index] = data[2] << 1;
update_dest(index);
}
}
break;
case MIDI_AFTERTOUCH:
/*
voice = 2;
for (u8 i = 0; i < VOICE_COUNT; i++) {
if (midi_notes[i] == data[1]) voice = i;
}
set_cv(voice, (MAX_LEVEL >> 7) * data[2]);
set_cv(0, MAX_LEVEL);
*/
break;
case SHNTH_BAR:
index = get_knob_count() + data[0];
if (index < MOD_COUNT) {
e.mod_value[index] = data[1];
update_dest(index);
// set_cv(index, (MAX_LEVEL >> 8) * data[1]);
}
break;
case SHNTH_ANTENNA:
index = get_knob_count() + data[0] + 4;
if (index < MOD_COUNT) {
e.mod_value[index] = data[1];
update_dest(index);
}
break;
case SHNTH_BUTTON:
index = data[0] >> 1;
if (data[0] & 1) { // play/stop
if (data[1]) {
if (playing[index]) {
print_int("STOPPING", index);
es_stop_playback(index);
} else {
print_int("STARTING", index);
es_start_playback(index, 0);
}
}
} else { // pause
if (playing[index]) {
print_int("PAUSING", index);
es_stop_playback(index);
} else {
print_int("UNPAUSING", index);
es_start_playback(index, es_pos[index]);
}
}
break;
default:
break;
}
}
void event_main_clock(u8 external, u8 phase) {
if (external & phase) external_clock_received();
}
void event_front_button(u8 pressed) {
if (!pressed) return;
if (is_midi_connected()) {
if (es_mode == es_playing)
es_stop_playback(e.p_select);
else if (es_mode == es_stopped) {
es_mode = es_armed;
midi_cc_ind = 0;
} else {
e.p[e.p_select].loop = 1;
es_start_playback(e.p_select, 0);
}
return;
}
preset_mode = !preset_mode;
refresh_grid();
}
void process_timed_event(u8 index) {
if (index == ES_BLINKER_TIMER)
es_blinker_callback();
else if (index == ES_KNOB_TIMER)
read_knobs();
else if (index == ES_PLAY_POS_TIMER)
es_play_pos_callback();
else if (index < VOICE_COUNT)
es_note_off_callback(index);
else if (index >= ES_PLAY_TIMER && index < ES_PSTART_TIMER)
es_play_callback(index - ES_PLAY_TIMER);
else
pattern_start(index - ES_PSTART_TIMER, 0);
}
// ----------------------------------------------------------------------------
// functions for engine.c
// ----------------------------------------------------------------------------
// main logic
static void es_note_off_i(u8 i) {
//if (!es_notes[i].active) return;
es_notes[i].active = 0;
es_notes[i].from_pattern = 255;
note_off(i);
update_mod_off(i);
}
static u8 es_note_off(s8 x, s8 y) {
u8 voice = 255;
for (u8 i = 0; i < VOICE_COUNT; i++)
if (es_notes[i].x == x && es_notes[i].y == y) {
es_note_off_i(i);
voice = i;
//break;
}
return voice;
}
void es_blinker_callback() {
es_blinker = !es_blinker;
refresh_grid();
}
static void es_note_off_callback(u8 note) {
es_note_off_i(note);
refresh_grid();
}
static void es_kill_all_notes(void) {
for (u8 i = 0; i < VOICE_COUNT; i++) es_note_off_i(i);
refresh_grid();
}
static void update_key_x_y(u8 voice, u8 x, u8 y, u8 key) {
u8 output;
for (u8 i = 0; i < VOICE_COUNT; i++) {
output = 1 << i;
if (e.cv_key_map[voice] & output) set_cv(i, MAX_LEVEL / 49 * key);
if (e.er301_key_map[voice] & output) set_er301_cv(i, MAX_LEVEL / 49 * key);
if (e.txo_key_map[voice] & output) set_txo_cv(i, MAX_LEVEL / 49 * key);
if (e.cv_x_map[voice] & output) set_cv(i, MAX_LEVEL / 15 * (x - 1));
if (e.er301_x_map[voice] & output) set_er301_cv(i, MAX_LEVEL / 15 * (x - 1));
if (e.txo_x_map[voice] & output) set_txo_cv(i, MAX_LEVEL / 15 * (x - 1));
if (e.cv_y_map[voice] & output) set_cv(i, MAX_LEVEL / 8 * (7 - y));
if (e.er301_key_map[voice] & output) set_er301_cv(i, MAX_LEVEL / 8 * (7 - y));
if (e.txo_y_map[voice] & output) set_txo_cv(i, MAX_LEVEL / 8 * (7 - y));
}
}
static u16 scale(u16 a, u16 b, u16 x, u16 y, u16 i) {
if ((b - a) == 0) return 0;
u32 result = (((i - a) * (y - x)) << 1) / (b - a);
return (result >> 1) + (result & 1) + x;
}
static int16_t push_random(int16_t a, int16_t b) {
int16_t min, max;
if (a < b) {
min = a;
max = b;
}
else {
min = b;
max = a;
}
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 update_dest(u8 mod) {
u8 v, mi, ma;
for (u8 i = 0; i < VOICE_COUNT; i++) {
v = 1 << i;
if (e.mod_octave[mod] & v) {
mi = min(e.octave_mm[i][VOICE_CV_GATE] & 15, e.octave_mm[i][VOICE_CV_GATE] >> 4);
ma = max(e.octave_mm[i][VOICE_CV_GATE] & 15, e.octave_mm[i][VOICE_CV_GATE] >> 4);
e.octave[i][VOICE_CV_GATE] = scale(0, 255, mi, ma, e.mod_value[mod]);
set_output_transpose(VOICE_CV_GATE, i, e.octave[i][VOICE_CV_GATE] * 12 + e.transpose[i][VOICE_CV_GATE]);
}
if (e.mod_er301_octave[mod] & v) {
mi = min(e.octave_mm[i][VOICE_ER301] & 15, e.octave_mm[i][VOICE_ER301] >> 4);
ma = max(e.octave_mm[i][VOICE_ER301] & 15, e.octave_mm[i][VOICE_ER301] >> 4);
e.octave[i][VOICE_ER301] = scale(0, 255, mi, ma, e.mod_value[mod]);
set_output_transpose(VOICE_ER301, i, e.octave[i][VOICE_ER301] * 12 + e.transpose[i][VOICE_ER301]);
}
if (e.mod_jf_octave[mod] & v) {
mi = min(e.octave_mm[i][VOICE_JF] & 15, e.octave_mm[i][VOICE_JF] >> 4);
ma = max(e.octave_mm[i][VOICE_JF] & 15, e.octave_mm[i][VOICE_JF] >> 4);
e.octave[i][VOICE_JF] = scale(0, 255, mi, ma, e.mod_value[mod]);
set_output_transpose(VOICE_JF, i, e.octave[i][VOICE_JF] * 12 + e.transpose[i][VOICE_JF]);
}
if (e.mod_txo_octave[mod] & v) {
mi = min(e.octave_mm[i][VOICE_TXO_NOTE] & 15, e.octave_mm[i][VOICE_TXO_NOTE] >> 4);
ma = max(e.octave_mm[i][VOICE_TXO_NOTE] & 15, e.octave_mm[i][VOICE_TXO_NOTE] >> 4);
e.octave[i][VOICE_TXO_NOTE] = scale(0, 255, mi, ma, e.mod_value[mod]);
mi = min(e.octave_mm[i][VOICE_TXO_CV_GATE] & 15, e.octave_mm[i][VOICE_TXO_CV_GATE] >> 4);
ma = max(e.octave_mm[i][VOICE_TXO_CV_GATE] & 15, e.octave_mm[i][VOICE_TXO_CV_GATE] >> 4);
set_output_transpose(VOICE_TXO_NOTE, i, e.octave[i][VOICE_TXO_NOTE] * 12 + e.transpose[i][VOICE_TXO_NOTE]);
set_output_transpose(VOICE_TXO_CV_GATE, i, e.octave[i][VOICE_TXO_CV_GATE] * 12 + e.transpose[i][VOICE_TXO_CV_GATE]);
}
if (e.mod_er301_volume[mod] & v) {
mi = min(e.er301_volume_mm[i] & 15, e.er301_volume_mm[i] >> 4);
ma = max(e.er301_volume_mm[i] & 15, e.er301_volume_mm[i] >> 4);
e.er301_volume[i] = scale(0, 255, mi, ma, e.mod_value[mod]);
set_output_max_volume(VOICE_ER301, i, (u16)e.er301_volume[i] * (MAX_LEVEL / 11));
}
if (e.mod_jf_volume[mod] & v) {
mi = min(e.jf_volume_mm[i] & 15, e.jf_volume_mm[i] >> 4);
ma = max(e.jf_volume_mm[i] & 15, e.jf_volume_mm[i] >> 4);
e.jf_volume[i] = scale(0, 255, mi, ma, e.mod_value[mod]);
set_output_max_volume(VOICE_JF, i, (u16)e.jf_volume[i] * (MAX_LEVEL / 11));
}
if (e.mod_txo_volume[mod] & v) {
mi = min(e.txo_volume_mm[i] & 15, e.txo_volume_mm[i] >> 4);
ma = max(e.txo_volume_mm[i] & 15, e.txo_volume_mm[i] >> 4);
e.txo_volume[i] = scale(0, 255, mi, ma, e.mod_value[mod]);
set_output_max_volume(VOICE_TXO_NOTE, i, (u16)e.txo_volume[i] * (MAX_LEVEL / 11));
}
if (e.mod_txo_attack[mod] & v) {
mi = min(e.txo_attack_mm[i] & 15, e.txo_attack_mm[i] >> 4);
ma = max(e.txo_attack_mm[i] & 15, e.txo_attack_mm[i] >> 4);
e.txo_attack[i] = scale(0, 255, mi, ma, e.mod_value[mod]);
set_txo_attack(i, e.txo_attack[i] * 50);
}
if (e.mod_txo_decay[mod] & v) {
mi = min(e.txo_decay_mm[i] & 15, e.txo_decay_mm[i] >> 4);
ma = max(e.txo_decay_mm[i] & 15, e.txo_decay_mm[i] >> 4);
e.txo_decay[i] = scale(0, 255, mi, ma, e.mod_value[mod]);
set_txo_decay(i, e.txo_decay[i] * 50);
}
if (e.mod_txo_wave[mod] & v) {
mi = min(e.txo_wave_mm[i] & 15, e.txo_wave_mm[i] >> 4);
ma = max(e.txo_wave_mm[i] & 15, e.txo_wave_mm[i] >> 4);
e.txo_wave[i] = scale(0, 255, mi, ma, e.mod_value[mod]);
set_txo_waveform(i, e.txo_wave[i] * 409 + e.txo_wavef[i] * TXOWAVF); // 0..4500*/
}
if (e.mod_txo_wavef[mod] & v) {
mi = min(e.txo_wavef_mm[i] & 15, e.txo_wavef_mm[i] >> 4);
ma = max(e.txo_wavef_mm[i] & 15, e.txo_wavef_mm[i] >> 4);
e.txo_wavef[i] = scale(0, 255, mi, ma, e.mod_value[mod]);
set_txo_waveform(i, e.txo_wave[i] * 409 + e.txo_wavef[i] * TXOWAVF); // 0..4500*/
}
}
refresh_grid();
}
void update_mod(u8 voice, u8 x, u8 y, u8 index) {
u8 v = 1 << voice;
for (u8 i = 0; i < MOD_COUNT; i++) {
if (e.mod_x[i] & v) {
e.mod_value[i] = scale(1, 15, 0, 255, x);
update_dest(i);
}
if (e.mod_y[i] & v) {
e.mod_value[i] = scale(0, 7, 0, 255, 7 - y);
update_dest(i);
}
if (e.mod_key[i] & v) {
e.mod_value[i] = scale(0, 49, 0, 255, index);
update_dest(i);
}
if (e.mod_gate[i] & v) {
e.mod_value[i] = push_random(0, 255);
update_dest(i);
}
}
// set_txo_cv(3, scale(0, 255, 0, MAX_LEVEL, e.mod_value[0]));
}
void update_mod_off(u8 voice) {
// u8 mod_value[MOD_COUNT];
}
void update_mod_arc(u8 index, s8 delta) {
u8 enc = index + get_knob_count();
if (enc >= MOD_COUNT) return;
s16 new_val = e.mod_value[enc];
if (delta)
new_val += 4;
else
new_val -= 4;
if (new_val < 0) new_val = 0;
else if (new_val > 255) new_val = 255;
e.mod_value[enc] = new_val;
update_dest(enc);
refresh_arc();
}
static void read_knobs(void) {
// if (is_arc_connected() || is_midi_connected()) return;
u8 value;
u8 changed = 0;
for (u8 i = 0; i < min(MOD_COUNT, get_knob_count()); i++) {
value = get_knob_value(i) >> 8;
if (value != e.mod_value[i]) {
e.mod_value[i] = value;
update_dest(i);
changed = 1;
}
}
if (changed) refresh_grid();
}
void pattern_start(u8 pattern, u8 on) {
if (on) add_timed_event(ES_PSTART_TIMER + pattern, 15, 0);
if (pattern == e.p_select || !on) set_led(0, on > 0);
u8 map;
for (u8 i = 0; i < VOICE_COUNT; i++) {
map = 1 << i;
if (e.pstart_map[pattern][VOICE_CV_GATE] & map) set_gate(i, on);
if (e.pstart_map[pattern][VOICE_ER301] & map) set_er301_gate(i, on);
if (e.pstart_map[pattern][VOICE_JF] & map) set_jf_gate(i, on);
if (e.pstart_map[pattern][VOICE_TXO_CV_GATE] & map) set_txo_gate(i, on);
}
if (!on) return;
map = 1 << pattern;
for (u8 i = 0; i < MOD_COUNT; i++) {
if (e.mod_pstart[i] & map) {
e.mod_value[i] = push_random(0, 255);
update_dest(i);
}
}
}
static u8 es_note_on(s8 x, s8 y, u8 from_pattern, u16 timer, u8 voices) {
u8 voice = 255;
for (u8 i = 0; i < VOICE_COUNT; i++)
if ((voices & (1 << i)) && (!es_notes[i].active || (es_notes[i].x == x && es_notes[i].y == y))) {
voice = i;
break;
}
if (voice == 255) {
u32 earliest = 0xffffffff;
for (u8 i = 0; i < VOICE_COUNT; i++)
if ((voices & (1 << i)) && es_notes[i].start < earliest) {
earliest = es_notes[i].start;
voice = i;
}
}
if (voice == 255) return 255;
if (!shared.voice_on[voice]) return 255;
es_note_off_i(voice);
es_notes[voice].active = 1;
es_notes[voice].x = x;
es_notes[voice].y = y;
es_notes[voice].start = get_global_time();
es_notes[voice].from_pattern = from_pattern;
s16 note_index = x + (7 - y) * 5 - 1;
if (note_index < 0)
note_index = 0;
else if (note_index > 119)
note_index = 119;
update_key_x_y(voice, x, y, note_index);
update_mod(voice, x, y, note_index);
note_on(voice, note_index, 16383);
if (timer) add_timed_event(voice, timer, 0);
return voice;
}
/*
static void es_update_pitches(void) {
u8 first_note_x = e.p[e.p_select].e[0].index & 15;
u8 first_note_y = e.p[e.p_select].e[0].index >> 4;
s16 x, y, note_index;
for (u8 i = 0; i < VOICE_COUNT; i++) {
es_notes[i].x = x = es_notes[i].x + e.p[e.p_select].root_x - first_note_x;
es_notes[i].y = y = es_notes[i].y + e.p[e.p_select].root_y - first_note_y;
note_index = x + (7 - y) * 5 - 1;
if (note_index < 0)
note_index = 0;
else if (note_index > 119)
note_index = 119;
update_note_output(i, note_index);
}
}
*/
static void es_complete_recording(void) {
if (!e.p[e.p_select].length) return;
e.p[e.p_select].e[e.p[e.p_select].length - 1].interval = get_global_time() - es_tick;
if (e.p[e.p_select].dir) {
for (s16 i = e.p[e.p_select].length - 1; i >= 0; i--) {
if (e.p[e.p_select].e[i].interval > ES_CHORD_THRESHOLD) {
e.p[e.p_select].interval_ind = i;
break;
}
}
} else {
for (u16 i = 0; i < e.p[e.p_select].length; i++) {
if (e.p[e.p_select].e[i].interval > ES_CHORD_THRESHOLD) {
e.p[e.p_select].interval_ind = i;
break;
}
}
}
playing[e.p_select] = 0;
es_mode = es_stopped;
es_kill_pattern_notes(e.p_select);
refresh_grid();
}
static void es_record_pattern_note(u8 x, u8 y, u8 on) {
u16 l = e.p[e.p_select].length;
if (l >= ES_EVENTS_PER_PATTERN) {
es_complete_recording(); // will update interval for the last event
return;
}
if (!l) {
e.p[e.p_select].root_x = x;
e.p[e.p_select].root_y = y;
}
if (l) e.p[e.p_select].e[l - 1].interval = get_global_time() - es_tick;
es_tick = get_global_time();
e.p[e.p_select].e[l].index = x + (y << 4);
if (x == 15 && y == 0) // rest
e.p[e.p_select].e[l].on = on ? 3 : 2;
else
e.p[e.p_select].e[l].on = on ? 1 : 0;
e.p[e.p_select].length++;
}
static void es_play_pattern_note(u8 pattern, u8 ext_clock) {
u16 i = e.p[pattern].dir ? e.p[pattern].length - 1 : 0;
u8 first_note_x = e.p[pattern].e[i].index & 15;
u8 first_note_y = e.p[pattern].e[i].index >> 4;
s16 x = (e.p[pattern].e[es_pos[pattern]].index & 15) + e.p[pattern].root_x - first_note_x;
s16 y = (e.p[pattern].e[es_pos[pattern]].index >> 4) + e.p[pattern].root_y - first_note_y;
if (e.p[pattern].e[es_pos[pattern]].on == 1)
es_note_on(x, y, pattern,
e.p[pattern].edge == ES_EDGE_FIXED || ext_clock ? e.p[pattern].edge_time : 0,
e.p[pattern].voices);
else if (e.p[pattern].e[es_pos[pattern]].on == 0 && e.p[pattern].edge == ES_EDGE_PATTERN)
es_note_off(x, y);
if (!ext_clock && e.is_leader_clock && pattern == e.p_leader) {
clock_next_note(1);
}
refresh_grid();
}
void es_kill_pattern_notes(u8 pattern) {
for (u8 i = 0; i < VOICE_COUNT; i++)
if (es_notes[i].from_pattern == pattern) es_note_off_i(i);
refresh_grid();
}
static void es_kill_all_pattern_notes(void) {
for (u8 i = 0; i < 16; i++) es_kill_pattern_notes(i);
}
static void es_update_total_time(void) {
u16 interval;
es_p_total = 0;
for (u16 i = 0; i < e.p[e.p_select].length; i++) {
interval = e.p[e.p_select].e[i].interval;
if (e.p[e.p_select].linearize) {
if (interval < ES_CHORD_THRESHOLD)
interval = 1;
else
interval = e.p[e.p_select].e[e.p[e.p_select].interval_ind].interval;
}
es_p_total += interval;
}
}
static void es_play_pos_callback() {
if (es_mode == es_playing) refresh_grid();
}
static u8 es_next_note(u8 pattern) {
if (++es_pos[pattern] >= e.p[pattern].length) {
es_pos[pattern] = 0;
if (pattern == e.p_select) {
es_p_start = get_global_time();
}
if (!e.p[pattern].loop) {
es_stop_playback(pattern);
return 1;
}
pattern_start(pattern, 1);
if (pattern == e.p_leader && e.leader_reset) es_reset_all_playing();
}
return 0;
}
static void es_play_callback(u8 pattern) {
if (is_external_clock_connected() || (e.is_leader_clock && (pattern != e.p_leader))) return;
if (es_next_note(pattern)) return;
u16 interval = e.p[pattern].e[es_pos[pattern]].interval;
if (e.p[pattern].linearize) {
if (interval < ES_CHORD_THRESHOLD)
interval = 1;
else
interval = e.p[pattern].e[e.p[pattern].interval_ind].interval;
}
if (!interval) interval = 1;
add_timed_event(ES_PLAY_TIMER + pattern, interval, 0);
es_play_pattern_note(pattern, 0);
}
void es_stop_playback(u8 pattern) {
if (pattern == e.p_select) {
stop_timed_event(ES_PLAY_POS_TIMER);
es_mode = es_stopped;
}
playing[pattern] = 0;
stop_timed_event(ES_PLAY_TIMER + pattern);
es_kill_pattern_notes(pattern);
}
void es_start_playback(u8 pattern, u8 pos) {
if (!wtf_update_devices) {
wtf_update_devices = 1;
update_devices();
}
if (pattern == e.p_select) {
if (es_mode == es_playing) {
es_stop_playback(pattern);
} else if (es_mode == es_recording) {
es_complete_recording();
}
} else if (playing[pattern]) {
es_stop_playback(pattern);
}
if (!e.p[pattern].length) {
es_stop_playback(pattern);
refresh_grid();
return;
}
if (pattern == e.p_select) es_mode = es_playing;
playing[pattern] = 1;
u32 interval;
if (pos) {
u32 start = (es_p_total * pos) >> 4;
u32 tick = 0;
for (es_pos[pattern] = 0; es_pos[pattern] < e.p[pattern].length; es_pos[pattern]++) {
interval = e.p[pattern].e[es_pos[pattern]].interval;
if (e.p[pattern].linearize) {
if (interval < ES_CHORD_THRESHOLD)
interval = 1;
else
interval = e.p[pattern].e[e.p[pattern].interval_ind].interval;
}
if (tick + interval > start) break;
tick += interval;
}
if (es_pos[pattern] >= e.p[pattern].length) {
es_pos[pattern] = e.p[pattern].length - 1;
interval = 1;
} else {
interval = tick + interval - start;
if (!interval) interval = 1;
}
if (is_external_clock_connected() || (e.is_leader_clock && (pattern != e.p_leader))) return;
if (pattern == e.p_select) {
es_p_start = get_global_time() - start;
add_timed_event(ES_PLAY_POS_TIMER, 25, 1);
}
add_timed_event(ES_PLAY_TIMER + pattern, interval, 0);
return;
}
es_pos[pattern] = 0;
if (pattern == e.p_leader && e.leader_reset) es_reset_all_playing();
if (pattern == e.p_select) {
es_p_start = get_global_time();
es_update_total_time();
}
if (is_external_clock_connected() || (e.is_leader_clock && (pattern != e.p_leader))) return;
interval = e.p[pattern].e[0].interval;
if (e.p[pattern].linearize) {
if (interval < ES_CHORD_THRESHOLD)
interval = 1;
else
interval = e.p[pattern].e[e.p[pattern].interval_ind].interval;
}
if (!interval) interval = 1;
if (pattern == e.p_select)add_timed_event(ES_PLAY_POS_TIMER, 25, 1);
add_timed_event(ES_PLAY_TIMER + pattern, interval, 0);
pattern_start(pattern, 1);
es_play_pattern_note(pattern, 0);
}
void es_reset_all_playing() {
for (u8 i = 0; i < PATTERN_COUNT; i++)
if (playing[i] && i != e.p_leader) es_start_playback(i, 0);
}
static void es_start_recording(void) {
e.p[e.p_select].length = 0;
e.p[e.p_select].start = 0;
e.p[e.p_select].end = 15;
e.p[e.p_select].dir = 0;
playing[e.p_select] = 0;
es_mode = es_recording;
refresh_grid();
}
static u8 is_arm_pressed(void) {
u8 found = 0;
for (u8 i = 0; i < key_count; i++) {
if (held_keys[i] == 32) found = 1;
break;
}
return found;
}
/*
static s8 top_row_pressed(void) {
s8 found = -1;
for (u8 i = 0; i < key_count; i++) {
if (held_keys[i] < 16) {
found = held_keys[i];
break;
}
}
return found;
}
*/
static u8 rest_pressed(void) {
for (u8 i = 0; i < key_count; i++) {
if (held_keys[i] == 15) return 1;
}
return 0;
}
static void es_prev_pattern(void) {
if (!e.p_select) return;
e.p_select--;
es_start_playback(e.p_select, 0);
}
static void es_next_pattern(void) {
if (e.p_select >= 15) return;
e.p_select++;
es_start_playback(e.p_select, 0);
}
static void es_double_speed(void) {
for (u16 i = 0; i < e.p[e.p_select].length; i++) {
if (e.p[e.p_select].e[i].interval > (ES_CHORD_THRESHOLD << 1))
e.p[e.p_select].e[i].interval >>= 1;
else if (e.p[e.p_select].e[i].interval > ES_CHORD_THRESHOLD)
e.p[e.p_select].e[i].interval = ES_CHORD_THRESHOLD + 1;
}
es_update_total_time();
}
static void es_faster_speed(void) {
u16 interval;
for (u16 i = 0; i < e.p[e.p_select].length; i++) {
if (e.p[e.p_select].e[i].interval < ES_CHORD_THRESHOLD) continue;
interval = e.p[e.p_select].e[i].interval - (e.p[e.p_select].e[i].interval / 10);
if (interval > ES_CHORD_THRESHOLD)
e.p[e.p_select].e[i].interval = interval;
else
e.p[e.p_select].e[i].interval = ES_CHORD_THRESHOLD + 1;
}
es_update_total_time();
}
static void es_half_speed(void) {
u16 interval;
for (u16 i = 0; i < e.p[e.p_select].length; i++)
if (e.p[e.p_select].e[i].interval > ES_CHORD_THRESHOLD) {
interval = e.p[e.p_select].e[i].interval << 1;
if (interval > e.p[e.p_select].e[i].interval) e.p[e.p_select].e[i].interval = interval;
}
es_update_total_time();
}
static void es_slower_speed(void) {
u16 interval;
for (u16 i = 0; i < e.p[e.p_select].length; i++)
if (e.p[e.p_select].e[i].interval > ES_CHORD_THRESHOLD) {
interval = e.p[e.p_select].e[i].interval + (e.p[e.p_select].e[i].interval / 10);
if (interval > e.p[e.p_select].e[i].interval) e.p[e.p_select].e[i].interval = interval;
}
es_update_total_time();
}
static void es_reverse(void) {
u16 l = e.p[e.p_select].length;
if (!l) return;
es_event_t te[ES_EVENTS_PER_PATTERN];
for (u16 i = 0; i < l; i++) {
te[i] = e.p[e.p_select].e[i];
if (te[i].on == 3)
te[i].on = 2;
else if (te[i].on == 2)
te[i].on = 3;
else if (te[i].on == 1)
te[i].on = 0;
else if (te[i].on == 0)
te[i].on = 1;
}
for (u16 i = 0; i < l; i++)
e.p[e.p_select].e[i] = te[l - i - 1];
for (u16 i = 0; i < l - 1; i++)
e.p[e.p_select].e[i].interval = te[l - i - 2].interval;
e.p[e.p_select].e[l - 1].interval = te[l - 1].interval;
if (e.p[e.p_select].dir) {
for (s16 i = e.p[e.p_select].length - 1; i >= 0; i--)
if ((e.p[e.p_select].e[i].on == 3 || e.p[e.p_select].e[i].on == 1)
&& e.p[e.p_select].e[i].interval > ES_CHORD_THRESHOLD) {
e.p[e.p_select].interval_ind = i;
break;
}
} else {
for (u16 i = 0; i < e.p[e.p_select].length; i++)
if ((e.p[e.p_select].e[i].on == 3 || e.p[e.p_select].e[i].on == 1)
&& e.p[e.p_select].e[i].interval > ES_CHORD_THRESHOLD) {
e.p[e.p_select].interval_ind = i;
break;
}
}
}
/////////////////////////
void clock_next_note(u8 is_leader) {
for (u8 pattern = 0; pattern < 16; pattern++) {
if (is_leader && pattern == e.p_leader) continue;
if (!playing[pattern] || !e.p[pattern].length) continue;
u16 pos = es_pos[pattern];
u8 played = 0;
while (true) {
//if (es_pos[pattern] == 0) pattern_start(pattern, 1);
if (e.p[pattern].e[es_pos[pattern]].on) {
es_play_pattern_note(pattern, 1);
played = 1;
}
if (es_next_note(pattern)) return;
if (played && e.p[pattern].e[es_pos[pattern]].interval > ES_CHORD_THRESHOLD) break;
if (es_pos[pattern] == pos) break;
}
}
}
void external_clock_received() {
clock_next_note(0);
}
void external_clock_switched(u8 external) {
es_kill_all_pattern_notes();
if (external) {
for (u8 i = 0; i < 16; i++) stop_timed_event(ES_PLAY_TIMER + i);
stop_timed_event(ES_PLAY_POS_TIMER);
} else {
add_timed_event(ES_PLAY_POS_TIMER, 25, 1);
for (u8 i = 0; i < 16; i++) if (playing[i]) es_play_callback(i);
}
}
void grid_key_held(u8 x, u8 y) {
if (preset_mode) save_to_preset(y);
}
void save_to_preset(u8 p) {
preset = p;
store_preset_index(preset);
store_preset_to_flash(preset, &meta, &e);
store_shared_data_to_flash(&shared);
preset_mode = 0;
refresh_grid();
}
void handler_ESGridKey(u8 x, u8 y, u8 z) {
u8 index = (y << 4) + x;
// track held keys and long presses
if (z) {
held_keys[key_count] = index;
if (key_count < MAX_HELD_KEYS) key_count++;
key_times[index] = 10;
} else {
u8 found = 0;
for (u8 i = 0; i < key_count; i++) {
if (held_keys[i] == index) found++;
if (found) held_keys[i] = held_keys[i + 1];
}
if (found) key_count--;
}
// preset screen
if (preset_mode) {
if (!z && x == 0) {
if (y != selected_preset) {
selected_preset = y;
load_preset_meta_from_flash(selected_preset, &meta);
} else {
// flash read
preset = selected_preset;
load_preset();
preset_mode = 0;
es_view = es_main;
}
} else if (z && x > 7) {
meta.glyph[y] ^= 1 << (x - 8);
}
refresh_grid();
return;
}
if (x == 0) {
if (es_edge && y == 7 && z) {
e.p[e.p_select].edge = ES_EDGE_FIXED;
e.p[e.p_select].edge_time = 16;
es_kill_all_notes();
} else if (z && y == 0) { // start/stop
if (es_view == es_patterns_held) {
es_view = es_patterns;
} else if (es_mode == es_stopped || es_mode == es_armed) {
es_start_playback(e.p_select, 0);
if (is_arm_pressed()) es_ignore_arm_release = 1;
} else if (es_mode == es_recording) {
e.p[e.p_select].loop = 1;
es_start_playback(e.p_select, 0);
} else if (es_mode == es_playing) {
if (is_arm_pressed()) {
es_start_playback(e.p_select, 0);
es_ignore_arm_release = 1;
} else
es_stop_playback(e.p_select);
}
} else if (y == 1) { // p_select
if (z && es_mode == es_recording) {
es_complete_recording();
es_mode = es_stopped;
}
if (z && es_view == es_patterns)
es_view = es_main;
else if (!z && es_view == es_patterns_held)
es_view = es_main;
else if (z)
es_view = es_patterns_held;
} else if (y == 2) { // arm
es_view = es_main;
if (z) {
if (es_mode == es_armed) {
es_mode = es_stopped;
es_ignore_arm_release = 1;
} else if (es_mode == es_recording) {
es_complete_recording();
es_mode = es_stopped;
es_ignore_arm_release = 1;
}
} else {
if (es_ignore_arm_release) {
es_ignore_arm_release = 0;
return;
}
if (es_mode == es_stopped) {
es_mode = es_armed;
} else if (es_mode == es_playing) {
es_stop_playback(e.p_select);
es_mode = es_armed;
}
}
} else if (z && y == 3) { // loop
e.p[e.p_select].loop = !e.p[e.p_select].loop;
} else if (z && y == 4) { // arp
e.arp = !e.arp;
} else if (y == 5) { // edge mode
es_edge = z;
} else if (y == 6) { // runes
if (es_view == es_voices_held) {
if (!z) return;
es_view = es_devices_held;
es_devices_changed = 0;
} else if (es_view == es_devices_held) {
if (z) return;
if (es_devices_changed)
es_view = es_main;
else
es_view = es_devices;
} else if (es_view == es_voices && z) {
es_view = es_devices_held;
es_devices_changed = 0;
} else es_runes = z;
} else if (y == 7) { // voices/devices
if (es_view == es_devices) {
if (z) es_view = es_main;
} else if (z && (es_view == es_main || es_view == es_patterns)) {
es_view = es_voices_held;
es_voices_changed = 0;
} else if (!z && es_view == es_voices) {
es_view = es_main;
} else if (!z && es_view == es_voices_held) {
if (es_voices_changed)
es_view = es_main;
else
es_view = es_voices;
}
}
refresh_grid();
return;
}
if (es_runes) {
if (!z) return;
if (x > 1 && x < 5 && y > 2 && y < 6) {
e.p[e.p_select].linearize = !e.p[e.p_select].linearize;
es_update_total_time();
} else if (x > 5 && x < 8 && y > 2 && y < 6) {
if (e.p[e.p_select].dir != 1) es_reverse();
e.p[e.p_select].dir = 1;
if (es_mode == es_playing) es_kill_pattern_notes(e.p_select);
} else if (x > 8 && x < 11 && y > 2 && y < 6) {
if (e.p[e.p_select].dir != 0) es_reverse();
e.p[e.p_select].dir = 0;
if (es_mode == es_playing) es_kill_pattern_notes(e.p_select);
} else if ((y == 1 && x == 13) || (x == 12 && y == 2) || (x == 14 && y == 2))
es_double_speed();
else if ((y == 2 && x == 13) || (x == 12 && y == 3) || (x == 14 && y == 3))
es_faster_speed();
else if ((y == 6 && x == 13) || (x == 12 && y == 5) || (x == 14 && y == 5))
es_slower_speed();
else if ((y == 7 && x == 13) || (x == 12 && y == 6) || (x == 14 && y == 6))
es_half_speed();
refresh_grid();
return;
}
if (es_edge) {
if (!z) return;
if (y == 7) {
e.p[e.p_select].edge = ES_EDGE_FIXED;
e.p[e.p_select].edge_time = (x + 1) << 4;
es_kill_all_notes();
} else {
if (x) {
if (x < 6) {
e.p[e.p_select].edge = ES_EDGE_PATTERN;
es_kill_all_notes();
} else if (x < 11) {
e.p[e.p_select].edge = ES_EDGE_FIXED;
es_kill_all_notes();
} else {
e.p[e.p_select].edge = ES_EDGE_DRONE;
}
}
}
refresh_grid();
return;
}
if (es_view == es_voices || es_view == es_voices_held) {
es_voices_changed = 1;
u8 voice = 1 << y;
u8 sel_voice = 1 << selected_voice;
if (y == 7 && x == 1) {
help_on = z;
help_sel = 0;
refresh_grid();
return;
}
if (y == 7 && x == 15) {
help_on = z << 1;
if (!help_sel) help_sel = 8;
refresh_grid();
return;
}
if (x == 2 && z) {
e.p[e.p_select].voices ^= voice;
es_kill_all_notes();
refresh_grid();
return;
}
if (x == 3 && z) {
shared.voice_on[y] = !shared.voice_on[y];
if (!shared.voice_on[y]) es_note_off_i(y);
refresh_grid();
return;
}
if (help_on == 2) {
if (x > 7 && z) {
help_sel = x;
refresh_grid();
}
return;
}
if (z && x == 5) { // select mapping
if (y < 4)
sel_mapping = y;
else if (y > 5)
sel_mapping = y - 2;
refresh_grid();
return;
}
if (help_on == 1 && x > 7) return;
if (x == 15 && !help_on) {
if (!z) return;
if (y < DEVICE_COUNT) {
shared.device_on[y] = !shared.device_on[y];
update_i2c();
} else if (y == 5) {
shared.i2c_mode = !shared.i2c_mode;
update_i2c();
}
refresh_grid();
return;
}
if (!z || y >= VOICE_COUNT) return;
if (x == 6) { // select voice or pattern
if (sel_mapping < 4)
selected_voice = min(y, VOICE_COUNT - 1);
else if (sel_mapping == 4)
sel_pattern_start = y;
else if (sel_mapping == 5)
sel_pattern_start = y + 8;
refresh_grid();
return;
}
if (x == 10 && y == 7) {
e.jf_mode = !e.jf_mode;
es_kill_all_notes();
update_i2c();
// set_debug(e.jf_mode);
refresh_grid();
return;
}
if (y >= VOICE_COUNT) {
refresh_grid();
return;
}
u8 txo_gate;
if (sel_mapping == 0) { // note
if (x == 8) {
e.voice_map[selected_voice][VOICE_CV_GATE] ^= voice;
remap_voices();
if (!(e.voice_map[selected_voice][VOICE_CV_GATE] & voice)) set_gate(y, 0);
} else if (x == 9) {
e.voice_map[selected_voice][VOICE_ER301] ^= voice;
remap_voices();
if (!(e.voice_map[selected_voice][VOICE_ER301] & voice)) set_er301_gate(y, 0);
} else if (x == 10 && y < 6) {
e.voice_map[selected_voice][VOICE_JF] ^= voice;
remap_voices();
if (!(e.voice_map[selected_voice][VOICE_JF] & voice)) set_jf_gate(y, 0);
} else if (x == 11) {
if ((e.voice_map[selected_voice][VOICE_TXO_NOTE] & voice)) {
e.voice_map[selected_voice][VOICE_TXO_NOTE] &= ~voice;
remap_voices();
set_txo_gate(y, 0);
} else {
e.voice_map[selected_voice][VOICE_TXO_NOTE] |= voice;
txo_gate = e.voice_map[selected_voice][VOICE_TXO_CV_GATE] & voice;
e.voice_map[selected_voice][VOICE_TXO_CV_GATE] &= ~voice;
remap_voices();
if (txo_gate) set_txo_gate(y, 0);
}
} else if (x == 12) {
if ((e.voice_map[selected_voice][VOICE_TXO_CV_GATE] & voice)) {
e.voice_map[selected_voice][VOICE_TXO_CV_GATE] &= ~voice;
remap_voices();
set_txo_gate(y, 0);
} else {
e.voice_map[selected_voice][VOICE_TXO_CV_GATE] |= voice;
txo_gate = e.voice_map[selected_voice][VOICE_TXO_NOTE] & voice;
e.voice_map[selected_voice][VOICE_TXO_NOTE] &= ~voice;
remap_voices();
if (txo_gate) set_txo_gate(y, 0);
}
} else if (x == 13) {
if (e.mod_gate[y] & sel_voice) {
e.mod_gate[y] &= ~sel_voice;
} else {
e.mod_gate[y] |= sel_voice;
}
}
} else if (sel_mapping == 1) { // key
if (x == 8) {
if (e.cv_key_map[selected_voice] & voice)
e.cv_key_map[selected_voice] &= ~voice;
else
e.cv_key_map[selected_voice] |= voice;
} else if (x == 9) {
if (e.txo_key_map[selected_voice] & voice)
e.txo_key_map[selected_voice] &= ~voice;
else
e.txo_key_map[selected_voice] |= voice;
} else if (x == 12) {
if (e.txo_key_map[selected_voice] & voice)
e.txo_key_map[selected_voice] &= ~voice;
else
e.txo_key_map[selected_voice] |= voice;
} else if (x == 13) {
if (e.mod_key[y] & sel_voice) {
e.mod_key[y] &= ~sel_voice;
} else {
e.mod_key[y] |= sel_voice;
}
}
} else if (sel_mapping == 2) { // x
if (x == 8) {
if (e.cv_x_map[selected_voice] & voice)
e.cv_x_map[selected_voice] &= ~voice;
else
e.cv_x_map[selected_voice] |= voice;
} else if (x == 9) {
if (e.er301_x_map[selected_voice] & voice)
e.er301_x_map[selected_voice] &= ~voice;
else
e.er301_x_map[selected_voice] |= voice;
} else if (x == 12) {
if (e.txo_x_map[selected_voice] & voice)
e.txo_x_map[selected_voice] &= ~voice;
else
e.txo_x_map[selected_voice] |= voice;
} else if (x == 13) {
if (e.mod_x[y] & sel_voice) {
e.mod_x[y] &= ~sel_voice;
} else {
e.mod_x[y] |= sel_voice;
}
}
} else if (sel_mapping == 3) { // y
if (x == 8) {
if (e.cv_y_map[selected_voice] & voice)
e.cv_y_map[selected_voice] &= ~voice;
else
e.cv_y_map[selected_voice] |= voice;
} else if (x == 9) {
if (e.er301_y_map[selected_voice] & voice)
e.er301_y_map[selected_voice] &= ~voice;
else
e.er301_y_map[selected_voice] |= voice;
} else if (x == 12) {
if (e.txo_y_map[selected_voice] & voice)
e.txo_y_map[selected_voice] &= ~voice;
else
e.txo_y_map[selected_voice] |= voice;
} else if (x == 13) {
if (e.mod_y[y] & sel_voice) {
e.mod_y[y] &= ~sel_voice;
} else {
e.mod_y[y] |= sel_voice;
}
}
} else if (sel_mapping == 4 || sel_mapping == 5) { // pstart
if (x == 8) {
if (e.pstart_map[sel_pattern_start][VOICE_CV_GATE] & voice)
e.pstart_map[sel_pattern_start][VOICE_CV_GATE] &= ~voice;
else
e.pstart_map[sel_pattern_start][VOICE_CV_GATE] |= voice;
} else if (x == 9) {
if (e.pstart_map[sel_pattern_start][VOICE_ER301] & voice)
e.pstart_map[sel_pattern_start][VOICE_ER301] &= ~voice;
else
e.pstart_map[sel_pattern_start][VOICE_ER301] |= voice;
} else if (x == 10) {
if (e.pstart_map[sel_pattern_start][VOICE_JF] & voice)
e.pstart_map[sel_pattern_start][VOICE_JF] &= ~voice;
else
e.pstart_map[sel_pattern_start][VOICE_JF] |= voice;
} else if (x == 12) {
if (e.pstart_map[sel_pattern_start][VOICE_TXO_CV_GATE] & voice)
e.pstart_map[sel_pattern_start][VOICE_TXO_CV_GATE] &= ~voice;
else
e.pstart_map[sel_pattern_start][VOICE_TXO_CV_GATE] |= voice;
} else if (x == 13) {
u16 ps = 1 << sel_pattern_start;
if (e.mod_pstart[y] & ps) {
e.mod_pstart[y] &= ~ps;
} else {
e.mod_pstart[y] |= ps;
}
}
}
refresh_grid();
return;
}
if (es_view == es_devices || es_view == es_devices_held) {
if (y == 7 && x == 1) {
help_on = z;
refresh_grid();
return;
}
if (!z) {
if (x == 3) sel_mod = 255;
if (prev_param_x == x && prev_param_y == y) {
prev_param_x = 0;
prev_param_y = 0;
}
return;
}
es_devices_changed = 1;
if (x == 1 && y < 4) {
sel_device = y;
if (sel_device == 0 && sel_param > 1) sel_param = 0;
else if (sel_device && sel_device < 3 && sel_param > 2) sel_param = 0;
} else if (x == 2) {
if (sel_device == 0 && y < 2) sel_param = y;
else if (sel_device && sel_device < 3 && y < 3) sel_param = y;
else if (sel_device == 3 && y < 7) sel_param = y;
} else if (x == 3 && !help_on) {
sel_mod = y;
} else if (x > 3 && !help_on) {
if (prev_param_x > 3 &&
((prev_param_x != x && prev_param_y == y) || (prev_param_x == x && prev_param_y != y))) {
// held
u8 range;
if (prev_param_y != y) {
range = ((x - 4) << 4) + x - 4;
y = prev_param_y;
} else {
range = ((max(prev_param_x, x) - 4) << 4) + min(prev_param_x, x) - 4;
}
if (sel_device == 0 && sel_param == 0 && x < 9) {
e.octave_mm[y][VOICE_CV_GATE] = range;
} else if (sel_device == 1 && sel_param == 0 && x < 9) {
e.octave_mm[y][VOICE_ER301] = range;
} else if (sel_device == 2 && sel_param == 0 && x < 9 && y < 6) {
e.octave_mm[y][VOICE_JF] = range;
} else if (sel_device == 3 && sel_param == 0 && x < 9) {
e.octave_mm[y][VOICE_TXO_NOTE] = e.octave[y][VOICE_TXO_CV_GATE] = range;
} else if (sel_device == 1 && sel_param == 2) {
e.er301_volume_mm[y] = range;
} else if (sel_device == 2 && sel_param == 2 && y < 6) {
e.jf_volume_mm[y] = range;
} else if (sel_device == 3 && sel_param == 2) {
e.txo_volume_mm[y] = range;
} else if (sel_device == 3 && sel_param == 3) {
e.txo_wave_mm[y] = range;
} else if (sel_device == 3 && sel_param == 4) {
e.txo_wavef_mm[y] = range;
} else if (sel_device == 3 && sel_param == 5) {
e.txo_attack_mm[y] = range;
} else if (sel_device == 3 && sel_param == 6) {
e.txo_decay_mm[y] = range;
}
} else {
prev_param_x = x;
prev_param_y = y;
if (sel_mod != 255) {
u8 out = 1 << y;
if (sel_device == 0 && sel_param == 0 && x < 9) {
e.mod_octave[sel_mod] ^= out;
} else if (sel_device == 1 && sel_param == 0 && x < 9) {
e.mod_er301_octave[sel_mod] ^= out;
} else if (sel_device == 2 && sel_param == 0 && x < 9 && y < 6) {
e.mod_jf_octave[sel_mod] ^= out;
} else if (sel_device == 3 && sel_param == 0 && x < 9) {
e.mod_txo_octave[sel_mod] ^= out;
} else if (sel_device == 1 && sel_param == 2) {
e.mod_er301_volume[sel_mod] ^= out;
} else if (sel_device == 2 && sel_param == 2 && y < 6) {
e.mod_jf_volume[sel_mod] ^= out;
} else if (sel_device == 3 && sel_param == 2) {
e.mod_txo_volume[sel_mod] ^= out;
} else if (sel_device == 3 && sel_param == 3) {
e.mod_txo_wave[sel_mod] ^= out;
} else if (sel_device == 3 && sel_param == 4) {
e.mod_txo_wavef[sel_mod] ^= out;
} else if (sel_device == 3 && sel_param == 5) {
e.mod_txo_attack[sel_mod] ^= out;
} else if (sel_device == 3 && sel_param == 6) {
e.mod_txo_decay[sel_mod] ^= out;
}
} else {
if (sel_device == 0 && sel_param == 0 && x < 9) {
e.octave[y][VOICE_CV_GATE] = x - 4;
} else if (sel_device == 1 && sel_param == 0 && x < 9) {
e.octave[y][VOICE_ER301] = x - 4;
} else if (sel_device == 2 && sel_param == 0 && x < 9 && y < 6) {
e.octave[y][VOICE_JF] = x - 4;
} else if (sel_device == 3 && sel_param == 0 && x < 9) {
e.octave[y][VOICE_TXO_NOTE] = e.octave[y][VOICE_TXO_CV_GATE] = x - 4;
} else if (sel_device == 0 && sel_param == 1) {
e.transpose[y][VOICE_CV_GATE] = x - 4;
} else if (sel_device == 1 && sel_param == 1) {
e.transpose[y][VOICE_ER301] = x - 4;
} else if (sel_device == 2 && sel_param == 1 && y < 6) {
e.transpose[y][VOICE_JF] = x - 4;
} else if (sel_device == 3 && sel_param == 1) {
e.transpose[y][VOICE_TXO_NOTE] = e.transpose[y][VOICE_TXO_CV_GATE] = x - 4;
} else if (sel_device == 1 && sel_param == 2) {
e.er301_volume[y] = x - 4;
} else if (sel_device == 2 && sel_param == 2 && y < 6) {
e.jf_volume[y] = x - 4;
} else if (sel_device == 3 && sel_param == 2) {
e.txo_volume[y] = x - 4;
} else if (sel_device == 3 && sel_param == 3) {
e.txo_wave[y] = x - 4;
} else if (sel_device == 3 && sel_param == 4) {
e.txo_wavef[y] = x - 4;
} else if (sel_device == 3 && sel_param == 5) {
e.txo_attack[y] = x - 4;
} else if (sel_device == 3 && sel_param == 6) {
e.txo_decay[y] = x - 4;
}
}
}
update_devices();
}
refresh_grid();
return;
}
if (es_view == es_patterns_held || es_view == es_patterns) {
if (y < 2 || y > 5) return;
if (x >= 2 && x <= 5) {
if (z) e.p_select = x - 2 + ((y - 2) << 2);
pattern_held = z ? e.p_select : 255;
// if (es_view == es_patterns) es_start_playback(e.p_select, 0);
} else if (z && x >= 10 && x <= 13) {
u8 pattern = x - 10 + ((y - 2) << 2);
if (pattern_held != 255) {
copy_pattern(pattern_held, pattern);
refresh_grid();
return;
}
if (pattern_leader) {
if (e.p_leader == pattern) {
e.p_leader = PATTERN_COUNT;
if (e.is_leader_clock)
for (u8 i = 0; i < PATTERN_COUNT; i++)
if (playing[i]) es_start_playback(i, es_pos[i]);
} else {
e.p_leader = pattern;
if (e.is_leader_clock)
if (!playing[e.p_leader]) es_kill_all_notes();
}
} else {
if (playing[pattern]) {
es_stop_playback(pattern);
} else {
es_start_playback(pattern, 0);
}
}
} else if (x == 15 && y == 2) {
pattern_leader = z;
} else if (x == 15 && y == 3 && z) {
e.leader_reset = !e.leader_reset;
} else if (x == 15 && y == 4 && z) {
e.is_leader_clock = !e.is_leader_clock;
if (e.is_leader_clock) {
if (!playing[e.p_leader]) es_kill_all_notes();
} else {
for (u8 i = 0; i < PATTERN_COUNT; i++)
if (playing[i]) es_start_playback(i, es_pos[i]);
}
}
refresh_grid();
return;
}
if (y == 0 && es_mode == es_playing) {
if (!z) return;
es_start_playback(e.p_select, e.p[e.p_select].dir ? 15 - x : x);
/*
s8 start = top_row_pressed();
if (start == -1 || start == x) {
es_start_playback(x);
} else {
e.p[e.p_select].start = min(x, start);
e.p[e.p_select].end = max(x, start);
}
*/
refresh_grid();
return;
}
if (x == 0) return;
if (es_mode == es_armed) es_start_recording(); // will change es_mode to es_recording
if (es_mode == es_recording) es_record_pattern_note(x, y, z);
if (e.arp && es_mode != es_recording) {
if (!z) return;
e.p[e.p_select].root_x = x;
e.p[e.p_select].root_y = y;
es_start_playback(e.p_select, 0);
// es_update_pitches();
} else if (es_mode == es_stopped && rest_pressed() && z) {
// keymap
e.keymap[(y << 4) + x] = (e.keymap[(y << 4) + x] + 1) % 3;
} else {
if (e.p[e.p_select].edge == ES_EDGE_DRONE) {
if (z) {
u8 found = 0;
for (u8 i = 0; i < 4; i++)
if (x == es_notes[i].x && y == es_notes[i].y && es_notes[i].active) {
es_note_off(x, y);
found = 1;
}
if (!found) es_note_on(x, y, 255, 0, e.p[e.p_select].voices);
}
} else {
if (z) {
if (x != 15 || y != 0)
es_note_on(x, y, 255, 0, e.p[e.p_select].voices);
} else es_note_off(x, y);
}
}
refresh_grid();
}
void render_grid() {
clear_screen();
draw_str("POLYEARTHSEA ON TELETYPE", 0, 15, 0);
if (es_mode == es_recording) {
draw_str("recording..", 2, 15, 0);
} else if (es_mode == es_playing) {
draw_str("playing ", 2, 15, 0);
}
refresh_screen();
if (!is_grid_connected()) return;
clear_all_grid_leds();
if (preset_mode) {
set_grid_led(0, preset, 4);
set_grid_led(0, selected_preset, 11);
for(u8 i1=0;i1<8;i1++)
for(u8 i2=0;i2<8;i2++)
if(meta.glyph[i1] & (1<<i2))
set_grid_led(i2 + 8, i1, 9);
return;
}
for (u8 i = 0; i < 8; i++)
set_grid_led(0, i, 2);
if (es_mode == es_playing)
set_grid_led(0, 0, 15);
else if (e.p[e.p_select].length)
set_grid_led(0, 0, 8);
if (es_view == es_patterns) set_grid_led(0, 1, 15);
if (es_mode == es_recording)
set_grid_led(0, 2, es_blinker ? 0 : 4);
else if (es_mode == es_armed)
set_grid_led(0, 2, 7);
if (e.p[e.p_select].loop) set_grid_led(0, 3, 11);
if (e.arp) set_grid_led(0, 4, 11);
if (es_mode == es_playing &&
(es_view == es_main || es_view == es_patterns || es_view == es_patterns_held)) {
//for (u8 i = e.p[e.p_select].start; i <= e.p[e.p_select].end; i++)
// monomeLedBuffer[i] = 4;
u8 pos;
if (is_external_clock_connected() || (e.is_leader_clock && (e.p_select != e.p_leader)))
pos = e.p[e.p_select].length ? (es_pos[e.p_select] << 4) / (e.p[e.p_select].length - 1) : 0;
else
pos = ((get_global_time() - es_p_start) << 4) / es_p_total;
if (e.p[e.p_select].dir) pos = 15 - pos;
for (u8 i = 1; i < 16; i++)
if (i <= pos) set_grid_led(i, 0, 8);
}
u8 l;
if (es_runes) {
l = e.p[e.p_select].linearize ? 15 : 7;
// linearize
set_grid_led(2, 3, l);
set_grid_led(4, 3, l);
set_grid_led(2, 5, l);
set_grid_led(4, 5, l);
l = e.p[e.p_select].dir ? 15 : 7;
// reverse
set_grid_led(7, 3, l);
set_grid_led(6, 4, l);
set_grid_led(7, 5, l);
l = e.p[e.p_select].dir ? 7 : 15;
// forward
set_grid_led(9, 3, l);
set_grid_led(10, 4, l);
set_grid_led(9, 5, l);
l = 8;
// increase speed
set_grid_led(13, 1, 13);
set_grid_led(12, 2, 13);
set_grid_led(14, 2, 13);
set_grid_led(13, 2, l);
set_grid_led(12, 3, l);
set_grid_led(14, 3, l);
// decrease speed
set_grid_led(12, 5, l);
set_grid_led(14, 5, l);
set_grid_led(13, 6, l);
set_grid_led(12, 6, 13);
set_grid_led(14, 6, 13);
set_grid_led(13, 7, 13);
return;
}
if (es_edge) {
l = e.p[e.p_select].edge == ES_EDGE_PATTERN ? 15 : 7;
set_grid_led_i(34, l);
set_grid_led_i(35, l);
set_grid_led_i(36, l);
set_grid_led_i(50, l);
set_grid_led_i(52, l);
set_grid_led_i(66, l);
set_grid_led_i(68, l);
set_grid_led_i(82, l);
set_grid_led_i(84, l);
set_grid_led_i(85, l);
l = e.p[e.p_select].edge == ES_EDGE_FIXED ? 15 : 7;
set_grid_led_i(39, l);
set_grid_led_i(40, l);
set_grid_led_i(41, l);
set_grid_led_i(42, l);
set_grid_led_i(55, l);
set_grid_led_i(58, l);
set_grid_led_i(71, l);
set_grid_led_i(74, l);
set_grid_led_i(87, l);
set_grid_led_i(90, l);
l = e.p[e.p_select].edge == ES_EDGE_DRONE ? 15 : 7;
set_grid_led_i(44, l);
set_grid_led_i(45, l);
set_grid_led_i(46, l);
set_grid_led_i(47, l);
if (e.p[e.p_select].edge == ES_EDGE_FIXED) {
for (u8 i = 0; i < 16; i++)
set_grid_led_i(112 + i, 4);
u8 edge_index = 111 + (e.p[e.p_select].edge_time >> 4);
if (edge_index <= 127) set_grid_led_i(edge_index, 11);
}
return;
}
u8 blink = help_on ? es_blinker : 0;
if (es_view == es_voices || es_view == es_voices_held) {
set_grid_led(1, 7, 4 + es_blinker);
set_grid_led(15, 7, 4 + es_blinker);
u8 un = 4;
if (!help_on || help_sel < 8) {
set_grid_led(5, 0, blink + (sel_mapping == 0 ? 8 : un));
set_grid_led(5, 1, blink + (sel_mapping == 1 ? 8 : un));
set_grid_led(5, 2, blink + (sel_mapping == 2 ? 8 : un));
set_grid_led(5, 3, blink + (sel_mapping == 3 ? 8 : un));
set_grid_led(5, 6, blink + (sel_mapping == 4 ? 8 : un)); // pattern start 1-8
set_grid_led(5, 7, blink + (sel_mapping == 5 ? 8 : un)); // pattern start 9-16
}
u8 voice, sel_v;
for (u8 i = 0; i < VOICE_COUNT; i++) {
set_grid_led_i(2 + (i << 4), e.p[e.p_select].voices & (1 << i) ? 15 : un);
set_grid_led(3, i, shared.voice_on[i] ? 8 : un);
}
if (help_on) {
u8 l = 8;
if (help_sel > 7) {
for (u8 i = 8; i < 14; i++)
set_grid_led(i, 0, blink + (help_sel == i ? 8 : un));
if (help_sel == 8) {
set_grid_led(5, 2, l); // m
set_grid_led(6, 2, l-4);
set_grid_led(7, 2, l);
set_grid_led(5, 3, l);
set_grid_led(6, 3, l-4);
set_grid_led(7, 3, l);
set_grid_led(5, 4, l);
set_grid_led(7, 4, l);
set_grid_led(9, 2, l); // o
set_grid_led(10, 2, l);
set_grid_led(11, 2, l);
set_grid_led(9, 3, l);
set_grid_led(11, 3, l);
set_grid_led(9, 4, l);
set_grid_led(10, 4, l);
set_grid_led(11, 4, l);
set_grid_led(13, 2, l); // d
set_grid_led(14, 2, l);
set_grid_led(13, 3, l);
set_grid_led(15, 3, l);
set_grid_led(13, 4, l);
set_grid_led(14, 4, l);
} else if (help_sel == 9) {
set_grid_led(5, 2, l); // 3
set_grid_led(6, 2, l);
set_grid_led(7, 2, l);
set_grid_led(6, 3, l-4);
set_grid_led(7, 3, l-4);
set_grid_led(5, 4, l);
set_grid_led(6, 4, l);
set_grid_led(7, 4, l);
set_grid_led(9, 2, l); // o
set_grid_led(10, 2, l);
set_grid_led(11, 2, l);
set_grid_led(9, 3, l);
set_grid_led(11, 3, l);
set_grid_led(9, 4, l);
set_grid_led(10, 4, l);
set_grid_led(11, 4, l);
set_grid_led(13, 2, l); // 1
set_grid_led(13, 3, l);
set_grid_led(13, 4, l);
} else if (help_sel == 10) {
set_grid_led(7, 2, l); // j
set_grid_led(7, 3, l);
set_grid_led(6, 4, l);
set_grid_led(7, 4, l);
set_grid_led(9, 2, l); // f
set_grid_led(10, 2, l);
set_grid_led(11, 2, l);
set_grid_led(9, 3, l-4);
set_grid_led(10, 3, l-4);
set_grid_led(9, 4, l);
} else if (help_sel == 11) {
set_grid_led(5, 2, l); // t
set_grid_led(6, 2, l);
set_grid_led(7, 2, l);
set_grid_led(6, 3, l);
set_grid_led(6, 4, l);
set_grid_led(9, 2, l); // x
set_grid_led(11, 2, l);
set_grid_led(10, 3, l);
set_grid_led(9, 4, l);
set_grid_led(11, 4, l);
set_grid_led(13, 2, l); // n
set_grid_led(14, 2, l);
set_grid_led(15, 2, l);
set_grid_led(13, 3, l);
set_grid_led(15, 3, l);
set_grid_led(13, 4, l);
set_grid_led(15, 4, l);
} else if (help_sel == 12) {
set_grid_led(5, 2, l); // t
set_grid_led(6, 2, l);
set_grid_led(7, 2, l);
set_grid_led(6, 3, l);
set_grid_led(6, 4, l);
set_grid_led(9, 2, l); // x
set_grid_led(11, 2, l);
set_grid_led(10, 3, l);
set_grid_led(9, 4, l);
set_grid_led(11, 4, l);
set_grid_led(13, 2, l); // c
set_grid_led(14, 2, l);
set_grid_led(15, 2, l);
set_grid_led(13, 3, l);
set_grid_led(13, 4, l);
set_grid_led(14, 4, l);
set_grid_led(15, 4, l);
} else if (help_sel == 13) {
// b
set_grid_led(5, 2, l);
set_grid_led(6, 2, l);
set_grid_led(5, 3, l);
set_grid_led(7, 3, l);
set_grid_led(5, 4, l);
set_grid_led(6, 4, l);
set_grid_led(5, 5, l);
set_grid_led(7, 5, l);
set_grid_led(5, 6, l);
set_grid_led(6, 6, l);
// u
set_grid_led(9, 2, l);
set_grid_led(11, 2, l);
set_grid_led(9, 3, l);
set_grid_led(11, 3, l);
set_grid_led(9, 4, l);
set_grid_led(11, 4, l);
set_grid_led(9, 5, l);
set_grid_led(11, 5, l);
set_grid_led(9, 6, l);
set_grid_led(10, 6, l);
set_grid_led(11, 6, l);
// s
set_grid_led(13, 2, l);
set_grid_led(14, 2, l);
set_grid_led(15, 2, l);
set_grid_led(13, 3, l);
set_grid_led(13, 4, l);
set_grid_led(14, 4, l);
set_grid_led(15, 4, l);
set_grid_led(15, 5, l);
set_grid_led(13, 6, l);
set_grid_led(14, 6, l);
set_grid_led(15, 6, l);
}
return;
}
if (sel_mapping == 0) {
// n
set_grid_led(7, 1, l);
set_grid_led(8, 1, l);
set_grid_led(9, 1, l);
set_grid_led(7, 2, l);
set_grid_led(9, 2, l);
set_grid_led(7, 3, l);
set_grid_led(9, 3, l);
// o
set_grid_led(11, 1, l);
set_grid_led(12, 1, l);
set_grid_led(13, 1, l);
set_grid_led(11, 2, l);
set_grid_led(13, 2, l);
set_grid_led(11, 3, l);
set_grid_led(12, 3, l);
set_grid_led(13, 3, l);
// t
set_grid_led(7, 5, l);
set_grid_led(8, 5, l);
set_grid_led(9, 5, l);
set_grid_led(8, 6, l);
set_grid_led(8, 7, l);
// e
set_grid_led(11, 5, l);
set_grid_led(12, 5, l);
set_grid_led(13, 5, l);
set_grid_led(11, 6, l-4);
set_grid_led(12, 6, l-4);
set_grid_led(11, 7, l);
set_grid_led(12, 7, l);
set_grid_led(13, 7, l);
} else if (sel_mapping == 1) {
// k
set_grid_led(7, 1, l);
set_grid_led(9, 1, l);
set_grid_led(7, 2, l);
set_grid_led(8, 2, l);
set_grid_led(7, 3, l);
set_grid_led(9, 3, l);
// e
set_grid_led(11, 1, l);
set_grid_led(12, 1, l);
set_grid_led(13, 1, l);
set_grid_led(11, 2, l-4);
set_grid_led(12, 2, l-4);
set_grid_led(11, 3, l);
set_grid_led(12, 3, l);
set_grid_led(13, 3, l);
// y
set_grid_led(9, 5, l);
set_grid_led(11, 5, l);
set_grid_led(10, 6, l);
set_grid_led(10, 7, l);
} else if (sel_mapping == 2) {
// x
set_grid_led(9, 3, l);
set_grid_led(11, 3, l);
set_grid_led(10, 4, l);
set_grid_led(9, 5, l);
set_grid_led(11, 5, l);
} else if (sel_mapping == 3) {
// y
set_grid_led(9, 3, l);
set_grid_led(11, 3, l);
set_grid_led(10, 4, l);
set_grid_led(10, 5, l);
} else if (sel_mapping == 4) {
// p
set_grid_led(7, 0, l);
set_grid_led(8, 0, l);
set_grid_led(9, 0, l);
set_grid_led(7, 1, l);
set_grid_led(9, 1, l);
set_grid_led(7, 2, l);
set_grid_led(8, 2, l);
set_grid_led(9, 2, l);
set_grid_led(7, 3, l);
set_grid_led(7, 4, l);
// s
set_grid_led(11, 0, l);
set_grid_led(12, 0, l);
set_grid_led(13, 0, l);
set_grid_led(11, 1, l);
set_grid_led(11, 2, l);
set_grid_led(12, 2, l);
set_grid_led(13, 2, l);
set_grid_led(13, 3, l);
set_grid_led(11, 4, l);
set_grid_led(12, 4, l);
set_grid_led(13, 4, l);
// i
set_grid_led(10, 6, l);
set_grid_led(10, 7, l);
} else if (sel_mapping == 5) {
// p
set_grid_led(7, 0, l);
set_grid_led(8, 0, l);
set_grid_led(9, 0, l);
set_grid_led(7, 1, l);
set_grid_led(9, 1, l);
set_grid_led(7, 2, l);
set_grid_led(8, 2, l);
set_grid_led(9, 2, l);
set_grid_led(7, 3, l);
set_grid_led(7, 4, l);
// s
set_grid_led(11, 0, l);
set_grid_led(12, 0, l);
set_grid_led(13, 0, l);
set_grid_led(11, 1, l);
set_grid_led(11, 2, l);
set_grid_led(12, 2, l);
set_grid_led(13, 2, l);
set_grid_led(13, 3, l);
set_grid_led(11, 4, l);
set_grid_led(12, 4, l);
set_grid_led(13, 4, l);
// ii
set_grid_led(9, 6, l);
set_grid_led(9, 7, l);
set_grid_led(11, 6, l);
set_grid_led(11, 7, l);
}
return;
}
set_grid_led(15, 5, shared.i2c_mode ? 8 : un);
for (u8 i = 0; i < DEVICE_COUNT; i++)
set_grid_led(15, i, shared.device_on[i] ? 8 : un);
for (u8 i = 0; i < VOICE_COUNT; i++) {
voice = 1 << i;
sel_v = 1 << selected_voice;
if (sel_mapping < 4)
set_grid_led(6, i, i == selected_voice ? 8 : un);
else if (sel_mapping == 4)
set_grid_led(6, i, i == sel_pattern_start ? 8 : un);
else if (sel_mapping == 5)
set_grid_led(6, i, i == (sel_pattern_start - 8) ? 8 : un);
if (sel_mapping == 0) { // note
set_grid_led(8, i, e.voice_map[selected_voice][VOICE_CV_GATE] & voice ? 8 : un);
set_grid_led(9, i, e.voice_map[selected_voice][VOICE_ER301] & voice? 8 : un);
if (i < 6) set_grid_led(10, i, e.voice_map[selected_voice][VOICE_JF] & voice ? 8 : un);
set_grid_led(11, i, e.voice_map[selected_voice][VOICE_TXO_NOTE] & voice ? 8 : un);
set_grid_led(12, i, e.voice_map[selected_voice][VOICE_TXO_CV_GATE] & voice ? 8 : un);
set_grid_led(13, i, e.mod_gate[i] & sel_v ? 8 : un);
} else if (sel_mapping == 1) { // key
set_grid_led(8, i, e.cv_key_map[selected_voice] & voice ? 8 : un);
set_grid_led(9, i, e.er301_key_map[selected_voice] & voice ? 8 : un);
set_grid_led(12, i, e.txo_key_map[selected_voice] & voice ? 8 : un);
set_grid_led(13, i, e.mod_key[i] & sel_v ? 8 : un);
} else if (sel_mapping == 2) { // x
set_grid_led(8, i, e.cv_x_map[selected_voice] & voice ? 8 : un);
set_grid_led(9, i, e.er301_x_map[selected_voice] & voice ? 8 : un);
set_grid_led(12, i, e.txo_x_map[selected_voice] & voice ? 8 : un);
set_grid_led(13, i, e.mod_x[i] & sel_v ? 8 : un);
} else if (sel_mapping == 3) { // y
set_grid_led(8, i, e.cv_y_map[selected_voice] & voice ? 8 : un);
set_grid_led(9, i, e.er301_y_map[selected_voice] & voice ? 8 : un);
set_grid_led(12, i, e.txo_y_map[selected_voice] & voice ? 8 : un);
set_grid_led(13, i, e.mod_y[i] & sel_v ? 8 : un);
} else if (sel_mapping == 4) { // pstart 1
set_grid_led(8, i, e.pstart_map[sel_pattern_start][0] & voice ? 8 : un);
set_grid_led(9, i, e.pstart_map[sel_pattern_start][1] & voice? 8 : un);
if (i < 6) set_grid_led(10, i, e.pstart_map[sel_pattern_start][2] & voice ? 8 : un);
set_grid_led(12, i, e.pstart_map[sel_pattern_start][4] & voice ? 8 : un);
set_grid_led(13, i, e.mod_pstart[i] & (1 << sel_pattern_start) ? 8 : un);
} else if (sel_mapping == 5) { // pstart 2
set_grid_led(8, i, e.pstart_map[sel_pattern_start][0] & voice ? 8 : un);
set_grid_led(9, i, e.pstart_map[sel_pattern_start][1] & voice? 8 : un);
if (i < 6) set_grid_led(10, i, e.pstart_map[sel_pattern_start][2] & voice ? 8 : un);
set_grid_led(12, i, e.pstart_map[sel_pattern_start][4] & voice ? 8 : un);
set_grid_led(13, i, e.mod_pstart[i] & (1 << sel_pattern_start) ? 8 : un);
}
}
set_grid_led(10, 7, e.jf_mode ? 8 : un);
return;
}
if (es_view == es_devices || es_view == es_devices_held) {
for (u8 i = 0; i < 4; i++)
set_grid_led(1, i, blink + (sel_device == i ? 12 : 4));
set_grid_led(1, 7, 4 + es_blinker);
set_grid_led(2, 0, blink + (sel_param == 0 ? 12 : 4)); // octave
set_grid_led(2, 1, blink + (sel_param == 1 ? 12 : 4)); // transpose
if (sel_device) set_grid_led(2, 2, blink + (sel_param == 2 ? 12 : 4)); // volume
if (sel_device == 3) {
set_grid_led(2, 3, blink + (sel_param == 3 ? 12 : 4)); // txo waveform
set_grid_led(2, 4, blink + (sel_param == 4 ? 12 : 4)); // txo waveform fine
set_grid_led(2, 5, blink + (sel_param == 5 ? 12 : 4)); // txo attack
set_grid_led(2, 6, blink + (sel_param == 6 ? 12 : 4)); // txo decay
}
if (!help_on)
for (u8 i = 0; i < MOD_COUNT; i++)
set_grid_led(3, i, (es_blinker & 1) + (i == sel_mod ? 12 : 4));
u8 l, o;
if (help_on) {
l = 8;
if (sel_device == VOICE_CV_GATE) {
set_grid_led(5, 1, l); // m
set_grid_led(6, 1, l-4);
set_grid_led(7, 1, l);
set_grid_led(5, 2, l);
set_grid_led(6, 2, l-4);
set_grid_led(7, 2, l);
set_grid_led(5, 3, l);
set_grid_led(7, 3, l);
set_grid_led(9, 1, l); // o
set_grid_led(10, 1, l);
set_grid_led(11, 1, l);
set_grid_led(9, 2, l);
set_grid_led(11, 2, l);
set_grid_led(9, 3, l);
set_grid_led(10, 3, l);
set_grid_led(11, 3, l);
set_grid_led(13, 1, l); // d
set_grid_led(14, 1, l);
set_grid_led(13, 2, l);
set_grid_led(15, 2, l);
set_grid_led(13, 3, l);
set_grid_led(14, 3, l);
} else if (sel_device == VOICE_ER301) {
set_grid_led(5, 1, l); // 3
set_grid_led(6, 1, l);
set_grid_led(7, 1, l);
set_grid_led(6, 2, l-4);
set_grid_led(7, 2, l-4);
set_grid_led(5, 3, l);
set_grid_led(6, 3, l);
set_grid_led(7, 3, l);
set_grid_led(9, 1, l); // o
set_grid_led(10, 1, l);
set_grid_led(11, 1, l);
set_grid_led(9, 2, l);
set_grid_led(11, 2, l);
set_grid_led(9, 3, l);
set_grid_led(10, 3, l);
set_grid_led(11, 3, l);
set_grid_led(13, 1, l); // 1
set_grid_led(13, 2, l);
set_grid_led(13, 3, l);
} else if (sel_device == VOICE_JF) {
set_grid_led(7, 1, l); // j
set_grid_led(7, 2, l);
set_grid_led(6, 3, l);
set_grid_led(7, 3, l);
set_grid_led(9, 1, l); // f
set_grid_led(10, 1, l);
set_grid_led(11, 1, l);
set_grid_led(9, 2, l-4);
set_grid_led(10, 2, l-4);
set_grid_led(9, 3, l);
} else if (sel_device == VOICE_TXO_NOTE) {
set_grid_led(5, 1, l); // t
set_grid_led(6, 1, l);
set_grid_led(7, 1, l);
set_grid_led(6, 2, l);
set_grid_led(6, 3, l);
set_grid_led(9, 1, l); // x
set_grid_led(11, 1, l);
set_grid_led(10, 2, l);
set_grid_led(9, 3, l);
set_grid_led(11, 3, l);
set_grid_led(13, 1, l); // o
set_grid_led(14, 1, l);
set_grid_led(15, 1, l);
set_grid_led(13, 2, l);
set_grid_led(15, 2, l);
set_grid_led(13, 3, l);
set_grid_led(14, 3, l);
set_grid_led(15, 3, l);
}
if (sel_param == 0) {
set_grid_led(5, 5, l); // o
set_grid_led(6, 5, l);
set_grid_led(7, 5, l);
set_grid_led(5, 6, l);
set_grid_led(7, 6, l);
set_grid_led(5, 7, l);
set_grid_led(6, 7, l);
set_grid_led(7, 7, l);
set_grid_led(9, 5, l); // c
set_grid_led(10, 5, l);
set_grid_led(11, 5, l);
set_grid_led(9, 6, l);
set_grid_led(9, 7, l);
set_grid_led(10, 7, l);
set_grid_led(11, 7, l);
set_grid_led(13, 5, l); // t
set_grid_led(14, 5, l);
set_grid_led(15, 5, l);
set_grid_led(14, 6, l);
set_grid_led(14, 7, l);
} else if (sel_param == 1) {
set_grid_led(5, 5, l); // t
set_grid_led(6, 5, l);
set_grid_led(7, 5, l);
set_grid_led(6, 6, l);
set_grid_led(6, 7, l);
set_grid_led(9, 5, l); // r
set_grid_led(10, 5, l);
set_grid_led(11, 5, l);
set_grid_led(9, 6, l);
set_grid_led(9, 7, l);
set_grid_led(13, 5, l); // n
set_grid_led(14, 5, l);
set_grid_led(15, 5, l);
set_grid_led(13, 6, l);
set_grid_led(15, 6, l);
set_grid_led(13, 7, l);
set_grid_led(15, 7, l);
} else if (sel_param == 2) {
set_grid_led(5, 5, l); // v
set_grid_led(7, 5, l);
set_grid_led(5, 6, l);
set_grid_led(7, 6, l);
set_grid_led(6, 7, l);
set_grid_led(9, 5, l); // o
set_grid_led(10, 5, l);
set_grid_led(11, 5, l);
set_grid_led(9, 6, l);
set_grid_led(11, 6, l);
set_grid_led(9, 7, l);
set_grid_led(10, 7, l);
set_grid_led(11, 7, l);
set_grid_led(13, 5, l); // l
set_grid_led(13, 6, l);
set_grid_led(13, 7, l);
set_grid_led(14, 7, l);
set_grid_led(15, 7, l);
} else if (sel_param == 3) {
set_grid_led(5, 5, l); // w
set_grid_led(7, 5, l);
set_grid_led(5, 6, l);
set_grid_led(6, 6, l-4);
set_grid_led(7, 6, l);
set_grid_led(5, 7, l);
set_grid_led(6, 7, l-4);
set_grid_led(7, 7, l);
set_grid_led(9, 5, l); // a
set_grid_led(10, 5, l);
set_grid_led(11, 5, l);
set_grid_led(9, 6, l);
set_grid_led(10, 6, l-4);
set_grid_led(11, 6, l);
set_grid_led(9, 7, l);
set_grid_led(11, 7, l);
set_grid_led(13, 5, l); // v
set_grid_led(15, 5, l);
set_grid_led(13, 6, l);
set_grid_led(15, 6, l);
set_grid_led(14, 7, l);
} else if (sel_param == 4) {
set_grid_led(5, 5, l); // w
set_grid_led(7, 5, l);
set_grid_led(5, 6, l);
set_grid_led(6, 6, l-4);
set_grid_led(7, 6, l);
set_grid_led(5, 7, l);
set_grid_led(6, 7, l-4);
set_grid_led(7, 7, l);
set_grid_led(9, 5, l); // v
set_grid_led(11, 5, l);
set_grid_led(9, 6, l);
set_grid_led(11, 6, l);
set_grid_led(10, 7, l);
set_grid_led(13, 5, l); // f
set_grid_led(14, 5, l);
set_grid_led(15, 5, l);
set_grid_led(13, 6, l-4);
set_grid_led(14, 6, l-4);
set_grid_led(13, 7, l);
} else if (sel_param == 5) {
set_grid_led(5, 5, l); // a
set_grid_led(6, 5, l);
set_grid_led(7, 5, l);
set_grid_led(5, 6, l);
set_grid_led(6, 6, l-4);
set_grid_led(7, 6, l);
set_grid_led(5, 7, l);
set_grid_led(7, 7, l);
set_grid_led(9, 5, l); // t
set_grid_led(10, 5, l);
set_grid_led(11, 5, l);
set_grid_led(10, 6, l);
set_grid_led(10, 7, l);
set_grid_led(13, 5, l); // t
set_grid_led(14, 5, l);
set_grid_led(15, 5, l);
set_grid_led(14, 6, l);
set_grid_led(14, 7, l);
} else if (sel_param == 6) {
set_grid_led(5, 5, l); // d
set_grid_led(6, 5, l);
set_grid_led(5, 6, l);
set_grid_led(7, 6, l);
set_grid_led(5, 7, l);
set_grid_led(6, 7, l);
set_grid_led(9, 5, l); // e
set_grid_led(10, 5, l);
set_grid_led(11, 5, l);
set_grid_led(9, 6, l-4);
set_grid_led(10, 6, l-4);
set_grid_led(9, 7, l);
set_grid_led(10, 7, l);
set_grid_led(11, 7, l);
set_grid_led(13, 5, l); // c
set_grid_led(14, 5, l);
set_grid_led(15, 5, l);
set_grid_led(13, 6, l);
set_grid_led(13, 7, l);
set_grid_led(14, 7, l);
set_grid_led(15, 7, l);
}
return;
}
u8 mod_on = sel_mod != 255;
for (u8 i = 0; i < VOICE_COUNT; i++) {
o = 1 << i;
if (sel_device == VOICE_CV_GATE) {
if (sel_param == 0) {
l = mod_on && (e.mod_octave[sel_mod] & o) ? 8 : 4;
for (u8 x = e.octave_mm[i][VOICE_CV_GATE] & 15;
x <= e.octave_mm[i][VOICE_CV_GATE] >> 4; x++) {
set_grid_led(4 + x, i, l);
}
set_grid_led(4 + e.octave[i][VOICE_CV_GATE], i, 12);
} else if (sel_param == 1) {
set_grid_led(4 + e.transpose[i][VOICE_CV_GATE], i, 12);
}
} else if (sel_device == VOICE_ER301) {
if (sel_param == 0) {
for (u8 x = e.octave_mm[i][VOICE_ER301] & 15;
x <= e.octave_mm[i][VOICE_ER301] >> 4; x++) {
l = mod_on && (e.mod_er301_octave[sel_mod] & o) ? 8 : 4;
set_grid_led(4 + x, i, l);
}
set_grid_led(4 + e.octave[i][VOICE_ER301], i, 12);
} else if (sel_param == 1) {
set_grid_led(4 + e.transpose[i][VOICE_ER301], i, 12);
} else if (sel_param == 2) {
for (u8 x = e.er301_volume_mm[i] & 15;
x <= e.er301_volume_mm[i] >> 4; x++) {
l = mod_on && (e.mod_er301_volume[sel_mod] & o) ? 8 : 4;
set_grid_led(4 + x, i, l);
}
set_grid_led(4 + e.er301_volume[i], i, 12);
}
} else if (sel_device == VOICE_JF) {
if (sel_param == 0) {
if (i < 6) {
for (u8 x = e.octave_mm[i][VOICE_JF] & 15;
x <= e.octave_mm[i][VOICE_JF] >> 4; x++) {
l = mod_on && (e.mod_jf_octave[sel_mod] & o) ? 8 : 4;
set_grid_led(4 + x, i, l);
}
set_grid_led(4 + e.octave[i][VOICE_JF], i, 12);
}
} else if (sel_param == 1) {
if (i < 6)
set_grid_led(4 + e.transpose[i][VOICE_JF], i, 12);
} else if (sel_param == 2) {
if (i < 6) {
for (u8 x = e.jf_volume_mm[i] & 15;
x <= e.jf_volume_mm[i] >> 4; x++) {
l = mod_on && (e.mod_jf_volume[sel_mod] & o) ? 8 : 4;
set_grid_led(4 + x, i, l);
}
set_grid_led(4 + e.jf_volume[i], i, 12);
}
}
} else if (sel_device == VOICE_TXO_NOTE) {
if (sel_param == 0) {
for (u8 x = e.octave_mm[i][VOICE_TXO_NOTE] & 15;
x <= e.octave_mm[i][VOICE_TXO_NOTE] >> 4; x++) {
l = mod_on && (e.mod_txo_octave[sel_mod] & o) ? 8 : 4;
set_grid_led(4 + x, i, l);
}
set_grid_led(4 + e.octave[i][VOICE_TXO_NOTE], i, 12);
} else if (sel_param == 1) {
set_grid_led(4 + e.transpose[i][VOICE_TXO_NOTE], i, 12);
} else if (sel_param == 2) {
for (u8 x = e.txo_volume_mm[i] & 15;
x <= e.txo_volume_mm[i] >> 4; x++) {
l = mod_on && (e.mod_txo_volume[sel_mod] & o) ? 8 : 4;
set_grid_led(4 + x, i, l);
}
set_grid_led(4 + e.txo_volume[i], i, 12);
} else if (sel_param == 3) {
for (u8 x = e.txo_wave_mm[i] & 15;
x <= e.txo_wave_mm[i] >> 4; x++) {
l = mod_on && (e.mod_txo_wave[sel_mod] & o) ? 8 : 4;
set_grid_led(4 + x, i, l);
}
set_grid_led(4 + e.txo_wave[i], i, 12);
} else if (sel_param == 4) {
for (u8 x = e.txo_wavef_mm[i] & 15;
x <= e.txo_wavef_mm[i] >> 4; x++) {
l = mod_on && (e.mod_txo_wavef[sel_mod] & o) ? 8 : 4;
set_grid_led(4 + x, i, l);
}
set_grid_led(4 + e.txo_wavef[i], i, 12);
} else if (sel_param == 5) {
for (u8 x = e.txo_attack_mm[i] & 15;
x <= e.txo_attack_mm[i] >> 4; x++) {
l = mod_on && (e.mod_txo_attack[sel_mod] & o) ? 8 : 4;
set_grid_led(4 + x, i, l);
}
set_grid_led(4 + e.txo_attack[i], i, 12);
} else if (sel_param == 6) {
for (u8 x = e.txo_decay_mm[i] & 15;
x <= e.txo_decay_mm[i] >> 4; x++) {
l = mod_on && (e.mod_txo_decay[sel_mod] & o) ? 8 : 4;
set_grid_led(4 + x, i, l);
}
set_grid_led(4 + e.txo_decay[i], i, 12);
}
}
}
return;
}
s16 index, x, y;
if (es_view == es_main) {
for (u8 i = 0; i < 128; i++)
if (e.keymap[i]) set_grid_led_i(i, e.keymap[i] << 1);
if (e.arp)
set_grid_led_i(e.p[e.p_select].root_x + (e.p[e.p_select].root_y << 4), 7);
for (u8 i = 0; i < 4; i++)
if (es_notes[i].active) {
x = es_notes[i].x;
y = es_notes[i].y;
while (x < 0) {
y++;
x += 5;
}
while (x > 15) {
y--;
x -= 5;
}
index = (y << 4) + x;
if (index >= 0 && (index & 15) != 0)
set_grid_led_i(index, 15);
}
} else { // pattern view
u8 l = es_blinker ? 2 : 0;
for (u8 i = 0; i < 16; i++) {
set_grid_led_i((i & 3) + 34 + ((i >> 2) << 4), e.p[i].length ? 7 : 4);
set_grid_led(10 + (i & 3), 2 + (i >> 2), i == e.p_leader ? (playing[i] ? 13 + l : 13) : (playing[i] ? 8 + l : 4));
}
set_grid_led_i((e.p_select & 3) + 34 + ((e.p_select >> 2) << 4), 15);
set_grid_led(15, 2, 8);
set_grid_led(15, 3, e.leader_reset ? 8 : 4);
set_grid_led(15, 4, e.is_leader_clock ? 8 : 4);
}
}
void render_arc() {
if (!is_arc_connected()) return;
clear_all_arc_leds();
u8 index;
for (u8 i = 0; i < get_arc_encoder_count(); i++) {
set_arc_led(i, 0, 6);
set_arc_led(i, 16, 6);
set_arc_led(i, 32, 6);
set_arc_led(i, 48, 6);
set_arc_led(i, 8, 2);
set_arc_led(i, 24, 2);
set_arc_led(i, 40, 2);
set_arc_led(i, 56, 2);
index = get_knob_count() + i;
set_arc_led(i, e.mod_value[index] >> 2, 8 + (e.mod_value[index] & 3));
}
}
void remap_voices() {
u8 out;
for (u8 i = 0; i < VOICE_COUNT; i++)
for (u8 output = 0; output < VOICE_COUNT; output++) {
out = 1 << output;
map_voice(i, VOICE_CV_GATE, output, e.voice_map[i][VOICE_CV_GATE] & out);
map_voice(i, VOICE_ER301, output, e.voice_map[i][VOICE_ER301] & out);
map_voice(i, VOICE_JF, output, e.voice_map[i][VOICE_JF] & out);
map_voice(i, VOICE_TXO_NOTE, output, e.voice_map[i][VOICE_TXO_NOTE] & out);
map_voice(i, VOICE_TXO_CV_GATE, output, e.voice_map[i][VOICE_TXO_CV_GATE] & out);
}
}
void update_devices() {
for (u8 i = 0; i < VOICE_COUNT; i++) {
for (u8 j = 0; j < DEVICE_COUNT; j++)
set_output_transpose(j, i, e.octave[i][j] * 12 + e.transpose[i][j]);
set_output_max_volume(VOICE_ER301, i, (u16)e.er301_volume[i] * (MAX_LEVEL / 11));
set_output_max_volume(VOICE_JF, i, (u16)e.jf_volume[i] * (MAX_LEVEL / 11));
set_output_max_volume(VOICE_TXO_NOTE, i, (u16)e.txo_volume[i] * (MAX_LEVEL / 11));
set_txo_attack(i, e.txo_attack[i] * 50);
set_txo_decay(i, e.txo_decay[i] * 50);
set_txo_waveform(i, e.txo_wave[i] * 409 + e.txo_wavef[i] * TXOWAVF); // 0..4500
set_txo_mode(i, 1);
}
}
void update_i2c() {
es_kill_all_notes();
for (u8 i = 0; i < DEVICE_COUNT; i++) mute_device(i, !shared.device_on[i]);
if (!shared.i2c_mode) {
set_as_i2c_follower(I2C_ADDRESS);
return;
}
set_as_i2c_leader();
set_jf_mode(e.jf_mode);
update_devices();
}
void ii_es(uint8_t *data, uint8_t l) {
if (!l) return;
s16 d = (data[1] << 8) | data[2];
u8 value;
switch(data[0]) {
case 0x51: // ES_PRESET:
if (d >= 0 && d < get_preset_count()) {
preset = selected_preset = d;
load_preset();
refresh_grid();
}
break;
case 0x55: // ES_PATTERN:
if (d >= 0 && d < 16) {
e.p_select = d;
refresh_grid();
}
break;
case 0x53: // ES_CLOCK:
clock_next_note(0);
break;
case 0x54: // ES_RESET:
value = d;
if (value > 15) value = 15;
es_start_playback(e.p_select, value);
break;
case 0x57: // ES_STOP:
es_stop_playback(e.p_select);
break;
case 0x56: // ES_TRANS:
if (d > 0) {
for (u8 i = 0; i < d; i++) {
if (e.p[e.p_select].root_y == 1 && e.p[e.p_select].root_x == 15) break;
e.p[e.p_select].root_x++;
if (e.p[e.p_select].root_x == 16)
{
e.p[e.p_select].root_x = 11;
e.p[e.p_select].root_y--;
}
}
} else {
for (u8 i = 0; i < abs(d); i++) {
if (e.p[e.p_select].root_y == 7 && e.p[e.p_select].root_x == 1) break;
e.p[e.p_select].root_x--;
if (e.p[e.p_select].root_x == 0)
{
e.p[e.p_select].root_x = 5;
e.p[e.p_select].root_y++;
}
}
}
es_start_playback(e.p_select, 0);
refresh_grid();
break;
case 0x59: // ES_MAGIC:
switch (d) {
case 1:
es_half_speed();
break;
case 2:
es_double_speed();
break;
case 3:
e.p[e.p_select].linearize = 1;
es_update_total_time();
break;
case 4:
e.p[e.p_select].linearize = 0;
es_update_total_time();
break;
case 5:
if (e.p[e.p_select].dir) es_reverse();
e.p[e.p_select].dir = 0;
if (es_mode == es_playing) es_kill_pattern_notes(e.p_select);
break;
case 6:
if (!e.p[e.p_select].dir) es_reverse();
e.p[e.p_select].dir = 1;
if (es_mode == es_playing) es_kill_pattern_notes(e.p_select);
break;
}
refresh_grid();
break;
case 0x52: // ES_MODE:
if (d < 0 || d >= 16) {
e.p[e.p_select].edge = ES_EDGE_PATTERN;
es_kill_all_notes();
} else if (d == 0) {
e.p[e.p_select].edge = ES_EDGE_DRONE;
} else {
u8 fixed = d;
if (fixed > 15) fixed = 15;
e.p[e.p_select].edge = ES_EDGE_FIXED;
e.p[e.p_select].edge_time = (fixed + 1) << 4;
es_kill_all_notes();
}
refresh_grid();
break;
}
}
void init_presets() {
preset = selected_preset = 0;
uint8_t i;
shared.i2c_mode = 0;
for (u8 i = 0; i < DEVICE_COUNT; i++) shared.device_on[i] = 1;
for (u8 i = 0; i < VOICE_COUNT; i++) shared.voice_on[i] = 1;
e.jf_mode = 1;
for (u8 i = 0; i < VOICE_COUNT; i++) {
for (u8 j = 0; j < DEVICE_COUNT; j++) {
e.voice_map[i][j] = 0;
e.pstart_map[i][j] = 0;
e.octave[i][j] = 1;
e.octave_mm[i][j] = 17;
e.transpose[i][j] = 0;
}
if (i < get_gate_output_count() || i < get_cv_output_count())
e.voice_map[i][VOICE_CV_GATE] |= 1 << i;
e.er301_volume[i] = 8;
e.jf_volume[i] = 8;
e.txo_volume[i] = 8;
e.txo_wave[i] = 0;
e.txo_wavef[i] = 0;
e.txo_attack[i] = 0;
e.txo_decay[i] = 1;
e.er301_volume_mm[i] = 72;
e.jf_volume_mm[i] = 72;
e.txo_volume_mm[i] = 72;
e.txo_wave_mm[i] = 0;
e.txo_wavef_mm[i] = 0;
e.txo_attack_mm[i] = 0;
e.txo_decay_mm[i] = 17;
e.cv_x_map[i] = 0;
e.cv_y_map[i] = 0;
e.cv_key_map[i] = 0;
e.er301_x_map[i] = 0;
e.er301_y_map[i] = 0;
e.er301_key_map[i] = 0;
e.txo_x_map[i] = 0;
e.txo_y_map[i] = 0;
e.txo_key_map[i] = 0;
}
for (u8 i = 0; i < MOD_COUNT; i++) {
e.mod_x[i] = 0;
e.mod_y[i] = 0;
e.mod_key[i] = 0;
e.mod_gate[i] = 0;
e.mod_pstart[i] = 0;
e.mod_octave[i] = 0;
e.mod_er301_octave[i] = 0;
e.mod_jf_octave[i] = 0;
e.mod_txo_octave[i] = 0;
e.mod_er301_volume[i] = 0;
e.mod_jf_volume[i] = 0;
e.mod_txo_volume[i] = 0;
e.mod_txo_attack[i] = 0;
e.mod_txo_decay[i] = 0;
e.mod_txo_wave[i] = 0;
e.mod_txo_wavef[i] = 0;
e.mod_value[i] = 0;
e.midi_cc[i] = 0;
}
e.arp = 0;
e.p_select = 0;
e.p_leader = PATTERN_COUNT;
e.is_leader_clock = 0;
for (u8 i = 0; i < 128; i++) e.keymap[i] = 0;
for (u8 i = 0; i < 16; i++) {
e.p[i].interval_ind = 0;
e.p[i].length = 0;
e.p[i].loop = 0;
e.p[i].edge = ES_EDGE_PATTERN;
e.p[i].edge_time = 16;
e.p[i].voices = 0;
for (u8 j = 0; j < VOICE_COUNT; j++) e.p[i].voices = (e.p[i].voices << 1) | 1;
e.p[i].dir = 0;
e.p[i].linearize = 0;
e.p[i].start = 0;
e.p[i].end = 15;
}
for (u8 i = 0; i < 8; i++) meta.glyph[i] = 0;
for (i = 0; i < get_preset_count(); i++) {
store_preset_to_flash(i, &meta, &e);
}
store_shared_data_to_flash(&shared);
store_preset_index(0);
}
void copy_pattern(u8 src, u8 dest) {
memcpy(&(e.p[dest]), &(e.p[src]), sizeof(es_pattern_t));
}
void load_preset() {
load_preset_from_flash(preset, &e);
load_preset_meta_from_flash(preset, &meta);
es_kill_all_notes();
remap_voices();
update_devices();
}