From 3b2641fdcd8addb31a4b834c8934f168fc54403d Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Thu, 23 Apr 2020 22:19:22 +0200 Subject: [PATCH] Added drums pattern editor --- Makefile | 2 +- drone.c | 33 ++++++++++++--- drums.c | 21 ++++++++-- drums.h | 3 +- settings.c | 1 + settings.h | 4 ++ ui.c | 14 ++++++- ui.h | 1 + ui_drone.c | 21 +++++----- ui_pattern.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 190 insertions(+), 23 deletions(-) create mode 100644 ui_pattern.c diff --git a/Makefile b/Makefile index c55048b..f19fd49 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ VERSION?=1 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\ - mutex.o ui_drone.o adc.o spi.o pot.o dac.o sound.o drone.o settings.o + mutex.o ui_drone.o adc.o spi.o pot.o dac.o sound.o drone.o settings.o ui_pattern.o UMX:=lib/unicore-mx/lib/libucmx_stm32f4.a diff --git a/drone.c b/drone.c index 19d8a16..6638977 100644 --- a/drone.c +++ b/drone.c @@ -13,16 +13,36 @@ #include "drone.h" #include "drums.h" #include "pot.h" +#include "settings.h" -static struct drone_slot drone_pattern[MAX_PATTERN_LEN] = { +#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} + { 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) { - pot_set(0, 0xFF); - pot_set(1, 0x0); + pot_set(0, 0); + pot_set(1, 99); } void drone_beat(int pattern_pos) @@ -34,7 +54,10 @@ void drone_beat(int pattern_pos) int lfo_rate = 7; int lfo_step = 2; int tgt_env; - pot_set(0, 99); + pot_set(0, 0); + pot_set(1, 99); + if ((key->pitch == 0) && (key->env == 0)) + return; if ((pattern_pos % lfo_step) == 0) { if (test_lfo_step == 0) { diff --git a/drums.c b/drums.c index 57c4153..1efd42f 100644 --- a/drums.c +++ b/drums.c @@ -13,6 +13,7 @@ #include "led.h" #include "drums.h" #include "drone.h" +#include "settings.h" #define TRACKS 8 @@ -39,12 +40,19 @@ static void beat_cb(uint32_t b) } } pattern_pos++; - if (pattern_pos >= pattern_len) { + if (pattern_pos >= Settings.pattern_len) { pattern_pos = 0; } led_beat((pattern_pos % 8) + 1); } +void drums_oneshot(int track) +{ + while(dac_is_busy()) + dac_stop(); + dac_play_direct(dsample[track], dsample_len[track]); +} + void drums_init(void) { dsample[0] = drumkit_0_au; @@ -76,16 +84,21 @@ void drums_stop(void) void drums_set_pattern_len(int l) { - pattern_len = l; + Settings.pattern_len = l; timer_set_beat(1); } void drums_set(uint32_t track, int pos) { - pattern[pos] |= track; + pattern[pos] |= (1 << track); } void drums_clear(uint32_t track, int pos) { - pattern[pos] &= ~track; + pattern[pos] &= ~(1 << track); +} + +int drums_get(uint32_t track, int pos) +{ + return (!!(pattern[pos] & (1 << track))); } diff --git a/drums.h b/drums.h index 8dda41f..ae5d592 100644 --- a/drums.h +++ b/drums.h @@ -2,13 +2,14 @@ #define DRUMS_H_INCLUDED #include -#define MAX_PATTERN_LEN 64 void drums_init(void); void drums_start(void); void drums_stop(void); void drums_set_pattern_len(int l); +int drums_get(uint32_t track, int pos); void drums_set(uint32_t track, int pos); void drums_clear(uint32_t track, int pos); +void drums_oneshot(int track); #define DRUMS_KICK (1 << 0) #define DRUMS_HIHAT (1 << 1) diff --git a/settings.c b/settings.c index 41b68b5..a9b0d0c 100644 --- a/settings.c +++ b/settings.c @@ -2,5 +2,6 @@ struct settings Settings = { .bpm = 125, + .pattern_len = 16, }; diff --git a/settings.h b/settings.h index 3305169..45babd9 100644 --- a/settings.h +++ b/settings.h @@ -3,11 +3,15 @@ #include #include "pot.h" +#define MAX_PATTERN_LEN 64 +#define MAX_TRACKS 8 + struct settings { int levels[NUM_POTS]; #define master_vol levels[2] int bpm; int sequencer_on; + int pattern_len; }; extern struct settings Settings; diff --git a/ui.c b/ui.c index aeb8bda..e1ed4f4 100644 --- a/ui.c +++ b/ui.c @@ -169,6 +169,11 @@ static void ui_display_menu_refresh(void) WFI(); } +int ui_get_menu_selection(void) +{ + return menu_selection; +} + void ui_display_menu(const struct display_menu *menu) { uint8_t i; @@ -259,10 +264,17 @@ void ui_init(void) now = jiffies; for (i = 1; i < 9; i++) { led_beat(i); - while((jiffies - now < 10)) + while((jiffies - now) < 100) WFI(); now = jiffies; } + for (i = 8; i > 0; i--) { + led_beat(i); + while((jiffies - now) < 100) + WFI(); + now = jiffies; + } + led_beat(0); } void ui_keepalive(uint32_t timeslice) diff --git a/ui.h b/ui.h index 920593d..5a244aa 100644 --- a/ui.h +++ b/ui.h @@ -40,5 +40,6 @@ void set_input_callback(void (*cb)(uint8_t press, int hold)); void clear_input_callback(void); void set_keepalive(void (*cb)(void)); void clear_keepalive(void); +int ui_get_menu_selection(void); #endif diff --git a/ui_drone.c b/ui_drone.c index 77d8ea4..71ecdfb 100644 --- a/ui_drone.c +++ b/ui_drone.c @@ -267,10 +267,6 @@ static void ui_bytebeat(const void *arg) } -static void ui_submenu(const void *arg) -{ - ui_display_menu(arg); -} const struct display_menu PatternMenu = { .entry_n = 1, @@ -299,6 +295,11 @@ const struct display_menu SettingsMenu = { #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) { if (Settings.sequencer_on) { @@ -326,19 +327,17 @@ static void ui_bpm_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 = 3, + .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 }, - /* - { "BPM" , ui_bpm, NULL}, - { "Pattern ", ui_submenu, &PatternMenu }, - { "Drone ", ui_submenu, &DroneMenu}, - { "Bytebeat ", ui_bytebeat }, - */ + { 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} } }; diff --git a/ui_pattern.c b/ui_pattern.c new file mode 100644 index 0000000..8286656 --- /dev/null +++ b/ui_pattern.c @@ -0,0 +1,113 @@ +#include +#include "ui.h" +#include +#include "adc.h" +#include "button.h" +#include "system.h" +#include "unicore-mx/stm32/gpio.h" +#include "unicore-mx/stm32/rcc.h" +#include "pot.h" +#include "dac.h" +#include "settings.h" +#include "timer.h" + + +static int sel_pos = 1; +static int sel_track = 0; +static int sel_val = 0; +extern volatile uint32_t jiffies; + +void ui_pattern_refresh_action(struct display_menu_entry *e, uint8_t b) +{ + int i; + int off; + sel_val = drums_get(sel_track, sel_pos - 1); + led_beat(0); + off = ((sel_pos - 1)/ 8) * 8; + for (i = 0; i < 8; i++) { + if (drums_get(sel_track, (off + i))) + led_on(i+1); + else + led_off(i+1); + } +} + +void ui_pattern_update_action(struct display_menu_entry *e, uint8_t b) +{ + if (sel_val) { + + drums_set(sel_track, sel_pos - 1); + drums_oneshot(sel_track); + } else + drums_clear(sel_track, sel_pos - 1); +} + +void ui_pattern_keepalive(void) +{ + static uint32_t blink_time = 0; + if (jiffies - blink_time > 20) { + led_toggle(((sel_pos - 1) % 8) + 1); + blink_time = jiffies; + } +} + +void ui_pattern_menu_return_to_main(struct display_menu_entry *e, uint8_t b) +{ + display_clear(NULL); + clear_input_callback(); + clear_keepalive(); + led_beat(0); + ui_display_menu(&MainMenu); +} + +struct display_menu PatternMenu = { + .entry_n = 4, + .entry = { + /* 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, "Pos : ", ui_pattern_refresh_action, 1, 8, 1, &sel_pos, NULL }, + { ENTRY_TYPE_BOOL, "Value : ", ui_pattern_update_action, 0, 0, 0, &sel_val, NULL }, + { ENTRY_TYPE_TEXT, "Back to main", ui_pattern_menu_return_to_main, 0, 0, 0, NULL, NULL }, + {0, "", NULL, 0,0,0,NULL,NULL} + } +}; + +void ui_pattern_input(int press, int hold) +{ + if (press == '*' && (ui_get_menu_selection() == 1)) { + sel_val = !sel_val; + ui_pattern_update_action(NULL, 0); + ui_pattern_refresh_action(NULL, 0); + press = 0; + return; + } + ui_button_press(press, hold); + if ((press == '+' || press == '-') && (ui_get_menu_selection() == 0)) { + drums_oneshot(sel_track); + } +} + +const char instr_txt[MAX_TRACKS][14] = { + "Kick", + "Snare", + "HitHat", + "Tom1", + "Tom2", + "Clap", + "Cow", + "", +}; + + + + +void ui_pattern_menu_action(struct display_menu_entry *e, uint8_t b) +{ + PatternMenu.entry[1].max = Settings.pattern_len; + sel_val = drums_get(sel_track, sel_pos - 1); + ui_display_menu(e->arg); + set_keepalive(ui_pattern_keepalive); + set_input_callback(ui_pattern_input); + ui_pattern_refresh_action(e, b); +} +