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