mirror of
https://github.com/jhbruhn/eurorack.git
synced 2025-03-15 02:55:49 +00:00
Add ability to change response curve of volume CV and volume pot
This commit is contained in:
parent
243f960a59
commit
48c256a2ef
7 changed files with 50 additions and 24 deletions
|
@ -32,6 +32,7 @@ FAMILY = f0xx
|
||||||
#APPLICATION = true
|
#APPLICATION = true
|
||||||
#BOOTLOADER = midi2cv_bootloader
|
#BOOTLOADER = midi2cv_bootloader
|
||||||
OPTIMIZE = TRUE
|
OPTIMIZE = TRUE
|
||||||
|
OPTIMIZE_FLAG = 1
|
||||||
# Preferred upload command
|
# Preferred upload command
|
||||||
UPLOAD_COMMAND = upload_jtag
|
UPLOAD_COMMAND = upload_jtag
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#include "processor.h"
|
#include "processor.h"
|
||||||
#include "stmlib/stmlib.h"
|
#include "stmlib/stmlib.h"
|
||||||
|
#include "stmlib/utils/dsp.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
using namespace stereo_mix;
|
using namespace stereo_mix;
|
||||||
|
using namespace stmlib;
|
||||||
|
|
||||||
const int kVolumeFilterValue = 4095;
|
const int kVolumeFilterValue = 65535;
|
||||||
|
|
||||||
void Processor::Process(int16_t cvs[], uint16_t* outs)
|
void Processor::Process(int16_t cvs[], uint16_t* outs)
|
||||||
{
|
{
|
||||||
|
@ -16,28 +18,33 @@ void Processor::Process(int16_t cvs[], uint16_t* outs)
|
||||||
int16_t pan_cv = cvs[0] >> (16 - 12);
|
int16_t pan_cv = cvs[0] >> (16 - 12);
|
||||||
int16_t vol_cv = cvs[1] >> (16 - 12);
|
int16_t vol_cv = cvs[1] >> (16 - 12);
|
||||||
int32_t pan = pan_pot + pan_cv;
|
int32_t pan = pan_pot + pan_cv;
|
||||||
int32_t vol = vol_pot + vol_cv;
|
int32_t lin = volume_offset + (cvs[1] * 2);
|
||||||
CONSTRAIN(pan, 0, (1 << 12) - 1);
|
CONSTRAIN(lin, 0, 65535);
|
||||||
CONSTRAIN(vol, 0, (1 << 12) - 1);
|
lin *= !mute;
|
||||||
|
linear_vol = lin;
|
||||||
|
|
||||||
if (mute) {
|
uint16_t vol_pot_exp = lut_linear_to_exp[vol_pot];
|
||||||
vol = 0;
|
uint16_t vol_pot_log = 65535 - lut_linear_to_exp[LUT_LINEAR_TO_EXP_SIZE - 1 - vol_pot];
|
||||||
}
|
|
||||||
|
|
||||||
if (vol > previous_vol + kVolumeFilterValue) {
|
vol_pot = Mix(vol_pot_exp, vol_pot_log, log_exp_mix_pot);
|
||||||
vol = previous_vol + kVolumeFilterValue;
|
|
||||||
} else if (vol < previous_vol - kVolumeFilterValue) {
|
|
||||||
vol = previous_vol - kVolumeFilterValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CONSTRAIN(pan, 0, (1 << 12) - 1);
|
uint16_t vol_cv_absu16 = abs(vol_cv) << 1;
|
||||||
CONSTRAIN(vol, 0, (1 << 12) - 1);
|
uint16_t vol_cv_exp = lut_linear_to_exp[vol_cv_absu16];
|
||||||
|
uint16_t vol_cv_log = 65535 - lut_linear_to_exp[LUT_LINEAR_TO_EXP_SIZE - 1 - vol_cv_absu16];
|
||||||
|
uint16_t vol_cv_pre = Mix(vol_cv_exp, vol_cv_log, log_exp_mix_cv);
|
||||||
|
int32_t vol = vol_pot;
|
||||||
|
vol += vol_cv > 0 ? vol_cv_pre : -vol_cv_pre;
|
||||||
|
|
||||||
|
vol *= !mute;
|
||||||
|
|
||||||
|
CONSTRAIN(pan, 0, (1 << 16) - 1);
|
||||||
|
CONSTRAIN(vol, 0, (1 << 16) - 1);
|
||||||
|
|
||||||
previous_vol = vol;
|
previous_vol = vol;
|
||||||
|
|
||||||
// leds.set_intensity(i, vol >> 4);
|
// leds.set_intensity(i, vol >> 4);
|
||||||
value_l = (lut_left_sin_pan[pan] * lut_linear_to_exp[vol]) >> 16;
|
value_l = (lut_left_sin_pan[pan] * vol) >> 16;
|
||||||
value_r = (lut_right_cos_pan[pan] * lut_linear_to_exp[vol]) >> 16;
|
value_r = (lut_right_cos_pan[pan] * vol) >> 16;
|
||||||
|
|
||||||
outs[0] = value_r;
|
outs[0] = value_r;
|
||||||
outs[1] = value_l;
|
outs[1] = value_l;
|
||||||
|
|
|
@ -22,13 +22,18 @@ class Processor {
|
||||||
mute = m;
|
mute = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t previous_volume() {
|
uint16_t linear_volume() {
|
||||||
return previous_vol;
|
return linear_vol;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t volume_offset = 0;
|
uint16_t volume_offset = 0;
|
||||||
int16_t pan_offset = 0;
|
int16_t pan_offset = 0;
|
||||||
uint16_t previous_vol;
|
uint16_t previous_vol;
|
||||||
|
uint16_t linear_vol;
|
||||||
|
|
||||||
|
uint16_t log_exp_mix_cv = 32767; // -> linear
|
||||||
|
uint16_t log_exp_mix_pot = 0;
|
||||||
|
|
||||||
bool mute = false;
|
bool mute = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import matplotlib
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
lookup_tables_u16 = []
|
lookup_tables_u16 = []
|
||||||
lookup_tables_u8 = []
|
lookup_tables_u8 = []
|
||||||
|
|
||||||
|
@ -7,11 +10,22 @@ OUTPUT_RESOLUTION = 2 ** 16 - 1
|
||||||
|
|
||||||
# linear to exponential conversion
|
# linear to exponential conversion
|
||||||
|
|
||||||
values = np.linspace(0, 1, num=ADC_RESOLUTION)
|
space = np.linspace(0, 1, num=ADC_RESOLUTION)
|
||||||
values = np.power(values, 2) * OUTPUT_RESOLUTION
|
values = np.power(space, 2) * OUTPUT_RESOLUTION
|
||||||
|
|
||||||
lookup_tables_u16.append(('linear_to_exp', values))
|
lookup_tables_u16.append(('linear_to_exp', values))
|
||||||
|
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
ax.plot(space, values)
|
||||||
|
other_values = OUTPUT_RESOLUTION - np.flip(values)
|
||||||
|
ax.plot(space, OUTPUT_RESOLUTION - (np.flip(values)))
|
||||||
|
ax.plot(space, values / 2 + other_values / 2)
|
||||||
|
|
||||||
|
ax.set(xlabel='space', ylabel='values')
|
||||||
|
ax.grid()
|
||||||
|
|
||||||
|
#plt.show()
|
||||||
|
|
||||||
|
|
||||||
# Left pan Lookup table
|
# Left pan Lookup table
|
||||||
|
|
||||||
|
@ -34,4 +48,3 @@ max_out = 511
|
||||||
input_vals = np.linspace(0, max_in, num=max_in + 1)
|
input_vals = np.linspace(0, max_in, num=max_in + 1)
|
||||||
gamma_correction = ((input_vals / max_in) ** gamma) * max_out + 0.5
|
gamma_correction = ((input_vals / max_in) ** gamma) * max_out + 0.5
|
||||||
lookup_tables_u16.append(('led_gamma', np.floor(gamma_correction)))
|
lookup_tables_u16.append(('led_gamma', np.floor(gamma_correction)))
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/python2.5
|
#!/usr/bin/python
|
||||||
#
|
#
|
||||||
# Copyright 2016 Emilie Gillet.
|
# Copyright 2016 Emilie Gillet.
|
||||||
#
|
#
|
||||||
|
|
|
@ -145,7 +145,7 @@ void Init(void)
|
||||||
HAL_NVIC_EnableIRQ(TIM6_IRQn);
|
HAL_NVIC_EnableIRQ(TIM6_IRQn);
|
||||||
htim6.Init.Prescaler = 64;
|
htim6.Init.Prescaler = 64;
|
||||||
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
|
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||||
htim6.Init.Period = 96; //128; //256; //512;
|
htim6.Init.Period = 96; // 512 without optimize
|
||||||
htim6.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
htim6.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||||
htim6.Init.RepetitionCounter = 0;
|
htim6.Init.RepetitionCounter = 0;
|
||||||
HAL_TIM_Base_Init(&htim6);
|
HAL_TIM_Base_Init(&htim6);
|
||||||
|
|
|
@ -113,7 +113,7 @@ void UI::TaskDrawLeds()
|
||||||
leds->set_blinking(i, pan_pots[i] - 32767 < 0);
|
leds->set_blinking(i, pan_pots[i] - 32767 < 0);
|
||||||
} else {
|
} else {
|
||||||
// show volume if not muted
|
// show volume if not muted
|
||||||
leds->set_intensity(i, processors[i].previous_volume() >> (4));
|
leds->set_intensity(i, processors[i].linear_volume() >> (8));
|
||||||
leds->set_blinking(i, false);
|
leds->set_blinking(i, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue