Skip to content

Commit 9f80181

Browse files
authored
Merge pull request #101 from robertlipe/timing-precision
timing precision & adds aurora borealis effect
2 parents 0bd595b + b7d5b60 commit 9f80181

18 files changed

Lines changed: 385 additions & 174 deletions

.github/workflows/CI.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ jobs:
4949
# Killing ndscpp is a bit rude and technically unnecessary, but we've been
5050
# raised to clean up after ourselves, so that's what we do.
5151
run: |
52+
make config.led
5253
./ndscpp > /dev/null 2>&1 &
5354
sleep 1
5455
LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib ./tests/tests

Makefile

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@ DEPFLAGS=-MT $@ -MMD -MP -MF $(DEPDIR)/$*.d
99

1010
SOURCES=main.cpp apihelpers.cpp
1111
EXECUTABLE=ndscpp
12-
CONFIG_FILES=config.led secrets.h
1312
DEPDIR=.deps
1413
OBJECTS:=$(SOURCES:.cpp=.o)
1514
DEPFILES:=$(SOURCES:%.cpp=$(DEPDIR)/%.d)
1615

16+
# Runtime config files (don't trigger a rebuild)
17+
RUNTIME_CONFIG=config.led
18+
# Compile-time header dependencies
19+
COMPILE_CONFIG=secrets.h
20+
1721
define helptext =
1822
Makefile for ndscpp
1923

@@ -42,11 +46,11 @@ $(EXECUTABLE): $(OBJECTS)
4246
@echo Linking $@...
4347
@$(CC) $(LDFLAGS) $^ -o $@ $(LIBS)
4448

