mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-06 15:01:28 +12:00
input: allow dynamic change of midi drum config
This commit is contained in:
parent
e790842007
commit
0679b502f2
4 changed files with 139 additions and 119 deletions
|
@ -9,9 +9,6 @@ using namespace std::chrono_literals;
|
||||||
|
|
||||||
LOG_CHANNEL(rb3_midi_drums_log);
|
LOG_CHANNEL(rb3_midi_drums_log);
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace controller
|
namespace controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -158,67 +155,6 @@ u8 min_velocity()
|
||||||
return g_cfg_rb3drums.minimum_velocity;
|
return g_cfg_rb3drums.minimum_velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Id : u8
|
|
||||||
{
|
|
||||||
// Each 'Note' can be triggered by multiple different numbers.
|
|
||||||
// Keeping them flattened in an enum for simplicity / switch statement usage.
|
|
||||||
|
|
||||||
// These follow the rockband 3 midi pro adapter support.
|
|
||||||
Snare0 = 38,
|
|
||||||
Snare1 = 31,
|
|
||||||
Snare2 = 34,
|
|
||||||
Snare3 = 37,
|
|
||||||
Snare4 = 39,
|
|
||||||
HiTom0 = 48,
|
|
||||||
HiTom1 = 50,
|
|
||||||
LowTom0 = 45,
|
|
||||||
LowTom1 = 47,
|
|
||||||
FloorTom0 = 41,
|
|
||||||
FloorTom1 = 43,
|
|
||||||
Hihat0 = 22,
|
|
||||||
Hihat1 = 26,
|
|
||||||
Hihat2 = 42,
|
|
||||||
Hihat3 = 54,
|
|
||||||
Ride0 = 51,
|
|
||||||
Ride1 = 53,
|
|
||||||
Ride2 = 56,
|
|
||||||
Ride3 = 59,
|
|
||||||
Crash0 = 49,
|
|
||||||
Crash1 = 52,
|
|
||||||
Crash2 = 55,
|
|
||||||
Crash3 = 57,
|
|
||||||
Kick0 = 33,
|
|
||||||
Kick1 = 35,
|
|
||||||
Kick2 = 36,
|
|
||||||
HihatPedal = 44,
|
|
||||||
|
|
||||||
// These are from alesis nitro mesh max. ymmv.
|
|
||||||
SnareRim = 40, // midi pro adapter counts this as snare.
|
|
||||||
HihatWithPedalUp = 46, // The midi pro adapter considers this a normal hihat hit.
|
|
||||||
HihatPedalPartial = 23, // If pedal is not 100% down, this will be sent instead of a normal hihat hit.
|
|
||||||
|
|
||||||
// Internal value used for converting midi CC.
|
|
||||||
// Values past 127 are not used in midi notes.
|
|
||||||
MidiCC = 255,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Intermediate mapping regardless of which midi ids triggered it.
|
|
||||||
enum class Note : u8
|
|
||||||
{
|
|
||||||
Invalid,
|
|
||||||
Kick,
|
|
||||||
HihatPedal,
|
|
||||||
Snare,
|
|
||||||
SnareRim,
|
|
||||||
HiTom,
|
|
||||||
LowTom,
|
|
||||||
FloorTom,
|
|
||||||
HihatWithPedalUp,
|
|
||||||
Hihat,
|
|
||||||
Ride,
|
|
||||||
Crash,
|
|
||||||
};
|
|
||||||
|
|
||||||
Note str_to_note(const std::string_view name)
|
Note str_to_note(const std::string_view name)
|
||||||
{
|
{
|
||||||
static const std::unordered_map<std::string_view, Note> mapping{
|
static const std::unordered_map<std::string_view, Note> mapping{
|
||||||
|
@ -298,27 +234,21 @@ std::unordered_map<Id, Note> create_id_to_note_mapping()
|
||||||
{Id::Crash2, Note::Crash},
|
{Id::Crash2, Note::Crash},
|
||||||
{Id::Crash3, Note::Crash},
|
{Id::Crash3, Note::Crash},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Apply configured overrides.
|
// Apply configured overrides.
|
||||||
auto split = fmt::split(g_cfg_rb3drums.midi_overrides.to_string(), {","});
|
const std::vector<std::string> segments = fmt::split(g_cfg_rb3drums.midi_overrides.to_string(), {","});
|
||||||
for (const auto& segment : split)
|
for (const std::string& segment : segments)
|
||||||
{
|
{
|
||||||
if (auto midi_override = parse_midi_override(segment))
|
if (const auto midi_override = parse_midi_override(segment))
|
||||||
{
|
{
|
||||||
auto id = midi_override->first;
|
const auto id = midi_override->first;
|
||||||
auto note = midi_override->second;
|
const auto note = midi_override->second;
|
||||||
mapping[id] = note;
|
mapping[id] = note;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
Note id_to_note(Id id)
|
|
||||||
{
|
|
||||||
static const auto mapping = create_id_to_note_mapping();
|
|
||||||
const auto it = mapping.find(id);
|
|
||||||
return it != mapping.cend() ? it->second : Note::Invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace combo
|
namespace combo
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -345,39 +275,18 @@ std::vector<u8> parse_combo(const std::string_view name, const std::string_view
|
||||||
return notes;
|
return notes;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Definition
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
std::vector<u8> notes;
|
|
||||||
std::function<rb3drums::KitState()> create_state;
|
|
||||||
|
|
||||||
Definition(std::string name, const std::string_view csv, const std::function<rb3drums::KitState()> create_state)
|
|
||||||
: name{std::move(name)}
|
|
||||||
, notes{parse_combo(this->name, csv)}
|
|
||||||
, create_state{create_state}
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::chrono::milliseconds window()
|
std::chrono::milliseconds window()
|
||||||
{
|
{
|
||||||
return std::chrono::milliseconds{g_cfg_rb3drums.combo_window_ms};
|
return std::chrono::milliseconds{g_cfg_rb3drums.combo_window_ms};
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<Definition>& definitions()
|
|
||||||
{
|
|
||||||
// Only parse once and cache.
|
|
||||||
static const std::vector<Definition> defs{
|
|
||||||
{"start", g_cfg_rb3drums.combo_start.to_string(), []{ return drum::start_state(); }},
|
|
||||||
{"select", g_cfg_rb3drums.combo_select.to_string(), []{ return drum::select_state(); }},
|
|
||||||
{"hold kick", g_cfg_rb3drums.combo_toggle_hold_kick.to_string(), []{ return drum::toggle_hold_kick_state(); }}
|
|
||||||
};
|
|
||||||
return defs;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace midi
|
} // namespace midi
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
void set_flag(u8* buf, [[maybe_unused]] std::string_view name, const controller::FlagByIndex& fbi)
|
void set_flag(u8* buf, [[maybe_unused]] std::string_view name, const controller::FlagByIndex& fbi)
|
||||||
{
|
{
|
||||||
auto i = fbi[drum::INDEX];
|
auto i = fbi[drum::INDEX];
|
||||||
|
@ -397,6 +306,12 @@ void set_flag_if_any(u8* buf, std::string_view name, const controller::FlagByInd
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usb_device_rb3_midi_drums::Definition::Definition(std::string name, const std::string_view csv, const std::function<rb3drums::KitState()> create_state)
|
||||||
|
: name{std::move(name)}
|
||||||
|
, notes{midi::combo::parse_combo(this->name, csv)}
|
||||||
|
, create_state{create_state}
|
||||||
|
{}
|
||||||
|
|
||||||
usb_device_rb3_midi_drums::usb_device_rb3_midi_drums(const std::array<u8, 7>& location, const std::string& device_name)
|
usb_device_rb3_midi_drums::usb_device_rb3_midi_drums(const std::array<u8, 7>& location, const std::string& device_name)
|
||||||
: usb_device_emulated(location)
|
: usb_device_emulated(location)
|
||||||
{
|
{
|
||||||
|
@ -603,6 +518,12 @@ void usb_device_rb3_midi_drums::interrupt_transfer(u32 buf_size, u8* buf, u32 /*
|
||||||
}
|
}
|
||||||
memcpy(buf, bytes.data(), bytes.size());
|
memcpy(buf, bytes.data(), bytes.size());
|
||||||
|
|
||||||
|
if (g_cfg_rb3drums.reload_requested)
|
||||||
|
{
|
||||||
|
m_id_to_note_mapping = midi::create_id_to_note_mapping();
|
||||||
|
combo.reload_definitions();
|
||||||
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
u8 midi_msg[32];
|
u8 midi_msg[32];
|
||||||
|
@ -712,6 +633,12 @@ rb3drums::KitState usb_device_rb3_midi_drums::parse_midi_message(u8* msg, usz si
|
||||||
return rb3drums::KitState{};
|
return rb3drums::KitState{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
midi::Note usb_device_rb3_midi_drums::id_to_note(midi::Id id)
|
||||||
|
{
|
||||||
|
const auto it = m_id_to_note_mapping.find(id);
|
||||||
|
return it != m_id_to_note_mapping.cend() ? it->second : midi::Note::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
rb3drums::KitState usb_device_rb3_midi_drums::parse_midi_note(const u8 id, const u8 velocity)
|
rb3drums::KitState usb_device_rb3_midi_drums::parse_midi_note(const u8 id, const u8 velocity)
|
||||||
{
|
{
|
||||||
if (velocity < midi::min_velocity())
|
if (velocity < midi::min_velocity())
|
||||||
|
@ -722,7 +649,7 @@ rb3drums::KitState usb_device_rb3_midi_drums::parse_midi_note(const u8 id, const
|
||||||
|
|
||||||
rb3drums::KitState kit_state{};
|
rb3drums::KitState kit_state{};
|
||||||
kit_state.expiry = std::chrono::steady_clock::now() + drum::hit_duration();
|
kit_state.expiry = std::chrono::steady_clock::now() + drum::hit_duration();
|
||||||
auto note = midi::id_to_note(static_cast<midi::Id>(id));
|
const midi::Note note = id_to_note(static_cast<midi::Id>(id));
|
||||||
switch (note)
|
switch (note)
|
||||||
{
|
{
|
||||||
case midi::Note::Kick: kit_state.kick_pedal = velocity; break;
|
case midi::Note::Kick: kit_state.kick_pedal = velocity; break;
|
||||||
|
@ -751,7 +678,8 @@ bool usb_device_rb3_midi_drums::is_midi_cc(const u8 id, const u8 value)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto is_past_threshold = [](u8 value)
|
|
||||||
|
const auto is_past_threshold = [](u8 value)
|
||||||
{
|
{
|
||||||
const u8 threshold = g_cfg_rb3drums.midi_cc_threshold;
|
const u8 threshold = g_cfg_rb3drums.midi_cc_threshold;
|
||||||
return g_cfg_rb3drums.midi_cc_invert_threshold
|
return g_cfg_rb3drums.midi_cc_invert_threshold
|
||||||
|
@ -834,6 +762,15 @@ bool rb3drums::KitState::is_drum() const
|
||||||
return std::max({snare, hi_tom, low_tom, floor_tom}) >= midi::min_velocity();
|
return std::max({snare, hi_tom, low_tom, floor_tom}) >= midi::min_velocity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void usb_device_rb3_midi_drums::ComboTracker::reload_definitions()
|
||||||
|
{
|
||||||
|
m_definitions = {
|
||||||
|
{"start", g_cfg_rb3drums.combo_start.to_string(), []{ return drum::start_state(); }},
|
||||||
|
{"select", g_cfg_rb3drums.combo_select.to_string(), []{ return drum::select_state(); }},
|
||||||
|
{"hold kick", g_cfg_rb3drums.combo_toggle_hold_kick.to_string(), []{ return drum::toggle_hold_kick_state(); }}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void usb_device_rb3_midi_drums::ComboTracker::add(u8 note)
|
void usb_device_rb3_midi_drums::ComboTracker::add(u8 note)
|
||||||
{
|
{
|
||||||
if (!midi_notes.empty() && std::chrono::steady_clock::now() >= expiry)
|
if (!midi_notes.empty() && std::chrono::steady_clock::now() >= expiry)
|
||||||
|
@ -843,9 +780,8 @@ void usb_device_rb3_midi_drums::ComboTracker::add(u8 note)
|
||||||
}
|
}
|
||||||
|
|
||||||
const usz i = midi_notes.size();
|
const usz i = midi_notes.size();
|
||||||
const auto& defs = midi::combo::definitions();
|
|
||||||
bool is_in_combo = false;
|
bool is_in_combo = false;
|
||||||
for (const auto& def : defs)
|
for (const auto& def : m_definitions)
|
||||||
{
|
{
|
||||||
if (i < def.notes.size() && note == def.notes[i])
|
if (i < def.notes.size() && note == def.notes[i])
|
||||||
{
|
{
|
||||||
|
@ -879,7 +815,7 @@ std::optional<rb3drums::KitState> usb_device_rb3_midi_drums::ComboTracker::take_
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
for (const auto& combo : midi::combo::definitions())
|
for (const auto& combo : m_definitions)
|
||||||
{
|
{
|
||||||
if (midi_notes == combo.notes)
|
if (midi_notes == combo.notes)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,10 +38,83 @@ struct KitState
|
||||||
bool is_drum() const;
|
bool is_drum() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace rb3drums
|
} // namespace rb3drums
|
||||||
|
|
||||||
|
namespace midi
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class Id : u8
|
||||||
|
{
|
||||||
|
// Each 'Note' can be triggered by multiple different numbers.
|
||||||
|
// Keeping them flattened in an enum for simplicity / switch statement usage.
|
||||||
|
|
||||||
|
// These follow the rockband 3 midi pro adapter support.
|
||||||
|
Snare0 = 38,
|
||||||
|
Snare1 = 31,
|
||||||
|
Snare2 = 34,
|
||||||
|
Snare3 = 37,
|
||||||
|
Snare4 = 39,
|
||||||
|
HiTom0 = 48,
|
||||||
|
HiTom1 = 50,
|
||||||
|
LowTom0 = 45,
|
||||||
|
LowTom1 = 47,
|
||||||
|
FloorTom0 = 41,
|
||||||
|
FloorTom1 = 43,
|
||||||
|
Hihat0 = 22,
|
||||||
|
Hihat1 = 26,
|
||||||
|
Hihat2 = 42,
|
||||||
|
Hihat3 = 54,
|
||||||
|
Ride0 = 51,
|
||||||
|
Ride1 = 53,
|
||||||
|
Ride2 = 56,
|
||||||
|
Ride3 = 59,
|
||||||
|
Crash0 = 49,
|
||||||
|
Crash1 = 52,
|
||||||
|
Crash2 = 55,
|
||||||
|
Crash3 = 57,
|
||||||
|
Kick0 = 33,
|
||||||
|
Kick1 = 35,
|
||||||
|
Kick2 = 36,
|
||||||
|
HihatPedal = 44,
|
||||||
|
|
||||||
|
// These are from alesis nitro mesh max. ymmv.
|
||||||
|
SnareRim = 40, // midi pro adapter counts this as snare.
|
||||||
|
HihatWithPedalUp = 46, // The midi pro adapter considers this a normal hihat hit.
|
||||||
|
HihatPedalPartial = 23, // If pedal is not 100% down, this will be sent instead of a normal hihat hit.
|
||||||
|
|
||||||
|
// Internal value used for converting midi CC.
|
||||||
|
// Values past 127 are not used in midi notes.
|
||||||
|
MidiCC = 255,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Intermediate mapping regardless of which midi ids triggered it.
|
||||||
|
enum class Note : u8
|
||||||
|
{
|
||||||
|
Invalid,
|
||||||
|
Kick,
|
||||||
|
HihatPedal,
|
||||||
|
Snare,
|
||||||
|
SnareRim,
|
||||||
|
HiTom,
|
||||||
|
LowTom,
|
||||||
|
FloorTom,
|
||||||
|
HihatWithPedalUp,
|
||||||
|
Hihat,
|
||||||
|
Ride,
|
||||||
|
Crash,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
class usb_device_rb3_midi_drums : public usb_device_emulated
|
class usb_device_rb3_midi_drums : public usb_device_emulated
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
usb_device_rb3_midi_drums(const std::array<u8, 7>& location, const std::string& device_name);
|
||||||
|
~usb_device_rb3_midi_drums();
|
||||||
|
|
||||||
|
void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override;
|
||||||
|
void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
usz response_pos{};
|
usz response_pos{};
|
||||||
bool buttons_enabled{};
|
bool buttons_enabled{};
|
||||||
|
@ -50,9 +123,19 @@ private:
|
||||||
bool hold_kick{};
|
bool hold_kick{};
|
||||||
bool midi_cc_triggered{};
|
bool midi_cc_triggered{};
|
||||||
|
|
||||||
|
struct Definition
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::vector<u8> notes;
|
||||||
|
std::function<rb3drums::KitState()> create_state;
|
||||||
|
|
||||||
|
Definition(std::string name, const std::string_view csv, const std::function<rb3drums::KitState()> create_state);
|
||||||
|
};
|
||||||
|
|
||||||
class ComboTracker
|
class ComboTracker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
void reload_definitions();
|
||||||
void add(u8 note);
|
void add(u8 note);
|
||||||
void reset();
|
void reset();
|
||||||
std::optional<rb3drums::KitState> take_state();
|
std::optional<rb3drums::KitState> take_state();
|
||||||
|
@ -60,18 +143,15 @@ private:
|
||||||
private:
|
private:
|
||||||
std::chrono::steady_clock::time_point expiry;
|
std::chrono::steady_clock::time_point expiry;
|
||||||
std::vector<u8> midi_notes;
|
std::vector<u8> midi_notes;
|
||||||
|
std::vector<Definition> m_definitions;
|
||||||
};
|
};
|
||||||
ComboTracker combo;
|
ComboTracker combo;
|
||||||
|
|
||||||
|
std::unordered_map<midi::Id, midi::Note> m_id_to_note_mapping;
|
||||||
|
|
||||||
|
midi::Note id_to_note(midi::Id id);
|
||||||
rb3drums::KitState parse_midi_message(u8* msg, usz size);
|
rb3drums::KitState parse_midi_message(u8* msg, usz size);
|
||||||
rb3drums::KitState parse_midi_note(u8 id, u8 velocity);
|
rb3drums::KitState parse_midi_note(u8 id, u8 velocity);
|
||||||
bool is_midi_cc(u8 id, u8 value);
|
bool is_midi_cc(u8 id, u8 value);
|
||||||
void write_state(u8* buf, const rb3drums::KitState&);
|
void write_state(u8* buf, const rb3drums::KitState&);
|
||||||
|
|
||||||
public:
|
|
||||||
usb_device_rb3_midi_drums(const std::array<u8, 7>& location, const std::string& device_name);
|
|
||||||
~usb_device_rb3_midi_drums();
|
|
||||||
|
|
||||||
void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override;
|
|
||||||
void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) override;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,7 +33,7 @@ bool cfg_rb3drums::load()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cfg_rb3drums::save() const
|
void cfg_rb3drums::save()
|
||||||
{
|
{
|
||||||
cfg_log.notice("Saving rb3drums config to '%s'", path);
|
cfg_log.notice("Saving rb3drums config to '%s'", path);
|
||||||
|
|
||||||
|
@ -41,4 +41,6 @@ void cfg_rb3drums::save() const
|
||||||
{
|
{
|
||||||
cfg_log.error("Failed to save rb3drums config to '%s' (error=%s)", path, fs::g_tls_error);
|
cfg_log.error("Failed to save rb3drums config to '%s' (error=%s)", path, fs::g_tls_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reload_requested = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,22 +6,24 @@ struct cfg_rb3drums final : cfg::node
|
||||||
{
|
{
|
||||||
cfg_rb3drums();
|
cfg_rb3drums();
|
||||||
bool load();
|
bool load();
|
||||||
void save() const;
|
void save();
|
||||||
|
|
||||||
cfg::uint<1, 100> pulse_ms{this, "Pulse width ms", 30, true};
|
cfg::uint<1, 100> pulse_ms{this, "Pulse width ms", 30, true};
|
||||||
cfg::uint<1, 127> minimum_velocity{this, "Minimum velocity", 10, true};
|
cfg::uint<1, 127> minimum_velocity{this, "Minimum velocity", 10, true};
|
||||||
cfg::uint<1, 5000> combo_window_ms{this, "Combo window in milliseconds", 2000, true};
|
cfg::uint<1, 5000> combo_window_ms{this, "Combo window in milliseconds", 2000, true};
|
||||||
cfg::_bool stagger_cymbals{this, "Stagger cymbal hits", true, true};
|
cfg::_bool stagger_cymbals{this, "Stagger cymbal hits", true, true};
|
||||||
cfg::string midi_overrides{this, "Midi id to note override", ""};
|
cfg::string midi_overrides{this, "Midi id to note override", "", true};
|
||||||
cfg::string combo_start{this, "Combo Start", "HihatPedal,HihatPedal,HihatPedal,Snare"};
|
cfg::string combo_start{this, "Combo Start", "HihatPedal,HihatPedal,HihatPedal,Snare", true};
|
||||||
cfg::string combo_select{this, "Combo Select", "HihatPedal,HihatPedal,HihatPedal,SnareRim"};
|
cfg::string combo_select{this, "Combo Select", "HihatPedal,HihatPedal,HihatPedal,SnareRim", true};
|
||||||
cfg::string combo_toggle_hold_kick{this, "Combo Toggle Hold Kick", "HihatPedal,HihatPedal,HihatPedal,Kick"};
|
cfg::string combo_toggle_hold_kick{this, "Combo Toggle Hold Kick", "HihatPedal,HihatPedal,HihatPedal,Kick", true};
|
||||||
cfg::uint<0, 255> midi_cc_status{this, "Midi CC status", 0xB0, true};
|
cfg::uint<0, 255> midi_cc_status{this, "Midi CC status", 0xB0, true};
|
||||||
cfg::uint<0, 127> midi_cc_number{this, "Midi CC control number", 4, true};
|
cfg::uint<0, 127> midi_cc_number{this, "Midi CC control number", 4, true};
|
||||||
cfg::uint<0, 127> midi_cc_threshold{this, "Midi CC threshold", 64, true};
|
cfg::uint<0, 127> midi_cc_threshold{this, "Midi CC threshold", 64, true};
|
||||||
cfg::_bool midi_cc_invert_threshold{this, "Midi CC invert threshold", false, true};
|
cfg::_bool midi_cc_invert_threshold{this, "Midi CC invert threshold", false, true};
|
||||||
|
|
||||||
const std::string path;
|
const std::string path;
|
||||||
|
|
||||||
|
atomic_t<bool> reload_requested = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern cfg_rb3drums g_cfg_rb3drums;
|
extern cfg_rb3drums g_cfg_rb3drums;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue