#include #include #include #include #define MAX_DELTA 808000 #define MAX_PEAK 170 namespace VIZ { RainbowMap::RainbowMap(AudioGrabber *pGrabber, Vulcan121 *vulcan) : VIZ(pGrabber, vulcan) { maxCols = keyboardData.num_cols * keyboardData.num_rows; colours = new rgba[maxCols]; for (int i = 0; i < maxCols; ++i) { double ratio = (double) i / maxCols; colours[i] = Color::Generator::rgbFromRatio(ratio, 128); } } RainbowMap::~RainbowMap() { delete[] colours; } void RainbowMap::onSetup() { currentColumn = 0; Vulcan121::fadeOutMap(data, 0); keyboard->sendToLEDs({ 0, 0, 0, 0 }); grabber->requestMode = AudioGrabber::ReqMode::FFT; usleep(100000); } void RainbowMap::onTick(float delta) { deltaElapsed += delta; auto fftData = grabber->fft.getData()->leftChannel; auto val = 0.0; for (int i = 0; i < 3; ++i) { auto avg = fftData[i]; if (avg > val) val = avg; } val = VUtils::Math::clamp(val, 0, 255); double avg = deltaMove(val); if (deltaElapsed >= deltaNeeded) { currentColumn++; if (currentColumn >= maxCols) currentColumn = 0; moveRainbow(avg); deltaElapsed -= deltaNeeded; } moveRainbow(avg); lastValue = avg; // we clean up the map self later! :) keyboard->sendLedMap(data); } double RainbowMap::deltaMove(double val) { auto avg = VUtils::Math::clamp((lastValue + val) * 0.5, 0, 200); if (avg > MAX_PEAK || avg > decayValue) { calcNextDelta(val < MAX_PEAK && firstUnder ? 160 : val); firstUnder = val > MAX_PEAK; decayValue = val; } if (val > MAX_PEAK) { firstUnder = true; } if (avg < 10) { deltaNeeded = 1000000000; } if (decayValue >= 0) decayValue -= 10; return avg; } const char *RainbowMap::name() { return m_name.c_str(); } void RainbowMap::calcNextDelta(double ratio) { double rRatio = ratio / MAX_PEAK; rRatio = VUtils::Math::clamp(rRatio, 0.05, 1.0); rRatio = (VUtils::Math::easeIn(rRatio) - 1.0) * -1; deltaNeeded = rRatio * MAX_DELTA; } void RainbowMap::moveRainbow(double d) { int i = 0; int color = currentColumn; while (i < keyboardData.num_cols) { colours[color].a = (uint8_t) d; updateColumn(i, color); color++; i++; if (color > maxCols - 1) color = 0; } } void RainbowMap::updateColumn(int col, int colIndex) { auto column = keyboard->getColumn(col); if (!column) { ERR("Column: %d not found", col); return; } for (int i = 0; i < column->count; ++i) { auto index = column->index[i]; data.key[index] = colours[colIndex]; } } }