MythTV master
synaesthesia.cpp
Go to the documentation of this file.
1// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
2//
3// Use, modification and distribution is allowed without limitation,
4// warranty, or liability of any kind.
5//
6// modified 12-2004 by Kyle Schlansker to add 64 bit support
7//
8
9// C++
10#include <algorithm>
11#include <cinttypes>
12#include <cmath>
13#include <cstdint>
14#include <cstdlib>
15#include <iostream>
16
17// Qt
18#include <QCoreApplication>
19#include <QPainter>
20#include <QImage>
21#include <numbers>
22
23// MythTV
24#include <libmythbase/compat.h>
26
27// MythMusic
28#include "mainvisual.h"
29#include "synaesthesia.h"
30
32{
33 m_fps = 29;
34
35 coreInit(); // init cosTable, negSinTable, bitReverse
36 setStarSize(m_starSize); // init scaleDown, maxStarRadius
37 setupPalette(); // init palette
38}
39
41{
42 delete m_outputImage;
43}
44
45//static constexpr uint8_t sBOUND(int x)
46// { return std::clamp(x, 0, 255); };
47//static constexpr uint8_t sPEAKIFY(int x)
48// {return sBOUND(x - x*(255-x)/255/2); };
49
51{
52 double fgRed = m_fgRedSlider;
53 double fgGreen = m_fgGreenSlider;
54 double fgBlue = 1.0 - std::max(m_fgRedSlider,m_fgGreenSlider);
55 //double scale = std::max({fgRed,fgGreen,fgBlue});
56 double scale = (fgRed + fgGreen + fgBlue) / 2.0;
57 fgRed /= scale;
58 fgGreen /= scale;
59 fgBlue /= scale;
60
61 double bgRed = m_bgRedSlider;
62 double bgGreen = m_bgGreenSlider;
63 double bgBlue = 1.0 - std::max(m_bgRedSlider,m_bgGreenSlider);
64 //scale = std::max({bgRed,bgGreen,bgBlue});
65 scale = (bgRed + bgGreen + bgBlue) / 2.0;
66 bgRed /= scale;
67 bgGreen /= scale;
68 bgBlue /= scale;
69
70 for (int i = 0; i < 256; i++) {
71 int f = i & 15;
72 int b = i / 16;
73 //m_palette[i * 3 + 0] = sPEAKIFY(b*bgRed*16+f*fgRed*16);
74 //m_palette[i * 3 + 1] = sPEAKIFY(b*bgGreen*16+f*fgGreen*16);
75 //m_palette[i * 3 + 2] = sPEAKIFY(b*bgBlue*16+f*fgBlue*16);
76
77 double red = (b * bgRed * 16) + (f * fgRed * 16);
78 double green = (b * bgGreen * 16) + (f * fgGreen * 16);
79 double blue = (b * bgBlue * 16) + (f * fgBlue * 16);
80
81 double excess = 0.0;
82 for (int j = 0; j < 5; j++)
83 {
84 red += excess / 3;
85 green += excess / 3;
86 blue += excess / 3;
87 excess = 0.0;
88
89
90 if (red > 255) { excess += red - 255; red = 255; }
91 if (green > 255) { excess += green - 255; green = 255; }
92 if (blue > 255) { excess += blue - 255; blue = 255; }
93 }
94
95 double scale2 = (0.5 + ((red + green + blue) / 768.0)) / 1.5;
96 red *= scale2;
97 green *= scale2;
98 blue *= scale2;
99
100 m_palette[(i * 3) + 0] = std::clamp(int(red), 0, 255);
101 m_palette[(i * 3) + 1] = std::clamp(int(green), 0, 255);
102 m_palette[(i * 3) + 2] = std::clamp(int(blue), 0, 255);
103 }
104}
105
106void Synaesthesia::resize(const QSize &newsize)
107{
108 m_size = newsize;
109
110 m_size.setHeight(m_size.height() / 2);
111 m_size.setWidth((m_size.width() / 4) * 4);
112 m_outputBmp.size(m_size.width(), m_size.height());
113 m_lastOutputBmp.size(m_size.width(), m_size.height());
114 m_lastLastOutputBmp.size(m_size.width(), m_size.height());
115 m_outWidth = m_size.width();
116 m_outHeight = m_size.height();
117
118 delete m_outputImage;
119
120 m_size.setHeight(m_size.height() * 2);
121 m_outputImage = new QImage(m_size, QImage::Format_Indexed8);
122
123 if (!m_outputImage)
124 {
125 LOG(VB_GENERAL, LOG_ERR,
126 "outputImage in Synaesthesia::resize() is NULL");
127 return;
128 }
129
130 for (size_t i = 0; i < 256; i++)
131 m_outputImage->setColor(i, qRgba(m_palette[i * 3], m_palette[(i * 3) + 1],
132 m_palette[(i * 3) + 2], 255));
133
134#if 0
135 surface = SDL_SetVideoMode(size.width(), size.height(), 8, 0);
136
137 if (!surface)
138 {
139 LOG(VB_GENERAL, LOG_ERR, "Couldn't get SDL surface");
140 return;
141 }
142
143 SDL_Color sdlPalette[256];
144
145 for (int i = 0; i < 256; i++)
146 {
147 sdlPalette[i].r = m_palette[i * 3];
148 sdlPalette[i].g = m_palette[i * 3 + 1];
149 sdlPalette[i].b = m_palette[i * 3 + 2];
150 }
151
152 SDL_SetColors(surface, sdlPalette, 0, 256);
153#endif
154}
155
157{
158 int sum = 0;
159 for (size_t j = 0; j < LogSize; j++)
160 {
161 sum = (i & 1) + (sum * 2);
162 i >>= 1;
163 }
164
165 return sum;
166}
167
168void Synaesthesia::fft(double *x, double *y)
169{
170 size_t n2 = NumSamples;
171 for (size_t twoToTheK = 1; twoToTheK < NumSamples; twoToTheK *= 2)
172 {
173 size_t n1 = n2;
174 n2 /= 2;
175 for (size_t j = 0; j < n2; j++)
176 {
177 double c = m_cosTable[(j * twoToTheK) & (NumSamples - 1)];
178 double s = m_negSinTable[(j * twoToTheK) & (NumSamples - 1)];
179 for (size_t i = j; i < NumSamples; i += n1)
180 {
181 size_t l = i + n2;
182 double xt = x[i] - x[l];
183 x[i] = (x[i] + x[l]);
184 double yt = y[i] - y[l];
185 y[i] = (y[i] + y[l]);
186 x[l] = (xt * c) - (yt * s);
187 y[l] = (xt * s) + (yt * c);
188 }
189 }
190 }
191}
192
194{
195 double fadeModeFudge { 0.78 };
196 if (m_fadeMode == Wave)
197 fadeModeFudge = 0.4;
198 else if (m_fadeMode == Flame)
199 fadeModeFudge = 0.6;
200
201 int factor = 0;
202 if (lsize > 0.0)
203 factor = int(exp(log(fadeModeFudge) / (lsize * 8.0)) * 255);
204 factor = std::min(factor, 255);
205
206 for (int i = 0; i < 256; i++)
207 m_scaleDown[i] = i * factor>>8;
208
209 m_maxStarRadius = 1;
210 for (int i = 255; i; i = m_scaleDown[i])
212}
213
215{
216 for (size_t i = 0; i < NumSamples; i++)
217 {
218 m_negSinTable[i] = -sin(std::numbers::pi * 2.0 / NumSamples * i);
219 m_cosTable[i] = cos(std::numbers::pi * 2.0 / NumSamples * i);
221 }
222}
223
224#define output ((unsigned char*)m_outputBmp.data)
225#define lastOutput ((unsigned char*)m_lastOutputBmp.data)
226#define lastLastOutput ((unsigned char*)m_lastLastOutputBmp.data)
227
228void Synaesthesia::addPixel(int x, int y, int br1, int br2) const
229{
230 if (x < 0 || x > m_outWidth || y < 0 || y >= m_outHeight)
231 return;
232
233 unsigned char *p = output + (static_cast<ptrdiff_t>(x) * 2) +
234 (static_cast<ptrdiff_t>(y) * m_outWidth * 2);
235 if (p[0] + br1 < 255)
236 p[0] += br1;
237 else
238 p[0] = 255;
239 if (p[1] + br2 < 255)
240 p[1] += br2;
241 else
242 p[1] = 255;
243}
244
245void Synaesthesia::addPixelFast(unsigned char *p, int br1, int br2)
246{
247 if (p[0] + br1 < 255)
248 p[0] += br1;
249 else
250 p[0] = 255;
251 if (p[1] + br2 < 255)
252 p[1] += br2;
253 else
254 p[1] = 255;
255}
256
257unsigned char Synaesthesia::getPixel(int x, int y, int where) const
258{
259 if (x < 0 || y < 0 || x >= m_outWidth || y >= m_outHeight)
260 return 0;
261
262 return lastOutput[where];
263}
264
266{
267 auto *ptr = (uint32_t *)output;
268 for (int i = static_cast<ptrdiff_t>(m_outWidth) * m_outHeight * 2 / sizeof(uint32_t);
269 i > 0; i--)
270 {
271 uint32_t x = *ptr;
272 if (x)
273 {
274 *(ptr++) = x - ((x & (uintptr_t)0xf0f0f0f0) >> 4) -
275 ((x & (uintptr_t)0xe0e0e0e0) >> 5);
276 }
277 else
278 {
279 ptr++;
280 }
281 }
282}
283
284void Synaesthesia::fadePixelWave(int x, int y, int where, int step)
285{
286 short j = short((int(getPixel(x - 1, y, where - 2)) +
287 int(getPixel(x + 1, y, where + 2)) +
288 int(getPixel(x, y - 1, where - step)) +
289 int(getPixel(x, y + 1, where + step))) >> 2) +
290 lastOutput[where];
291
292 if (!j)
293 {
294 output[where] = 0;
295 return;
296 }
297 j = j - lastLastOutput[where] - 1;
298 if (j < 0)
299 output[where] = 0;
300 else if (j & (255 * 256))
301 output[where] = 255;
302 else
303 output[where] = j;
304}
305
307{
308 unsigned short *t = m_lastLastOutputBmp.data;
312
313 int step = m_outWidth*2;
314 for (int x = 0, i = 0, j = m_outWidth * (m_outHeight - 1) * 2;
315 x < m_outWidth; x++, i += 2, j += 2)
316 {
317 fadePixelWave(x, 0, i, step);
318 fadePixelWave(x, 0, i + 1, step);
319 fadePixelWave(x, m_outHeight - 1, j, step);
320 fadePixelWave(x, m_outHeight - 1, j + 1, step);
321 }
322
323 for (int y = 1, i = m_outWidth * 2, j = (m_outWidth * 4) - 2;
324 y < m_outHeight; y++, i += step, j += step)
325 {
326 fadePixelWave(0, y, i, step);
327 fadePixelWave(0, y, i + 1, step);
328 fadePixelWave(m_outWidth - 1, y, j, step);
329 fadePixelWave(m_outWidth - 1, y, j + 1, step);
330 }
331
332 for (int y = 1, start = (m_outWidth * 2) + 2, end = (m_outWidth * 4) - 2;
333 y < m_outHeight - 1; y++, start += step, end += step)
334 {
335 for (int i2 = start; i2 < end; i2++)
336 {
337 short j2 = short((int(lastOutput[i2 - 2]) +
338 int(lastOutput[i2 + 2]) +
339 int(lastOutput[i2 - step]) +
340 int(lastOutput[i2 + step])) >> 2) +
341 lastOutput[i2];
342 if (!j2)
343 {
344 output[i2] = 0;
345 }
346 else
347 {
348 j2 = j2 - lastLastOutput[i2] - 1;
349 if (j2 < 0)
350 output[i2] = 0;
351 else if (j2 & (255*256))
352 output[i2] = 255;
353 else
354 output[i2] = j2;
355 }
356 }
357 }
358}
359
360void Synaesthesia::fadePixelHeat(int x, int y, int where, int step)
361{
362 short j = short((int(getPixel(x - 1, y, where - 2)) +
363 int(getPixel(x + 1, y, where + 2)) +
364 int(getPixel(x, y - 1, where - step)) +
365 int(getPixel(x, y + 1, where + step))) >> 2) +
366 lastOutput[where];
367 if (!j)
368 {
369 output[where] = 0;
370 return;
371 }
372 j = j -lastLastOutput[where] - 1;
373 if (j < 0)
374 output[where] = 0;
375 else if (j & (255 * 256))
376 output[where] = 255;
377 else
378 output[where] = j;
379}
380
382{
383 unsigned short *t = m_lastLastOutputBmp.data;
387
388 int step = m_outWidth * 2;
389 for (int x = 0, i = 0, j = m_outWidth * (m_outHeight - 1) * 2;
390 x < m_outWidth; x++, i += 2, j += 2)
391 {
392 fadePixelHeat(x, 0, i, step);
393 fadePixelHeat(x, 0, i + 1, step);
394 fadePixelHeat(x, m_outHeight - 1, j, step);
395 fadePixelHeat(x, m_outHeight - 1, j + 1, step);
396 }
397
398 for(int y = 1, i = m_outWidth * 2, j = (m_outWidth * 4) - 2; y < m_outHeight;
399 y++, i += step, j += step)
400 {
401 fadePixelHeat(0, y, i, step);
402 fadePixelHeat(0, y, i + 1, step);
403 fadePixelHeat(m_outWidth - 1, y, j, step);
404 fadePixelHeat(m_outWidth - 1, y, j + 1, step);
405 }
406
407 for(int y = 1, start = (m_outWidth * 2) + 2, end = (m_outWidth * 4) - 2;
408 y < m_outHeight - 1; y++, start += step, end += step)
409 {
410 for (int i2 = start; i2 < end; i2++)
411 {
412 short j2 = short((int(lastOutput[i2 - 2]) +
413 int(lastOutput[i2 + 2]) +
414 int(lastOutput[i2 - step]) +
415 int(lastOutput[i2 + step])) >> 2) +
416 lastOutput[i2];
417 if (!j2)
418 {
419 output[i2] = 0;
420 }
421 else
422 {
423 j2 = j2 - lastLastOutput[i2] +
424 ((lastLastOutput[i2] - lastOutput[i2]) >> 2) - 1;
425 if (j2 < 0)
426 output[i2] = 0;
427 else if (j2 & (255*256))
428 output[i2] = 255;
429 else
430 output[i2] = j2;
431 }
432 };
433 }
434}
435
437{
438 switch(m_fadeMode)
439 {
440 case Stars: fadeFade(); break;
441 case Flame: fadeHeat(); break;
442 case Wave: fadeWave(); break;
443 default: break;
444 }
445}
446
448{
449 fade();
450
451 if (!node)
452 return false;
453
454 samp_dbl_array x {};
455 samp_dbl_array y {};
456 samp_dbl_array a {};
457 samp_dbl_array b {};
458 samp_int_array clarity {};
459
460 int brightFactor = int(Brightness * m_brightnessTwiddler / (m_starSize + 0.01));
461
462 size_t numSamps = NumSamples;
463 if (node->m_length < NumSamples)
464 numSamps = node->m_length;
465
466 for (size_t i = 0; i < numSamps; i++)
467 {
468 x[i] = node->m_left[i];
469 if (node->m_right)
470 y[i] = node->m_right[i];
471 else
472 y[i] = x[i];
473 }
474
475 fft(x.data(), y.data());
476
477 double energy = 0.0;
478
479 for (size_t i = 0 + 1; i < NumSamples / 2; i++)
480 {
481 double x1 = x[m_bitReverse[i]];
482 double y1 = y[m_bitReverse[i]];
483 double x2 = x[m_bitReverse[NumSamples - i]];
484 double y2 = y[m_bitReverse[NumSamples - i]];
485 double aa = ((x1 + x2) * (x1 + x2)) + ((y1 - y2) * (y1 - y2));
486 double bb = ((x1 - x2) * (x1 - x2)) + ((y2 + y2) * (y1 + y2));
487 a[i] = sqrt(aa);
488 b[i] = sqrt(bb);
489 if (aa + bb != 0.0)
490 {
491 clarity[i] = (int)((((x1 + x2) * (x1 - x2)) + ((y1 + y2) * (y1 - y2))) /
492 (aa + bb) * 256);
493 }
494 else
495 {
496 clarity[i] = 0;
497 }
498
499 energy += (aa + bb) * i * i;
500 }
501
502 energy = sqrt(energy / NumSamples) / 65536.0;
503
504 //int heightFactor = NumSamples / 2 / outHeight + 1;
505 //int actualHeight = NumSamples / 2 / heightFactor;
506 //int heightAdd = (outHeight + actualHeight) >> 1;
507
508 double brightFactor2 = (brightFactor / 65536.0 / NumSamples) *
509 sqrt(m_outHeight * m_outWidth / (320.0 * 200.0));
510
511 m_energyAvg = (m_energyAvg * 0.95) + (energy * 0.05);
512 if (m_energyAvg > 0.0)
513 brightFactor2 *= 80.0 / (m_energyAvg + 5.0);
514
515 for (size_t i = 1; i < NumSamples / 2; i++)
516 {
517 if (a[i] > 0 || b[i] > 0)
518 {
519 int h = (int)(b[i] * m_outWidth / (a[i] + b[i]));
520 int br = (int)((a[i] + b[i]) * i * brightFactor2);
521 int br1 = br * (clarity[i] + 128) >> 8;
522 int br2 = br * (128 - clarity[i]) >> 8;
523 if (br1 < 0) br1 = 0; else if (br1 > 255) br1 = 255;
524 if (br2 < 0) br2 = 0; else if (br2 > 255) br2 = 255;
525
526 int px = h;
527 int py = m_outHeight - (i * m_outHeight / (NumSamples / 2));
528
530 {
531 addPixel(px, py, br1, br2);
532 br1 = m_scaleDown[br1];
533 br2 = m_scaleDown[br2];
534
535 for(int j = 1; br1 > 0 || br2 > 0;
536 j++, br1 = m_scaleDown[br1], br2 = m_scaleDown[br2])
537 {
538 for (int k = 0; k < j; k++)
539 {
540 addPixel(px - j + k,py - k, br1, br2);
541 addPixel(px + k, py - j + k, br1, br2);
542 addPixel(px + j - k, py + k, br1, br2);
543 addPixel(px - k, py + j - k, br1, br2);
544 }
545 }
546 }
547 else
548 {
549 if (px < m_maxStarRadius || py < m_maxStarRadius ||
550 px > m_outWidth - m_maxStarRadius ||
552 {
553 addPixel(px, py, br1, br2);
554 for(int j = 1; br1 > 0 || br2 > 0;
555 j++, br1 = m_scaleDown[br1], br2 = m_scaleDown[br2])
556 {
557 addPixel(px + j, py, br1, br2);
558 addPixel(px, py + j, br1, br2);
559 addPixel(px - j, py, br1, br2);
560 addPixel(px, py - j, br1, br2);
561 }
562 }
563 else
564 {
565 unsigned char *p = output + (static_cast<ptrdiff_t>(px) * 2) +
566 (static_cast<ptrdiff_t>(py) * m_outWidth * 2);
567 unsigned char *p1 = p;
568 unsigned char *p2 = p;
569 unsigned char *p3 = p;
570 unsigned char *p4 = p;
571 addPixelFast(p, br1, br2);
572 for (; br1 > 0 || br2 > 0;
573 br1 = m_scaleDown[br1], br2 = m_scaleDown[br2])
574 {
575 p1 += 2;
576 addPixelFast(p1, br1, br2);
577 p2 -= 2;
578 addPixelFast(p2, br1, br2);
579 p3 += static_cast<ptrdiff_t>(m_outWidth) * 2;
580 addPixelFast(p3, br1, br2);
581 p4 -= static_cast<ptrdiff_t>(m_outWidth) * 2;
582 addPixelFast(p4, br1, br2);
583 }
584 }
585 }
586 }
587 }
588
589 return false;
590}
591
592bool Synaesthesia::draw(QPainter *p, [[maybe_unused]] const QColor &back)
593{
594 if (!m_outputImage)
595 return true;
596
597 auto *ptrOutput = (uint32_t *)output;
598
599 for (int j = 0; j < m_outHeight * 2; j += 2)
600 {
601 auto *ptrTop = (uint32_t *)(m_outputImage->scanLine(j));
602 auto *ptrBot = (uint32_t *)(m_outputImage->scanLine(j+1));
603
604 for (int i = m_outWidth / 4; i > 0; i--)
605 {
606 unsigned int const r1 = *(ptrOutput++);
607 unsigned int const r2 = *(ptrOutput++);
608
609 unsigned int const v = ((r1 & 0x000000f0UL) >> 4) |
610 ((r1 & 0x0000f000UL) >> 8) |
611 ((r1 & 0x00f00000UL) >> 12) |
612 ((r1 & 0xf0000000UL) >> 16);
613
614 *(ptrTop++) = v | (((r2 & 0x000000f0UL) << 12) |
615 ((r2 & 0x0000f000UL) << 8) |
616 ((r2 & 0x00f00000UL) << 4) |
617 ( r2 & 0xf0000000UL));
618
619 *(ptrBot++) = v | (((r2 & 0x000000f0UL) << 12) |
620 ((r2 & 0x0000f000UL) << 8) |
621 ((r2 & 0x00f00000UL) << 4) |
622 ( r2 & 0xf0000000UL));
623 }
624 }
625
626 p->drawImage(0, 0, *m_outputImage);
627
628 return true;
629}
630
631static class SynaesthesiaFactory : public VisFactory
632{
633 public:
634 const QString &name(void) const override // VisFactory
635 {
636 static QString s_name = QCoreApplication::translate("Visualizers",
637 "Synaesthesia");
638 return s_name;
639 }
640
641 uint plugins(QStringList *list) const override // VisFactory
642 {
643 *list << name();
644 return 1;
645 }
646
647 VisualBase *create([[maybe_unused]] MainVisual *parent,
648 [[maybe_unused]] const QString &pluginName) const override // VisFactory
649 {
650 return new Synaesthesia();
651 }
void size(int w, int h)
Definition: polygon.h:18
Pixel * data
Definition: polygon.h:13
VisualBase * create(MainVisual *parent, const QString &pluginName) const override
const QString & name(void) const override
uint plugins(QStringList *list) const override
void fadeFade(void) const
Synaesthesia(void)
Bitmap< unsigned short > m_outputBmp
Definition: synaesthesia.h:70
void resize(const QSize &size) override
static void addPixelFast(unsigned char *p, int br1, int br2)
~Synaesthesia() override
static int bitReverser(int i)
double m_bgGreenSlider
Definition: synaesthesia.h:79
samp_int_array m_bitReverse
Definition: synaesthesia.h:59
void fadePixelHeat(int x, int y, int where, int step)
void fade(void)
void fft(double *x, double *y)
bool process(VisualNode *node) override
void setStarSize(double lsize)
void coreInit(void)
std::array< uint8_t, 768 > m_palette
Definition: synaesthesia.h:75
void fadeWave(void)
double m_fgRedSlider
Definition: synaesthesia.h:76
unsigned char getPixel(int x, int y, int where) const
std::array< int, 256 > m_scaleDown
Definition: synaesthesia.h:60
samp_dbl_array m_cosTable
Definition: synaesthesia.h:57
QImage * m_outputImage
Definition: synaesthesia.h:73
void addPixel(int x, int y, int br1, int br2) const
void setupPalette(void)
bool m_pointsAreDiamonds
Definition: synaesthesia.h:63
int m_maxStarRadius
Definition: synaesthesia.h:61
bool draw(QPainter *p, const QColor &back) override
double m_starSize
Definition: synaesthesia.h:65
void fadeHeat(void)
double m_fgGreenSlider
Definition: synaesthesia.h:77
Bitmap< unsigned short > m_lastLastOutputBmp
Definition: synaesthesia.h:72
double m_energyAvg
Definition: synaesthesia.h:81
Bitmap< unsigned short > m_lastOutputBmp
Definition: synaesthesia.h:71
double m_brightnessTwiddler
Definition: synaesthesia.h:64
samp_dbl_array m_negSinTable
Definition: synaesthesia.h:58
double m_bgRedSlider
Definition: synaesthesia.h:78
void fadePixelWave(int x, int y, int where, int step)
int m_fps
Definition: visualize.h:90
long m_length
Definition: videovisual.h:38
short * m_left
Definition: videovisual.h:36
short * m_right
Definition: videovisual.h:37
unsigned int uint
Definition: compat.h:60
static std::vector< uint32_t > back
Definition: goom_core.cpp:27
static uint32_t * p1
Definition: goom_core.cpp:28
static uint32_t * p2
Definition: goom_core.cpp:28
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
static int x1
Definition: mythsocket.cpp:55
static int x2
Definition: mythsocket.cpp:56
None log(str msg, int level=LOGDEBUG)
Definition: xbmc.py:9
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:204
#define lastOutput
#define lastLastOutput
SynaesthesiaFactory SynaesthesiaFactory
#define output
static constexpr size_t LogSize
Definition: synaesthesia.h:13
std::array< double, NumSamples > samp_dbl_array
Definition: synaesthesia.h:17
static constexpr size_t NumSamples
Definition: synaesthesia.h:14
@ Wave
Definition: synaesthesia.h:22
@ Stars
Definition: synaesthesia.h:23
@ Flame
Definition: synaesthesia.h:21
std::array< int, NumSamples > samp_int_array
Definition: synaesthesia.h:18