Added storage for pattern and settings

This commit is contained in:
Daniele Lacamera 2020-04-26 19:46:21 +02:00
parent b43948ded3
commit e3d1ff9c0d
18 changed files with 331 additions and 99 deletions

View file

@ -5,7 +5,8 @@ VERSION?=1
OBJS:=startup.o main.o system.o mem.o led.o \ OBJS:=startup.o main.o system.o mem.o led.o \
i2c.o display.o font_twisted.o button.o systick.o newlib.o uart.o ui.o timer.o\ i2c.o display.o font_twisted.o button.o systick.o newlib.o uart.o ui.o timer.o\
mutex.o ui_drone.o adc.o spi.o pot.o dac.o sound.o drone.o settings.o ui_pattern.o mutex.o ui_drone.o adc.o spi.o pot.o dac.o sound.o drone.o settings.o ui_pattern.o \
flash.o
UMX:=lib/unicore-mx/lib/libucmx_stm32f4.a UMX:=lib/unicore-mx/lib/libucmx_stm32f4.a

28
drone.c
View file

@ -19,27 +19,6 @@
#define MUTE { 0 , 0 } #define MUTE { 0 , 0 }
static struct drone_slot drone_pattern[MAX_PATTERN_LEN] = {
{ 28, 10 }, { 28, 20}, {36,20}, {40,20},
{ 40, 10 }, { 40, 10}, {36, 10}, {32,10},
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
MUTE, MUTE, MUTE, MUTE,
};
void drone_mute(void) void drone_mute(void)
{ {
@ -51,13 +30,17 @@ void drone_mute(void)
void drone_beat(int pattern_pos) void drone_beat(int pattern_pos)
{ {
struct drone_slot *key = &drone_pattern[pattern_pos];
static int test_lfo_step = 0; static int test_lfo_step = 0;
static int test_lfo = 0; static int test_lfo = 0;
int lfo_depth = 80; int lfo_depth = 80;
int lfo_rate = 7; int lfo_rate = 7;
int lfo_step = 2; int lfo_step = 2;
int tgt_env; int tgt_env;
static struct drone_slot *pattern;
struct drone_slot *key;
pattern = Settings->drone[Settings->current_pattern].data;
key = &pattern[pattern_pos];
if ((key->pitch == 0) && (key->env == 0)) { if ((key->pitch == 0) && (key->env == 0)) {
pot_set(0, 99); pot_set(0, 99);
pot_set(1, 0); pot_set(1, 0);
@ -93,7 +76,6 @@ void drone_beat(int pattern_pos)
tgt_env = 99; tgt_env = 99;
test_lfo_step = 1; test_lfo_step = 1;
} }
pot_set(0, key->pitch); pot_set(0, key->pitch);
pot_set(1, tgt_env); pot_set(1, tgt_env);
} }

View file

@ -2,11 +2,9 @@
#ifndef DRONE_H_INCLUDED #ifndef DRONE_H_INCLUDED
#define DRONE_H_INCLUDED #define DRONE_H_INCLUDED
#include <stdint.h> #include <stdint.h>
#include "settings.h"
void drone_mute(void); void drone_mute(void);
void drone_select_pattern(struct drone_pattern *p);
struct __attribute__((packed)) drone_slot {
uint8_t pitch;
uint8_t env;
};
#endif #endif

27
drums.c
View file

@ -17,8 +17,7 @@
#define TRACKS 8 #define TRACKS 8
//static uint32_t pattern[MAX_PATTERN_LEN] = { DRUMS_KICK, DRUMS_HIHAT, DRUMS_SNARE, DRUMS_HIHAT, DRUMS_KICK, DRUMS_KICK, DRUMS_SNARE, DRUMS_HIHAT }; static struct drums_pattern *pattern = NULL;
static uint32_t pattern[MAX_PATTERN_LEN] = { DRUMS_KICK, DRUMS_KICK, DRUMS_CLAP, 0, 0, DRUMS_KICK, 0};
static uint32_t pattern_len = 8; static uint32_t pattern_len = 8;
static uint32_t pattern_pos = 0; static uint32_t pattern_pos = 0;
static unsigned char *dsample[TRACKS] = {}; static unsigned char *dsample[TRACKS] = {};
@ -26,9 +25,11 @@ static unsigned int dsample_len[TRACKS] = {};
static void beat_cb(uint32_t b) static void beat_cb(uint32_t b)
{ {
uint32_t key = pattern[pattern_pos];
int i; int i;
drone_beat(pattern_pos); uint32_t key;
pattern = &Settings->drums[Settings->current_pattern];
//drone_beat(pattern_pos);
key = pattern->data[pattern_pos];
for (i = 0; i < TRACKS; i++) { for (i = 0; i < TRACKS; i++) {
if ((key & (1 << i)) == (1 << i)) { if ((key & (1 << i)) == (1 << i)) {
if (dsample[i]) { if (dsample[i]) {
@ -40,7 +41,7 @@ static void beat_cb(uint32_t b)
} }
} }
pattern_pos++; pattern_pos++;
if (pattern_pos >= Settings.pattern_len) { if (pattern_pos >= pattern->len) {
pattern_pos = 0; pattern_pos = 0;
} }
led_beat((pattern_pos % 8) + 1); led_beat((pattern_pos % 8) + 1);
@ -82,23 +83,21 @@ void drums_stop(void)
timer_clear_beat_callback(); timer_clear_beat_callback();
} }
void drums_set_pattern_len(int l)
{
Settings.pattern_len = l;
timer_set_beat(1);
}
void drums_set(uint32_t track, int pos) void drums_set(uint32_t track, int pos)
{ {
pattern[pos] |= (1 << track); pattern = Settings->drums[Settings->current_pattern].data;
pattern->data[pos] |= (1 << track);
} }
void drums_clear(uint32_t track, int pos) void drums_clear(uint32_t track, int pos)
{ {
pattern[pos] &= ~(1 << track); pattern = Settings->drums[Settings->current_pattern].data;
pattern->data[pos] &= ~(1 << track);
} }
int drums_get(uint32_t track, int pos) int drums_get(uint32_t track, int pos)
{ {
return (!!(pattern[pos] & (1 << track))); pattern = Settings->drums[Settings->current_pattern].data;
return (!!(pattern->data[pos] & (1 << track)));
} }

View file

@ -2,14 +2,15 @@
#define DRUMS_H_INCLUDED #define DRUMS_H_INCLUDED
#include <stdint.h> #include <stdint.h>
#include "settings.h"
void drums_init(void); void drums_init(void);
void drums_start(void); void drums_start(void);
void drums_stop(void); void drums_stop(void);
void drums_set_pattern_len(int l);
int drums_get(uint32_t track, int pos); int drums_get(uint32_t track, int pos);
void drums_set(uint32_t track, int pos); void drums_set(uint32_t track, int pos);
void drums_clear(uint32_t track, int pos); void drums_clear(uint32_t track, int pos);
void drums_oneshot(int track); void drums_oneshot(int track);
void drums_select_pattern(struct drums_pattern *p);
#define DRUMS_KICK (1 << 0) #define DRUMS_KICK (1 << 0)
#define DRUMS_HIHAT (1 << 1) #define DRUMS_HIHAT (1 << 1)

122
flash.c Normal file
View file

@ -0,0 +1,122 @@
/* stm32f4.c
*
* Copyright (C) 2020 Danielinux
*
*/
#include <stdint.h>
#include "system.h"
/* STM32F4 FLASH Geometry */
#define FLASH_SECTOR_0 0x0000000 /* 16 Kb */
#define FLASH_SECTOR_1 0x0004000 /* 16 Kb */
#define FLASH_SECTOR_2 0x0008000 /* 16 Kb */
#define FLASH_SECTOR_3 0x000C000 /* 16 Kb */
#define FLASH_SECTOR_4 0x0010000 /* 64 Kb */
#define FLASH_SECTOR_5 0x0020000 /* 128 Kb */
#define FLASH_SECTOR_6 0x0040000 /* 128 Kb */
#define FLASH_SECTOR_7 0x0060000 /* 128 Kb */
#define FLASH_SECTOR_8 0x0080000 /* 128 Kb */
#define FLASH_SECTOR_9 0x00A0000 /* 128 Kb */
#define FLASH_SECTOR_10 0x00C0000 /* 128 Kb */
#define FLASH_SECTOR_11 0x00E0000 /* 128 Kb */
#define FLASH_TOP 0x0100000
#define FLASH_SECTORS 12
const uint32_t flash_sector[FLASH_SECTORS + 1] = {
FLASH_SECTOR_0,
FLASH_SECTOR_1,
FLASH_SECTOR_2,
FLASH_SECTOR_3,
FLASH_SECTOR_4,
FLASH_SECTOR_5,
FLASH_SECTOR_6,
FLASH_SECTOR_7,
FLASH_SECTOR_8,
FLASH_SECTOR_9,
FLASH_SECTOR_10,
FLASH_SECTOR_11,
FLASH_TOP
};
static void flash_wait_complete(void)
{
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY)
;
}
static void flash_erase_sector(uint32_t sec)
{
uint32_t reg = FLASH_CR & (~(FLASH_CR_SNB_MASK << FLASH_CR_SNB_SHIFT));
FLASH_CR = reg | (sec & FLASH_CR_SNB_MASK) << FLASH_CR_SNB_SHIFT;
FLASH_CR |= FLASH_CR_SER;
FLASH_CR |= FLASH_CR_STRT;
flash_wait_complete();
FLASH_CR &= ~FLASH_CR_SER;
FLASH_CR &= ~(FLASH_CR_SNB_MASK << FLASH_CR_SNB_SHIFT);
}
static void clear_errors(void)
{
FLASH_SR |= ( FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_OPERR | FLASH_SR_EOP );
}
int flash_write(uint32_t address, const uint8_t *data, int len)
{
int i;
uint32_t val;
flash_wait_complete();
clear_errors();
/* Set 8-bit write */
FLASH_CR &= (~(0x03 << 8));
for (i = 0; i < len; i++) {
FLASH_CR |= FLASH_CR_PG;
*((uint8_t *)(address + i)) = data[i];
flash_wait_complete();
FLASH_CR &= ~FLASH_CR_PG;
}
return 0;
}
void flash_unlock(void)
{
FLASH_CR |= FLASH_CR_LOCK;
FLASH_KEYR = FLASH_KEY1;
FLASH_KEYR = FLASH_KEY2;
}
void flash_lock(void)
{
FLASH_CR |= FLASH_CR_LOCK;
}
int flash_erase(uint32_t address, int len)
{
int start = -1, end = -1;
uint32_t end_address;
int i;
if (len == 0)
return -1;
end_address = address + len - 1;
if (address < flash_sector[0] || end_address > FLASH_TOP)
return -1;
for (i = 0; i < FLASH_SECTORS; i++)
{
if ((address >= flash_sector[i]) && (address < flash_sector[i + 1])) {
start = i;
}
if ((end_address >= flash_sector[i]) && (end_address < flash_sector[i + 1])) {
end = i;
}
if (start > 0 && end > 0)
break;
}
if (start < 0 || end < 0)
return -1;
for (i = start; i <= end; i++)
flash_erase_sector(i);
return 0;
}

10
flash.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef FLASH_H_INCLUDED
#define FLASH_H_INCLUDED
#include <stdint.h>
int flash_write(uint32_t address, const uint8_t *data, int len);
void flash_unlock(void);
void flash_lock(void);
int flash_erase(uint32_t address, int len);
#endif

1
main.c
View file

@ -34,6 +34,7 @@ static void bootlevel_0(void)
uart2_setup(115200, 8, 0, 1); uart2_setup(115200, 8, 0, 1);
systick_enable(); systick_enable();
WFI(); WFI();
settings_load();
printf("Console on USART2 Enabled.\r\n"); printf("Console on USART2 Enabled.\r\n");
printf("\r\n=====================\r\n"); printf("\r\n=====================\r\n");
printf("Entering bootlevel 0.\r\n"); printf("Entering bootlevel 0.\r\n");

4
pot.c
View file

@ -109,7 +109,7 @@ void pot_init(void)
void pot_sync(int p) void pot_sync(int p)
{ {
pot_set(p, Settings.levels[p]); pot_set(p, Settings->levels[p]);
} }
@ -130,7 +130,7 @@ void pot_set(int p, int val)
if (val > 100) if (val > 100)
val = 100; val = 100;
Settings.levels[p] = val; Settings->levels[p] = val;
off = val - old; off = val - old;
if (off == 0) if (off == 0)

View file

@ -1,7 +1,39 @@
#include <string.h>
#include "settings.h" #include "settings.h"
#include "flash.h"
struct settings Settings = {
.bpm = 125, #define RAM_SETTINGS (0x20012000)
.pattern_len = 16, #define FLASH_SETTINGS (0x0E0000)
#define SETTINGS_PART_SIZE (0x20000) /* 128 KB */
};
struct settings *Settings = (struct settings *)(RAM_SETTINGS);
void settings_save(void)
{
flash_unlock();
flash_erase(FLASH_SETTINGS, SETTINGS_PART_SIZE);
flash_write(FLASH_SETTINGS, (const void *)(RAM_SETTINGS), sizeof(struct settings));
flash_lock();
}
static void restore_defaults(void)
{
memset(Settings, 0, sizeof(struct settings));
Settings->storage_hdr = STORAGE_HDR;
Settings->bpm = 125;
settings_save();
}
void settings_load(void)
{
struct settings *s = (struct settings *)FLASH_SETTINGS;
if (s->storage_hdr != STORAGE_HDR) {
restore_defaults();
return;
}
memcpy((void *)RAM_SETTINGS, (const void *)FLASH_SETTINGS, sizeof(struct settings));
}

View file

@ -5,14 +5,38 @@
#define MAX_PATTERN_LEN 64 #define MAX_PATTERN_LEN 64
#define MAX_TRACKS 8 #define MAX_TRACKS 8
#define MAX_PATTERNS 32
#define STORAGE_HDR (0xDA1EDA1E)
struct settings;
extern struct settings *Settings;
struct __attribute__((packed)) drone_slot {
uint8_t pitch;
uint8_t env;
};
struct settings { struct settings {
uint32_t storage_hdr;
int levels[NUM_POTS]; int levels[NUM_POTS];
#define master_vol levels[2] #define master_vol levels[2]
int bpm; int bpm;
int beatcount;
int sequencer_on; int sequencer_on;
int pattern_len; int current_pattern;
struct drums_pattern {
uint32_t len;
uint32_t data[MAX_PATTERN_LEN];
} drums[MAX_PATTERNS];
struct drone_pattern {
struct drone_slot data[MAX_PATTERN_LEN];
} drone[MAX_PATTERNS];
}; };
extern struct settings Settings;
void settings_load(void);
void settings_save(void);
#endif #endif

View file

@ -153,10 +153,47 @@ static inline void nvic_irq_clear(uint8_t n)
} }
/*** FLASH ***/ /*** FLASH ***/
#define FLASH_BASE (0x40023C00) #define FLASH_BASE (0x40023C00)
#define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00)) #define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00))
#define FLASH_KEYR (*(volatile uint32_t *)(FLASH_BASE + 0x04))
#define FLASH_SR (*(volatile uint32_t *)(FLASH_BASE + 0x0C))
#define FLASH_CR (*(volatile uint32_t *)(FLASH_BASE + 0x10))
#define FLASH_ACR_ENABLE_DATA_CACHE (1 << 10) #define FLASH_ACR_ENABLE_DATA_CACHE (1 << 10)
#define FLASH_ACR_ENABLE_INST_CACHE (1 << 9) #define FLASH_ACR_ENABLE_INST_CACHE (1 << 9)
/* Register values */
#define FLASH_ACR_RESET_DATA_CACHE (1 << 12)
#define FLASH_ACR_RESET_INST_CACHE (1 << 11)
#define FLASH_ACR_ENABLE_DATA_CACHE (1 << 10)
#define FLASH_ACR_ENABLE_INST_CACHE (1 << 9)
#define FLASH_ACR_ENABLE_PRFT (1 << 8)
#define FLASH_SR_BSY (1 << 16)
#define FLASH_SR_PGSERR (1 << 7)
#define FLASH_SR_PGPERR (1 << 6)
#define FLASH_SR_PGAERR (1 << 5)
#define FLASH_SR_WRPERR (1 << 4)
#define FLASH_SR_OPERR (1 << 1)
#define FLASH_SR_EOP (1 << 0)
#define FLASH_CR_LOCK (1 << 31)
#define FLASH_CR_ERRIE (1 << 25)
#define FLASH_CR_EOPIE (1 << 24)
#define FLASH_CR_STRT (1 << 16)
#define FLASH_CR_MER (1 << 2)
#define FLASH_CR_SER (1 << 1)
#define FLASH_CR_PG (1 << 0)
#define FLASH_CR_SNB_SHIFT 3
#define FLASH_CR_SNB_MASK 0x1f
#define FLASH_CR_PROGRAM_X8 (0 << 8)
#define FLASH_CR_PROGRAM_X16 (1 << 8)
#define FLASH_CR_PROGRAM_X32 (2 << 8)
#define FLASH_CR_PROGRAM_X64 (3 << 8)
#define FLASH_KEY1 (0x45670123)
#define FLASH_KEY2 (0xCDEF89AB)
/*** SPI ***/ /*** SPI ***/
#define SPI1 (0x40013000) #define SPI1 (0x40013000)
#define SPI1_CR1 (*(volatile uint32_t *)(SPI1)) #define SPI1_CR1 (*(volatile uint32_t *)(SPI1))

View file

@ -1,8 +1,9 @@
MEMORY MEMORY
{ {
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K - 0x100 FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K - 0x100
RAM (rw) : ORIGIN = 0x20001000, LENGTH = 252K
RAM_S (rw) : ORIGIN = 0x20000000, LENGTH = 4K RAM_S (rw) : ORIGIN = 0x20000000, LENGTH = 4K
RAM (rw) : ORIGIN = 0x20001000, LENGTH = 64K
RAM_SETTINGS (rw) : ORIGIN = 0x2012000, LENGTH = 60K
} }
SECTIONS SECTIONS
@ -25,6 +26,7 @@ SECTIONS
_stored_data = .; _stored_data = .;
.data : AT (_stored_data) .data : AT (_stored_data)
{ {
_start_data = .; _start_data = .;
@ -42,6 +44,11 @@ SECTIONS
_end_bss = .; _end_bss = .;
_end = .; _end = .;
} > RAM } > RAM
.settings :
{
*(.settings*)
} > RAM_SETTINGS
} }

