MythTV  master
videovisualspectrum.cpp
Go to the documentation of this file.
1 #include <QPen>
2 
3 #include "videovisualspectrum.h"
4 
5 #define FFTW_N 512
6 extern "C" {
7 void *av_malloc(unsigned int size);
8 void av_free(void *ptr);
9 }
10 
12  : VideoVisual(audio, render)
13 {
14  m_lin = (myth_fftw_float*) av_malloc(sizeof(myth_fftw_float)*FFTW_N);
15  m_rin = (myth_fftw_float*) av_malloc(sizeof(myth_fftw_float)*FFTW_N);
16  m_lout = (myth_fftw_complex*)
17  av_malloc(sizeof(myth_fftw_complex)*(FFTW_N/2+1));
18  m_rout = (myth_fftw_complex*)
19  av_malloc(sizeof(myth_fftw_complex)*(FFTW_N/2+1));
20 
21  m_lplan = fftw_plan_dft_r2c_1d(FFTW_N, m_lin, (myth_fftw_complex_cast*)m_lout, FFTW_MEASURE);
22  m_rplan = fftw_plan_dft_r2c_1d(FFTW_N, m_rin, (myth_fftw_complex_cast*)m_rout, FFTW_MEASURE);
23 }
24 
26 {
27  if (m_lin)
28  av_free(m_lin);
29  if (m_rin)
30  av_free(m_rin);
31  if (m_lout)
32  av_free(m_lout);
33  if (m_rout)
34  av_free(m_rout);
35  fftw_destroy_plan(m_lplan);
36  fftw_destroy_plan(m_rplan);
37 }
38 
39 template<typename T> T sq(T a) { return a*a; };
40 
41 void VideoVisualSpectrum::Draw(const QRect &area, MythPainter *painter,
42  QPaintDevice* device)
43 {
44  if (m_disabled)
45  return;
46 
47  mutex()->lock();
48  VisualNode *node = GetNode();
49 
50  if (area.isEmpty() || !painter)
51  {
52  mutex()->unlock();
53  return;
54  }
55 
56  if (!Initialise(area))
57  {
58  mutex()->unlock();
59  return;
60  }
61 
62  uint i = 0;
63  if (node)
64  {
65  i = node->m_length;
66  fast_real_set_from_short(m_lin, node->m_left, node->m_length);
67  if (node->m_right)
68  fast_real_set_from_short(m_rin, node->m_right, node->m_length);
69  }
70  mutex()->unlock();
71 
72  fast_reals_set(m_lin + i, m_rin + i, 0, FFTW_N - i);
73  fftw_execute(m_lplan);
74  fftw_execute(m_rplan);
75 
76  double falloff = (((double)SetLastUpdate()) / 40.0) * m_falloff;
77  if (falloff < 0.0)
78  falloff = 0.0;
79  if (falloff > 2048.0)
80  falloff = 2048.0;
81  for (int l = 0, r = m_scale.range(); l < m_scale.range(); l++, r++)
82  {
83  int index = m_scale[l];
84 
85  // The 1D output is Hermitian symmetric (Yk = Yn-k) so Yn = Y0 etc.
86  // The dft_r2c_1d plan doesn't output these redundant values
87  // and furthermore they're not allocated in the ctor
88  double tmp = 2 * sq(real(m_lout[index]));
89  double magL = (tmp > 1.) ? (log(tmp) - 22.0) * m_scaleFactor : 0.;
90 
91  tmp = 2 * sq(real(m_rout[index]));
92  double magR = (tmp > 1.) ? (log(tmp) - 22.0) * m_scaleFactor : 0.;
93 
94  if (magL > m_range)
95  magL = 1.0;
96 
97  if (magL < m_magnitudes[l])
98  {
99  tmp = m_magnitudes[l] - falloff;
100  if (tmp < magL)
101  tmp = magL;
102  magL = tmp;
103  }
104 
105  if (magL < 1.0)
106  magL = 1.0;
107 
108  if (magR > m_range)
109  magR = 1.0;
110 
111  if (magR < m_magnitudes[r])
112  {
113  tmp = m_magnitudes[r] - falloff;
114  if (tmp < magR)
115  tmp = magR;
116  magR = tmp;
117  }
118 
119  if (magR < 1.0)
120  magR = 1.0;
121 
122  m_magnitudes[l] = magL;
123  m_magnitudes[r] = magR;
124  }
125 
126  DrawPriv(painter, device);
127 }
128 
130 {
131  // NOLINTNEXTLINE(modernize-loop-convert)
132  for (int i = 0; i < m_magnitudes.size(); i++)
133  m_magnitudes[i] = 0.0;
135 }
136 
137 void VideoVisualSpectrum::DrawPriv(MythPainter *painter, QPaintDevice* device)
138 {
139  static const QBrush kBrush(QColor(0, 0, 200, 180));
140  static const QPen kPen(QColor(255, 255, 255, 255));
141  double range = m_area.height() / 2.0;
142  int count = m_scale.range();
143  painter->Begin(device);
144  for (int i = 0; i < count; i++)
145  {
146  m_rects[i].setTop(range - int(m_magnitudes[i]));
147  m_rects[i].setBottom(range + int(m_magnitudes[i + count]));
148  if (m_rects[i].height() > 4)
149  painter->DrawRect(m_rects[i], kBrush, kPen, 255);
150  }
151  painter->End();
152 }
153 
154 bool VideoVisualSpectrum::Initialise(const QRect &area)
155 {
156  if (area == m_area)
157  return true;
158 
159  m_area = area;
160  m_barWidth = m_area.width() / m_numSamples;
161  if (m_barWidth < 6)
162  m_barWidth = 6;
163  m_scale.setMax(192, m_area.width() / m_barWidth);
164 
165  m_magnitudes.resize(m_scale.range() * 2);
166  // NOLINTNEXTLINE(modernize-loop-convert)
167  for (int i = 0; i < m_magnitudes.size(); i++)
168  m_magnitudes[i] = 0.0;
169  InitialisePriv();
170  return true;
171 }
172 
174 {
175  m_range = m_area.height() / 2.0;
176  m_rects.resize(m_scale.range());
177  for (int i = 0, x = 0; i < m_rects.size(); i++, x+= m_barWidth)
178  m_rects[i].setRect(x, m_area.height() / 2, m_barWidth - 1, 1);
179 
180  m_scaleFactor = (static_cast<double>(m_area.height()) / 2.0)
181  / log((double)(FFTW_N));
182  m_falloff = (double)m_area.height() / 150.0;
183 
184  LOG(VB_GENERAL, LOG_INFO, DESC +
185  QString("Initialised Spectrum with %1 bars") .arg(m_scale.range()));
186  return true;
187 }
188 
190 {
191  public:
192  const QString &name(void) const override // VideoVisualFactory
193  {
194  static QString s_name("Spectrum");
195  return s_name;
196  }
197 
199  MythRender *render) const override // VideoVisualFactory
200  {
201  return new VideoVisualSpectrum(audio, render);
202  }
203 
204  bool SupportedRenderer(RenderType /*type*/) override { return true; } // VideoVisualFactory
#define DESC
Definition: videovisual.h:17
VideoVisualSpectrumFactory VideoVisualSpectrumFactory
VisualNode * GetNode(void)
Definition: videovisual.cpp:88
myth_fftw_complex * m_lout
const QString & name(void) const override
void prepare() override
Definition: videovisual.cpp:82
int64_t SetLastUpdate(void)
Definition: videovisual.cpp:63
bool m_disabled
Definition: videovisual.h:64
VideoVisual * Create(AudioPlayer *audio, MythRender *render) const override
void setMax(int maxscale, int maxrange)
static guint32 * tmp
Definition: goom_core.cpp:30
short * m_right
Definition: videovisual.h:35
virtual void End()
Definition: mythpainter.h:51
myth_fftw_float * m_lin
#define FFTW_N
myth_fftw_complex * m_rout
virtual void DrawRect(const QRect &area, const QBrush &fillBrush, const QPen &linePen, int alpha)
T sq(T a)
def log(debug, txt)
Definition: utilities.py:7
VideoVisualSpectrum(AudioPlayer *audio, MythRender *render)
unsigned int uint
Definition: compat.h:140
void * av_malloc(unsigned int size)
QVector< QRect > m_rects
myth_fftw_float * m_rin
bool SupportedRenderer(RenderType) override
long m_length
Definition: videovisual.h:36
QMutex * mutex()
Definition: visual.h:25
QVector< double > m_magnitudes
virtual void DrawPriv(MythPainter *painter, QPaintDevice *device)
void av_free(void *ptr)
void Draw(const QRect &area, MythPainter *painter, QPaintDevice *device) override
RenderType
virtual void Begin(QPaintDevice *parent)
Definition: mythpainter.h:50
QRect m_area
Definition: videovisual.h:65
short * m_left
Definition: videovisual.h:34
virtual bool Initialise(const QRect &area)
int range() const
virtual bool InitialisePriv(void)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23