00001 #include <QPen>
00002
00003 #include "videovisualspectrum.h"
00004
00005 #define FFTW_N 512
00006 extern "C" {
00007 void *av_malloc(unsigned int size);
00008 void av_free(void *ptr);
00009 }
00010
00011 VideoVisualSpectrum::VideoVisualSpectrum(AudioPlayer *audio, MythRender *render)
00012 : VideoVisual(audio, render), m_range(1.0), m_scaleFactor(2.0),
00013 m_falloff(3.0), m_barWidth(1)
00014 {
00015 m_numSamples = 64;
00016 lin = (myth_fftw_float*) av_malloc(sizeof(myth_fftw_float)*FFTW_N);
00017 rin = (myth_fftw_float*) av_malloc(sizeof(myth_fftw_float)*FFTW_N);
00018 lout = (myth_fftw_complex*)
00019 av_malloc(sizeof(myth_fftw_complex)*(FFTW_N/2+1));
00020 rout = (myth_fftw_complex*)
00021 av_malloc(sizeof(myth_fftw_complex)*(FFTW_N/2+1));
00022
00023 lplan = fftw_plan_dft_r2c_1d(FFTW_N, lin, (myth_fftw_complex_cast*)lout, FFTW_MEASURE);
00024 rplan = fftw_plan_dft_r2c_1d(FFTW_N, rin, (myth_fftw_complex_cast*)rout, FFTW_MEASURE);
00025 }
00026
00027 VideoVisualSpectrum::~VideoVisualSpectrum()
00028 {
00029 if (lin)
00030 av_free(lin);
00031 if (rin)
00032 av_free(rin);
00033 if (lout)
00034 av_free(lout);
00035 if (rout)
00036 av_free(rout);
00037 fftw_destroy_plan(lplan);
00038 fftw_destroy_plan(rplan);
00039 }
00040
00041 template<typename T> T sq(T a) { return a*a; };
00042
00043 void VideoVisualSpectrum::Draw(const QRect &area, MythPainter *painter,
00044 QPaintDevice* device)
00045 {
00046 if (m_disabled)
00047 return;
00048
00049 mutex()->lock();
00050 VisualNode *node = GetNode();
00051
00052 if (area.isEmpty() || !painter)
00053 {
00054 mutex()->unlock();
00055 return;
00056 }
00057
00058 if (!Initialise(area))
00059 {
00060 mutex()->unlock();
00061 return;
00062 }
00063
00064 uint i = 0;
00065 if (node)
00066 {
00067 i = node->length;
00068 fast_real_set_from_short(lin, node->left, node->length);
00069 if (node->right)
00070 fast_real_set_from_short(rin, node->right, node->length);
00071 }
00072 mutex()->unlock();
00073
00074 fast_reals_set(lin + i, rin + i, 0, FFTW_N - i);
00075 fftw_execute(lplan);
00076 fftw_execute(rplan);
00077
00078 double magL, magR, tmp;
00079 double falloff = (((double)SetLastUpdate()) / 40.0) * m_falloff;
00080 if (falloff < 0.0)
00081 falloff = 0.0;
00082 if (falloff > 2048.0)
00083 falloff = 2048.0;
00084 for (int l = 0, r = m_scale.range(); l < m_scale.range(); l++, r++)
00085 {
00086 int index = m_scale[l];
00087 magL = (log(sq(real(lout[index])) + sq(real(lout[FFTW_N - index]))) - 22.0) *
00088 m_scaleFactor;
00089 magR = (log(sq(real(rout[index])) + sq(real(rout[FFTW_N - index]))) - 22.0) *
00090 m_scaleFactor;
00091
00092 if (magL > m_range)
00093 magL = 1.0;
00094
00095 if (magL < m_magnitudes[l])
00096 {
00097 tmp = m_magnitudes[l] - falloff;
00098 if (tmp < magL)
00099 tmp = magL;
00100 magL = tmp;
00101 }
00102
00103 if (magL < 1.0)
00104 magL = 1.0;
00105
00106 if (magR > m_range)
00107 magR = 1.0;
00108
00109 if (magR < m_magnitudes[r])
00110 {
00111 tmp = m_magnitudes[r] - falloff;
00112 if (tmp < magR)
00113 tmp = magR;
00114 magR = tmp;
00115 }
00116
00117 if (magR < 1.0)
00118 magR = 1.0;
00119
00120 m_magnitudes[l] = magL;
00121 m_magnitudes[r] = magR;
00122 }
00123
00124 DrawPriv(painter, device);
00125 }
00126
00127 void VideoVisualSpectrum::prepare(void)
00128 {
00129 for (int i = 0; i < m_magnitudes.size(); i++)
00130 m_magnitudes[i] = 0.0;
00131 VideoVisual::prepare();
00132 }
00133
00134 void VideoVisualSpectrum::DrawPriv(MythPainter *painter, QPaintDevice* device)
00135 {
00136 static const QBrush brush(QColor(0, 0, 200, 180));
00137 static const QPen pen(QColor(255, 255, 255, 255));
00138 double range = m_area.height() / 2.0;
00139 int count = m_scale.range();
00140 painter->Begin(device);
00141 for (int i = 0; i < count; i++)
00142 {
00143 m_rects[i].setTop(range - int(m_magnitudes[i]));
00144 m_rects[i].setBottom(range + int(m_magnitudes[i + count]));
00145 if (m_rects[i].height() > 4)
00146 painter->DrawRect(m_rects[i], brush, pen, 255);
00147 }
00148 painter->End();
00149 }
00150
00151 bool VideoVisualSpectrum::Initialise(const QRect &area)
00152 {
00153 if (area == m_area)
00154 return true;
00155
00156 m_area = area;
00157 m_barWidth = m_area.width() / m_numSamples;
00158 if (m_barWidth < 6)
00159 m_barWidth = 6;
00160 m_scale.setMax(192, m_area.width() / m_barWidth);
00161
00162 m_magnitudes.resize(m_scale.range() * 2);
00163 for (int i = 0; i < m_magnitudes.size(); i++)
00164 m_magnitudes[i] = 0.0;
00165
00166 InitialisePriv();
00167 return true;
00168 }
00169
00170 bool VideoVisualSpectrum::InitialisePriv(void)
00171 {
00172 m_range = m_area.height() / 2.0;
00173 m_rects.resize(m_scale.range());
00174 for (int i = 0, x = 0; i < m_rects.size(); i++, x+= m_barWidth)
00175 m_rects[i].setRect(x, m_area.height() / 2, m_barWidth - 1, 1);
00176
00177 m_scaleFactor = double(m_area.height() / 2) / log((double)(FFTW_N));
00178 m_falloff = (double)m_area.height() / 150.0;
00179
00180 LOG(VB_GENERAL, LOG_INFO, DESC +
00181 QString("Initialised Spectrum with %1 bars") .arg(m_scale.range()));
00182 return true;
00183 }
00184
00185 static class VideoVisualSpectrumFactory : public VideoVisualFactory
00186 {
00187 public:
00188 const QString &name(void) const
00189 {
00190 static QString name("Spectrum");
00191 return name;
00192 }
00193
00194 VideoVisual *Create(AudioPlayer *audio,
00195 MythRender *render) const
00196 {
00197 return new VideoVisualSpectrum(audio, render);
00198 }
00199
00200 virtual bool SupportedRenderer(RenderType type) { return true; }
00201 } VideoVisualSpectrumFactory;