View file

@ -27,7 +27,7 @@ int timer_set_bpm(void)
uint32_t psc = 1; uint32_t psc = 1;
uint32_t err = 0; uint32_t err = 0;
uint32_t reg = 0; uint32_t reg = 0;
uint32_t clock = (cpu_freq / (4 * Settings.bpm)) * (S_PER_MINUTE);; uint32_t clock = (cpu_freq / (4 * Settings->bpm)) * (S_PER_MINUTE);;
while (psc < 65535) { while (psc < 65535) {
val = clock / psc; val = clock / psc;

4
ui.c
View file

@ -84,6 +84,7 @@ void ui_menu_autoscroll(void)
display_scroll(NULL, display_cur_v); display_scroll(NULL, display_cur_v);
} }
extern struct display_menu MainMenu;
static void ui_display_menu_refresh(void) static void ui_display_menu_refresh(void)
{ {
const struct display_menu *menu = CurrentMenu; const struct display_menu *menu = CurrentMenu;
@ -92,7 +93,8 @@ static void ui_display_menu_refresh(void)
char txt[16]; char txt[16];
display_scroll(NULL, display_cur_v); display_scroll(NULL, display_cur_v);
display_clear(NULL); display_clear(NULL);
if (menu->render)
menu->render(menu);
for (i = 0; i < menu->entry_n; i++) { for (i = 0; i < menu->entry_n; i++) {
vline = i + 4; vline = i + 4;
if (vline > 7) if (vline > 7)

5
ui.h
View file

@ -24,12 +24,9 @@ struct display_menu {
int *var; int *var;
const void *arg; const void *arg;
} entry[MAX_ENTRY]; } entry[MAX_ENTRY];
void (*render)(struct display_menu *menu);
}; };
const struct display_menu MainMenu, MeasureMenu, SignalGenMenu,
ExtraMenu;
void ui_display_menu(const struct display_menu *menu); void ui_display_menu(const struct display_menu *menu);
void ui_button_press(uint8_t b, int hold); void ui_button_press(uint8_t b, int hold);

View file

@ -15,6 +15,32 @@
#define CENTER_Y ((int)(50)) #define CENTER_Y ((int)(50))
#define NEUTRAL 2 #define NEUTRAL 2
static void ui_sequencer_action(struct display_menu_entry *e, uint8_t b);
static void ui_master_action(struct display_menu_entry *e, uint8_t b);
static void ui_bpm_action(struct display_menu_entry *e, uint8_t b);
static void ui_pattern_save_action(struct display_menu_entry *e, uint8_t b);
static void main_menu_prepare(struct display_menu *m);
extern struct display_menu PatternMenu;
static void ui_submenu_action(struct display_menu_entry *e, uint8_t b)
{
ui_display_menu(e->arg);
}
struct display_menu MainMenu = {
.entry_n = 7,
.render = main_menu_prepare,
.entry = {
{ ENTRY_TYPE_BOOL, "Sequencer", ui_sequencer_action, .min = 0, .max = 0, .step = 0, NULL, .arg = NULL },
{ ENTRY_TYPE_DEC, "Volume: ", ui_master_action, 0, 100, 2, NULL, NULL },
{ ENTRY_TYPE_DEC, "BPM: ", ui_bpm_action, 30, 300, 1, NULL, NULL },
{ ENTRY_TYPE_DEC, "Pattern :", NULL, 0, MAX_PATTERNS, 1, NULL, NULL },
{ ENTRY_TYPE_DEC, "Pattern Len:", NULL, 8, MAX_PATTERN_LEN, 8, NULL, NULL },
{ ENTRY_TYPE_TEXT, "Edit Pattern", ui_submenu_action, 0, 0, 0, NULL, &PatternMenu},
{ ENTRY_TYPE_TEXT, "Save Pattern", ui_pattern_save_action, 0, 0, 0, NULL, NULL},
}
};
struct display_menu *CurrentMenu = &MainMenu; struct display_menu *CurrentMenu = &MainMenu;
extern volatile uint32_t jiffies; extern volatile uint32_t jiffies;
@ -197,6 +223,8 @@ static void ui_bpm_input(uint8_t press, int hold)
timer_stop(); timer_stop();
timer_set_bpm(); timer_set_bpm();
led_beat(1); led_beat(1);
settings_save();
timer_set_beat(1);
timer_set_beat(1); timer_set_beat(1);
timer_start(); timer_start();
} }
@ -207,6 +235,7 @@ static void ui_bpm_input(uint8_t press, int hold)
timer_stop(); timer_stop();
timer_set_bpm(sys_bpm - 1); timer_set_bpm(sys_bpm - 1);
led_beat(1); led_beat(1);
settings_save();
timer_set_beat(1); timer_set_beat(1);
timer_start(); timer_start();
} }
@ -266,16 +295,6 @@ static void ui_bytebeat(const void *arg)
set_keepalive(ui_bytebeat_keepalive); set_keepalive(ui_bytebeat_keepalive);
} }
const struct display_menu PatternMenu = {
.entry_n = 1,
.entry = {
{ "TODO! ", ui_submenu, &MainMenu},
{ "", NULL, NULL}
}
};
const struct display_menu DroneMenu = { const struct display_menu DroneMenu = {
.entry_n = 2, .entry_n = 2,
.entry = { .entry = {
@ -295,14 +314,10 @@ const struct display_menu SettingsMenu = {
#endif #endif
static void ui_submenu_action(struct display_menu_entry *e, uint8_t b)
{
ui_display_menu(e->arg);
}
static void ui_sequencer_action(struct display_menu_entry *e, uint8_t b) static void ui_sequencer_action(struct display_menu_entry *e, uint8_t b)
{ {
if (Settings.sequencer_on) { if (Settings->sequencer_on) {
timer_set_beat(1); timer_set_beat(1);
timer_start(); timer_start();
} else { } else {
@ -326,23 +341,27 @@ static void ui_bpm_action(struct display_menu_entry *e, uint8_t b)
timer_start(); timer_start();
} }
static void ui_pattern_save_action(struct display_menu_entry *e, uint8_t b)
{
display_clear();
display_scroll(NULL, 0);
display_text(5, "Saving to FLASH");
settings_save();
ui_display_menu(&MainMenu);
}
static void main_menu_prepare(struct display_menu *m)
{
if (m != &MainMenu)
return;
MainMenu.entry[0].var = &Settings->sequencer_on;
MainMenu.entry[1].var = &Settings->levels[2];
MainMenu.entry[2].var = &Settings->bpm;
MainMenu.entry[3].var = &Settings->current_pattern;
MainMenu.entry[4].var = &(Settings->drums[Settings->current_pattern].len);
}
extern void ui_pattern_menu_action(struct display_menu_entry *e, uint8_t b); extern void ui_pattern_menu_action(struct display_menu_entry *e, uint8_t b);
extern struct display_menu PatternMenu;
const struct display_menu MainMenu = {
.entry_n = 5,
.entry = {
/* TYPE, label, action, min, max, var, arg */
{ ENTRY_TYPE_BOOL, "Sequencer", ui_sequencer_action, 0, 0, 0, &Settings.sequencer_on, NULL },
{ ENTRY_TYPE_DEC, "Volume: ", ui_master_action, 0, 100, 2, &Settings.levels[2], NULL },
{ ENTRY_TYPE_DEC, "BPM: ", ui_bpm_action, 30, 300, 1, &Settings.bpm, NULL },
{ ENTRY_TYPE_DEC, "Pattern Len:", NULL, 8, MAX_PATTERN_LEN, 8, &Settings.pattern_len, NULL },
{ ENTRY_TYPE_TEXT, "Edit Pattern", ui_pattern_menu_action, 0, 0, 0, NULL, &PatternMenu},
{0, "", NULL, 0,0,0,NULL,NULL}
}
};

View file

@ -51,6 +51,7 @@ void ui_pattern_keepalive(void)
} }
} }
extern struct display_menu MainMenu;
void ui_pattern_menu_return_to_main(struct display_menu_entry *e, uint8_t b) void ui_pattern_menu_return_to_main(struct display_menu_entry *e, uint8_t b)
{ {
display_clear(NULL); display_clear(NULL);
@ -60,8 +61,10 @@ void ui_pattern_menu_return_to_main(struct display_menu_entry *e, uint8_t b)
ui_display_menu(&MainMenu); ui_display_menu(&MainMenu);
} }
static void pattern_menu_prepare(struct display_menu *m);
struct display_menu PatternMenu = { struct display_menu PatternMenu = {
.entry_n = 4, .entry_n = 4,
.render = pattern_menu_prepare,
.entry = { .entry = {
/* TYPE, label, action, min, max, var, arg */ /* TYPE, label, action, min, max, var, arg */
{ ENTRY_TYPE_DEC, "Track: ", ui_pattern_refresh_action, 0, (MAX_TRACKS - 1), 1, &sel_track, NULL }, { ENTRY_TYPE_DEC, "Track: ", ui_pattern_refresh_action, 0, (MAX_TRACKS - 1), 1, &sel_track, NULL },
@ -98,16 +101,13 @@ const char instr_txt[MAX_TRACKS][14] = {
"", "",
}; };
static void pattern_menu_prepare(struct display_menu *m)
void ui_pattern_menu_action(struct display_menu_entry *e, uint8_t b)
{ {
PatternMenu.entry[1].max = Settings.pattern_len; if (m != &PatternMenu)
return;
PatternMenu.entry[1].max = Settings->drums[Settings->current_pattern].len;
sel_val = drums_get(sel_track, sel_pos - 1); sel_val = drums_get(sel_track, sel_pos - 1);
ui_display_menu(e->arg);
set_keepalive(ui_pattern_keepalive); set_keepalive(ui_pattern_keepalive);
set_input_callback(ui_pattern_input); set_input_callback(ui_pattern_input);
ui_pattern_refresh_action(e, b);
} }