-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from Gadgetoid/feature/display-plugins
Significant refactor to support pluggable effects.
- Loading branch information
Showing
16 changed files
with
479 additions
and
210 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
add_library(classic_fft INTERFACE) | ||
|
||
target_sources(classic_fft INTERFACE | ||
${CMAKE_CURRENT_LIST_DIR}/classic_fft.cpp | ||
${CMAKE_CURRENT_LIST_DIR}/lib/fixed_fft.cpp | ||
) | ||
|
||
target_include_directories(classic_fft INTERFACE | ||
${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
|
||
# Choose one: | ||
# SCALE_LOGARITHMIC | ||
# SCALE_SQRT | ||
# SCALE_LINEAR | ||
target_compile_definitions(classic_fft INTERFACE | ||
-DSCALE_SQRT | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
#include "lib/rgb.hpp" | ||
#include "effect.hpp" | ||
|
||
void ClassicFFT::update(int16_t *buffer16, size_t sample_count) { | ||
int16_t* fft_array = &fft.sample_array[SAMPLES_PER_AUDIO_BUFFER * (BUFFERS_PER_FFT_SAMPLE - 1)]; | ||
memmove(fft.sample_array, &fft.sample_array[SAMPLES_PER_AUDIO_BUFFER], (BUFFERS_PER_FFT_SAMPLE - 1) * sizeof(uint16_t)); | ||
|
||
for (auto i = 0u; i < SAMPLES_PER_AUDIO_BUFFER; i++) { | ||
fft_array[i] = buffer16[i]; | ||
} | ||
|
||
fft.update(); | ||
|
||
for (auto i = 0u; i < display.WIDTH; i++) { | ||
fix15 sample = std::min(float_to_fix15(max_sample_from_fft), fft.get_scaled_as_fix15(i + FFT_SKIP_BINS)); | ||
uint8_t maxy = 0; | ||
|
||
for (int j = 0; j < HISTORY_LEN; ++j) { | ||
if (eq_history[i][j] > maxy) { | ||
maxy = eq_history[i][j]; | ||
} | ||
} | ||
|
||
#ifdef SCALE_SQRT | ||
fix15 subtract = subtract_step; | ||
#endif | ||
for (auto y = 0; y < display.HEIGHT; y++) { | ||
uint8_t r = 0; | ||
uint8_t g = 0; | ||
uint8_t b = 0; | ||
if (sample > int_to_fix15(lower_threshold)) { | ||
r = (uint16_t)(palette[y].r); | ||
g = (uint16_t)(palette[y].g); | ||
b = (uint16_t)(palette[y].b); | ||
#ifdef SCALE_LOGARITHMIC | ||
sample = multiply_fix15_unit(multiple, sample); | ||
#else | ||
sample = std::max(1, sample - subtract); | ||
#ifdef SCALE_SQRT | ||
subtract += subtract_step; | ||
#endif | ||
#endif | ||
} | ||
else if (sample > 0) { | ||
uint16_t int_sample = (uint16_t)fix15_to_int(sample); | ||
r = std::min((uint16_t)(palette[y].r), int_sample); | ||
g = std::min((uint16_t)(palette[y].g), int_sample); | ||
b = std::min((uint16_t)(palette[y].b), int_sample); | ||
eq_history[i][history_idx] = y; | ||
sample = 0; | ||
if (maxy < y) { | ||
maxy = y; | ||
} | ||
} else if (y < maxy) { | ||
r = (uint16_t)(palette[y].r) >> 3; | ||
g = (uint16_t)(palette[y].g) >> 3; | ||
b = (uint16_t)(palette[y].b) >> 3; | ||
} | ||
display.set_pixel(i, display.HEIGHT - 1 - y, r, g, b); | ||
} | ||
if (maxy > 0) { | ||
RGB c = palette[display.HEIGHT - 1]; | ||
display.set_pixel(i, display.HEIGHT - 1 - maxy, c.r, c.g, c.b); | ||
} | ||
} | ||
history_idx = (history_idx + 1) % HISTORY_LEN; | ||
} | ||
|
||
void ClassicFFT::init(uint32_t sample_frequency) { | ||
printf("ClassicFFT: %ix%i\n", display.WIDTH, display.HEIGHT); | ||
|
||
history_idx = 0; | ||
|
||
fft.set_scale(display.HEIGHT * .318f); | ||
|
||
for(auto i = 0u; i < display.HEIGHT; i++) { | ||
int n = floor(i / 4) * 4; | ||
float h = 0.4 * float(n) / display.HEIGHT; | ||
h = 0.333 - h; | ||
palette[i] = RGB::from_hsv(h, 1.0f, 1.0f); | ||
} | ||
|
||
max_sample_from_fft = 4000.f + 130.f * display.HEIGHT; | ||
lower_threshold = 270 - 2 * display.HEIGHT; | ||
#ifdef SCALE_LOGARITHMIC | ||
multiple = float_to_fix15(pow(max_sample_from_fft / lower_threshold, -1.f / (display.HEIGHT - 1))); | ||
#elif defined(SCALE_SQRT) | ||
subtract_step = float_to_fix15((max_sample_from_fft - lower_threshold) * 2.f / (display.HEIGHT * (display.HEIGHT - 1))); | ||
#elif defined(SCALE_LINEAR) | ||
subtract = float_to_fix15((max_sample_from_fft - lower_threshold) / (display.HEIGHT - 1)); | ||
#endif | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#pragma once | ||
#include <functional> | ||
#include "display.hpp" | ||
#include "lib/fixed_fft.hpp" | ||
#include "lib/rgb.hpp" | ||
|
||
class Effect { | ||
public: | ||
Display &display; | ||
FIX_FFT &fft; | ||
Effect(Display& display, FIX_FFT& fft) : | ||
display(display), | ||
fft(fft) {}; | ||
virtual void init(uint32_t sample_frequency); | ||
virtual void update(int16_t *buffer16, size_t sample_count); | ||
}; | ||
|
||
class RainbowFFT : public Effect { | ||
private: | ||
// Number of FFT bins to skip on the left, the low frequencies tend to be pretty boring visually | ||
static constexpr unsigned int FFT_SKIP_BINS = 1; | ||
static constexpr unsigned int BUFFERS_PER_FFT_SAMPLE = 2; | ||
static constexpr unsigned int SAMPLES_PER_AUDIO_BUFFER = SAMPLE_COUNT / BUFFERS_PER_FFT_SAMPLE; | ||
static constexpr int HISTORY_LEN = 21; // About 0.25s | ||
uint history_idx; | ||
uint8_t eq_history[Display::WIDTH][HISTORY_LEN]; | ||
|
||
RGB palette_peak[Display::WIDTH]; | ||
RGB palette_main[Display::WIDTH]; | ||
|
||
float max_sample_from_fft; | ||
int lower_threshold; | ||
#ifdef SCALE_LOGARITHMIC | ||
fix15 multiple; | ||
#elif defined(SCALE_SQRT) | ||
fix15 subtract_step; | ||
#elif defined(SCALE_LINEAR) | ||
fix15 subtract; | ||
#else | ||
#error "Choose a scale mode" | ||
#endif | ||
|
||
public: | ||
RainbowFFT(Display& display, FIX_FFT& fft) : Effect(display, fft) {} | ||
void update(int16_t *buffer16, size_t sample_count) override; | ||
void init(uint32_t sample_frequency) override; | ||
}; | ||
|
||
class ClassicFFT : public Effect { | ||
private: | ||
// Number of FFT bins to skip on the left, the low frequencies tend to be pretty boring visually | ||
static constexpr unsigned int FFT_SKIP_BINS = 1; | ||
static constexpr unsigned int BUFFERS_PER_FFT_SAMPLE = 2; | ||
static constexpr unsigned int SAMPLES_PER_AUDIO_BUFFER = SAMPLE_COUNT / BUFFERS_PER_FFT_SAMPLE; | ||
static constexpr int HISTORY_LEN = 21; // About 0.25s | ||
uint history_idx; | ||
uint8_t eq_history[Display::WIDTH][HISTORY_LEN]; | ||
|
||
RGB palette[Display::HEIGHT]; | ||
|
||
float max_sample_from_fft; | ||
int lower_threshold; | ||
#ifdef SCALE_LOGARITHMIC | ||
fix15 multiple; | ||
#elif defined(SCALE_SQRT) | ||
fix15 subtract_step; | ||
#elif defined(SCALE_LINEAR) | ||
fix15 subtract; | ||
#else | ||
#error "Choose a scale mode" | ||
#endif | ||
|
||
public: | ||
ClassicFFT(Display& display, FIX_FFT &fft) : Effect(display, fft) {} | ||
void update(int16_t *buffer16, size_t sample_count) override; | ||
void init(uint32_t sample_frequency) override; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.