From 8c33aeda7cd65a5797930340c2728a9464e98b9f Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Tue, 16 Jan 2024 10:32:28 +0100 Subject: [WIP] Full implementation of attack/decay for ch3 (bugs?) --- Makefile | 2 +- src/main.c | 4 +-- src/sequencer.c | 84 ++++++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 65 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index 7afaf9d..d7c0b05 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ INC_FLAGS := $(addprefix -I,$(INC_DIRS)) INC_FLAGS += -I$(LIBGBA_SRC) # Output library names and executables. -TARGET := STEPPER-v1.8-dev-15 +TARGET := STEPPER-v1.8-dev-16 ELF := $(BUILD_DIR)/$(TARGET).elf BIN := $(BUILD_DIR)/$(TARGET).gba diff --git a/src/main.c b/src/main.c index cea35f6..a068bc8 100644 --- a/src/main.c +++ b/src/main.c @@ -28,9 +28,8 @@ WITH REGARD TO THIS SOFTWARE. // + Hold L/R retriggers at short intervals? // to key release to enable trigs. // + Fix bug with not being able to stop the sound when synced +// + Add attack and decay envelope for ch3 (synced to tempo) // - Fix any bugs we currently have -// - Add an envelope to ch3, would need to work with a timer in order to make -// it work I think (Can reuse the 96bpq sequencer timer for this). // - Add clipboard sharing between banks. // - Make sure transposing a sequence past the keyboard limit doesn't affect // the sequence and can be reversed. @@ -38,6 +37,7 @@ WITH REGARD TO THIS SOFTWARE. // - When putting a new trigger, make sure it uses the global parameters // - Bad performance when selecting patterns // - Add help for attack/decay on ch3 +// - Fix A+B on ch3 // // Low priority: // diff --git a/src/sequencer.c b/src/sequencer.c index 4b5f34f..66f1d24 100644 --- a/src/sequencer.c +++ b/src/sequencer.c @@ -227,33 +227,18 @@ play_step(void) { TriggerNote *trig = &pat->ch3.notes[step_counter]; ChannelWaveParams *params = &pat->ch3.params[step_counter]; if (trig->active && should_play(params->prob)) { - Wave wave_zero = { - 0x77777777, 0x77777777, 0x77777777, 0x77777777, - }; switch (params->wave_mode) { case 0: { wave_target = &waves[params->shape_a][params->type_a]; wave_env_attack = params->wave_attack; wave_env_decay = params->wave_decay; wave_env = WAV_ENV_START; - SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(0); - memcpy32(SOUND_WAVE_RAM, wave_zero, 16); - SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(1); - memcpy32(SOUND_WAVE_RAM, wave_zero, 16); - SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) - | SOUND_WAVE_BANK_SELECT(0); } break; case 1: { wave_target = &waves[params->shape_b][params->type_b]; wave_env_attack = params->wave_attack; wave_env_decay = params->wave_decay; wave_env = WAV_ENV_START; - SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(0); - memcpy32(SOUND_WAVE_RAM, wave_zero, 16); - SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(1); - memcpy32(SOUND_WAVE_RAM, wave_zero, 16); - SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) - | SOUND_WAVE_BANK_SELECT(0); } break; case 2: { SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(0); @@ -361,21 +346,30 @@ play_step(void) { static int nseq_ticks = 0; +UNROLL_LOOPS IWRAM_CODE void wave_ad_tick(void) { Wave wave_active = {0}; + Wave wave_zero = { + 0x77777777, 0x77777777, 0x77777777, 0x77777777, + }; env_start: switch (wave_env) { case WAV_ENV_START: { wave_env_ticks = 0; wave_env_prog = 0; + SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(0); + memcpy32(SOUND_WAVE_RAM, wave_zero, 16); + SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(1); + memcpy32(SOUND_WAVE_RAM, wave_zero, 16); + SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) + | SOUND_WAVE_BANK_SELECT(0); SOUND_WAVE_MODE |= SOUND_WAVE_ENABLE; SOUND_WAVE_FREQ = SOUND_FREQ_RESET | wave_freq; if (wave_env_attack == 0) { - memcpy32(wave_active, wave_target, 16); - memcpy32(SOUND_WAVE_RAM, wave_active, 16); + memcpy32(SOUND_WAVE_RAM, wave_target, 16); SOUND_WAVE_MODE ^= SOUND_WAVE_BANK_SELECT(1); } else { wave_env = WAV_ENV_ATTACK; @@ -391,7 +385,57 @@ env_start: return; } break; case WAV_ENV_ATTACK: { - // TODO: Attack envelope + if (wave_env_ticks++ < wave_env_attack) { + return; + } + wave_env_ticks = 0; + + // Attack. + int powers[] = { + 20, 57, 104, 143, 177, 208, 235, 256, + }; + int power = powers[wave_env_prog]; + if (++wave_env_prog >= 8) { + if (wave_env_decay == 0) { + wave_env = WAV_ENV_OFF; + } else { + wave_env_prog = 0; + wave_env = WAV_ENV_DECAY; + } + } + for (size_t j = 0; j < 4; j++) { + u32 next = 0; + u32 prev = (*wave_target)[j]; + for (size_t i = 0; i < 8; i++) { + u8 val = (prev >> 4 * i) & 0xF; + // Operating in 24.8 fixed point: + if (val < 0x7) { + int tmp = 0x7 - val; + tmp *= power; + tmp >>= 8; + val = (0x7 - tmp) & 0xf; + } else if (val > 0x7) { + int tmp = (val - 0x7); + tmp *= power; + tmp >>= 8; + val = tmp + 0x7; + if (val <= 0x7) { + val = 0x7; + } + } + next |= (val << 4 * i); + } + wave_active[j] = next; + } + + // DEBUG: + // int x = 50; + // int y = 50; + // draw_filled_rect(0 + x, 0 + y, 100 + x, 32 + y, COL_BG); + // draw_wave_pattern(&wave_active, 0 + x, 0 + y, 1); + + memcpy32(SOUND_WAVE_RAM, wave_active, 16); + SOUND_WAVE_MODE ^= SOUND_WAVE_BANK_SELECT(1); } break; case WAV_ENV_DECAY: { if (wave_env_ticks++ < wave_env_decay) { @@ -401,11 +445,7 @@ env_start: // Decay. int powers[] = { - // FP_NUM(1,8), 230, 205, 192, 150, 100, 50, 0 - // 256, 128, 85, 64, 51, 43, 37, 32, 28, 0 // Logarithmic volume range. - // 256, 245, 224, 202, 177, 150, 120, 86, 47, 0, - // 0., 57., 104., 143., 177., 208., 235., 259. 256, 235, 208, 177, 143, 104, 57, 0 }; int power = powers[wave_env_prog]; -- cgit v1.2.1