Skip to content

Instantly share code, notes, and snippets.

@xxv
Created September 11, 2020 02:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xxv/fcba34658d0d04e7f72f3916e48f87e7 to your computer and use it in GitHub Desktop.
Save xxv/fcba34658d0d04e7f72f3916e48f87e7 to your computer and use it in GitHub Desktop.
TV simulator for FastLED
#include <FastLED.h>
#include "tv.h"
namespace {
// Shot durations; the number of frames.
const static uint8_t DURATIONS[] = {
// Short shot lengths
6, 8, 12, 16, 24, 24, 24, 24,
// Longer shot lengths
24, 24, 24, 24,
36, 36, 26, 36, 36, 36, 26, 36,
48, 48, 48, 48, 48, 48, 48, 48,
72, 72, 72, 96, 120
};
const static uint8_t DURATIONS_LEN = sizeof(DURATIONS) / sizeof(DURATIONS[0]);
const static uint8_t DURATIONS_SHORT_LEN = 8;
} // namespace
/**
* Return the next frame to display. If the current shot has finished, a new one
* will be generated.
*/
CHSV TvSim::GetNextFrame() {
if (this->frame_ >= this->shot_length_) {
CHSV last_frame = this->shot_[this->frame_ > 0 ? this->frame_ - 1 : 0];
this->GenerateShot(last_frame);
this->frame_ = 0;
}
return this->shot_[this->frame_++];
}
void TvSim::GenerateShot(const CHSV start_frame) {
CHSV end_frame = blend(this->RandomShotHsv(), start_frame, random8(64));
if (random8(2) == 1) {
this->GenerateFlat(end_frame);
} else {
this->GenerateFade(start_frame, end_frame);
}
this->AddNoise();
}
void TvSim::GenerateFade(const CHSV start_frame, const CHSV end_frame) {
this->shot_length_ = this->RandomDurationShort();
fill_gradient(this->shot_, this->shot_length_, start_frame, end_frame);
}
void TvSim::GenerateFlat(const CHSV end_frame) {
this->shot_length_ = this->RandomDuration();
for (uint8_t i = 0; i < this->shot_length_; i++) {
this->shot_[i] = end_frame;
}
}
/**
* Generate a random TV-like HSV color.
*/
CHSV TvSim::RandomShotHsv() {
return CHSV(random8(140, 200), random(50, 155), random8(179, 255));
}
/**
* Add a random amount of simplex noise to the current shot.
*/
void TvSim::AddNoise() {
uint8_t magnitude_h = random8(25);
uint8_t magnitude_s = random8(25);
uint8_t magnitude_v = random8(25);
for (uint8_t i = 0; i < this->shot_length_; i++) {
this->shot_[i] = CHSV(qadd8(this->shot_[i].h,
scale8(inoise8(i << 6, 0), magnitude_h)),
qadd8(this->shot_[i].s,
scale8(inoise8(i << 6, 1 << 6), magnitude_s)),
qadd8(this->shot_[i].v,
scale8(inoise8(i << 6, 2 << 6), magnitude_v)));
}
}
uint8_t TvSim::RandomChoice(const uint8_t *options, const uint8_t length) {
return options[random8(length)];
}
uint8_t TvSim::RandomDuration() {
return this->RandomChoice(DURATIONS, DURATIONS_LEN);
}
uint8_t TvSim::RandomDurationShort() {
return this->RandomChoice(DURATIONS, DURATIONS_SHORT_LEN);
}
#include <FastLED.h>
class TvSim {
public:
static const uint8_t FRAME_DELAY_MS = 41; // 24fps
CHSV GetNextFrame();
private:
uint8_t frame_ = 0;
CHSV shot_[120] = { CHSV(0, 0, 0) };
uint8_t shot_length_ = 0;
void GenerateShot(const CHSV start_frame);
void GenerateFade(const CHSV start_frame, const CHSV end_frame);
void GenerateFlat(const CHSV end_frame);
CHSV RandomShotHsv();
void AddNoise();
uint8_t RandomChoice(const uint8_t *options, const uint8_t max);
uint8_t RandomDuration();
uint8_t RandomDurationShort();
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment