MythTV  master
videovisualspectrum.cpp
Go to the documentation of this file.
1 // QT
2 #include <QPen>
3 
4 // MythTV
5 #include "videovisualspectrum.h"
6 
7 // FFmpeg
8 static constexpr int k_FFT_sample_length { 512 };
9 
10 // Std
11 #include <algorithm>
12 
14  : VideoVisual(Audio, Render),
15  m_dftL(static_cast<FFTComplex*>(av_malloc(sizeof(FFTComplex) * k_FFT_sample_length))),
16  m_dftR(static_cast<FFTComplex*>(av_malloc(sizeof(FFTComplex) * k_FFT_sample_length))),
17  m_fftContextForward(av_fft_init(std::log2(k_FFT_sample_length), 0))
18 {
19 }
20 
22 {
23  av_freep(reinterpret_cast<void*>(&m_dftL));
24  av_freep(reinterpret_cast<void*>(&m_dftR));
25  av_fft_end(m_fftContextForward);
26 }
27 
28 template<typename T> T sq(T a) { return a*a; };
29 
30 void VideoVisualSpectrum::Draw(const QRect Area, MythPainter* Painter, QPaintDevice* Device)
31 {
32  if (m_disabled)
33  return;
34 
35  uint i = 0;
36  {
37  QMutexLocker locker(mutex());
38  VisualNode* node = GetNode();
39  if (Area.isEmpty() || !Painter)
40  return;
41 
42  if (!Initialise(Area))
43  return;
44 
45  if (node)
46  {
47  i = static_cast<uint>(node->m_length);
48  for (auto k = 0; k < node->m_length; k++)
49  {
50  m_dftL[k] = (FFTComplex){ .re = (FFTSample)node->m_left[k], .im = 0 };
51  if (node->m_right)
52  m_dftR[k] = (FFTComplex){ .re = (FFTSample)node->m_right[k], .im = 0 };
53  }
54  }
55  }
56 
57  for (auto k = i; k < k_FFT_sample_length; k++)
58  {
59  m_dftL[k] = (FFTComplex){ .re = 0, .im = 0 };
60  m_dftL[k] = (FFTComplex){ .re = 0, .im = 0 };
61  }
62  av_fft_permute(m_fftContextForward, m_dftL);
63  av_fft_calc(m_fftContextForward, m_dftL);
64 
65  av_fft_permute(m_fftContextForward, m_dftR);
66  av_fft_calc(m_fftContextForward, m_dftR);
67 
68  double falloff = std::clamp(((static_cast<double>(SetLastUpdate().count())) / 40.0) * m_falloff, 0.0, 2048.0);
69  for (int l = 0, r = m_scale.range(); l < m_scale.range(); l++, r++)
70  {
71  int index = m_scale[l];
72 
73  // The 1D output is Hermitian symmetric (Yk = Yn-k) so Yn = Y0 etc.
74  // The dft_r2c_1d plan doesn't output these redundant values
75  // and furthermore they're not allocated in the ctor
76  double tmp = 2 * sq(m_dftL[index].re);
77  double magL = (tmp > 1.) ? (log(tmp) - 22.0) * m_scaleFactor : 0.;
78 
79  tmp = 2 * sq(m_dftR[index].re);
80  double magR = (tmp > 1.) ? (log(tmp) - 22.0) * m_scaleFactor : 0.;
81  if (magL > m_range)
82  magL = 1.0;
83 
84  if (magL < m_magnitudes[l])
85  {
86  tmp = m_magnitudes[l] - falloff;
87  tmp = std::max(tmp, magL);
88  magL = tmp;
89  }
90 
91  magL = std::max(magL, 1.0);
92 
93  if (magR > m_range)
94  magR = 1.0;
95 
96  if (magR < m_magnitudes[r])
97  {
98  tmp = m_magnitudes[r] - falloff;
99  tmp = std::max(tmp, magR);
100  magR = tmp;
101  }
102 
103  magR = std::max(magR, 1.0);
104 
105  m_magnitudes[l] = magL;
106  m_magnitudes[r] = magR;
107  }
108 
109  DrawPriv(Painter, Device);
110 }
111 
113 {
114  std::fill(m_magnitudes.begin(), m_magnitudes.end(), 0.0);
116 }
117 
118 void VideoVisualSpectrum::DrawPriv(MythPainter* Painter, QPaintDevice* Device)
119 {
120  static const QBrush kBrush(QColor(0, 0, 200, 180));
121  static const QPen kPen(QColor(255, 255, 255, 255));
122  double range = m_area.top() + (m_area.height() / 2.0);
123  int count = m_scale.range();
124  Painter->Begin(Device);
125  for (int i = 0; i < count; i++)
126  {
127  m_rects[i].setTop(static_cast<int>(range - static_cast<int>(m_magnitudes[i])));
128  m_rects[i].setBottom(static_cast<int>(range + static_cast<int>(m_magnitudes[i + count])));
129  if (m_rects[i].height() > 4)
130  Painter->DrawRect(m_rects[i], kBrush, kPen, 255);
131  }
132  Painter->End();
133 }
134 
135 bool VideoVisualSpectrum::Initialise(const QRect Area)
136 {
137  if (Area == m_area)
138  return true;
139 
140  m_area = Area;
141  m_barWidth = m_area.width() / m_numSamples;
142  m_barWidth = std::max(m_barWidth, 6);
143  m_scale.setMax(192, m_area.width() / m_barWidth);
144 
145  m_magnitudes.resize(m_scale.range() * 2);
146  std::fill(m_magnitudes.begin(), m_magnitudes.end(), 0.0);
147  InitialisePriv();
148  return true;
149 }
150 
152 {
153  m_range = m_area.height() / 2.0;
154  m_rects.resize(m_scale.range());
155  int y = m_area.top() + static_cast<int>(m_range);
156  for (int i = 0, x = m_area.left(); i < m_rects.size(); i++, x+= m_barWidth)
157  m_rects[i].setRect(x, y, m_barWidth - 1, 1);
158 
159  m_scaleFactor = (static_cast<double>(m_area.height()) / 2.0) / log(static_cast<double>(k_FFT_sample_length));
160  m_falloff = static_cast<double>(m_area.height()) / 150.0;
161 
162  LOG(VB_GENERAL, LOG_INFO, DESC + QString("Initialised Spectrum with %1 bars").arg(m_scale.range()));
163  return true;
164 }
165 
167 {
168  public:
169  const QString &name() const override;
170  VideoVisual *Create(AudioPlayer* Audio, MythRender* Render) const override;
171  bool SupportedRenderer(RenderType /*Type*/) override { return true; }
173 
174 const QString& VideoVisualSpectrumFactory::name() const
175 {
176  static QString s_name(SPECTRUM_NAME);
177  return s_name;
178 }
179 
181 {
182  return new VideoVisualSpectrum(Audio, Render);
183 }
VideoVisualSpectrum::m_scale
LogScale m_scale
Definition: videovisualspectrum.h:32
k_FFT_sample_length
static constexpr int k_FFT_sample_length
Definition: videovisualspectrum.cpp:8
VideoVisualSpectrum::InitialisePriv
virtual bool InitialisePriv()
Definition: videovisualspectrum.cpp:151
AudioPlayer
Definition: audioplayer.h:22
VisualNode
Definition: videovisual.h:25
VideoVisualSpectrum::m_rects
QVector< QRect > m_rects
Definition: videovisualspectrum.h:41
VideoVisual::prepare
void prepare() override
Definition: videovisual.cpp:78
VideoVisual::m_disabled
bool m_disabled
Definition: videovisual.h:71
VideoVisualSpectrumFactory::name
const QString & name() const override
Definition: videovisualspectrum.cpp:174
VideoVisualSpectrum::m_fftContextForward
FFTContext * m_fftContextForward
Definition: videovisualspectrum.h:38
VideoVisualSpectrum::Initialise
virtual bool Initialise(QRect Area)
Definition: videovisualspectrum.cpp:135
VideoVisualSpectrum::m_magnitudes
QVector< double > m_magnitudes
Definition: videovisualspectrum.h:30
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythPainter::DrawRect
virtual void DrawRect(QRect area, const QBrush &fillBrush, const QPen &linePen, int alpha)
Definition: mythpainter.cpp:157
Device
A device containing images (ie. USB stick, CD, storage group etc)
Definition: imagemanager.cpp:35
sq
T sq(T a)
Definition: videovisualspectrum.cpp:28
VisualNode::m_left
short * m_left
Definition: videovisual.h:37
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
VideoVisualSpectrum::m_barWidth
int m_barWidth
Definition: videovisualspectrum.h:42
VideoVisualSpectrum
Definition: videovisualspectrum.h:14
DESC
#define DESC
Definition: videovisual.h:20
VideoVisualSpectrum::m_range
double m_range
Definition: videovisualspectrum.h:31
VisualNode::m_right
short * m_right
Definition: videovisual.h:38
LogScale::range
int range() const
Definition: videovisualdefs.h:16
VideoVisualFactory
Definition: videovisual.h:78
MythTV::Visual::mutex
QMutex * mutex()
Definition: visual.h:26
LogScale::setMax
void setMax(int maxscale, int maxrange)
Definition: videovisualdefs.h:18
VideoVisualSpectrumFactory::SupportedRenderer
bool SupportedRenderer(RenderType) override
Definition: videovisualspectrum.cpp:171
VideoVisualSpectrum::m_falloff
double m_falloff
Definition: videovisualspectrum.h:34
RenderType
RenderType
Definition: mythrender_base.h:15
VideoVisualSpectrum::VideoVisualSpectrum
VideoVisualSpectrum(AudioPlayer *Audio, MythRender *Render)
Definition: videovisualspectrum.cpp:13
VideoVisualSpectrumFactory
Definition: videovisualspectrum.cpp:166
uint
unsigned int uint
Definition: compat.h:81
clamp
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:204
MythPainter::End
virtual void End()
Definition: mythpainter.h:55
VideoVisualSpectrum::~VideoVisualSpectrum
~VideoVisualSpectrum() override
Definition: videovisualspectrum.cpp:21
VideoVisualSpectrumFactory::Create
VideoVisual * Create(AudioPlayer *Audio, MythRender *Render) const override
Definition: videovisualspectrum.cpp:180
VisualNode::m_length
long m_length
Definition: videovisual.h:39
VideoVisualSpectrum::m_numSamples
int m_numSamples
Definition: videovisualspectrum.h:29
SPECTRUM_NAME
#define SPECTRUM_NAME
Definition: videovisualspectrum.h:12
MythRender
Definition: mythrender_base.h:23
MythPainter
Definition: mythpainter.h:34
VideoVisualSpectrum::m_dftL
FFTComplex * m_dftL
Definition: videovisualspectrum.h:36
VideoVisualSpectrumFactory
VideoVisualSpectrumFactory VideoVisualSpectrumFactory
videovisualspectrum.h
VideoVisualSpectrum::prepare
void prepare() override
Definition: videovisualspectrum.cpp:112
VideoVisual
Definition: videovisual.h:43
VideoVisualSpectrum::Draw
void Draw(QRect Area, MythPainter *Painter, QPaintDevice *Device) override
Definition: videovisualspectrum.cpp:30
VideoVisualSpectrum::DrawPriv
virtual void DrawPriv(MythPainter *Painter, QPaintDevice *Device)
Definition: videovisualspectrum.cpp:118
VideoVisualSpectrum::m_dftR
FFTComplex * m_dftR
Definition: videovisualspectrum.h:37
VideoVisualSpectrum::m_scaleFactor
double m_scaleFactor
Definition: videovisualspectrum.h:33
VideoVisual::m_area
QRect m_area
Definition: videovisual.h:72
VideoVisual::GetNode
VisualNode * GetNode(void)
Definition: videovisual.cpp:84
xbmc.log
None log(str msg, int level=LOGDEBUG)
Definition: xbmc.py:9
MythPainter::Begin
virtual void Begin(QPaintDevice *)
Definition: mythpainter.h:54
VideoVisual::SetLastUpdate
std::chrono::milliseconds SetLastUpdate(void)
Definition: videovisual.cpp:59