sTodo-m5paper-client/libraries/FastLED/examples/LuminescentGrand/shared/Keyboard.cpp
2025-06-30 20:47:33 +02:00

213 lines
5.4 KiB
C++

#include <Arduino.h>
#include "./util.h"
#include "./color_mapper.h"
#include "./Keyboard.h"
#include "./dprint.h"
Key::Key() : on_(false), sustained_(false), sustain_pedal_on_(false),
velocity_(0), idx_(0), event_time_(0) {}
void Key::SetOn(uint8_t vel, const ColorHSV& color, uint32_t now_ms) {
if (curr_color_.v_ < color.v_) { // if the new color is "brighter" than the current color.
velocity_ = vel;
curr_color_ = color;
event_time_ = now_ms;
}
orig_color_ = curr_color_;
event_time_ = now_ms;
on_ = true;
}
void Key::SetOff(uint32_t now_ms) {
orig_color_ = curr_color_;
on_ = false;
event_time_ = now_ms;
sustained_ = false;
}
void Key::SetSustained() {
sustained_ = true;
}
void Key::Update(uint32_t now_ms, uint32_t delta_ms, bool sustain_pedal_on) {
if (sustained_ && !sustain_pedal_on) {
sustained_ = false;
SetOff(now_ms);
}
sustain_pedal_on_ = sustain_pedal_on;
UpdateIntensity(now_ms, delta_ms);
}
float Key::VelocityFactor() const { return velocity_ / 127.f; }
float Key::CalcAttackDecayFactor(uint32_t delta_ms) const {
bool dampened_key = (idx_ < kFirstNoteNoDamp);
float active_lights_factor = ::CalcDecayFactor(
sustain_pedal_on_,
on_,
idx_,
VelocityFactor(),
dampened_key,
delta_ms);
return active_lights_factor;
}
float Key::AttackRemapFactor(uint32_t now_ms) {
if (on_) {
return ::AttackRemapFactor(now_ms - event_time_);
} else {
return 1.0;
}
}
float Key::IntensityFactor() const {
return intensity_;
}
void Key::UpdateIntensity(uint32_t now_ms, uint32_t delta_ms) {
if (on_) {
// Intensity can be calculated by a
float intensity =
CalcAttackDecayFactor(now_ms - event_time_) *
VelocityFactor() *
AttackRemapFactor(now_ms);
// This is FRAME RATE DEPENDENT FUNCTION!!!!
// CHANGE TO TIME INDEPENDENT BEFORE SUBMIT.
intensity_ = (.9f * intensity) + (.1f * intensity_);
} else if(intensity_ > 0.0f) { // major cpu hotspot.
if (sustain_pedal_on_) {
float delta_s = delta_ms / 1000.f;
if (intensity_ > .5f) {
const float kRate = .12f;
// Time flexible decay function. Stays accurate
// even as the frame rate changes.
// Formula: A = Pe^(r*t)
intensity_ = intensity_ * exp(-delta_s * kRate);
} else {
// Quickly fade at the bottom end of the transition.
const float kRate = .05f;
intensity_ -= delta_s * kRate;
}
} else {
float delta_s = delta_ms / 1000.f;
if (intensity_ > .5f) {
const float kRate = 12.0f;
// Time flexible decay function. Stays accurate
// even as the frame rate changes.
// Formula: A = Pe^(r*t)
intensity_ = intensity_ * exp(-delta_s * kRate);
} else {
// Quickly fade at the bottom end of the transition.
const float kRate = 2.0f;
intensity_ -= delta_s * kRate;
}
}
intensity_ = constrain(intensity_, 0.0f, 1.0f);
}
}
void KeyboardState::HandleNoteOn(uint8_t midi_note, uint8_t velocity, int color_selector_value, uint32_t now_ms) {
if (0 == velocity) {
// Some keyboards signify "NoteOff" with a velocity of zero.
HandleNoteOff(midi_note, velocity, now_ms);
return;
}
#ifdef DEBUG_KEYBOARD
dprint("HandleNoteOn:");
dprint("midi_note = ");
dprint(midi_note);
dprint(", velocity = ");
dprintln(velocity);
#endif
float brightness = ToBrightness(velocity);
dprint("brightness: "); dprintln(brightness);
ColorHSV pixel_color_hsv = SelectColor(midi_note, brightness,
color_selector_value);
// TODO: Give a key access to the Keyboard owner, therefore it could inspect the
// sustained variable instead of passing it here.
Key* key = GetKey(midi_note);
dprint("key indx: "); dprintln(key->idx_);
key->SetOn(velocity, pixel_color_hsv, now_ms);
}
void KeyboardState::HandleNoteOff(uint8_t midi_note, uint8_t /*velocity*/, uint32_t now_ms) {
#ifdef DEBUG_KEYBOARD
dprint("HandleNoteOff:");
dprint("midi_note = ");
dprint(midi_note);
dprint(", velocity = ");
dprintln(velocity);
#endif
Key* key = GetKey(midi_note);
if (sustain_pedal_) {
key->SetSustained();
} else {
key->SetOff(now_ms);
}
}
void KeyboardState::HandleControlChange(uint8_t d1, uint8_t d2) {
// Note that d1 and d2 just mean "data-1" and "data-2".
// TODO: Find out what d1 and d2 should be called.
const bool foot_pedal = (d1 == kMidiFootPedal);
if (foot_pedal) {
// Spec says that if that values 0-63 are OFF, otherwise ON.
sustain_pedal_ = (d2 >= 64);
}
}
void KeyboardState::HandleAfterTouchPoly(uint8_t note, uint8_t pressure) {
dprintln("HandleAfterTouchPoly");
dprint("\tnote = ");
dprint(note);
dprint(", pressure = ");
dprintln(pressure);
}
KeyboardState::KeyboardState() : sustain_pedal_(false), keys_() {
for (int i = 0; i < kNumKeys; ++i) {
keys_[i].idx_ = i;
}
}
void KeyboardState::Update(uint32_t now_ms, uint32_t delta_ms) {
for (int i = 0; i < kNumKeys; ++i) {
keys_[i].Update(now_ms, delta_ms, sustain_pedal_);
}
}
uint8_t KeyboardState::KeyIndex(int midi_pitch) {
//return constrain(midi_pitch, 21, 108) - 21;
return ::KeyIndex(midi_pitch);
}
Key* KeyboardState::GetKey(int midi_pitch) {
uint8_t idx = KeyIndex(midi_pitch);
return &keys_[idx];
}