18 #include <QApplication>
19 #include <QCoreApplication>
43 #include <libavutil/mem.h>
44 #include <libavutil/tx.h>
50 : m_xscreensaverenable(screensaverenable)
70 p->fillRect(0, 0, size.width(), size.height(),
back);
74 QFont font = QApplication::font();
78 int logicalDpiY = 100;
79 HDC hdc = GetDC(
nullptr);
82 logicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY);
83 ReleaseDC(
nullptr, hdc);
90 float floatSize = (16 * 100.0F) / logicalDpiY;
95 floatSize = floatSize * hmult;
97 font.setPointSize(lroundf(floatSize));
98 font.setWeight(QFont::Bold);
99 font.setPointSizeF(fontSize * (size.width() / 800.0));
102 p->drawText(0, 0, size.width(), size.height(), Qt::AlignVCenter | Qt::AlignHCenter | Qt::TextWordWrap, warning);
110 setMax(maxscale, maxrange);
115 if (maxscale == 0 || maxrange == 0)
121 auto domain = (
long double) maxscale;
122 auto range = (
long double) maxrange;
124 long double dx = 1.0;
125 long double e4 = 1.0E-8;
131 for (
uint i=0; i<10000 && (std::abs(dx) > e4); i++)
134 double y = (x *
t) -
range;
135 double yy =
t - (domain / (x + domain));
141 for (
int i = 1; i < (int) domain; i++)
143 int scaled = (int) floor(0.5 + (alpha *
log((
double(i) + alpha) / alpha)));
144 scaled = std::max(scaled, 1);
159 setMax(maxscale, maxrange, maxfreq);
164 if (maxscale == 0 || maxrange == 0 || maxfreq == 0)
175 double next = pow(2.0, 1.0 / 12.0);
177 double maxmel =
hz2mel(maxfreq);
178 double hzperbin = (double) maxfreq / (
double) maxscale;
180 for (
int i = 0; i < maxrange; i++)
182 double mel = maxmel * i / maxrange;
184 int bin = int(hz / hzperbin);
204 if (note < 0 || note > 125)
211 if (note < 0 || note > 125)
218 if (note < 0 || note > 125)
250 for (
int i = 0; i <
m_size.width(); i++)
252 auto indexTo = (
unsigned long)(index + step);
253 if (indexTo == (
unsigned long)(index))
254 indexTo = (
unsigned long)(index + 1);
287 for (
auto s = (
unsigned long)index; s < indexTo && s < node->
m_length; s++)
289 double adjHeight =
static_cast<double>(
m_size.height()) / 4.0;
290 double tmpL = ( ( node->
m_left ?
static_cast<double>(node->
m_left[s]) : 0.) *
291 adjHeight ) / 32768.0;
292 double tmpR = ( ( node->
m_right ?
static_cast<double>(node->
m_right[s]) : 0.) *
293 adjHeight ) / 32768.0;
295 valL = (tmpL > valL) ? tmpL : valL;
297 valL = (tmpL < valL) ? tmpL : valL;
299 valR = (tmpR > valR) ? tmpR : valR;
301 valR = (tmpR < valR) ? tmpR : valR;
304 if (valL != 0. || valR != 0.)
310 index = index + step;
316 for (
int i = 0; i <
m_size.width(); i++)
342 if (valL != 0. || valR != 0.)
352 for (
int i = 0; (unsigned) i <
m_magnitudes.size(); i++ )
361 if (
back != Qt::green)
365 for (
int i = 1; i <
m_size.width(); i++ )
369 double per = (
static_cast<double>(
m_magnitudes[i]) * 2.0 ) /
370 (
static_cast<double>(
m_size.height()) / 4.0 );
400 p->setPen( QColor(
int(r), int(g), int(b) ) );
404 double adjHeight =
static_cast<double>(
m_size.height()) / 4.0;
443 p->setPen( QColor(
int(r), int(g), int(b) ) );
447 adjHeight =
static_cast<double>(
m_size.height()) * 3.0 / 4.0;
468 for (
int i = 0; i <
m_size.width(); i++)
470 auto indexTo = (
unsigned long)(index + step);
471 if (indexTo == (
unsigned long)index)
472 indexTo = (
unsigned long)(index + 1);
497 for (
auto s = (
unsigned long)index; s < indexTo && s < node->
m_length; s++)
499 double tmp = (
static_cast<double>(node->
m_left[s]) +
501 :
static_cast<double>(node->
m_left[s])) *
502 (
static_cast<double>(
m_size.height()) / 2.0 ) ) / 65536.0;
505 val = (
tmp > val) ?
tmp : val;
509 val = (
tmp < val) ?
tmp : val;
518 index = index + step;
524 for (
int i = 0; i <
m_size.width(); i++) {
544 for (
int i = 0; i <
m_size.width(); i++ )
553 if (
back != Qt::green)
557 for (
int i = 1; i <
m_size.width(); i++ ) {
559 double per = (
static_cast<double>(
m_magnitudes[i]) * 2.0 ) /
560 (
static_cast<double>(
m_size.height()) / 4.0 );
590 p->setPen(QColor(
int(r), int(g), int(b)));
594 double adjHeight =
static_cast<double>(
m_size.height()) / 2.0;
621 LOG(VB_PLAYBACK, LOG_INFO, QString(
"WF going down"));
627 QString cache =
GetConfDir() +
"/MythMusic/WaveForm";
637 filename = QString(
"%1/%2.png").arg(cache)
639 LOG(VB_PLAYBACK, LOG_INFO, QString(
"WF saving to %1").arg(
filename));
642 LOG(VB_GENERAL, LOG_ERR,
643 QString(
"WF saving to %1 failed: " +
ENO).arg(
filename));
650 LOG(VB_PLAYBACK, LOG_INFO, QString(
"WF loading from %1").arg(
filename));
653 LOG(VB_GENERAL, LOG_WARNING,
654 QString(
"WF loading %1 failed, recreating").arg(
filename));
682 m_font = QApplication::font();
731 for (
uint i = 0; i < n; i++)
733 short int val = node->
m_left[i];
736 m_sqrl +=
static_cast<long>(val) *
static_cast<long>(val);
742 m_sqrr +=
static_cast<long>(val) *
static_cast<long>(val);
776 painter.fillRect(x, 0, 32 * 5,
778 painter.fillRect(x -
m_wfsize.width(), 0, 32 * 5,
781 painter.fillRect(x, 0, 1,
787 painter.setPen(qRgb(25, 25, 150));
788 painter.drawLine(x, y - (h *
m_maxl / 32768),
789 x, y - (h *
m_minl / 32768));
792 painter.drawLine(x, yr - (h *
m_maxr / 32768),
793 x, yr - (h *
m_minr / 32768));
795 painter.setPen(qRgb(150, 25, 25));
797 painter.drawLine(x, y - rmsl, x, y + rmsl);
801 painter.drawLine(x, yr - rmsr, x, yr + rmsr);
802 painter.drawLine(x,
m_wfsize.height() / 2,
803 x, (
m_wfsize.height() / 2) - rmsl + rmsr);
821 p->fillRect(0, 0, 0, 0,
back);
825 Qt::IgnoreAspectRatio,
826 Qt::SmoothTransformation));
832 1,
m_size.height(), Qt::darkGray);
836 p->setPen(Qt::darkGray);
838 QRect text(5, 5,
m_size.width() - 10,
m_size.height() - 10);
839 p->drawText(text, Qt::AlignTop | Qt::AlignLeft,
842 .arg(
m_offset / 1000 % 60, 2, 10, QChar(
'0')));
843 p->drawText(text, Qt::AlignTop | Qt::AlignHCenter,
846 p->drawText(text, Qt::AlignTop | Qt::AlignRight,
849 .arg(
m_duration / 1000 % 60, 2, 10, QChar(
'0')));
850 p->drawText(text, Qt::AlignBottom | Qt::AlignLeft,
851 QString(
"%1 lines/s")
853 p->drawText(text, Qt::AlignBottom | Qt::AlignRight,
854 QString(
"%1 ms/line")
862 LOG(VB_PLAYBACK, LOG_DEBUG, QString(
"WF keypress = %1").arg(
action));
880 const QString &
name(
void)
const override
882 static QString s_name = QCoreApplication::translate(
"Visualizers",
906 const QString &
name(
void)
const override
908 static QString s_name = QCoreApplication::translate(
"Visualizers",
931 const QString &
name(
void)
const override
933 static QString s_name = QCoreApplication::translate(
"Visualizers",
969 LOG(VB_GENERAL, LOG_INFO,
970 QString(
"Spectrogram : Being Initialised, history=%1").arg(hist));
995 m_dftL =
static_cast<float*
>(av_malloc(
sizeof(
float) *
m_fftlen));
996 m_dftR =
static_cast<float*
>(av_malloc(
sizeof(
float) *
m_fftlen));
1019 static constexpr
int UP { 2 };
1020 static constexpr
int DN { 3 };
1021 static const std::array<int,6> red { 0, 0, UP, 1, 1, DN };
1022 static const std::array<int,6> green { UP, 1, 1, DN, 0, 0 };
1023 static const std::array<int,6> blue { 1, DN, 0, 0, UP, 1 };
1025 auto updateColor = [](
int color,
int up,
int down)
1034 for (
int i = 0; i < 6; i++)
1039 for (
int u = 0; u < 256; u++) {
1041 m_red[ (i * 256) + u] = updateColor(r, u,
d);
1042 m_green[(i * 256) + u] = updateColor(g, u,
d);
1043 m_blue[ (i * 256) + u] = updateColor(b, u,
d);
1050 av_freep(
reinterpret_cast<void*
>(&
m_dftL));
1051 av_freep(
reinterpret_cast<void*
>(&
m_dftR));
1052 av_freep(
reinterpret_cast<void*
>(&
m_rdftTmp));
1062 template<
typename T> T
sq(T a) {
return a*a; };
1076 painter.setPen(Qt::white);
1077 QFont font = QApplication::font();
1078 font.setPixelSize(16);
1079 painter.setFont(font);
1084 for (
auto h =
m_sgsize.height(); h > 0; h -= half)
1086 for (
auto i = 0; i < half; i += 20)
1090 h - i - 20, 255, 40,
1091 Qt::AlignRight|Qt::AlignVCenter,
1103 for (
auto i = 0; i < 125; i++)
1105 painter.drawText(
m_scale.
pixel(i) - 20, half - ((i % 12) * 15) - 40,
1110 40, 40, Qt::AlignCenter,
1111 QString(
"%1").arg(i / 12));
1116 for (
auto i = 0; i < 125; i++)
1121 if (now >= prev + 20) {
1122 painter.drawText(half + 20, (-1 * now) - 40,
1123 80, 80, Qt::AlignVCenter|Qt::AlignLeft,
1127 painter.drawText(half + 100, (-1 * now) - 40,
1128 80, 80, Qt::AlignVCenter|Qt::AlignLeft,
1147 m_image =
new QImage(w, h, QImage::Format_RGB32);
1157 for (
int k = 0; k < start; k++)
1159 if (k > start - i && start > i)
1161 mult = mult + (1 - mult) *
1162 (1 - (
float)(start - k) / (
float)(start - i));
1167 for (
int k = 0; k < i; k++)
1177 mult = (float)k / (
float)end;
1179 mult = (float)(
m_fftlen - k) / (float)end;
1195 painter.setPen(Qt::black);
1198 painter.fillRect(
s_offset, 0, 256, h, Qt::black);
1199 painter.fillRect(
s_offset - w, 0, 256, h, Qt::black);
1201 painter.fillRect(0, 0, w, h, Qt::black);
1207 for (
int i = 1; i < (
m_history ? h / 2 : w); i++)
1213 for (
auto j = prev + 1; j <= index; j++)
1230 left = 10 * log10(left);
1231 right = 10 * log10(right);
1240 int mag =
clamp(left, 255, 0);
1242 left > 255 ? painter.setPen(Qt::white) :
1252 painter.setPen(Qt::white);
1254 painter.setPen(Qt::black);
1256 left > 255 ? painter.setPen(Qt::yellow) :
1257 painter.setPen(qRgb(mag, mag, mag));
1259 painter.drawPoint(
s_offset, h - i);
1261 painter.drawLine(i, h / 2, i, (h / 2) - (h / 2 * mag / 256));
1265 mag =
clamp(right, 255, 0);
1267 right > 255 ? painter.setPen(Qt::white) :
1277 painter.setPen(Qt::white);
1279 painter.setPen(Qt::black);
1281 right > 255 ? painter.setPen(Qt::yellow) :
1282 painter.setPen(qRgb(mag, mag, mag));
1284 painter.drawPoint(
s_offset, h - i);
1286 painter.drawLine(i, h / 2, i, (h / 2) + (h / 2 * mag / 256));
1291 prev = std::min(prev, index - 1);
1302 if (isnan(cur))
return 0;
1308 p->fillRect(0, 0, 0, 0,
back);
1312 Qt::IgnoreAspectRatio,
1313 Qt::SmoothTransformation));
1328 LOG(VB_PLAYBACK, LOG_DEBUG, QString(
"SG keypress = %1").arg(
action));
1354 const QString &
name(
void)
const override
1356 static QString s_name = QCoreApplication::translate(
"Visualizers",
1378 const QString &
name(
void)
const override
1380 static QString s_name = QCoreApplication::translate(
"Visualizers",
1403 LOG(VB_GENERAL, LOG_INFO, QString(
"Spectrum : Being Initialised"));
1407 m_dftL =
static_cast<float*
>(av_malloc(
sizeof(
float) *
m_fftlen));
1408 m_dftR =
static_cast<float*
>(av_malloc(
sizeof(
float) *
m_fftlen));
1417 av_freep(
reinterpret_cast<void*
>(&
m_dftL));
1418 av_freep(
reinterpret_cast<void*
>(&
m_dftR));
1419 av_freep(
reinterpret_cast<void*
>(&
m_rdftTmp));
1479 for (
int k = 0; k < start; k++)
1481 if (k > start - i && start > i)
1483 mult = mult + (1 - mult) *
1484 (1 - (
float)(start - k) / (
float)(start - i));
1489 for (
int k = 0; k < i; k++)
1499 mult =
static_cast<float>(k) / end;
1501 mult =
static_cast<float>(
m_fftlen - k) / end;
1523 float adjHeight =
m_size.height() / 2.0;
1530 for (
auto j = prev + 1; j <= index; j++)
1533 magL =
tmp > magL ?
tmp : magL;
1535 magR =
tmp > magR ?
tmp : magR;
1540 magL = std::min(magL, adjHeight);
1541 if (magL < magnitudesp[i])
1544 tmp = std::max(
tmp, magL);
1547 magL = std::max<float>(magL, 1);
1549 magR = std::min(magR, adjHeight);
1553 tmp = std::max(
tmp, magR);
1556 magR = std::max<float>(magR, 1);
1558 magnitudesp[i] = magL;
1560 rectspL[i].setTop( (
m_size.height() / 2) -
int( magL ) );
1561 rectspR[i].setBottom( (
m_size.height() / 2) +
int( magR ) );
1565 (prev < index) || (prev = index -1);
1590 double per = ( rectspL[i].height() - 2. ) / (
m_size.height() / 2.);
1592 per =
clamp(per, 1.0, 0.0);
1601 r =
clamp(r, 255.0, 0.0);
1602 g =
clamp(g, 255.0, 0.0);
1603 b =
clamp(b, 255.0, 0.0);
1605 if(rectspL[i].height() > 4)
1606 p->fillRect(rectspL[i], QColor(
int(r),
int(g),
int(b)));
1608 per = ( rectspR[i].height() - 2. ) / (
m_size.height() / 2.);
1610 per =
clamp(per, 1.0, 0.0);
1619 r =
clamp(r, 255.0, 0.0);
1620 g =
clamp(g, 255.0, 0.0);
1621 b =
clamp(b, 255.0, 0.0);
1623 if(rectspR[i].height() > 4)
1624 p->fillRect(rectspR[i], QColor(
int(r),
int(g),
int(b)));
1633 const QString &
name(
void)
const override
1635 static QString s_name = QCoreApplication::translate(
"Visualizers",
1672 int x = ((i / 2) * w) + correction;
1686 per =
clamp(per, 1.0, 0.0);
1695 r =
clamp(r, 255.0, 0.0);
1696 g =
clamp(g, 255.0, 0.0);
1697 b =
clamp(b, 255.0, 0.0);
1699 p->fillRect (x, y, w, h, QColor (
int(r),
int(g),
int(b)));
1711 drawRect(
p, &(rectsp[i]), i, center, w, h);
1714 drawRect(
p, &(rectsp[i]), i, center, w, h);
1722 const QString &
name(
void)
const override
1724 static QString s_name = QCoreApplication::translate(
"Visualizers",
1747 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Piano : Being Initialised"));
1752 double sample_rate = 44100.0;
1756 double concert_A = 440.0;
1757 double semi_tone = pow(2.0, 1.0/12.0);
1760 double bottom_A = concert_A / 2.0 / 2.0 / 2.0 / 2.0;
1762 double current_freq = bottom_A;
1769 double samples_required = sample_rate/current_freq * 20.0;
1772 samples_required =
std::clamp(samples_required,
1773 sample_rate/(
double)
m_fps * 0.75,
1778 current_freq *= semi_tone;
1818 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Piano : Being Resized"));
1823 double key_unit_size = (double)
m_size.width() / 54.0;
1824 key_unit_size = std::max(key_unit_size, 10.0);
1826 double white_width_pct = .8;
1827 double black_width_pct = .6;
1828 double black_offset_pct = .05;
1830 double white_height_pct = 6;
1831 double black_height_pct = 4;
1835 double left = ((double)
m_size.width() / 2.0) - ((4.0*7.0 + 3.5) * key_unit_size);
1836 double top_of_keys = ((double)
m_size.height() / 2.0) - (key_unit_size * white_height_pct / 2.0);
1842 int note = ((int)key - 3 + 12) % 12;
1845 left += key_unit_size*7.0;
1848 double center = 0.0;
1849 double offset = 0.0;
1850 bool is_black =
false;
1854 case 0: center = 0.5;
break;
1855 case 1: center = 1.0; is_black =
true; offset = -1;
break;
1856 case 2: center = 1.5;
break;
1857 case 3: center = 2.0; is_black =
true; offset = +1;
break;
1858 case 4: center = 2.5;
break;
1859 case 5: center = 3.5;
break;
1860 case 6: center = 4.0; is_black =
true; offset = -2;
break;
1861 case 7: center = 4.5;
break;
1862 case 8: center = 5.0; is_black =
true; offset = 0;
break;
1863 case 9: center = 5.5;
break;
1864 case 10: center = 6.0; is_black =
true; offset = 2;
break;
1865 case 11: center = 6.5;
break;
1869 double width = (is_black ? black_width_pct:white_width_pct) * key_unit_size;
1870 double height = (is_black? black_height_pct:white_height_pct) * key_unit_size;
1873 left + (center * key_unit_size)
1875 + (is_black ? (offset * black_offset_pct * key_unit_size):0.0),
1917 bool allZero =
true;
1927 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Piano : Node offset=%1 too far backwards : NEW SONG").arg(node->
m_offset.count()));
1934 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Piano : Already seen node offset=%1, returning without processing").arg(node->
m_offset.count()));
1943 for (
uint i = 0; i < n; i++)
1950 for (
uint i = 0; i < n; i++)
1958 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Hit an empty node, and returning empty-handed"));
1968 for (
uint i = 0; i < n; i++)
1982 if (n_samples >
m_pianoData[key].samples_process_before_display_update)
1984 goertzel_data magnitude2 = (q1*q1) + (q2*q2) - (q1*q2*coeff);
1998 if(magnitude_av > 0.0F)
2000 magnitude_av =
log(magnitude_av);
2008 if (magnitude_av < 0.0F)
2021 std::max(
m_pianoData[key].max_magnitude_seen, magnitude_av);
2022 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Piano : Updated Key %1 from %2 samples, magnitude=%3")
2023 .arg(key).arg(n_samples).arg(magnitude_av));
2053 QRect *rectsp = (
m_rects).data();
2065 for (
uint key = 0; key < n; key++)
2067 if (
m_pianoData[key].max_magnitude_seen <
static_cast<float>(mag))
2082 for (
int key_i = n - 1; key_i >= 0; key_i--)
2085 if (
m_pianoData[key].max_magnitude_seen <
static_cast<float>(mag))
2101 for (
uint key = 0; key < n; key++)
2104 magnitude_max = std::max(magnitude_max, mag);
2106 magnitudep[key] = mag;
2110 for (
uint key = 0; key < n; key++)
2115 double per = magnitudep[key] / magnitude_max;
2116 per =
clamp(per, 1.0, 0.0);
2120 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Piano : Display key %1, magnitude=%2, seen=%3")
2121 .arg(key).arg(per*100.0).arg(
m_pianoData[key].max_magnitude_seen));
2127 p->fillRect(rectsp[key], QColor(
int(r), int(g), int(b)));
2131 for (
uint key = 0; key < n; key++)
2136 double per = magnitudep[key]/magnitude_max;
2137 per =
clamp(per, 1.0, 0.0);
2146 p->fillRect(rectsp[key], QColor(
int(r), int(g), int(b)));
2155 const QString &
name(
void)
const override
2157 static QString s_name = QCoreApplication::translate(
"Visualizers",
2175 m_lastCycle(QDateTime::currentDateTime())
2300 if (imageFilename.startsWith(
"myth://"))
2302 auto *rf =
new RemoteFile(imageFilename,
false,
false, 0ms);
2305 bool ret = rf->SaveAs(data);
2310 art.loadFromData(data);
2313 if (!imageFilename.isEmpty())
2315 art.load(imageFilename);
2325 m_image = art.scaled(
m_size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
2350 const QString &
name(
void)
const override
2352 static QString s_name = QCoreApplication::translate(
"Visualizers",
2396 const QString &
name(
void)
const override
2398 static QString s_name = QCoreApplication::translate(
"Visualizers",