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