17 uint8_t
r = 0,
g = 0,
b = 0,
a = 255;
36 if (std::isnan(t)) t = 0.0f;
37 t = std::clamp(t, 0.0f, 1.0f);
45 return map_grayscale(t);
54 struct CP {
float t; uint8_t r, g, b; };
56 static SpectrogramColor interpolate(
const CP* pts,
int count,
float t) {
57 if (t <= pts[0].t)
return {pts[0].r, pts[0].g, pts[0].b, 255};
58 if (t >= pts[count - 1].t)
return {pts[count-1].r, pts[count-1].g, pts[count-1].b, 255};
60 for (
int i = 0;
i <
count - 1; ++
i) {
61 if (t >= pts[
i].t && t <= pts[
i + 1].t) {
62 float f = (
t - pts[
i].t) / (pts[
i + 1].t - pts[
i].t);
64 static_cast<uint8_t
>(pts[
i].r +
f * (pts[
i + 1].r - pts[
i].r)),
65 static_cast<uint8_t
>(pts[
i].g + f * (pts[
i + 1].g - pts[
i].g)),
66 static_cast<uint8_t
>(pts[
i].b +
f * (pts[
i + 1].b - pts[
i].b)),
71 return {0, 0, 0, 255};
74 static SpectrogramColor map_inferno(
float t) {
75 static constexpr CP pts[] = {
80 {1.0f, 252, 255, 164},
82 return interpolate(pts, 5, t);
85 static SpectrogramColor map_viridis(
float t) {
86 static constexpr CP pts[] = {
93 return interpolate(pts, 5, t);
96 static SpectrogramColor map_grayscale(
float t) {
97 auto v =
static_cast<uint8_t
>(
t * 255);
98 return {
v,
v,
v, 255};
101 static SpectrogramColor map_heat(
float t) {
102 static constexpr CP pts[] = {
105 {0.66f, 255, 200, 0},
106 {1.0f, 255, 255, 255},
108 return interpolate(pts, 4, t);
122 fft_size_ = fft_size;
123 sample_rate_ = sample_rate;
125 num_bins_ = fft_size / 2 + 1;
126 nyquist_ = sample_rate / 2.0f;
143 return static_cast<float>(bin) * sample_rate_ / fft_size_;
148 int bin =
static_cast<int>(std::round(hz * fft_size_ / sample_rate_));
149 return std::clamp(bin, 0, num_bins_ - 1);
154 hz = std::clamp(hz, 1.0f, nyquist_);
157 return hz / nyquist_;
159 return std::log2(hz) / std::log2(nyquist_);
161 return hz_to_mel(hz) / hz_to_mel(nyquist_);
163 return hz / nyquist_;
168 pos = std::clamp(pos, 0.0f, 1.0f);
171 return pos * nyquist_;
173 return std::pow(2.0f, pos * std::log2(nyquist_));
175 return mel_to_hz(pos * hz_to_mel(nyquist_));
177 return pos * nyquist_;
185 int fft_size_ = 1024;
186 float sample_rate_ = 44100.0f;
189 float nyquist_ = 22050.0f;
191 static float hz_to_mel(
float hz) {
192 return 2595.0f * std::log10(1.0f + hz / 700.0f);
195 static float mel_to_hz(
float mel) {
196 return 700.0f * (std::pow(10.0f,
mel / 2595.0f) - 1.0f);
211 width_ = std::max(0,
width);
212 height_ = std::max(0,
height);
213 pixels_.resize(
static_cast<std::size_t
>(width_) *
static_cast<std::size_t
>(height_));
221 template <
typename SampleType =
float>
224 float min_db = -80.0f,
float max_db = 0.0f) {
225 if (width_ <= 0 || height_ <= 0)
return;
227 float range = max_db - min_db;
228 if (range <= 0) range = 1.0f;
230 for (
int row = 0; row < height_; ++row) {
233 int bin = (num_bins > 0 && height_ > 0)
234 ? std::clamp(row * num_bins / height_, 0, num_bins - 1)
237 float magnitude_db = magnitudes_db !=
nullptr && num_bins > 0
238 ?
static_cast<float>(magnitudes_db[bin])
241 pixels_[row * width_ + write_col_] = mapper.
map(normalized);
244 write_col_ = (write_col_ + 1) % width_;
250 float min_db = -80.0f,
float max_db = 0.0f) {
262 int width()
const {
return width_; }
270 int frames_written_ = 0;
271 std::vector<SpectrogramColor> pixels_;
Maps a normalized value [0,1] to a color using a predefined ramp.
Definition spectrogram.hpp:27
ColorMapper(ColorRamp ramp=ColorRamp::inferno)
Definition spectrogram.hpp:29
ColorRamp ramp() const
Definition spectrogram.hpp:49
SpectrogramColor map(float t) const
Map a normalized value (0 = minimum, 1 = maximum) to a color.
Definition spectrogram.hpp:32
void set_ramp(ColorRamp ramp)
Definition spectrogram.hpp:48
Utilities for mapping FFT bins to display coordinates.
Definition spectrogram.hpp:118
void configure(int fft_size, float sample_rate, FrequencyScale scale=FrequencyScale::logarithmic)
Configure the axis for a given FFT size and sample rate.
Definition spectrogram.hpp:121
float bin_to_hz(int bin) const
Convert bin index to frequency in Hz.
Definition spectrogram.hpp:142
float nyquist() const
Definition spectrogram.hpp:181
FrequencyScale scale() const
Definition spectrogram.hpp:182
int hz_to_bin(float hz) const
Convert frequency in Hz to nearest bin index.
Definition spectrogram.hpp:147
float bin_to_display(int bin) const
Map a frequency bin index to a normalized display position [0, 1].
Definition spectrogram.hpp:130
float hz_to_display(float hz) const
Map Hz to normalized display position [0, 1].
Definition spectrogram.hpp:153
float display_to_hz(float pos) const
Map normalized display position [0, 1] back to Hz.
Definition spectrogram.hpp:167
int num_bins() const
Definition spectrogram.hpp:180
int display_to_bin(float display_pos) const
Map a normalized display position [0, 1] to the nearest bin index.
Definition spectrogram.hpp:136
Scrolling spectrogram buffer that accumulates STFT frames as rows.
Definition spectrogram.hpp:205
void push_column(const SampleType *magnitudes_db, int num_bins, const ColorMapper &mapper, float min_db=-80.0f, float max_db=0.0f)
Push a new STFT frame as a column of colors.
Definition spectrogram.hpp:222
void push_column(std::nullptr_t magnitudes_db, int num_bins, const ColorMapper &mapper, float min_db=-80.0f, float max_db=0.0f)
Definition spectrogram.hpp:248
int height() const
Definition spectrogram.hpp:263
int write_column() const
Get the column index where the next frame will be written.
Definition spectrogram.hpp:260
int frames_written() const
Definition spectrogram.hpp:264
int width() const
Definition spectrogram.hpp:262
const SpectrogramColor * pixels() const
Access the pixel buffer for rendering.
Definition spectrogram.hpp:257
void configure(int width, int height)
Configure the buffer.
Definition spectrogram.hpp:210
@ count
sentinel: number of real capabilities (keep LAST)
Definition canvas_capability.hpp:38
@ f
Definition pitch.hpp:25
Definition additive_bank.hpp:218
float magnitude_db(const BiquadT< SampleType > &filter, double freq_hz, double sample_rate)
Ask a live filter what it looks like: the magnitude, in dB, that this BiquadT is applying at freq_hz ...
Definition frequency_response.hpp:130
@ logarithmic
Definition modulation_curve.hpp:29
FrequencyScale
Frequency axis scaling modes.
Definition spectrogram.hpp:113
@ mel
Definition spectrogram.hpp:113
@ logarithmic
Definition spectrogram.hpp:113
@ linear
Definition spectrogram.hpp:113
@ i
Definition formant_filter_bank.hpp:20
@ linear
2-point. Cheapest; audible imaging when pitching up.
Definition granular.hpp:133
ColorRamp
Predefined color ramp types for spectrogram rendering.
Definition spectrogram.hpp:21
@ viridis
Definition spectrogram.hpp:21
@ grayscale
Definition spectrogram.hpp:21
@ heat
Definition spectrogram.hpp:21
@ inferno
Definition spectrogram.hpp:21
@ v
Definition input_events.hpp:41
@ t
Definition input_events.hpp:41
RGBA color for spectrogram pixels.
Definition spectrogram.hpp:16
uint8_t a
Definition spectrogram.hpp:17
uint8_t g
Definition spectrogram.hpp:17
uint8_t b
Definition spectrogram.hpp:17
uint8_t r
Definition spectrogram.hpp:17