arduino-audio-tools
LEDOutput.h
1 #pragma once
2 #include <FastLED.h>
3 
4 #include "AudioTools/AudioLibs/AudioFFT.h"
5 #include "FFTDisplay.h"
6 
7 namespace audio_tools {
8 
9 class LEDOutput;
10 struct LEDOutputConfig;
11 
12 // default callback function which implements led update
13 void fftLEDOutput(LEDOutputConfig *cfg, LEDOutput *matrix);
14 // led update for volume
15 void volumeLEDOutput(LEDOutputConfig *cfg, LEDOutput *matrix);
16 // default color
17 CHSV getDefaultColor(int x, int y, int magnitude);
18 
26  int x = 0;
28  int y = 1;
31  CHSV (*color_callback)(int x, int y, int magnitude) = getDefaultColor;
34  void (*update_callback)(LEDOutputConfig *cfg, LEDOutput *matrix) = nullptr;
36  int update_frequency = 1; // update every call
37  bool is_serpentine_layout = true;
38  bool is_matrix_vertical = true;
40  int max_magnitude = 700;
41 };
42 
47 class LEDOutput {
48  public:
50  LEDOutput() = default;
51 
55  p_fft = &fft;
57  }
58 
62  p_vol = &vol;
64  }
65 
67  LEDOutputConfig defaultConfig() { return cfg; }
68 
71  cfg = config;
72  if (ledCount() == 0) {
73  LOGE("x or y == 0");
74  return false;
75  }
76 
77  // allocate leds
78  leds.resize(ledCount());
79  for (int j = 0; j < ledCount(); j++) {
80  led(j) = CRGB::Black;
81  }
82 
83  // clear LED
84  FastLED.clear(); // clear all pixel data
85 
86  if (p_fft != nullptr) {
87  p_fft->begin();
88  }
89 
90  max_column = -1;
91 
92  return true;
93  }
94 
96  int ledCount() {
97  int num_leds = cfg.x * cfg.y;
98  return num_leds;
99  }
100 
102  CRGB *ledData() {
103  if (ledCount() == 0) {
104  LOGE("x or y == 0");
105  return nullptr;
106  }
107  // leds.resize(ledCount());
108  return leds.data();
109  }
110 
112  virtual void update() {
113  if (cfg.update_callback != nullptr && count++ % cfg.update_frequency == 0) {
114  // use custom update logic defined in config
115  cfg.update_callback(&cfg, this);
116  } else {
117  display();
118  }
119  }
120 
122  CRGB &ledXY(uint8_t x, uint8_t y) {
123  if (x > cfg.x) x = cfg.x - 1;
124  if (x < 0) x = 0;
125  if (y > cfg.y) y = cfg.y - 1;
126  if (y < 0) y = 0;
127  int index = xy(x, y);
128  return leds[index];
129  }
130 
132  CRGB &led(uint8_t index) {
133  if (index > cfg.x * cfg.y) return not_valid;
134  return leds[index];
135  }
136 
138  void setColumnBar(int x, int currY) {
139  // update vertical bar
140  for (uint8_t y = 0; y < currY; y++) {
141  // determine color
142  CHSV color = cfg.color_callback(x, y, currY);
143  // update LED
144  ledXY(x, y) = color;
145  }
146  for (uint8_t y = currY; y < cfg.y; y++) {
147  ledXY(x, y) = CRGB::Black;
148  }
149  if (x > max_column) max_column = x;
150  }
151 
153  void setColumnBar(int currY) { setColumnBar(cfg.x - 1, currY); }
154 
156  void addColumnBar(int currY) {
157  max_column++;
158  if (max_column >= cfg.x) {
159  addEmptyColumn();
160  }
161  if (max_column > cfg.x - 1) {
162  max_column = cfg.x - 1;
163  }
164  setColumnBar(max_column, currY);
165  }
166 
168  LEDOutputConfig &config() { return cfg; }
169 
171  virtual float getMaxMagnitude() {
172  // get magnitude from
173  if (p_vol != nullptr) {
174  return p_vol->volume();
175  }
176  float max = 0;
177  if (p_fft != nullptr) {
178  for (int j = 0; j < cfg.x; j++) {
179  float value = p_fft->getMagnitude(j);
180  if (value > max) {
181  max = value;
182  }
183  }
184  }
185  return max;
186  }
187 
189  void display() {
190  FastLED.show();
191  }
192 
194  FFTDisplay &fftDisplay() { return *p_fft; }
195 
196  protected:
197  friend class AudioFFTBase;
198  CRGB not_valid;
199  Vector<CRGB> leds{0};
200  LEDOutputConfig cfg;
201  VolumeMeter *p_vol = nullptr;
202  FFTDisplay *p_fft = nullptr;
203  uint64_t count = 0;
204  int max_column = -1;
205 
207  void addEmptyColumn() {
208  for (int x = 1; x < cfg.x; x++) {
209  for (int y = 0; y < cfg.y; y++) {
210  ledXY(x - 1, y) = ledXY(x, y);
211  }
212  }
213  for (int y = 0; y < cfg.y; y++) {
214  ledXY(cfg.x - 1, y) = CRGB::Black;
215  }
216  }
217 
218  uint16_t xy(uint8_t x, uint8_t y) {
219  uint16_t i;
220 
221  if (cfg.is_serpentine_layout == false) {
222  if (cfg.is_matrix_vertical == false) {
223  i = (y * cfg.x) + x;
224  } else {
225  i = cfg.y * (cfg.x - (x + 1)) + y;
226  }
227  }
228 
229  if (cfg.is_serpentine_layout == true) {
230  if (cfg.is_matrix_vertical == false) {
231  if (y & 0x01) {
232  // Odd rows run backwards
233  uint8_t reverseX = (cfg.x - 1) - x;
234  i = (y * cfg.x) + reverseX;
235  } else {
236  // Even rows run forwards
237  i = (y * cfg.x) + x;
238  }
239  } else { // vertical positioning
240  if (x & 0x01) {
241  i = cfg.y * (cfg.x - (x + 1)) + y;
242  } else {
243  i = cfg.y * (cfg.x - x) - (y + 1);
244  }
245  }
246  }
247 
248  return i;
249  }
250 };
251 
254  // process horizontal
255  LockGuard guard(fft_mux);
256  for (int x = 0; x < cfg->x; x++) {
257  // max y determined by magnitude
258  int currY = matrix->fftDisplay().getMagnitudeScaled(x, cfg->y);
259  LOGD("x: %d, y: %d", x, currY);
260  matrix->setColumnBar(x, currY);
261  }
262  FastLED.show();
263 }
264 
267  float vol = matrix->getMaxMagnitude();
268  int currY = mapT<float>(vol, 0,
269  cfg->max_magnitude, 0.0f,
270  static_cast<float>(cfg->y));
271  matrix->addColumnBar(currY);
272  FastLED.show();
273 }
274 
276 CHSV getDefaultColor(int x, int y, int magnitude) {
277  int color = map(magnitude, 0, 7, 255, 0);
278  return CHSV(color, 255, 100); // blue CHSV(160, 255, 255
279 }
280 
281 } // namespace audio_tools
Executes FFT using audio data. The Driver which is passed in the constructor selects a specifc FFT im...
Definition: AudioFFT.h:125
Definition: FFTDisplay.h:18
float getMagnitude(int x)
Definition: FFTDisplay.h:46
LED output using the FastLED library.
Definition: LEDOutput.h:47
FFTDisplay & fftDisplay()
Provides acces to the FFTDisplay object.
Definition: LEDOutput.h:194
void setColumnBar(int x, int currY)
Update the indicated column with the indicated bar.
Definition: LEDOutput.h:138
void display()
Update the led_matrix (calling FastLED.show();.
Definition: LEDOutput.h:189
CRGB & ledXY(uint8_t x, uint8_t y)
Determine the led with the help of the x and y pos.
Definition: LEDOutput.h:122
void addColumnBar(int currY)
Update the last column with the indicated bar.
Definition: LEDOutput.h:156
LEDOutput()=default
Default Constructor.
virtual float getMaxMagnitude()
Provodes the max magnitude for both the.
Definition: LEDOutput.h:171
void addEmptyColumn()
Adds an empty column to the end shifting the content to the left.
Definition: LEDOutput.h:207
LEDOutput(VolumeMeter &vol)
Constructor for VolumeMeter scenario.
Definition: LEDOutput.h:61
int ledCount()
Provides the number of LEDs: call begin() first!
Definition: LEDOutput.h:96
CRGB * ledData()
Provides the address fo the CRGB array: call begin() first!
Definition: LEDOutput.h:102
LEDOutputConfig & config()
Provides access to the actual config object. E.g. to change the update logic.
Definition: LEDOutput.h:168
bool begin(LEDOutputConfig config)
Setup Led matrix.
Definition: LEDOutput.h:70
LEDOutputConfig defaultConfig()
Provides the default config object.
Definition: LEDOutput.h:67
CRGB & led(uint8_t index)
Determine the led with the help of the index pos.
Definition: LEDOutput.h:132
virtual void update()
Updates the display: call this method in your loop.
Definition: LEDOutput.h:112
LEDOutput(FFTDisplay &fft)
Constructor for FFT scenario.
Definition: LEDOutput.h:54
void setColumnBar(int currY)
Update the last column with the indicated bar.
Definition: LEDOutput.h:153
RAII implementaion using a Mutex: Only a few microcontrollers provide lock guards,...
Definition: LockGuard.h:91
A simple class to determine the volume. You can use it as final output or as output or input in your ...
Definition: AudioStreams.h:1612
float volume()
Definition: AudioStreams.h:1665
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:823
long map(long x, long in_min, long in_max, long out_min, long out_max)
Maps input to output values.
Definition: NoArduino.h:162
CHSV getDefaultColor(int x, int y, int magnitude)
Default logic to update the color for the indicated x,y position.
Definition: LEDOutput.h:276
void volumeLEDOutput(LEDOutputConfig *cfg, LEDOutput *matrix)
Default update implementation which provides the fft result as "barchart".
Definition: LEDOutput.h:266
void fftLEDOutput(LEDOutputConfig *cfg, LEDOutput *matrix)
Default update implementation which provides the fft result as "barchart".
Definition: LEDOutput.h:253
Definition: LEDOutput.h:24
int y
Number of leds in y direction.
Definition: LEDOutput.h:28
int max_magnitude
Influences the senitivity.
Definition: LEDOutput.h:40
void(* update_callback)(LEDOutputConfig *cfg, LEDOutput *matrix)
Definition: LEDOutput.h:34
int x
Number of leds in x direction.
Definition: LEDOutput.h:26
int update_frequency
Update the leds only ever nth call.
Definition: LEDOutput.h:36
CHSV(* color_callback)(int x, int y, int magnitude)
Definition: LEDOutput.h:31