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

115 lines
3.9 KiB
C++

#include <Arduino.h>
#include "./util.h"
#include "ApproximatingFunction.h"
#include "settings.h"
/*
// C - 0, C# - 1, D - 2, D# - 3... B - 11.
// http://cote.cc/w/wp-content/uploads/drupal/blog/logic-midi-note-numbers.png
*/
uint8_t FundamentalNote(int midi_note) {
return midi_note % 12;
}
float mapf(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
// Given an input time.
float AttackRemapFactor(uint32_t delta_t_ms) {
typedef InterpData<uint32_t, float> Datum;
static const Datum kData[] = {
Datum(0, .5),
Datum(80, 1.0),
};
static const int n = sizeof(kData) / sizeof(kData[0]);
return Interp(delta_t_ms, kData, n);
}
float MapDecayTime(uint8_t key_idx) {
typedef InterpData<uint8_t, float> Datum;
static const float bias = 1.3f;
// key then time for decay in milliseconds.
// First value is the KEY on the keyboard, second value is the
// time. The KEY must be IN ORDER or else the algorithm will fail.
static const Datum kInterpData[] = {
Datum(0, 21.0f * 1000.0f * bias),
Datum(11, 19.4 * 1000.0f * bias),
Datum(22, 15.1f * 1000.0f * bias),
Datum(35, 12.5f * 1000.0f * bias),
Datum(44, 10.f * 1000.0f * bias),
Datum(50, 8.1f * 1000.0f * bias),
Datum(53, 5.3f * 1000.0f * bias),
Datum(61, 4.0f * 1000.0f * bias),
Datum(66, 5.0f * 1000.0f * bias),
Datum(69, 4.6f * 1000.0f * bias),
Datum(70, 4.4f * 1000.0f * bias),
Datum(71, 4.3f * 1000.0f * bias),
Datum(74, 3.9f * 1000.0f * bias),
Datum(80, 1.9f * 1000.0f * bias),
Datum(81, 1.8f * 1000.0f * bias),
Datum(82, 1.7f * 1000.0f * bias),
Datum(83, 1.5f * 1000.0f * bias),
Datum(84, 1.3f * 1000.0f * bias),
Datum(86, 1.0f * 1000.0f * bias),
Datum(87, 0.9f * 1000.0f * bias),
};
static const int n = sizeof(kInterpData) / sizeof(kInterpData[0]);
float approx_val = Interp(key_idx, kInterpData, n);
return approx_val;
}
// Returns a value in the range 1->0 indicating how intense the note is. This
// value will go to 0 as time progresses, and will be 1 when the note is first
// pressed.
float CalcDecayFactor(bool sustain_pedal_on,
bool key_on,
int key_idx,
float velocity,
bool dampened_key,
float time_elapsed_ms) {
static const float kDefaultDecayTime = .2f * 1000.f;
static const float kBias = 1.10;
float decay_time = kDefaultDecayTime; // default - no sustain.
if (key_on || sustain_pedal_on || !dampened_key) {
decay_time = MapDecayTime(key_idx) * max(0.25f, velocity);
}
// decay_interp is a value which starts off as 1.0 to signify the start of the
// key press and gradually decreases to 0.0. For example, if the decay time is 1 second
// then at the time = 0s, decay_interp is 1.0, and after one second decay_interp is 0.0
float intensity_factor = mapf(time_elapsed_ms,
0.0, decay_time * kBias,
1.0, 0.0); // Startup at full brightness -> no brighness.
// When decay_interp reaches 0, the lighting sequence is effectively finished. However
// because this is time based and time keeps on going this value will move into negative
// territory, we take care of this by simply clamping all negative values to 0.0.
intensity_factor = constrain(intensity_factor, 0.0f, 1.0f);
return intensity_factor;
}
float ToBrightness(int velocity) {
typedef InterpData<int, float> Datum;
static const Datum kData[] = {
Datum(0, 0.02),
Datum(32, 0.02),
Datum(64, 0.10),
Datum(80, 0.30),
Datum(90, 0.90),
Datum(100, 1.00),
Datum(120, 1.00),
Datum(127, 1.00)
};
static const int n = sizeof(kData) / sizeof(kData[0]);
const float val = Interp(velocity, kData, n);
return val;
}