MythTV  0.26-pre
mainvisual.cpp
Go to the documentation of this file.
00001 // Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
00002 //
00003 // Use, modification and distribution is allowed without limitation,
00004 // warranty, or liability of any kind.
00005 //
00006 
00007 // C
00008 #include <cmath>
00009 #include <cstdio>
00010 
00011 // C++
00012 #include <algorithm>
00013 #include <iostream>
00014 using namespace std;
00015 
00016 // Qt
00017 #include <QPainter>
00018 
00019 // mythtv
00020 #include <mythuivideo.h>
00021 
00022 // mythmusic
00023 #include "visualize.h"
00024 #include "mainvisual.h"
00025 #include "constants.h"
00026 #include "musicplayer.h"
00027 
00028 // fast inlines
00029 #include "inlines.h"
00030 
00031 
00033 // MainVisual
00034 
00035 MainVisual::MainVisual(MythUIVideo *visualizer)
00036     : QObject(NULL), MythTV::Visual(), m_visualizerVideo(visualizer),
00037       m_vis(NULL), m_playing(false), m_fps(20), m_samples(SAMPLES_DEFAULT_SIZE),
00038       m_updateTimer(NULL)
00039 {
00040     setObjectName("MainVisual");
00041 
00042     for (const VisFactory* pVisFactory = VisFactory::VisFactories();
00043         pVisFactory; pVisFactory = pVisFactory->next())
00044     {
00045         pVisFactory->plugins(&m_visualizers);
00046     }
00047     m_visualizers.sort();
00048 
00049     m_currentVisualizer = gCoreContext->GetNumSetting("MusicLastVisualizer", 0);
00050 
00051     resize(m_visualizerVideo->GetArea().size());
00052 
00053     m_updateTimer = new QTimer(this);
00054     m_updateTimer->setInterval(1000 / m_fps);
00055     m_updateTimer->setSingleShot(true);
00056     connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(timeout()));
00057 }
00058 
00059 MainVisual::~MainVisual()
00060 {
00061     m_updateTimer->stop();
00062     delete m_updateTimer;
00063 
00064     if (m_vis)
00065         delete m_vis;
00066 
00067     while (!m_nodes.empty())
00068         delete m_nodes.takeLast();
00069 
00070     gCoreContext->SaveSetting("MusicLastVisualizer", m_currentVisualizer);
00071 }
00072 
00073 void MainVisual::stop(void)
00074 {
00075     m_updateTimer->stop();
00076 
00077     if (m_vis)
00078     {
00079         delete m_vis;
00080         m_vis = NULL;
00081     }
00082 }
00083 
00084 void MainVisual::setVisual(const QString &name)
00085 {
00086     m_updateTimer->stop();
00087 
00088     int index = m_visualizers.indexOf(name);
00089 
00090     if (index == -1)
00091     {
00092         LOG(VB_GENERAL, LOG_ERR, QString("MainVisual: visualizer %1 not found!").arg(name));
00093         return;
00094     }
00095 
00096     m_currentVisualizer = index;
00097 
00098     m_pixmap.fill(m_visualizerVideo->GetBackgroundColor());
00099 
00100     QString visName, pluginName;
00101 
00102     if (name.contains("-"))
00103     {
00104         visName = name.section('-', 0, 0);
00105         pluginName = name.section('-', 1, 1);
00106     }
00107     else
00108     {
00109         visName = name;
00110         pluginName.clear();
00111     }
00112 
00113     if (m_vis)
00114     {
00115         delete m_vis;
00116         m_vis = NULL;
00117     }
00118 
00119     for (const VisFactory* pVisFactory = VisFactory::VisFactories();
00120          pVisFactory; pVisFactory = pVisFactory->next())
00121     {
00122         if (pVisFactory->name() == visName)
00123         {
00124             m_vis = pVisFactory->create(this, pluginName);
00125             m_vis->resize(m_visualizerVideo->GetArea().size());
00126             m_fps = m_vis->getDesiredFPS();
00127             m_samples = m_vis->getDesiredSamples();
00128 
00129             QMutexLocker locker(mutex());
00130             prepare();
00131 
00132             break;
00133         }
00134     }
00135 
00136     // force an update
00137     m_updateTimer->start(1000 / m_fps);
00138 }
00139 
00140 // Caller holds mutex() lock
00141 void MainVisual::prepare()
00142 {
00143     while (!m_nodes.empty())
00144         delete m_nodes.takeLast();
00145 }
00146 
00147 // This is called via : mythtv/libs/libmyth/output.cpp :: OutputListeners::dispatchVisual
00148 //    from : mythtv/libs/libmyth/audio/audiooutputbase.cpp :: AudioOutputBase::AddData
00149 // Caller holds mutex() lock
00150 void MainVisual::add(uchar *buffer, unsigned long b_len, unsigned long timecode, int source_channels, int bits_per_sample)
00151 {
00152     unsigned long len = b_len, cnt;
00153     short *l = 0, *r = 0;
00154 
00155     // len is length of buffer in fully converted samples
00156     len /= source_channels;
00157     len /= (bits_per_sample / 8);
00158 
00159     if (len > m_samples)
00160         len = m_samples;
00161 
00162     cnt = len;
00163 
00164     if (source_channels == 2)
00165     {
00166         l = new short[len];
00167         r = new short[len];
00168 
00169         if (bits_per_sample == 8)
00170             stereo16_from_stereopcm8(l, r, buffer, cnt);
00171         else if (bits_per_sample == 16)
00172             stereo16_from_stereopcm16(l, r, (short *) buffer, cnt);
00173     }
00174     else if (source_channels == 1)
00175     {
00176         l = new short[len];
00177 
00178         if (bits_per_sample == 8)
00179             mono16_from_monopcm8(l, buffer, cnt);
00180         else if (bits_per_sample == 16)
00181             mono16_from_monopcm16(l, (short *) buffer, cnt);
00182     }
00183     else
00184         len = 0;
00185 
00186     m_nodes.append(new VisualNode(l, r, len, timecode));
00187 }
00188 
00189 void MainVisual::timeout()
00190 {
00191     VisualNode *node = NULL;
00192     if (m_playing && gPlayer->getOutput())
00193     {
00194         QMutexLocker locker(mutex());
00195         int64_t timestamp = gPlayer->getOutput()->GetAudiotime();
00196         while (m_nodes.size() > 1)
00197         {
00198             if ((int64_t)m_nodes.first()->offset > timestamp)
00199                 break;
00200 
00201             if (m_vis)
00202                 m_vis->processUndisplayed(node);
00203 
00204             delete m_nodes.first();
00205             m_nodes.removeFirst();
00206         }
00207 
00208         if (!m_nodes.isEmpty())
00209             node = m_nodes.first();
00210     }
00211 
00212     bool stop = true;
00213     if (m_vis)
00214         stop = m_vis->process(node);
00215 
00216     if (m_vis && !stop)
00217     {
00218         QPainter p(&m_pixmap);
00219         if (m_vis->draw(&p, m_visualizerVideo->GetBackgroundColor()))
00220             m_visualizerVideo->UpdateFrame(&m_pixmap);
00221     }
00222 
00223     if (m_playing && !stop)
00224         m_updateTimer->start();
00225 }
00226 
00227 void MainVisual::resize(const QSize &size)
00228 {
00229     m_pixmap = QPixmap(size);
00230     m_pixmap.fill(m_visualizerVideo->GetBackgroundColor());
00231 
00232     if (m_vis)
00233         m_vis->resize(size);
00234 }
00235 
00236 void MainVisual::customEvent(QEvent *event)
00237 {
00238     if ((event->type() == OutputEvent::Playing)   ||
00239         (event->type() == OutputEvent::Info)      ||
00240         (event->type() == OutputEvent::Buffering) ||
00241         (event->type() == OutputEvent::Paused))
00242     {
00243         m_playing = true;
00244         if (!m_updateTimer->isActive())
00245             m_updateTimer->start();
00246     }
00247     else if ((event->type() == OutputEvent::Stopped) ||
00248              (event->type() == OutputEvent::Error))
00249     {
00250         m_playing = false;
00251     }
00252 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends