Compare commits
4 Commits
787bf50957
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 052ac9eb17 | |||
| e9564f42eb | |||
| bd2ac926b0 | |||
| a8c231df50 |
Vendored
+10
-20
@@ -1,32 +1,22 @@
|
|||||||
{
|
{
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "Cortex Debug",
|
"name": "Cortex Debug (Pico 2W / RP2350)",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"executable": "${command:cmake.launchTargetPath}",
|
"executable": "${workspaceRoot}/build/sint-gauntlet.elf",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "cortex-debug",
|
"type": "cortex-debug",
|
||||||
"servertype": "openocd",
|
"servertype": "external",
|
||||||
"gdbPath": "gdb-multiarch",
|
"gdbPath": "arm-none-eabi-gdb",
|
||||||
"serverArgs": [
|
"gdbTarget": "localhost:3333",
|
||||||
|
"device": "RP2350",
|
||||||
],
|
"svdFile": "${env:PICO_SDK_PATH}/src/rp2350/hardware_regs/rp2350.svd",
|
||||||
"device": "RP2040",
|
|
||||||
"configFiles": [
|
|
||||||
"interface/raspberrypi-swd.cfg",
|
|
||||||
"target/rp2040.cfg"
|
|
||||||
],
|
|
||||||
"svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd",
|
|
||||||
"runToEntryPoint": "main",
|
"runToEntryPoint": "main",
|
||||||
// Give restart the same functionality as runToEntryPoint - main
|
|
||||||
"postRestartCommands": [
|
"postRestartCommands": [
|
||||||
"break main",
|
"break main",
|
||||||
"continue"
|
"continue"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -58,10 +58,13 @@ target_include_directories(sint-gauntlet PRIVATE
|
|||||||
|
|
||||||
# Add any user requested libraries
|
# Add any user requested libraries
|
||||||
target_link_libraries(sint-gauntlet
|
target_link_libraries(sint-gauntlet
|
||||||
|
pico_stdlib
|
||||||
|
pico_cyw43_arch_none
|
||||||
hardware_pio
|
hardware_pio
|
||||||
hardware_interp
|
hardware_interp
|
||||||
hardware_timer
|
hardware_timer
|
||||||
hardware_clocks
|
hardware_clocks
|
||||||
|
hardware_sync
|
||||||
hardware_pwm
|
hardware_pwm
|
||||||
hardware_adc
|
hardware_adc
|
||||||
pico_multicore
|
pico_multicore
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
DISK_ID=usb-RPI_RP2350_6F361FE334DD320F-0
|
DISK_ID=usb-RPI_RP2350_DD85828F2371B53B-0:0
|
||||||
|
#DISK_ID=usb-RPI_RP2350_6F361FE334DD320F-0:0
|
||||||
TARGET=sint-gauntlet.uf2
|
TARGET=sint-gauntlet.uf2
|
||||||
|
|
||||||
cd ./build
|
cd ./build
|
||||||
cmake ..
|
cmake ..
|
||||||
make -j
|
make -j
|
||||||
sudo mount "/dev/disk/by-id/$DISK_ID:0-part1" /mnt
|
sudo mount "/dev/disk/by-id/$DISK_ID-part1" /mnt
|
||||||
sudo cp $TARGET /mnt
|
sudo cp $TARGET /mnt
|
||||||
sync
|
sync
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +1,72 @@
|
|||||||
#include <hardware/adc.h>
|
#include <hardware/adc.h>
|
||||||
#include <hardware/gpio.h>
|
#include <hardware/gpio.h>
|
||||||
|
#include <math.h>
|
||||||
#include <pico/stdlib.h>
|
#include <pico/stdlib.h>
|
||||||
#include <pico/time.h>
|
#include <pico/time.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <math.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
|
||||||
bool is_toggle[BUTTON_COUNT] = { false };
|
bool is_toggle[BUTTON_COUNT] = {false};
|
||||||
bool btn_prev[BUTTON_COUNT] = { false };
|
bool btn_prev[BUTTON_COUNT] = {false};
|
||||||
|
|
||||||
void set_mux_addr(uint8_t addr) {
|
void set_mux_addr(uint8_t addr) {
|
||||||
gpio_put(MUX_S0, addr & 1);
|
gpio_put(MUX_S0, addr & 1);
|
||||||
gpio_put(MUX_S1, (addr >> 1) & 1);
|
gpio_put(MUX_S1, (addr >> 1) & 1);
|
||||||
gpio_put(MUX_S2, (addr >> 2) & 1);
|
gpio_put(MUX_S2, (addr >> 2) & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_inputs(input_t* input) {
|
void update_pot(input_t *input) {
|
||||||
// Pots
|
static volatile uint function_call_counter = 0;
|
||||||
for (uint8_t j = 0; j < 2; j++) {
|
function_call_counter++;
|
||||||
adc_select_input(j);
|
static uint8_t i = 0;
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
for (; i < 2; i++, adc_select_input(i)) {
|
||||||
set_mux_addr(i);
|
{
|
||||||
sleep_us(50); // Let multiplexers multiplex
|
static uint8_t j = 0;
|
||||||
float old_val = input->buttons[i + j * 8];
|
for (; j < 8;) {
|
||||||
float new_val = (float)adc_read() / 4096.0f;
|
set_mux_addr(j);
|
||||||
if (fabs(new_val - old_val) >= 0.01f) input->pots[i + j * 8] = new_val;
|
sleep_ms(5); // Let multiplexers multiplex (5ms smallest reliable delay)
|
||||||
}
|
float old_val = input->pots[j + i * 8];
|
||||||
}
|
float new_val = (float)adc_read() / 4096.0f;
|
||||||
|
|
||||||
// Buttons
|
if (!(new_val > 0.99f) && (fabs(new_val - old_val) >= 0.01f)) {
|
||||||
for (uint8_t i = 0; i < BUTTON_COUNT; i++) {
|
|
||||||
bool btn_curr = gpio_get(BUTTON_BASE + i);
|
|
||||||
|
|
||||||
if (btn_curr == true && btn_prev[i] == false) {
|
input->pots[j + i * 8] = new_val;
|
||||||
if (is_toggle[i]) input->buttons[i] = !input->buttons[i];
|
}
|
||||||
}
|
|
||||||
|
j++;
|
||||||
if (!is_toggle[i]) input->buttons[i] = btn_curr;
|
return;
|
||||||
|
}
|
||||||
btn_prev[i] = btn_curr;
|
j = 0;
|
||||||
sleep_ms(1); // Why don't you bounce on this dihh
|
}
|
||||||
}
|
}
|
||||||
|
i = 0;
|
||||||
|
adc_select_input(i);
|
||||||
|
sleep_ms(5);
|
||||||
|
update_pot(input); // dont skip the tick
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update_inputs(input_t *input) {
|
||||||
|
|
||||||
|
// Pots
|
||||||
|
update_pot(input);
|
||||||
|
__asm__("nop");
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
for (uint8_t i = 0; i < BUTTON_COUNT; i++) {
|
||||||
|
bool btn_curr = gpio_get(BUTTON_BASE + i);
|
||||||
|
|
||||||
|
if (btn_curr == true && btn_prev[i] == false) {
|
||||||
|
if (is_toggle[i])
|
||||||
|
input->buttons[i] = !input->buttons[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_toggle[i])
|
||||||
|
input->buttons[i] = btn_curr;
|
||||||
|
|
||||||
|
btn_prev[i] = btn_curr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
|
#include "pico/cyw43_arch.h"
|
||||||
|
#include <arm_acle.h>
|
||||||
#include <hardware/irq.h>
|
#include <hardware/irq.h>
|
||||||
|
#include <hardware/sync.h>
|
||||||
#include <pico/stdio.h>
|
#include <pico/stdio.h>
|
||||||
#include <pico/time.h>
|
#include <pico/time.h>
|
||||||
#include <stdnoreturn.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdnoreturn.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "hardware/gpio.h"
|
#include "hardware/gpio.h"
|
||||||
#include "hardware/pwm.h"
|
#include "hardware/pwm.h"
|
||||||
@@ -70,30 +73,58 @@ void core1_init(void) {
|
|||||||
set_toggle_button(2, true);
|
set_toggle_button(2, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void debug_print(void) {
|
||||||
|
printf("\x1b[H\x1b[J");
|
||||||
|
printf("0: %f, 1: %f, 2: %f, 3: %f, 4: %f, 5: %f, 6: %f, 7: %f\n",
|
||||||
|
input.pots[0], input.pots[1], input.pots[2], input.pots[3],
|
||||||
|
input.pots[4], input.pots[5], input.pots[6], input.pots[7]);
|
||||||
|
printf(
|
||||||
|
"vco_freq: %f\n"
|
||||||
|
"vco_volume: %f\n"
|
||||||
|
"filter_freq: %f\n"
|
||||||
|
"filter_resonance: %f\n"
|
||||||
|
"clock_bpm: %f\n"
|
||||||
|
"env1_attack: %f\n"
|
||||||
|
"env1_decay: %f\n"
|
||||||
|
"env2_attack: %f\n"
|
||||||
|
"env2_decay: %f\n"
|
||||||
|
"reverb_amount: %f\n",
|
||||||
|
state.vco_freq,
|
||||||
|
state.vco_volume,
|
||||||
|
state.filter_freq,
|
||||||
|
state.filter_resonance,
|
||||||
|
state.clock_bpm,
|
||||||
|
state.env1_attack,
|
||||||
|
state.env1_decay,
|
||||||
|
state.env2_attack,
|
||||||
|
state.env2_decay,
|
||||||
|
state.reverb_amount
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
noreturn void core1_loop(void) {
|
noreturn void core1_loop(void) {
|
||||||
while (1) {
|
while (1) {
|
||||||
update_inputs(&input);
|
update_inputs(&input);
|
||||||
update_state(&state, &input);
|
update_state(&state, &input);
|
||||||
printf("%d %f\n", input.buttons[0], input.pots[0]);
|
|
||||||
printf("%d\n", input.buttons[1]);
|
|
||||||
printf("%d\n", input.buttons[2]);
|
|
||||||
printf("%d\n", input.buttons[3]);
|
|
||||||
sleep_ms(1);
|
sleep_ms(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
noreturn void core0_loop(void) {
|
noreturn void core0_loop(void) {
|
||||||
while (1) {
|
while (1) __wfi();
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
core0_init();
|
if (cyw43_arch_init())
|
||||||
core1_init();
|
return -1;
|
||||||
|
|
||||||
multicore_launch_core1(core1_loop);
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); // sign of life
|
||||||
core0_loop();
|
|
||||||
|
core1_init();
|
||||||
|
core0_init();
|
||||||
|
|
||||||
|
multicore_launch_core1(core1_loop);
|
||||||
|
core0_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,45 @@
|
|||||||
#include <stdio.h>
|
#include "const.h"
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
|
||||||
void update_state(state_t* state, input_t* input) {
|
float quantize(float freq) {
|
||||||
puts("AHHHHHH");
|
if (freq <= 0.0f) return 0.0f;
|
||||||
|
float midi = 69.0f + 12.0f * log2f(freq / 440.0f);
|
||||||
|
return 440.0f * powf(2.0f, (roundf(midi) - 69.0f) / 12.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void update_state(state_t* state, input_t* input) {
|
||||||
|
state->vco_freq = map_exponential(input->pots[0], VCO_FREQ_MIN, VCO_FREQ_MAX);
|
||||||
|
state->vco_volume = map_exponential(input->pots[1], VCO_VOLUME_MIN, VCO_VOLUME_MAX);
|
||||||
|
state->filter_freq = map_exponential(input->pots[2], FILTER_FREQ_MIN, FILTER_FREQ_MAX);
|
||||||
|
state->filter_resonance = map_linear(input->pots[3], FILTER_RES_MIN, FILTER_RES_MAX);
|
||||||
|
state->clock_bpm = map_linear(input->pots[4], BPM_MIN, BPM_MAX);
|
||||||
|
state->env1_attack = map_linear(input->pots[5], ENV_ATTACK_MIN, ENV_ATTACK_MAX);
|
||||||
|
state->env1_decay = map_linear(input->pots[6], ENV_RELEASE_MIN, ENV_RELEASE_MAX);
|
||||||
|
state->env2_attack = map_linear(input->pots[7], ENV_ATTACK_MIN, ENV_ATTACK_MAX);
|
||||||
|
state->env2_decay = map_linear(input->pots[8], ENV_RELEASE_MIN, ENV_RELEASE_MAX);
|
||||||
|
state->reverb_amount = map_linear(input->pots[9], REVERB_AMOUNT_MIN, REVERB_AMOUNT_MAX);
|
||||||
|
|
||||||
|
static bool pressed = false;
|
||||||
|
if (!pressed && input->buttons[0]) {
|
||||||
|
state->vco_mode = (vco_mode_t)((state->vco_mode + 1) % 4);
|
||||||
|
pressed = true;
|
||||||
|
} else pressed = false;
|
||||||
|
|
||||||
|
|
||||||
|
if (input->buttons[1]) {
|
||||||
|
if (state->vco_freq <= 0.0f) state->vco_freq = 0.0f;
|
||||||
|
else state->vco_freq = quantize(state->vco_freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
state->amen_enabled = input->buttons[2];
|
||||||
|
//state->amen_enabled = true;
|
||||||
|
|
||||||
|
state->beat_samples = SAMPLE_RATE * 60.0f / state->clock_bpm;
|
||||||
|
state->playback_rate = state->clock_bpm / AMEN_BPM;
|
||||||
|
state->clock_inc = state->clock_bpm / 60.0f / SAMPLE_RATE;
|
||||||
|
state->amen_inc_fp = (uint32_t)(state->playback_rate * 65536.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,48 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "vco.h"
|
#include "vco.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float clock_bpm;
|
float clock_bpm;
|
||||||
|
|
||||||
float vco_freq;
|
float vco_freq;
|
||||||
float vco_volume;
|
float vco_volume;
|
||||||
vco_mode_t vco_mode;
|
vco_mode_t vco_mode;
|
||||||
|
|
||||||
float filter_freq;
|
float filter_freq;
|
||||||
float filter_resonance;
|
float filter_resonance;
|
||||||
|
|
||||||
float env1_attack;
|
float env1_attack;
|
||||||
float env1_release;
|
float env1_decay;
|
||||||
float env2_attack;
|
float env2_attack;
|
||||||
float env2_release;
|
float env2_decay;
|
||||||
|
|
||||||
float reverb_amount;
|
float reverb_amount;
|
||||||
bool quant_enabled;
|
bool quant_enabled;
|
||||||
bool amen_enabled;
|
bool amen_enabled;
|
||||||
|
float beat_samples;
|
||||||
|
float playback_rate;
|
||||||
|
float clock_inc;
|
||||||
|
uint32_t amen_inc_fp;
|
||||||
} state_t;
|
} state_t;
|
||||||
|
|
||||||
|
static inline float map_linear(float v, float min, float max) {
|
||||||
|
return min + v * (max - min);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float map_exponential(float v, float min, float max) {
|
||||||
|
if (min == 0.0f) min = 1e-6f;
|
||||||
|
return min * powf(max / min, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float map_squared(float v, float min, float max) {
|
||||||
|
return min + (v * v) * (max - min);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float max_constant(float _0, float val, float _1) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
void update_state(state_t* state, input_t* input);
|
void update_state(state_t* state, input_t* input);
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +1,25 @@
|
|||||||
#include <math.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "daisysp.h"
|
#include "daisysp.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
#include "vco.h"
|
#include "vco.h"
|
||||||
#include "dsp.h"
|
|
||||||
|
|
||||||
#include "synth.h"
|
#include "synth.h"
|
||||||
|
|
||||||
using namespace daisysp;
|
using namespace daisysp;
|
||||||
|
|
||||||
static state_t* state;
|
static state_t* state = NULL;
|
||||||
|
|
||||||
Oscillator osc;
|
Oscillator osc;
|
||||||
Svf filter;
|
Svf filter;
|
||||||
AdEnv vco_env;
|
AdEnv vco_env;
|
||||||
AdEnv filter_env;
|
AdEnv filter_env;
|
||||||
|
|
||||||
DelayLine<float, COMB0_SIZE> comb0;
|
|
||||||
DelayLine<float, COMB1_SIZE> comb1;
|
|
||||||
DelayLine<float, COMB2_SIZE> comb2;
|
|
||||||
DelayLine<float, COMB3_SIZE> comb3;
|
|
||||||
DelayLine<float, AP0_SIZE> ap0;
|
|
||||||
DelayLine<float, AP1_SIZE> ap1;
|
|
||||||
|
|
||||||
float clock_phase = 0.0f;
|
float clock_phase = 0.0f;
|
||||||
bool clock_trig = false;
|
bool clock_trig = false;
|
||||||
|
|
||||||
float amen_phase = 0.0f;
|
uint32_t amen_phase_fp = 0;
|
||||||
float amen_length = 0.0f;
|
float amen_length = 0.0f;
|
||||||
|
|
||||||
static inline auto vco_mode_to_daisy(vco_mode_t mode) {
|
static inline auto vco_mode_to_daisy(vco_mode_t mode) {
|
||||||
@@ -41,104 +32,45 @@ static inline auto vco_mode_to_daisy(vco_mode_t mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline float pot_to_freq(float v, float min, float max) { return min * powf(max / min, v); }
|
|
||||||
|
|
||||||
static inline float pot_to_time(float v, float min, float max) { return min * powf(max / min, v); }
|
|
||||||
|
|
||||||
static inline float quantize(float freq, float temp) {
|
|
||||||
float midi = temp * log2f(freq / 440.0f) + 69.0f;
|
|
||||||
float note = roundf(midi);
|
|
||||||
return 440.0f * powf(2.0f, (note - 69.0f) / temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float low_pass(float in, float* z, float coeff) {
|
|
||||||
*z += coeff * (in - *z);
|
|
||||||
return *z;
|
|
||||||
}
|
|
||||||
|
|
||||||
float reverb(float in, float amount) {
|
|
||||||
static float damp0 = 0.0f, damp1 = 0.0f, damp2 = 0.0f, damp3 = 0.0f;
|
|
||||||
float feedback = 0.84f;
|
|
||||||
float damp = 0.3f;
|
|
||||||
|
|
||||||
float c0 = comb0.Read(); low_pass(in + c0 * feedback, &damp0, damp); comb0.Write(damp0);
|
|
||||||
float c1 = comb1.Read(); low_pass(in + c1 * feedback, &damp1, damp); comb1.Write(damp1);
|
|
||||||
float c2 = comb2.Read(); low_pass(in + c2 * feedback, &damp2, damp); comb2.Write(damp2);
|
|
||||||
float c3 = comb3.Read(); low_pass(in + c3 * feedback, &damp3, damp); comb3.Write(damp3);
|
|
||||||
|
|
||||||
float wet = (c0 + c1 + c2 + c3) * 0.25f;
|
|
||||||
|
|
||||||
const float g = 0.7f;
|
|
||||||
float a0r = ap0.Read();
|
|
||||||
float a0in = wet + (-g * a0r);
|
|
||||||
ap0.Write(a0in);
|
|
||||||
wet = a0r + g * a0in;
|
|
||||||
|
|
||||||
float a1r = ap1.Read();
|
|
||||||
float a1in = wet + (-g * a1r);
|
|
||||||
ap1.Write(a1in);
|
|
||||||
wet = a1r + g * a1in;
|
|
||||||
|
|
||||||
return in + amount * (wet - in);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "amenbreak.h"
|
#include "amenbreak.h"
|
||||||
|
|
||||||
float amenbreak(float beat_samples, float playback_rate) {
|
|
||||||
amen_length = beat_samples * 4.0f * AMEN_BARS;
|
|
||||||
|
|
||||||
uint32_t idx0 = (uint32_t)amen_phase % amen_sample_count;
|
float amenbreak() {
|
||||||
uint32_t idx1 = (idx0 + 1) % amen_sample_count;
|
amen_phase_fp += state->amen_inc_fp;
|
||||||
float frac = amen_phase - floorf(amen_phase);
|
|
||||||
float s0 = amen_samples[idx0] * (1.0f / 32768.0f);
|
uint32_t idx0 = (amen_phase_fp >> 16) % amen_sample_count;
|
||||||
float s1 = amen_samples[idx1] * (1.0f / 32768.0f);
|
uint32_t idx1 = (idx0 + 1) % amen_sample_count;
|
||||||
float amen_out = s0 + frac * (s1 - s0);
|
|
||||||
|
float frac = (float)(amen_phase_fp & 0xFFFF) * 0.0000152588f;
|
||||||
amen_phase += playback_rate;
|
|
||||||
if (amen_phase >= amen_length) amen_phase -= amen_length;
|
const float INV_INT16 = 0.00003051757f;
|
||||||
return amen_out;
|
float s0 = amen_samples[idx0] * INV_INT16;
|
||||||
|
float s1 = amen_samples[idx1] * INV_INT16;
|
||||||
|
|
||||||
|
return s0 + frac * (s1 - s0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void synth_init(state_t* state) {
|
void synth_init(state_t* _state) {
|
||||||
|
state = _state;
|
||||||
osc.Init(SAMPLE_RATE);
|
osc.Init(SAMPLE_RATE);
|
||||||
osc.SetWaveform(vco_mode_to_daisy(VCO_SAW));
|
|
||||||
osc.SetFreq(440.0f);
|
|
||||||
osc.SetAmp(1.0f);
|
|
||||||
|
|
||||||
filter.Init(SAMPLE_RATE);
|
filter.Init(SAMPLE_RATE);
|
||||||
filter.SetFreq(2000.0f);
|
|
||||||
filter.SetRes(0.0f);
|
|
||||||
|
|
||||||
vco_env.Init(SAMPLE_RATE);
|
vco_env.Init(SAMPLE_RATE);
|
||||||
vco_env.SetTime(ADENV_SEG_ATTACK, 0.01f);
|
|
||||||
vco_env.SetTime(ADENV_SEG_DECAY, 0.8f);
|
|
||||||
vco_env.SetMin(0.0f);
|
vco_env.SetMin(0.0f);
|
||||||
vco_env.SetMax(1.0f);
|
vco_env.SetMax(VCO_VOLUME_MAX);
|
||||||
|
|
||||||
filter_env.Init(SAMPLE_RATE);
|
filter_env.Init(SAMPLE_RATE);
|
||||||
filter_env.SetTime(ADENV_SEG_ATTACK, 0.01f);
|
|
||||||
filter_env.SetTime(ADENV_SEG_DECAY, 0.5f);
|
|
||||||
filter_env.SetMin(0.0f);
|
filter_env.SetMin(0.0f);
|
||||||
filter_env.SetMax(2000.0f);
|
filter_env.SetMax(FILTER_FREQ_MAX);
|
||||||
|
|
||||||
state->clock_bpm = 0.1f;
|
|
||||||
|
|
||||||
clock_phase = 0.0f;
|
clock_phase = 0.0f;
|
||||||
clock_trig = false;
|
clock_trig = false;
|
||||||
|
amen_phase_fp = 0;
|
||||||
amen_phase = 0.0f;
|
|
||||||
state->amen_enabled = true;
|
|
||||||
state->reverb_amount = 1.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float get_sample(void) {
|
float get_sample(void) {
|
||||||
float bpm = BPM_MIN + state->clock_bpm * (BPM_MAX - BPM_MIN);
|
if (state == NULL) return 0.0f;
|
||||||
float beat_samples = SAMPLE_RATE * 60.0f / bpm;
|
|
||||||
float playback_rate = bpm / AMEN_BPM;
|
|
||||||
|
|
||||||
float clock_inc = bpm / 60.0f / SAMPLE_RATE;
|
bool clock_trig = false;
|
||||||
clock_phase += clock_inc;
|
|
||||||
clock_trig = false;
|
clock_phase += state->clock_inc;
|
||||||
if (clock_phase >= 1.0f) {
|
if (clock_phase >= 1.0f) {
|
||||||
clock_phase -= 1.0f;
|
clock_phase -= 1.0f;
|
||||||
clock_trig = true;
|
clock_trig = true;
|
||||||
@@ -149,42 +81,35 @@ float get_sample(void) {
|
|||||||
filter_env.Trigger();
|
filter_env.Trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
vco_env.SetTime(ADENV_SEG_ATTACK, pot_to_time(state->env1_attack, ENV_ATTACK_MIN, ENV_ATTACK_MAX));
|
vco_env.SetTime(ADENV_SEG_ATTACK, state->env1_attack);
|
||||||
vco_env.SetTime(ADENV_SEG_DECAY, pot_to_time(state->env1_release, ENV_RELEASE_MIN, ENV_RELEASE_MAX));
|
vco_env.SetTime(ADENV_SEG_DECAY, state->env1_decay);
|
||||||
filter_env.SetTime(ADENV_SEG_ATTACK, pot_to_time(state->env2_attack, ENV_ATTACK_MIN, ENV_ATTACK_MAX));
|
filter_env.SetTime(ADENV_SEG_ATTACK, state->env2_attack);
|
||||||
filter_env.SetTime(ADENV_SEG_DECAY, pot_to_time(state->env2_release, ENV_RELEASE_MIN, ENV_RELEASE_MAX));
|
filter_env.SetTime(ADENV_SEG_DECAY, state->env2_decay);
|
||||||
|
|
||||||
float vco_env_out = vco_env.Process();
|
float vco_env_out = vco_env.Process();
|
||||||
float filter_env_out = filter_env.Process();
|
float filter_env_out = filter_env.Process();
|
||||||
|
// make it emit only continuous tone
|
||||||
float vco_freq = pot_to_freq(state->vco_freq, VCO_FREQ_MIN, VCO_FREQ_MAX);
|
// float vco_env_out = 1.0f;
|
||||||
if (state->quant_enabled) vco_freq = quantize(vco_freq, 12.0f);
|
// float filter_env_out = 0.0f;
|
||||||
|
|
||||||
//osc.SetFreq(vco_freq);
|
|
||||||
static int n = VCO_SINE;
|
|
||||||
osc.SetWaveform(vco_mode_to_daisy((vco_mode_t)(n++ % 4)));
|
|
||||||
//osc.SetAmp(1.0f);
|
|
||||||
|
|
||||||
|
osc.SetFreq(state->vco_freq);
|
||||||
|
osc.SetWaveform(vco_mode_to_daisy(state->vco_mode));
|
||||||
|
osc.SetAmp(1.0f);
|
||||||
float vco_out = osc.Process();
|
float vco_out = osc.Process();
|
||||||
|
|
||||||
float base_cutoff = pot_to_freq(state->filter_freq, FILTER_FREQ_MIN, FILTER_FREQ_MAX);
|
float cutoff = state->filter_freq + filter_env_out;
|
||||||
float mod_cutoff = base_cutoff + filter_env_out * (FILTER_FREQ_MAX - FILTER_FREQ_MIN);
|
if (cutoff > 16000.0f) cutoff = 16000.0f;
|
||||||
mod_cutoff = fclamp(mod_cutoff, FILTER_FREQ_MIN, FILTER_FREQ_MAX);
|
|
||||||
|
|
||||||
//filter.SetFreq(mod_cutoff);
|
filter.SetFreq(cutoff);
|
||||||
//filter.SetRes(state.filter_resonance);
|
filter.SetRes(state->filter_resonance);
|
||||||
filter.Process(vco_out);
|
filter.Process(vco_out);
|
||||||
float filtered = filter.Low();
|
|
||||||
|
|
||||||
float vca_out = filtered * vco_env_out;// * state.vco_volume;
|
float vca_out = filter.Low() * vco_env_out * state->vco_volume;
|
||||||
|
float amen_out = state->amen_enabled ? amenbreak() : 0.0f;
|
||||||
|
float mix = vca_out + amen_out;
|
||||||
|
|
||||||
float reverb_out = vca_out; //reverb(vca_out, state.reverb_amount);
|
if (mix > 1.0f) return 1.0f;
|
||||||
|
if (mix < -1.0f) return -1.0f;
|
||||||
float amen_out = 0.0f;
|
|
||||||
if (state->amen_enabled) amen_out = amenbreak(beat_samples, playback_rate);
|
|
||||||
|
|
||||||
float mix = reverb_out + amen_out;
|
|
||||||
mix = fclamp(mix, -1.0f, 1.0f);
|
|
||||||
|
|
||||||
return mix;
|
return mix;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user