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  for (int i = 0; i < m_magnitudes.size(); i++)
132  m_magnitudes[i] = 0.0;
134 }
135 
136 void VideoVisualSpectrum::DrawPriv(MythPainter *painter, QPaintDevice* device)
137 {
138  static const QBrush brush(QColor(0, 0, 200, 180));
139  static const QPen pen(QColor(255, 255, 255, 255));
140  double range = m_area.height() / 2.0;
141  int count = m_scale.range();
142  painter->Begin(device);
143  for (int i = 0; i < count; i++)
144  {
145  m_rects[i].setTop(range - int(m_magnitudes[i]));
146  m_rects[i].setBottom(range + int(m_magnitudes[i + count]));
147  if (m_rects[i].height() > 4)
148  painter->DrawRect(m_rects[i], brush, pen, 255);
149  }
150  painter->End();
151 }
152 
153 bool VideoVisualSpectrum::Initialise(const QRect &area)
154 {
155  if (area == m_area)
156  return true;
157 
158  m_area = area;
159  m_barWidth = m_area.width() / m_numSamples;
160  if (m_barWidth < 6)
161  m_barWidth = 6;
162  m_scale.setMax(192, m_area.width() / m_barWidth);
163 
164  m_magnitudes.resize(m_scale.range() * 2);
165  for (int i = 0; i < m_magnitudes.size(); i++)
166  m_magnitudes[i] = 0.0;
167 
168  InitialisePriv();
169  return true;
170 }
171 
173 {
174  m_range = m_area.height() / 2.0;
175  m_rects.resize(m_scale.range());
176  for (int i = 0, x = 0; i < m_rects.size(); i++, x+= m_barWidth)
177  m_rects[i].setRect(x, m_area.height() / 2, m_barWidth - 1, 1);
178 
179  m_scaleFactor = (static_cast<double>(m_area.height()) / 2.0)
180  / log((double)(FFTW_N));
181  m_falloff = (double)m_area.height() / 150.0;
182 
183  LOG(VB_GENERAL, LOG_INFO, DESC +
184  QString("Initialised Spectrum with %1 bars") .arg(m_scale.range()));
185  return true;
186 }
187 
189 {
190  public:
191  const QString &name(void) const override // VideoVisualFactory
192  {
193  static QString name("Spectrum");
194  return name;
195  }
196 
198  MythRender *render) const override // VideoVisualFactory
199  {
200  return new VideoVisualSpectrum(audio, render);
201  }
202 
203  bool SupportedRenderer(RenderType /*type*/) override { return true; } // VideoVisualFactory
#define DESC
Definition: videovisual.h:16
VideoVisualSpectrumFactory VideoVisualSpectrumFactory
VisualNode * GetNode(void)
Definition: videovisual.cpp:90
myth_fftw_complex * m_lout
const QString & name(void) const override
void prepare() override
Definition: videovisual.cpp:84
int64_t SetLastUpdate(void)
Definition: videovisual.cpp:65
bool m_disabled
Definition: videovisual.h:63
VideoVisual * Create(AudioPlayer *audio, MythRender *render) const override
void setMax(int maxscale, int maxrange)
unsigned int uint
Definition: compat.h:140
static guint32 * tmp
Definition: goom_core.c:35
short * m_right
Definition: videovisual.h:34
unsigned char r
Definition: ParseText.cpp:329
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:5
VideoVisualSpectrum(AudioPlayer *audio, MythRender *render)
void * av_malloc(unsigned int size)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QVector< QRect > m_rects
myth_fftw_float * m_rin
bool SupportedRenderer(RenderType) override
long m_length
Definition: videovisual.h:35
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:64
short * m_left
Definition: videovisual.h:33
virtual bool Initialise(const QRect &area)
int range() const
virtual bool InitialisePriv(void)