mirror of
https://github.com/ravinrabbid/DonCon2040.git
synced 2024-11-20 03:37:07 +01:00
Simplify false hit detection
For now, only allow one input at a time
This commit is contained in:
parent
b17b98068a
commit
092eeb4f07
11
README.md
11
README.md
@ -47,7 +47,8 @@ Few things which you probably want to change more regularly can be changed using
|
||||
|
||||
- Controller emulation mode
|
||||
- LED brightness
|
||||
- Trigger thresholds and scale level
|
||||
- Trigger thresholds
|
||||
- Hold Time
|
||||
- Enter BOOTSEL mode for firmware flashing
|
||||
|
||||
Those settings are persisted to flash memory if you choose 'Save' when exiting the Menu and will survive power cycles.
|
||||
@ -60,14 +61,6 @@ The debounce delay also implicitly serves as the hold time of the input after a
|
||||
|
||||
If you notice dropped inputs even if the controller signals a hit on the LED/Display, try to increase this value.
|
||||
|
||||
### Trigger Scale Level
|
||||
|
||||
To avoid false inputs for very hard hits, trigger levels of the non-hit pads are scaled dynamically. The trigger scale level defines how much trigger levels are increased.
|
||||
|
||||
Increase the value if you get false inputs on hard hits, decrease if simultaneous left and right hits are not registered properly.
|
||||
|
||||
Mind that the scaling is non-linear and changes in the higher end of the scale level range have a much larger impact.
|
||||
|
||||
## Hardware
|
||||
|
||||
### IO Board
|
||||
|
@ -44,9 +44,8 @@ const Peripherals::Drum::Config drum_config = {
|
||||
80, // Don Right
|
||||
50, // Ka Right
|
||||
},
|
||||
230, // Trigger threshold scale level
|
||||
|
||||
50, // ADC sample count
|
||||
10, // ADC sample count
|
||||
25, // Debounce delay in milliseconds
|
||||
|
||||
true, // Use external ADC
|
||||
|
@ -32,7 +32,6 @@ class Drum {
|
||||
|
||||
AdcInputs adc_inputs;
|
||||
Thresholds trigger_thresholds;
|
||||
uint8_t trigger_threshold_scale_level;
|
||||
|
||||
uint8_t sample_count;
|
||||
uint16_t debounce_delay_ms;
|
||||
@ -51,6 +50,7 @@ class Drum {
|
||||
|
||||
private:
|
||||
enum class Id {
|
||||
NONE,
|
||||
DON_LEFT,
|
||||
KA_LEFT,
|
||||
DON_RIGHT,
|
||||
@ -64,11 +64,11 @@ class Drum {
|
||||
bool active;
|
||||
|
||||
public:
|
||||
Pad(uint8_t channel);
|
||||
Pad(const uint8_t channel);
|
||||
|
||||
uint8_t getChannel() const { return channel; };
|
||||
bool getState() const { return active; };
|
||||
void setState(bool state, uint16_t debounce_delay);
|
||||
void setState(const bool state, const uint16_t debounce_delay);
|
||||
};
|
||||
|
||||
class AdcInterface {
|
||||
@ -105,7 +105,6 @@ class Drum {
|
||||
|
||||
void setDebounceDelay(const uint16_t delay);
|
||||
void setThresholds(const Config::Thresholds &thresholds);
|
||||
void setThresholdScaleLevel(const uint8_t threshold_scale_level);
|
||||
};
|
||||
|
||||
} // namespace Doncon::Peripherals
|
||||
|
@ -23,7 +23,6 @@ class Menu {
|
||||
TriggerThresholdDonLeft,
|
||||
TriggerThresholdDonRight,
|
||||
TriggerThresholdKaRight,
|
||||
TriggerThresholdScaleLevel,
|
||||
DebounceDelay,
|
||||
LedBrightness,
|
||||
Reset,
|
||||
@ -54,7 +53,6 @@ class Menu {
|
||||
GotoPageTriggerThresholdDonLeft,
|
||||
GotoPageTriggerThresholdDonRight,
|
||||
GotoPageTriggerThresholdKaRight,
|
||||
GotoPageTriggerThresholdScaleLevel,
|
||||
GotoPageDebounceDelay,
|
||||
GotoPageLedBrightness,
|
||||
GotoPageReset,
|
||||
@ -74,7 +72,6 @@ class Menu {
|
||||
SetTriggerThresholdDonLeft,
|
||||
SetTriggerThresholdDonRight,
|
||||
SetTriggerThresholdKaRight,
|
||||
SetTriggerThresholdScaleLevel,
|
||||
SetDebounceDelay,
|
||||
SetLedBrightness,
|
||||
|
||||
|
@ -20,13 +20,11 @@ class SettingsStore {
|
||||
uint8_t in_use;
|
||||
usb_mode_t usb_mode;
|
||||
Peripherals::Drum::Config::Thresholds trigger_thresholds;
|
||||
uint8_t trigger_threshold_scale_level;
|
||||
uint8_t led_brightness;
|
||||
uint16_t debounce_delay;
|
||||
|
||||
uint8_t _padding[m_store_size - sizeof(uint8_t) - sizeof(usb_mode_t) -
|
||||
sizeof(Peripherals::Drum::Config::Thresholds) - sizeof(uint8_t) - sizeof(uint8_t) -
|
||||
sizeof(uint16_t)];
|
||||
sizeof(Peripherals::Drum::Config::Thresholds) - sizeof(uint8_t) - sizeof(uint16_t)];
|
||||
};
|
||||
static_assert(sizeof(Storecache) == m_store_size);
|
||||
|
||||
@ -53,9 +51,6 @@ class SettingsStore {
|
||||
void setTriggerThresholds(const Peripherals::Drum::Config::Thresholds &thresholds);
|
||||
Peripherals::Drum::Config::Thresholds getTriggerThresholds();
|
||||
|
||||
void setTriggerThresholdScaleLevel(const uint8_t threshold_scale_level);
|
||||
uint8_t getTriggerThresholdScaleLevel();
|
||||
|
||||
void setLedBrightness(const uint8_t brightness);
|
||||
uint8_t getLedBrightness();
|
||||
|
||||
|
@ -92,8 +92,6 @@ void core1_task() {
|
||||
|
||||
led.update();
|
||||
display.update();
|
||||
|
||||
// sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,7 +129,6 @@ int main() {
|
||||
|
||||
drum.setDebounceDelay(settings_store->getDebounceDelay());
|
||||
drum.setThresholds(settings_store->getTriggerThresholds());
|
||||
drum.setThresholdScaleLevel(settings_store->getTriggerThresholdScaleLevel());
|
||||
};
|
||||
|
||||
readSettings();
|
||||
|
@ -49,9 +49,9 @@ Drum::ExternalAdc::ExternalAdc(const Drum::Config::Spi &spi_config) : m_mcp3204(
|
||||
|
||||
uint16_t Drum::ExternalAdc::read(uint8_t channel) { return m_mcp3204.read(channel); }
|
||||
|
||||
Drum::Pad::Pad(uint8_t channel) : channel(channel), last_change(0), active(false) {}
|
||||
Drum::Pad::Pad(const uint8_t channel) : channel(channel), last_change(0), active(false) {}
|
||||
|
||||
void Drum::Pad::setState(bool state, uint16_t debounce_delay) {
|
||||
void Drum::Pad::setState(const bool state, const uint16_t debounce_delay) {
|
||||
if (active == state) {
|
||||
return;
|
||||
}
|
||||
@ -99,28 +99,37 @@ void Drum::updateInputState(Utils::InputState &input_state) {
|
||||
// Oversample ADC inputs to get rid of ADC noise
|
||||
const auto raw_values = sampleInputs();
|
||||
|
||||
const auto max_value = std::max_element(raw_values.cbegin(), raw_values.cend(),
|
||||
[](const auto a, const auto b) { return a.second < b.second; });
|
||||
|
||||
auto do_set_state = [&](const auto &id, const auto &threshold) {
|
||||
// Increase threshold for very hard hits to avoid false inputs on neighboring pads
|
||||
float mult = 1.0;
|
||||
if (id != max_value->first && m_config.trigger_threshold_scale_level > 0) {
|
||||
mult = float(max_value->second) / (((UINT8_MAX * 16) - (m_config.trigger_threshold_scale_level * 16)) + 1);
|
||||
mult = mult < 1.0 ? 1.0 : mult;
|
||||
}
|
||||
|
||||
if (raw_values.at(id) > (threshold * mult)) {
|
||||
m_pads.at(id).setState(true, m_config.debounce_delay_ms);
|
||||
} else {
|
||||
m_pads.at(id).setState(false, m_config.debounce_delay_ms);
|
||||
auto get_threshold = [&](const Id target) {
|
||||
switch (target) {
|
||||
case Id::DON_LEFT:
|
||||
return m_config.trigger_thresholds.don_left;
|
||||
case Id::DON_RIGHT:
|
||||
return m_config.trigger_thresholds.don_right;
|
||||
case Id::KA_LEFT:
|
||||
return m_config.trigger_thresholds.ka_left;
|
||||
case Id::KA_RIGHT:
|
||||
return m_config.trigger_thresholds.ka_right;
|
||||
case Id::NONE:
|
||||
return (uint16_t)0;
|
||||
}
|
||||
return (uint16_t)0;
|
||||
};
|
||||
|
||||
do_set_state(Id::DON_LEFT, m_config.trigger_thresholds.don_left);
|
||||
do_set_state(Id::KA_LEFT, m_config.trigger_thresholds.ka_left);
|
||||
do_set_state(Id::DON_RIGHT, m_config.trigger_thresholds.don_right);
|
||||
do_set_state(Id::KA_RIGHT, m_config.trigger_thresholds.ka_right);
|
||||
// Consider the hardest hit pad the one that actually was hit,
|
||||
const auto max_hit = std::max_element(raw_values.cbegin(), raw_values.cend(),
|
||||
[](const auto a, const auto b) { return a.second < b.second; });
|
||||
|
||||
if (max_hit->second > get_threshold(max_hit->first)) {
|
||||
m_pads.at(max_hit->first).setState(true, m_config.debounce_delay_ms);
|
||||
} else {
|
||||
m_pads.at(max_hit->first).setState(false, m_config.debounce_delay_ms);
|
||||
}
|
||||
|
||||
for (const auto &input : raw_values) {
|
||||
if (input.first != max_hit->first) {
|
||||
m_pads.at(input.first).setState(false, m_config.debounce_delay_ms);
|
||||
}
|
||||
}
|
||||
|
||||
input_state.drum.don_left.raw = raw_values.at(Id::DON_LEFT);
|
||||
input_state.drum.ka_left.raw = raw_values.at(Id::KA_LEFT);
|
||||
@ -137,8 +146,4 @@ void Drum::setDebounceDelay(const uint16_t delay) { m_config.debounce_delay_ms =
|
||||
|
||||
void Drum::setThresholds(const Config::Thresholds &thresholds) { m_config.trigger_thresholds = thresholds; }
|
||||
|
||||
void Drum::setThresholdScaleLevel(const uint8_t threshold_scale_level) {
|
||||
m_config.trigger_threshold_scale_level = threshold_scale_level;
|
||||
}
|
||||
|
||||
} // namespace Doncon::Peripherals
|
||||
|
@ -28,15 +28,14 @@ const std::map<Menu::Page, const Menu::Descriptor> Menu::descriptors = {
|
||||
{"Debug", Menu::Descriptor::Action::ChangeUsbModeDebug}}, //
|
||||
0}}, //
|
||||
|
||||
{Menu::Page::TriggerThreshold, //
|
||||
{Menu::Descriptor::Type::Selection, //
|
||||
"Sensitivity", //
|
||||
{{"Ka Left", Menu::Descriptor::Action::GotoPageTriggerThresholdKaLeft}, //
|
||||
{"Don Left", Menu::Descriptor::Action::GotoPageTriggerThresholdDonLeft}, //
|
||||
{"Don Right", Menu::Descriptor::Action::GotoPageTriggerThresholdDonRight}, //
|
||||
{"Ka Right", Menu::Descriptor::Action::GotoPageTriggerThresholdKaRight}, //
|
||||
{"Scale Lvl", Menu::Descriptor::Action::GotoPageTriggerThresholdScaleLevel}}, //
|
||||
0}}, //
|
||||
{Menu::Page::TriggerThreshold, //
|
||||
{Menu::Descriptor::Type::Selection, //
|
||||
"Sensitivity", //
|
||||
{{"Ka Left", Menu::Descriptor::Action::GotoPageTriggerThresholdKaLeft}, //
|
||||
{"Don Left", Menu::Descriptor::Action::GotoPageTriggerThresholdDonLeft}, //
|
||||
{"Don Right", Menu::Descriptor::Action::GotoPageTriggerThresholdDonRight}, //
|
||||
{"Ka Right", Menu::Descriptor::Action::GotoPageTriggerThresholdKaRight}}, //
|
||||
0}}, //
|
||||
|
||||
{Menu::Page::TriggerThresholdKaLeft, //
|
||||
{Menu::Descriptor::Type::Value, //
|
||||
@ -62,12 +61,6 @@ const std::map<Menu::Page, const Menu::Descriptor> Menu::descriptors = {
|
||||
{{"", Menu::Descriptor::Action::SetTriggerThresholdKaRight}}, //
|
||||
4095}},
|
||||
|
||||
{Menu::Page::TriggerThresholdScaleLevel, //
|
||||
{Menu::Descriptor::Type::Value, //
|
||||
"Sensitivity Scale Lvl", //
|
||||
{{"", Menu::Descriptor::Action::SetTriggerThresholdScaleLevel}}, //
|
||||
UINT8_MAX}},
|
||||
|
||||
{Menu::Page::DebounceDelay, //
|
||||
{Menu::Descriptor::Type::Value, //
|
||||
"Hit Hold Time (ms)", //
|
||||
@ -202,9 +195,6 @@ uint16_t Menu::getCurrentSelection(Menu::Page page) {
|
||||
case Page::TriggerThresholdKaRight:
|
||||
return m_store->getTriggerThresholds().ka_right;
|
||||
break;
|
||||
case Page::TriggerThresholdScaleLevel:
|
||||
return m_store->getTriggerThresholdScaleLevel();
|
||||
break;
|
||||
case Page::DebounceDelay:
|
||||
return m_store->getDebounceDelay();
|
||||
break;
|
||||
@ -252,9 +242,6 @@ void Menu::performSelectionAction(Menu::Descriptor::Action action) {
|
||||
case Descriptor::Action::GotoPageTriggerThresholdKaRight:
|
||||
gotoPage(Page::TriggerThresholdKaRight);
|
||||
break;
|
||||
case Descriptor::Action::GotoPageTriggerThresholdScaleLevel:
|
||||
gotoPage(Page::TriggerThresholdScaleLevel);
|
||||
break;
|
||||
case Descriptor::Action::GotoPageLedBrightness:
|
||||
gotoPage(Page::LedBrightness);
|
||||
break;
|
||||
@ -307,7 +294,6 @@ void Menu::performSelectionAction(Menu::Descriptor::Action action) {
|
||||
case Descriptor::Action::SetTriggerThresholdDonLeft:
|
||||
case Descriptor::Action::SetTriggerThresholdDonRight:
|
||||
case Descriptor::Action::SetTriggerThresholdKaRight:
|
||||
case Descriptor::Action::SetTriggerThresholdScaleLevel:
|
||||
gotoParent();
|
||||
break;
|
||||
case Descriptor::Action::SetDebounceDelay:
|
||||
@ -359,9 +345,6 @@ void Menu::performValueAction(Menu::Descriptor::Action action, uint16_t value) {
|
||||
thresholds.ka_right = value;
|
||||
m_store->setTriggerThresholds(thresholds);
|
||||
} break;
|
||||
case Descriptor::Action::SetTriggerThresholdScaleLevel:
|
||||
m_store->setTriggerThresholdScaleLevel(value);
|
||||
break;
|
||||
case Descriptor::Action::SetDebounceDelay:
|
||||
m_store->setDebounceDelay(value);
|
||||
break;
|
||||
|
@ -14,7 +14,6 @@ SettingsStore::SettingsStore()
|
||||
: m_store_cache({m_magic_byte,
|
||||
Config::Default::usb_mode,
|
||||
Config::Default::drum_config.trigger_thresholds,
|
||||
Config::Default::drum_config.trigger_threshold_scale_level,
|
||||
Config::Default::led_config.brightness,
|
||||
Config::Default::drum_config.debounce_delay_ms,
|
||||
{}}),
|
||||
@ -59,14 +58,6 @@ void SettingsStore::setTriggerThresholds(const Peripherals::Drum::Config::Thresh
|
||||
}
|
||||
Peripherals::Drum::Config::Thresholds SettingsStore::getTriggerThresholds() { return m_store_cache.trigger_thresholds; }
|
||||
|
||||
void SettingsStore::setTriggerThresholdScaleLevel(const uint8_t threshold_scale_level) {
|
||||
if (threshold_scale_level != m_store_cache.trigger_threshold_scale_level) {
|
||||
m_store_cache.trigger_threshold_scale_level = threshold_scale_level;
|
||||
m_dirty = true;
|
||||
}
|
||||
}
|
||||
uint8_t SettingsStore::getTriggerThresholdScaleLevel() { return m_store_cache.trigger_threshold_scale_level; }
|
||||
|
||||
void SettingsStore::setLedBrightness(const uint8_t brightness) {
|
||||
if (m_store_cache.led_brightness != brightness) {
|
||||
m_store_cache.led_brightness = brightness;
|
||||
|
Loading…
Reference in New Issue
Block a user