45-
%.o: %.cpp $(CONFIG_FILES) $(DEPDIR)/%.d | $(DEPDIR)
49+
%.o: %.cpp $(COMPILE_CONFIG) $(DEPDIR)/%.d | $(DEPDIR)
4650
@echo Compiling $<...
4751
@$(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@
4852

49-
$(CONFIG_FILES): % : %.example
53+
$(RUNTIME_CONFIG) $(COMPILE_CONFIG): % : %.example
5054
@if [ ! -f $@ ]; then \
5155
echo "Copying $< to $@..."; \
5256
cp $< $@; \

effects/auroraeffect.h

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#pragma once
2+
using namespace std;
3+
4+
#include "../interfaces.h"
5+
#include "../ledeffectbase.h"
6+
#include "../pixeltypes.h"
7+
#include <cmath>
8+
9+
class AuroraEffect : public LEDEffectBase
10+
{
11+
private:
12+
double _time;
13+
double _speed;
14+
double _brightness;
15+
16+
public:
17+
AuroraEffect(const string& name, double speed = 0.2, double brightness = 1.0)
18+
: LEDEffectBase(name, "AuroraEffect"), _time(0.0), _speed(speed), _brightness(brightness)
19+
{
20+
}
21+
22+
void Start(ICanvas& canvas) override
23+
{
24+
_time = 0.0;
25+
}
26+
27+
void Update(ICanvas& canvas, microseconds deltaTime) override
28+
{
29+
_time += _speed * deltaTime.count() / 1000000.0;
30+
31+
auto& graphics = canvas.Graphics();
32+
int width = graphics.Width();
33+
int height = graphics.Height();
34+
35+
for (int y = 0; y < height; ++y)
36+
{
37+
for (int x = 0; x < width; ++x)
38+
{
39+
// Create some "dancing" waves using multiple sine waves
40+
double xf = x / static_cast<double>(width);
41+
double yf = y / static_cast<double>(height);
42+
43+
double v1 = sin(xf * 2.0 + _time * 0.7);
44+
double v2 = sin(yf * 3.0 + _time * 0.5);
45+
double v3 = sin((xf + yf) * 1.5 + _time * 0.3);
46+
double v4 = sin(sqrt(xf*xf + yf*yf) * 4.0 + _time * 0.2);
47+
48+
double combined = (v1 + v2 + v3 + v4) / 4.0; // range [-1, 1]
49+
combined = (combined + 1.0) / 2.0; // range [0, 1]
50+
51+
// Aurora colors: green, blue, purple
52+
// We want a nice transition between these colors
53+
double hue;
54+
if (combined < 0.3) {
55+
// Deep Blue to Cyan (240 to 180)
56+
hue = 240.0 - (combined / 0.3) * 60.0;
57+
} else if (combined < 0.6) {
58+
// Cyan to Green (180 to 120)
59+
hue = 180.0 - ((combined - 0.3) / 0.3) * 60.0;
60+
} else {
61+
// Green to Purple (120 to 280)
62+
double t = (combined - 0.6) / 0.4;
63+
if (t < 0.5) {
64+
hue = 120.0 - (t * 2.0) * 40.0; // Green to Lime (120 to 80)
65+
} else {
66+
hue = 260.0 + (t - 0.5) * 2.0 * 60.0; // Purple to Violet (260 to 320)
67+
}
68+
}
69+
70+
// Value (brightness) should also pulse
71+
// Lift the floor significantly and use a smoother curve
72+
double brightness = (0.4 + 0.6 * combined) * _brightness;
73+
74+
// Add some vertical bands to make it look more like aurora curtains
75+
double curtain = sin(xf * 15.0 + sin(_time * 0.2) * 5.0) * 0.15 + 0.85;
76+
brightness *= curtain;
77+
78+
// Max saturation for visibility
79+
CRGB color = CRGB::HSV2RGB(hue, 1.0, brightness);
80+
graphics.SetPixel(x, y, color);
81+
}
82+
}
83+
}
84+
85+
friend inline void to_json(nlohmann::json& j, const AuroraEffect & effect);
86+
friend inline void from_json(const nlohmann::json& j, shared_ptr<AuroraEffect>& effect);
87+
};
88+
89+
inline void to_json(nlohmann::json& j, const AuroraEffect & effect)
90+
{
91+
j = {
92+
{"name", effect.Name()},
93+
{"speed", effect._speed},
94+
{"brightness", effect._brightness}
95+
};
96+
}
97+
98+
inline void from_json(const nlohmann::json& j, shared_ptr<AuroraEffect>& effect)
99+
{
100+
effect = make_shared<AuroraEffect>(
101+
j.at("name").get<string>(),
102+
j.value("speed", 0.2),
103+
j.value("brightness", 1.0)
104+
);
105+
}

effects/bouncingballeffect.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,14 @@ class BouncingBallEffect : public LEDEffectBase
5454
{
5555
_height[i] = StartHeight;
5656
_impactVelocity[i] = ImpactVelocityStart;
57-
_clockTimeSinceLastBounce[i] = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
57+
_clockTimeSinceLastBounce[i] = duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
5858
_dampening[i] = 1.0f - static_cast<float>(i) / powf(static_cast<float>(_ballCount), 2.0f);
5959
_timeSinceLastBounce[i] = 0;
6060
_colors[i] = BallColors[i % BallColors.size()];
6161
}
6262
}
6363

