43float advance(
float pos,
float turnsPerSec,
float dtSec) {
62 mBreath += kTwoPi * kBreathHz * dtSec;
65 mPosA = advance(
mPosA, kBreathDriftTurnsPerSec, dtSec);
66 mPosB = advance(
mPosB, -kBreathDriftTurnsPerSec * 0.7f, dtSec);
74 const float aGain = 0.35f + 0.25f * (0.5f + 0.5f *
fl::sin(
mBreath + 1.2f));
75 const float bGain = 0.35f + 0.25f * (0.5f + 0.5f *
fl::sin(
mBreath + 3.6f));
85 const float rate = kGrainsPerSecAtFull *
86 (
static_cast<float>(ringSize) / 100.0f) * s.
shimmer *
87 (0.5f + 0.5f * s.
high);
97 static_cast<int>(
mRng.unit() *
static_cast<float>(ringSize));
112 if (grain.
ageSec >= kGrainLifeSec) {
116 const float e = grainEnvelope(grain.
ageSec);
128 const float dtMs = dtSec * 1000.0f;
131 const float speed = kFlowBaseTurnsPerSec +
132 kFlowMidTurnsPerSec * s.
mid * (1.0f + 0.5f * s.
trend);
140 float sigmaTarget = kFlowSigmaMin + (kFlowSigmaMax - kFlowSigmaMin) * s.
low;
141 sigmaTarget *= 1.0f + 0.35f * s.
trend;
143 clampf(sigmaTarget, kFlowSigmaMin * 0.7f, kFlowSigmaMax * 1.4f);
145 mSigma.update(sigmaTarget, dtMs, kFlowSigmaSlewMs, kFlowSigmaSlewMs);
148 const float bodyTarget = 0.45f + 0.45f * s.
energy + 0.4f * s.
punch;
150 mBody.update(bodyTarget, dtMs, kFlowBodyAttackMs, kFlowBodyReleaseMs);
167 const float dtMs = dtSec * 1000.0f;
168 const float slot = 1.0f /
static_cast<float>(
kMarkers);
169 const float beatsPerSec = (s.
bpm > 20.0f) ? s.
bpm / 60.0f : 0.0f;
179 slot *
static_cast<float>(
static_cast<int>(
mRotation / slot));
182 const float err = (inSlot < slot * 0.5f) ? -inSlot : (slot - inSlot);
186 const float maxStep = slot * beatsPerSec * dtSec / kCorrectionBeats;
208 mSwell.update(swellTarget, dtMs, kSwellAttackMs, kSwellReleaseMs);
212 kFlashAttackMs, kFlashReleaseMs);
214 kSnareAttackMs, kSnareReleaseMs);
216 const float markerGain = 0.45f + 0.55f * swell + 0.5f * s.
punch;
223 for (
int k = 0; k <
kMarkers; ++k) {
225 const float t = (k & 1) ? 1.0f : 0.4f;
231 if (snare > 0.001f) {
232 for (
int k = 0; k <
kMarkers; ++k) {
240 if (flash > 0.001f) {
void render(const RoomSense &s, const MoodPalette &pal, float dtSec, RingCanvas &c)
void drawGrains(const MoodPalette &pal, float dtSec, RingCanvas &c)
Grain mGrains[kMaxGrains]
void render(const RoomSense &s, const MoodPalette &pal, float dtSec, RingCanvas &c)
static const int kMaxGrains
void spawnGrains(const RoomSense &s, float dtSec, int ringSize)
float mCorrection
remaining phase correction, turns
void render(const RoomSense &s, const MoodPalette &pal, float dtSec, RingCanvas &c)
float mRotation
turns, advanced continuously
static const int kMarkers
void pixel(int i, const RGBf &color, float gain)
Add to one pixel, index wrapped.
void lobe(float pos, float sigma, const RGBf &color, float gain)
Add a smooth lobe centred at pos (turns) with half-width sigma (turns).
void fill(const RGBf &color, float gain)
Add the same colour to every pixel.
Additive drawing helpers over a span of float pixels.
enable_if< is_fixed_point< T >::value, T >::type sin(T angle) FL_NO_EXCEPT
constexpr float kGrainLifeSec
constexpr float kBreathHz
constexpr float kFlashReleaseMs
constexpr float kCorrectionBeats
constexpr float kFlashAttackMs
constexpr float kBreathDriftTurnsPerSec
constexpr float kSwellAttackMs
constexpr float kFlowSigmaMax
constexpr float kFlowSigmaSlewMs
constexpr float kGrainsPerSecAtFull
constexpr float kFlowSigmaMin
float advance(float pos, float turnsPerSec, float dtSec)
constexpr float kFlowMidTurnsPerSec
constexpr float kBreathSigma
float grainEnvelope(float ageSec)
Rise over attack, hold, fall to zero at life. Smooth at both ends.
constexpr float kFlowHueWalkPerSec
constexpr float kGrainAttackSec
constexpr float kFlowBodyReleaseMs
constexpr float kMarkerSigma
constexpr float kSnareReleaseMs
constexpr float kFlowBaseTurnsPerSec
constexpr float kSwellReleaseMs
constexpr float kBreathFloor
constexpr float kSnareAttackMs
constexpr float kSwellStart
constexpr float kFlowBodyAttackMs
float smoothstepf(float e0, float e1, float x)
0 below e0, 1 above e1, smooth in between.
float clampf(float v, float lo, float hi)
RGBf paletteColor(const MoodPalette &p, float t)
Colour at position t in [0, 1] along the family, at value v.
float wrapTurns(float t)
Wrap into [0, 1).
float shimmer
treble transient
float punch
bass transient (a hit, not loudness)
float energy
smoothed loudness
float measurePhase
0 on the downbeat
float trend
[-1, 1] falling .. rising
float beatPhase
0 on the beat, ramps to 1 before the next
Everything a visual is allowed to react to.
Linear-light float pixel, nominal range [0, 1], may exceed 1 before clip.