17 #include <QApplication>
18 #include <QCoreApplication>
43 : m_xscreensaverenable(screensaverenable)
63 p->fillRect(0, 0, size.width(), size.height(),
back);
67 QFont font = QApplication::font();
71 int logicalDpiY = 100;
72 HDC hdc = GetDC(
nullptr);
75 logicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY);
76 ReleaseDC(
nullptr, hdc);
83 float floatSize = (16 * 100.0F) / logicalDpiY;
88 floatSize = floatSize * hmult;
90 font.setPointSize(lroundf(floatSize));
91 font.setWeight(QFont::Bold);
92 font.setPointSizeF(fontSize * (size.width() / 800.0));
95 p->drawText(0, 0, size.width(), size.height(), Qt::AlignVCenter | Qt::AlignHCenter | Qt::TextWordWrap, warning);
103 setMax(maxscale, maxrange);
108 if (maxscale == 0 || maxrange == 0)
114 auto domain = (
long double) maxscale;
115 auto range = (
long double) maxrange;
117 long double dx = 1.0;
118 long double e4 = 1.0E-8;
124 for (
uint i=0; i<10000 && (std::abs(dx) > e4); i++)
127 double y = (x *
t) -
range;
128 double yy =
t - (domain / (x + domain));
134 for (
int i = 1; i < (int) domain; i++)
136 int scaled = (int) floor(0.5 + (alpha *
log((
double(i) + alpha) / alpha)));
154 setMax(maxscale, maxrange, maxfreq);
159 if (maxscale == 0 || maxrange == 0 || maxfreq == 0)
168 double maxmel =
hz2mel(maxfreq);
169 double hzperbin = (double) maxfreq / (
double) maxscale;
171 for (
int i = 0; i < maxrange; i++)
173 double mel = maxmel * i / maxrange;
175 int bin = int(hz / hzperbin);
214 for (
int i = 0; i <
m_size.width(); i++)
216 auto indexTo = (
unsigned long)(index + step);
217 if (indexTo == (
unsigned long)(index))
218 indexTo = (
unsigned long)(index + 1);
251 for (
auto s = (
unsigned long)index; s < indexTo && s < node->
m_length; s++)
253 double adjHeight =
static_cast<double>(
m_size.height()) / 4.0;
254 double tmpL = ( ( node->
m_left ?
static_cast<double>(node->
m_left[s]) : 0.) *
255 adjHeight ) / 32768.0;
256 double tmpR = ( ( node->
m_right ?
static_cast<double>(node->
m_right[s]) : 0.) *
257 adjHeight ) / 32768.0;
259 valL = (tmpL > valL) ? tmpL : valL;
261 valL = (tmpL < valL) ? tmpL : valL;
263 valR = (tmpR > valR) ? tmpR : valR;
265 valR = (tmpR < valR) ? tmpR : valR;
268 if (valL != 0. || valR != 0.)
274 index = index + step;
280 for (
int i = 0; i <
m_size.width(); i++)
306 if (valL != 0. || valR != 0.)
316 for (
int i = 0; (unsigned) i <
m_magnitudes.size(); i++ )
325 if (
back != Qt::green)
329 for (
int i = 1; i <
m_size.width(); i++ )
333 double per = (
static_cast<double>(
m_magnitudes[i]) * 2.0 ) /
334 (
static_cast<double>(
m_size.height()) / 4.0 );
364 p->setPen( QColor(
int(r), int(g), int(b) ) );
368 double adjHeight =
static_cast<double>(
m_size.height()) / 4.0;
407 p->setPen( QColor(
int(r), int(g), int(b) ) );
411 adjHeight =
static_cast<double>(
m_size.height()) * 3.0 / 4.0;
432 for (
int i = 0; i <
m_size.width(); i++)
434 auto indexTo = (
unsigned long)(index + step);
435 if (indexTo == (
unsigned long)index)
436 indexTo = (
unsigned long)(index + 1);
461 for (
auto s = (
unsigned long)index; s < indexTo && s < node->
m_length; s++)
463 double tmp = (
static_cast<double>(node->
m_left[s]) +
465 :
static_cast<double>(node->
m_left[s])) *
466 (
static_cast<double>(
m_size.height()) / 2.0 ) ) / 65536.0;
469 val = (
tmp > val) ?
tmp : val;
473 val = (
tmp < val) ?
tmp : val;
482 index = index + step;
488 for (
int i = 0; i <
m_size.width(); i++) {
508 for (
int i = 0; i <
m_size.width(); i++ )
517 if (
back != Qt::green)
521 for (
int i = 1; i <
m_size.width(); i++ ) {
523 double per = (
static_cast<double>(
m_magnitudes[i]) * 2.0 ) /
524 (
static_cast<double>(
m_size.height()) / 4.0 );
554 p->setPen(QColor(
int(r), int(g), int(b)));
558 double adjHeight =
static_cast<double>(
m_size.height()) / 2.0;
585 LOG(VB_PLAYBACK, LOG_INFO, QString(
"WF going down"));
591 QString cache =
GetConfDir() +
"/MythMusic/WaveForm";
601 filename = QString(
"%1/%2.png").arg(cache)
603 LOG(VB_PLAYBACK, LOG_INFO, QString(
"WF saving to %1").arg(
filename));
606 LOG(VB_GENERAL, LOG_ERR,
607 QString(
"WF saving to %1 failed: " +
ENO).arg(
filename));
614 LOG(VB_PLAYBACK, LOG_INFO, QString(
"WF loading from %1").arg(
filename));
617 LOG(VB_GENERAL, LOG_WARNING,
618 QString(
"WF loading %1 failed, recreating").arg(
filename));
637 m_font = QApplication::font();
687 for (
uint i = 0; i < n; i++)
689 short int val = node->
m_left[i];
692 m_sqrl +=
static_cast<long>(val) *
static_cast<long>(val);
698 m_sqrr +=
static_cast<long>(val) *
static_cast<long>(val);
732 painter.fillRect(x, 0, 32 * 5,
734 painter.fillRect(x -
m_wfsize.width(), 0, 32 * 5,
737 painter.fillRect(x, 0, 1,
743 painter.setPen(qRgb(25, 25, 150));
744 painter.drawLine(x, y - h *
m_maxl / 32768,
745 x, y - h *
m_minl / 32768);
748 painter.drawLine(x, yr - h *
m_maxr / 32768,
749 x, yr - h *
m_minr / 32768);
751 painter.setPen(qRgb(150, 25, 25));
753 painter.drawLine(x, y - rmsl, x, y + rmsl);
757 painter.drawLine(x, yr - rmsr, x, yr + rmsr);
758 painter.drawLine(x,
m_wfsize.height() / 2,
759 x,
m_wfsize.height() / 2 - rmsl + rmsr);
777 p->fillRect(0, 0, 0, 0,
back);
781 Qt::IgnoreAspectRatio,
782 Qt::SmoothTransformation));
788 1,
m_size.height(), Qt::darkGray);
792 p->setPen(Qt::darkGray);
794 QRect text(5, 5,
m_size.width() - 10,
m_size.height() - 10);
795 p->drawText(text, Qt::AlignTop | Qt::AlignLeft,
798 .arg(
m_offset / 1000 % 60, 2, 10, QChar(
'0')));
799 p->drawText(text, Qt::AlignTop | Qt::AlignHCenter,
802 p->drawText(text, Qt::AlignTop | Qt::AlignRight,
805 .arg(
m_duration / 1000 % 60, 2, 10, QChar(
'0')));
806 p->drawText(text, Qt::AlignBottom | Qt::AlignLeft,
807 QString(
"%1 lines/s")
809 p->drawText(text, Qt::AlignBottom | Qt::AlignRight,
810 QString(
"%1 ms/line")
818 LOG(VB_PLAYBACK, LOG_INFO, QString(
"WF keypress = %1").arg(
action));
834 const QString &
name(
void)
const override
836 static QString s_name = QCoreApplication::translate(
"Visualizers",
860 const QString &
name(
void)
const override
862 static QString s_name = QCoreApplication::translate(
"Visualizers",
885 const QString &
name(
void)
const override
887 static QString s_name = QCoreApplication::translate(
"Visualizers",
923 LOG(VB_GENERAL, LOG_INFO,
924 QString(
"Spectrogram : Being Initialised, history=%1").arg(hist));
947 m_dftL =
static_cast<FFTSample*
>(av_malloc(
sizeof(FFTSample) *
m_fftlen));
948 m_dftR =
static_cast<FFTSample*
>(av_malloc(
sizeof(FFTSample) *
m_fftlen));
969 static constexpr
int UP { 2 };
970 static constexpr
int DN { 3 };
971 static const std::array<int,6> red { 0, 0, UP, 1, 1, DN };
972 static const std::array<int,6> green { UP, 1, 1, DN, 0, 0 };
973 static const std::array<int,6> blue { 1, DN, 0, 0, UP, 1 };
974 for (
int i = 0; i < 6; i++)
979 for (
int u = 0; u < 256; u++) {
981 m_red[ i * 256 + u] = r == UP ? u : r == DN ?
d : r * 255;
982 m_green[i * 256 + u] = g == UP ? u : g == DN ?
d : g * 255;
983 m_blue[ i * 256 + u] = b == UP ? u : b == DN ?
d : b * 255;
1001 template<
typename T> T
sq(T a) {
return a*a; };
1050 m_image =
new QImage(w, h, QImage::Format_RGB32);
1060 for (
int k = 0; k < start; k++)
1062 if (k > start - i && start > i)
1064 mult = mult + (1 - mult) *
1065 (1 - (
float)(start - k) / (
float)(start - i));
1070 for (
int k = 0; k < i; k++)
1079 mult = k < end ? (float)k / (
float)end
1081 (float)(
m_fftlen - k) / (float)end : 1;
1090 painter.setPen(Qt::black);
1093 painter.fillRect(
s_offset, 0, 256, h, Qt::black);
1094 painter.fillRect(
s_offset - w, 0, 256, h, Qt::black);
1096 painter.fillRect(0, 0, w, h, Qt::black);
1102 for (
int i = 1; i < (
m_history ? h / 2 : w); i++)
1108 for (
auto j = prev + 1; j <= index; j++)
1125 left = 10 * log10(left);
1126 right = 10 * log10(right);
1135 int mag =
clamp(left, 255, 0);
1136 int z = (int)(mag * 6);
1137 left > 255 ? painter.setPen(Qt::white) :
1144 left > 255 ? painter.setPen(Qt::yellow) :
1145 painter.setPen(qRgb(mag, mag, mag));
1146 painter.drawPoint(
s_offset, h - i);
1148 painter.drawLine(i, h / 2, i, h / 2 - h / 2 * mag / 256);
1152 mag =
clamp(right, 255, 0);
1154 right > 255 ? painter.setPen(Qt::white) :
1161 right > 255 ? painter.setPen(Qt::yellow) :
1162 painter.setPen(qRgb(mag, mag, mag));
1163 painter.drawPoint(
s_offset, h - i);
1165 painter.drawLine(i, h / 2, i, h / 2 + h / 2 * mag / 256);
1170 prev = std::min(prev, index - 1);
1181 if (isnan(cur))
return 0;
1182 if (cur > max) cur = max;
1183 if (cur < min) cur = min;
1189 p->fillRect(0, 0, 0, 0,
back);
1193 Qt::IgnoreAspectRatio,
1194 Qt::SmoothTransformation));
1209 LOG(VB_PLAYBACK, LOG_INFO, QString(
"SG keypress = %1").arg(
action));
1215 LOG(VB_PLAYBACK, LOG_INFO, QString(
"SG keypress SELECT hit"));
1224 const QString &
name(
void)
const override
1226 static QString s_name = QCoreApplication::translate(
"Visualizers",
1248 const QString &
name(
void)
const override
1250 static QString s_name = QCoreApplication::translate(
"Visualizers",
1273 LOG(VB_GENERAL, LOG_INFO, QString(
"Spectrum : Being Initialised"));
1277 m_dftL =
static_cast<FFTSample*
>(av_malloc(
sizeof(FFTSample) *
m_fftlen));
1278 m_dftR =
static_cast<FFTSample*
>(av_malloc(
sizeof(FFTSample) *
m_fftlen));
1347 for (
int k = 0; k < start; k++)
1349 if (k > start - i && start > i)
1351 mult = mult + (1 - mult) *
1352 (1 - (
float)(start - k) / (
float)(start - i));
1357 for (
int k = 0; k < i; k++)
1366 mult = k < end ? k / end : k >
m_fftlen - end ?
1382 float adjHeight =
m_size.height() / 2.0;
1389 for (
auto j = prev + 1; j <= index; j++)
1392 magL =
tmp > magL ?
tmp : magL;
1394 magR =
tmp > magR ?
tmp : magR;
1399 if (magL > adjHeight)
1403 if (magL < magnitudesp[i])
1417 if (magR > adjHeight)
1435 magnitudesp[i] = magL;
1437 rectspL[i].setTop(
m_size.height() / 2 -
int( magL ) );
1438 rectspR[i].setBottom(
m_size.height() / 2 +
int( magR ) );
1442 (prev < index) || (prev = index -1);
1471 double per = ( rectspL[i].height() - 2. ) / (
m_size.height() / 2.);
1473 per =
clamp(per, 1.0, 0.0);
1482 r =
clamp(r, 255.0, 0.0);
1483 g =
clamp(g, 255.0, 0.0);
1484 b =
clamp(b, 255.0, 0.0);
1486 if(rectspL[i].height() > 4)
1487 p->fillRect(rectspL[i], QColor(
int(r),
int(g),
int(b)));
1489 per = ( rectspR[i].height() - 2. ) / (
m_size.height() / 2.);
1491 per =
clamp(per, 1.0, 0.0);
1500 r =
clamp(r, 255.0, 0.0);
1501 g =
clamp(g, 255.0, 0.0);
1502 b =
clamp(b, 255.0, 0.0);
1504 if(rectspR[i].height() > 4)
1505 p->fillRect(rectspR[i], QColor(
int(r),
int(g),
int(b)));
1514 const QString &
name(
void)
const override
1516 static QString s_name = QCoreApplication::translate(
"Visualizers",
1553 int x = ((i / 2) * w) + correction;
1567 per =
clamp(per, 1.0, 0.0);
1576 r =
clamp(r, 255.0, 0.0);
1577 g =
clamp(g, 255.0, 0.0);
1578 b =
clamp(b, 255.0, 0.0);
1580 p->fillRect (x, y, w, h, QColor (
int(r),
int(g),
int(b)));
1592 drawRect(
p, &(rectsp[i]), i, center, w, h);
1595 drawRect(
p, &(rectsp[i]), i, center, w, h);
1603 const QString &
name(
void)
const override
1605 static QString s_name = QCoreApplication::translate(
"Visualizers",
1628 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Piano : Being Initialised"));
1633 double sample_rate = 44100.0;
1637 double concert_A = 440.0;
1638 double semi_tone = pow(2.0, 1.0/12.0);
1641 double bottom_A = concert_A / 2.0 / 2.0 / 2.0 / 2.0;
1643 double current_freq = bottom_A;
1650 double samples_required = sample_rate/current_freq * 20.0;
1651 if (samples_required > sample_rate/4.0)
1654 samples_required = sample_rate/4.0;
1656 if (samples_required < sample_rate/(
double)
m_fps * 0.75)
1658 samples_required = sample_rate/(double)
m_fps * 0.75;
1663 current_freq *= semi_tone;
1703 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Piano : Being Resized"));
1708 double key_unit_size = (double)
m_size.width() / 54.0;
1709 if (key_unit_size < 10.0)
1710 key_unit_size = 10.0;
1712 double white_width_pct = .8;
1713 double black_width_pct = .6;
1714 double black_offset_pct = .05;
1716 double white_height_pct = 6;
1717 double black_height_pct = 4;
1721 double left = (double)
m_size.width() / 2.0 - (4.0*7.0 + 3.5) * key_unit_size;
1722 double top_of_keys = (double)
m_size.height() / 2.0 - key_unit_size * white_height_pct / 2.0;
1728 int note = ((int)key - 3 + 12) % 12;
1731 left += key_unit_size*7.0;
1734 double center = 0.0;
1735 double offset = 0.0;
1736 bool is_black =
false;
1740 case 0: center = 0.5;
break;
1741 case 1: center = 1.0; is_black =
true; offset = -1;
break;
1742 case 2: center = 1.5;
break;
1743 case 3: center = 2.0; is_black =
true; offset = +1;
break;
1744 case 4: center = 2.5;
break;
1745 case 5: center = 3.5;
break;
1746 case 6: center = 4.0; is_black =
true; offset = -2;
break;
1747 case 7: center = 4.5;
break;
1748 case 8: center = 5.0; is_black =
true; offset = 0;
break;
1749 case 9: center = 5.5;
break;
1750 case 10: center = 6.0; is_black =
true; offset = 2;
break;
1751 case 11: center = 6.5;
break;
1755 double width = (is_black ? black_width_pct:white_width_pct) * key_unit_size;
1756 double height = (is_black? black_height_pct:white_height_pct) * key_unit_size;
1759 left + center * key_unit_size
1761 + (is_black ? (offset * black_offset_pct * key_unit_size):0.0),
1803 bool allZero =
true;
1813 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Piano : Node offset=%1 too far backwards : NEW SONG").arg(node->
m_offset.count()));
1820 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Piano : Already seen node offset=%1, returning without processing").arg(node->
m_offset.count()));
1829 for (
uint i = 0; i < n; i++)
1836 for (
uint i = 0; i < n; i++)
1844 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Hit an empty node, and returning empty-handed"));
1854 for (
uint i = 0; i < n; i++)
1868 if (n_samples >
m_pianoData[key].samples_process_before_display_update)
1884 if(magnitude_av > 0.0F)
1886 magnitude_av =
log(magnitude_av);
1894 if (magnitude_av < 0.0F)
1906 if (
m_pianoData[key].max_magnitude_seen < magnitude_av)
1910 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Piano : Updated Key %1 from %2 samples, magnitude=%3")
1911 .arg(key).arg(n_samples).arg(magnitude_av));
1945 QRect *rectsp = (
m_rects).data();
1958 for (
uint key = 0; key < n; key++)
1960 if (
m_pianoData[key].max_magnitude_seen <
static_cast<float>(mag))
1975 for (
int key_i = n - 1; key_i >= 0; key_i--)
1978 if (
m_pianoData[key].max_magnitude_seen <
static_cast<float>(mag))
1994 for (
uint key = 0; key < n; key++)
1997 if (magnitude_max < mag)
1998 magnitude_max = mag;
2000 magnitudep[key] = mag;
2004 for (
uint key = 0; key < n; key++)
2009 double per = magnitudep[key] / magnitude_max;
2010 per =
clamp(per, 1.0, 0.0);
2014 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Piano : Display key %1, magnitude=%2, seen=%3")
2015 .arg(key).arg(per*100.0).arg(
m_pianoData[key].max_magnitude_seen));
2021 p->fillRect(rectsp[key], QColor(
int(r), int(g), int(b)));
2025 for (
uint key = 0; key < n; key++)
2030 double per = magnitudep[key]/magnitude_max;
2031 per =
clamp(per, 1.0, 0.0);
2040 p->fillRect(rectsp[key], QColor(
int(r), int(g), int(b)));
2049 const QString &
name(
void)
const override
2051 static QString s_name = QCoreApplication::translate(
"Visualizers",
2069 m_lastCycle(QDateTime::currentDateTime())
2194 if (imageFilename.startsWith(
"myth://"))
2196 auto *rf =
new RemoteFile(imageFilename,
false,
false, 0ms);
2199 bool ret = rf->SaveAs(data);
2204 art.loadFromData(data);
2207 if (!imageFilename.isEmpty())
2208 art.load(imageFilename);
2217 m_image = art.scaled(
m_size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
2242 const QString &
name(
void)
const override
2244 static QString s_name = QCoreApplication::translate(
"Visualizers",
2288 const QString &
name(
void)
const override
2290 static QString s_name = QCoreApplication::translate(
"Visualizers",