64-
void Update(ICanvas& canvas, milliseconds deltaTime) override
64+
void Update(ICanvas& canvas, microseconds deltaTime) override
6565
{
6666
auto& graphics = canvas.Graphics();
6767
size_t length = graphics.Width();
@@ -81,7 +81,7 @@ class BouncingBallEffect : public LEDEffectBase
8181
// Draw each ball
8282
for (size_t i = 0; i < _ballCount; ++i)
8383
{
84-
_timeSinceLastBounce[i] += deltaTime.count() / 1000.0; // Convert to seconds
84+
_timeSinceLastBounce[i] += deltaTime.count() / 1000000.0; // Convert to seconds
8585
_height[i] = 0.5f * Gravity * powf(_timeSinceLastBounce[i], 2.0f) + _impactVelocity[i] * _timeSinceLastBounce[i];
8686

8787
if (_height[i] < 0)

effects/colorwaveeffect.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ class ColorWaveEffect : public LEDEffectBase
2424
_hue = 0.0;
2525
}
2626

27-
void Update(ICanvas& canvas, milliseconds deltaTime) override
27+
void Update(ICanvas& canvas, microseconds deltaTime) override
2828
{
2929
// Increment the hue based on speed and elapsed time
30-
_hue += _speed * deltaTime.count() / 1000.0;
30+
_hue += _speed * deltaTime.count() / 1000000.0;
3131
if (_hue >= 1.0) _hue -= 1.0; // Wrap around hue to stay in [0, 1)
3232

3333
auto& graphics = canvas.Graphics();

effects/fireworkseffect.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ class FireworksEffect : public LEDEffectBase
4848
private:
4949
static double GetCurrentTime()
5050
{
51-
return static_cast<double>(chrono::duration_cast<chrono::milliseconds>(
51+
return static_cast<double>(chrono::duration_cast<chrono::microseconds>(
5252
chrono::steady_clock::now().time_since_epoch())
5353
.count()) /
54-
1000.0;
54+
1000000.0;
5555
}
5656
};
5757

@@ -92,7 +92,7 @@ class FireworksEffect : public LEDEffectBase
9292
{
9393
}
9494

95-
void Update(ICanvas &canvas, milliseconds deltaTime) override
95+
void Update(ICanvas &canvas, microseconds deltaTime) override
9696
{
9797
const auto ledCount = canvas.Graphics().Width() * canvas.Graphics().Height();
9898

@@ -133,7 +133,7 @@ class FireworksEffect : public LEDEffectBase
133133
Particle particle = _particles.front();
134134
_particles.pop();
135135

136-
particle.Update(deltaTime.count() / 1000.0);
136+
particle.Update(deltaTime.count() / 1000000.0);
137137
CRGB color = particle._starColor;
138138

139139
double fade = 0.0;

effects/misceffects.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class SolidColorFill : public LEDEffectBase
2525
{
2626
}
2727

28-
void Update(ICanvas& canvas, milliseconds deltaTime) override
28+
void Update(ICanvas& canvas, microseconds deltaTime) override
2929
{
3030
canvas.Graphics().Clear(_color);
3131
}
@@ -58,7 +58,7 @@ class DaveDebugEffect : public LEDEffectBase
5858
{
5959
}
6060

61-
void Update(ICanvas& canvas, milliseconds deltaTime) override
61+
void Update(ICanvas& canvas, microseconds deltaTime) override
6262
{
6363
(void) deltaTime;
6464

effects/paletteeffect.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class PaletteEffect : public LEDEffectBase
5959
{
6060
}
6161

62-
void Update(ICanvas& canvas, milliseconds deltaTime) override
62+
void Update(ICanvas& canvas, microseconds deltaTime) override
6363
{
6464
auto& graphics = canvas.Graphics();
6565
const auto width = graphics.Width();
@@ -69,7 +69,7 @@ class PaletteEffect : public LEDEffectBase
6969
graphics.Clear(CRGB::Black);
7070

7171
// Pre-calculate constants
72-
const double secondsElapsed = deltaTime.count() / 1000.0;
72+
const double secondsElapsed = deltaTime.count() / 1000000.0;
7373
const double cPixelsToScroll = secondsElapsed * _LEDScrollSpeed;
7474
const double cColorsToScroll = secondsElapsed * _LEDColorPerSecond;
7575
const uint32_t cLength = (_Mirrored ? dotcount / 2 : dotcount);

effects/starfield.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,17 @@ class StarfieldEffect : public LEDEffectBase
5555
canvas.Graphics().Clear(CRGB::Black);
5656
}
5757

58-
void Update(ICanvas& canvas, milliseconds deltaTime) override
58+
void Update(ICanvas& canvas, microseconds deltaTime) override
5959
{
6060
auto& graphics = canvas.Graphics();
6161
graphics.FadeFrameBy(32);
6262

63-
double timeFactor = deltaTime.count() / 1000.0; // Convert delta time to seconds
63+
double timeFactor = deltaTime.count() / 1000000.0; // Convert delta time to seconds
6464

6565
for (auto& star : _stars)
6666
{
6767
// Update position based on velocity and time
68-
const auto xScale = (double) (graphics.Width() / graphics.Height()) / 2.0;
68+
const auto xScale = (double)graphics.Width() / (double)max(1u, graphics.Height()) / 2.0;
6969
star.x += star.dx * timeFactor * xScale;
7070
star.y += star.dy * timeFactor;
7171

effects/videoeffect.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class MP4PlaybackEffect : public LEDEffectBase
142142
SWS_BILINEAR, nullptr, nullptr, nullptr);
143143
}
144144

145-
void Update(ICanvas& canvas, milliseconds deltaTime) override
145+
void Update(ICanvas& canvas, microseconds deltaTime) override
146146
{
147147
if (!_initialized)
148148
return;

0 commit comments

Comments
 (0)