Ticket #4479: lyrics_visualizer.patch

File lyrics_visualizer.patch, 11.7 KB (added by Mike Rice <mikerice1969@…>, 13 years ago)

updated for current trunk (21437)

  • visualize.cpp

     
    2222// mythtv
    2323#include <mythtv/mythdbcon.h>
    2424#include <mythtv/mythcontext.h>
     25#include <mythtv/libmythui/mythuihelper.h>
    2526
    2627// mythmusic
    2728#include "mainvisual.h"
     
    455456    }
    456457}AlbumArtFactory;
    457458
     459Lyrics::Lyrics(MainVisual *parent)
     460{
     461    m_pParent = parent;
     462
     463    findFrontCover();
     464
     465    Decoder *dec = m_pParent->decoder();
     466    if (dec)
     467        m_filename = dec->getFilename();
     468
     469    fps = 1;
     470}
     471
     472void Lyrics::findFrontCover(void)
     473{
     474    // if a front cover image is available show that first
     475    AlbumArtImages albumArt(m_pParent->metadata());
     476    if (albumArt.getImage(IT_FRONTCOVER))
     477        m_currImageType = IT_FRONTCOVER;
     478    else
     479    {
     480        // not available so just show the first image available
     481        if (albumArt.getImageCount() > 0)
     482            m_currImageType = albumArt.getImageAt(0)->imageType;
     483        else
     484            m_currImageType = IT_UNKNOWN;
     485    }
     486}
     487
     488Lyrics::~Lyrics()
     489{
     490}
     491
     492void Lyrics::resize(const QSize &newsize)
     493{
     494    m_size = newsize;
     495}
     496
     497bool Lyrics::process(VisualNode *node)
     498{
     499    node = node;
     500    return true;
     501}
     502
     503void Lyrics::handleKeyPress(const QString &action)
     504{
     505    if (action == "DOWN")
     506    {
     507        if (m_start + 1 + m_visible_lines < int(m_lyrics.size()))
     508            m_start++;
     509    }
     510
     511    if (action == "UP")
     512    {
     513        if (m_start != 0)
     514            m_start--;
     515    }
     516
     517    if (action == "PAGEDOWN")
     518    {
     519        if (m_start + m_page_amount + m_visible_lines < int(m_lyrics.size()))
     520            m_start += m_page_amount;
     521        else
     522            m_start = int(m_lyrics.size()) - m_page_amount;
     523    }
     524
     525    if (action == "PAGEUP")
     526    {
     527        if (m_start < m_page_amount)
     528            m_start = 0;
     529        else
     530            m_start -= m_page_amount;
     531    }
     532
     533    if (action == "SELECT")
     534    {
     535        AlbumArtImages albumArt(m_pParent->metadata());
     536        int newType = m_currImageType;
     537
     538        if (albumArt.getImageCount() > 0)
     539        {
     540            newType++;
     541
     542            while (!albumArt.getImage((ImageType) newType))
     543            {
     544                newType++;
     545                if (newType == IT_LAST)
     546                    newType = IT_UNKNOWN;
     547            }
     548        }
     549
     550        if (newType != m_currImageType)
     551        {
     552            m_currImageType = (ImageType) newType;
     553            // force an update
     554            m_cursize = QSize(0, 0);
     555        }
     556    }
     557}
     558
     559bool Lyrics::needsUpdate()
     560{
     561    if (m_cursize != m_size)
     562        return true;
     563
     564    if (m_filename != m_pParent->decoder()->getFilename())
     565    {
     566        m_filename = m_pParent->decoder()->getFilename();
     567        findFrontCover();
     568        return true;
     569    }
     570
     571    return false;
     572}
     573
     574void Lyrics::calculateScreenInfo(QPainter *p)
     575{
     576    m_start = 0;
     577    m_indentx = 0;
     578    m_indenty = 0;
     579    m_max_line_width = 0;
     580    m_visible_lines = 0;
     581    m_page_amount = 0;
     582    m_font_height = 0;
     583    m_lyrics_too_wide = false;
     584    m_image_too_small = false;
     585
     586    if (!m_lyrics.empty())
     587    {
     588        p->setFont(GetMythUI()->GetMediumFont());
     589       
     590        QFontMetrics fm(p->font());
     591        m_font_height = fm.height();
     592
     593        for (QVector<QString>::iterator i = m_lyrics.begin();
     594                                        i != m_lyrics.end(); i++)
     595        {
     596            int width = fm.width(*i);
     597            if (width > m_max_line_width) m_max_line_width = width;
     598        }
     599
     600        m_indentx = int(0.03 * m_size.width());
     601        m_indenty = int(0.03 * m_size.height());
     602
     603        if ((m_max_line_width + 2 * m_indentx) > m_size.width())
     604        {
     605            // Lyrics don't fit.  Remove them.
     606            m_lyrics.clear();
     607            m_max_line_width = 0;
     608            m_indentx = 0;
     609            m_indenty = 0;
     610            m_lyrics_too_wide = true;
     611        }
     612        else
     613        {
     614            m_visible_lines = (m_size.height() - 2 * m_indenty) / m_font_height;
     615            m_page_amount = m_visible_lines / 2;
     616            if (m_size.width() < m_max_line_width + 3 * m_indentx +
     617                                     int(0.1 * m_size.width()))
     618            {
     619                // Don't draw really small images
     620                m_image_too_small = true;
     621            }
     622        }
     623    }
     624}
     625
     626bool Lyrics::draw(QPainter *p, const QColor &back)
     627{
     628    if (!m_pParent->decoder())
     629        return false;
     630
     631    // If the song has changed or the size, reload
     632    if (needsUpdate())
     633    {
     634        m_lyrics = m_pParent->metadata()->getUnsynchronizedLyrics();
     635        calculateScreenInfo(p);
     636
     637        // Now we know how much room we have for the image.
     638        QImage art(m_pParent->metadata()->getAlbumArt(m_currImageType));
     639        if (art.isNull())
     640        {
     641            m_cursize = m_size;
     642            m_image = QImage();
     643        }
     644        else if (!m_image_too_small)
     645        {
     646            int height_adjustment = m_lyrics_too_wide ?  m_font_height : 0;
     647            QSize a_size(m_size.width() - m_max_line_width - 3 * m_indentx,
     648                         m_size.height() - height_adjustment);
     649            m_image = art.scaled(a_size, Qt::KeepAspectRatio,
     650                                         Qt::SmoothTransformation);
     651        }
     652    }
     653
     654    if (m_image.isNull() && !m_image_too_small && m_lyrics.empty())
     655    {
     656        drawWarning(p, back, m_size, QObject::tr("?"));
     657        return true;
     658    }
     659
     660    p->fillRect(0, 0, m_size.width(), m_size.height(), back);
     661
     662    // Paint the image
     663    if (!m_image_too_small)
     664    {
     665        int xpos = (m_size.width() - m_max_line_width -
     666                                   m_indentx - m_image.width()) /2;
     667        int ypos = m_lyrics_too_wide ? 0 :
     668                               (m_size.height() - m_image.height()) / 2;
     669        p->drawImage(xpos, ypos, m_image);
     670    }
     671
     672    // Paint the Lyrics
     673    p->setFont(GetMythUI()->GetMediumFont());
     674    if (m_lyrics_too_wide)
     675    {
     676        // Lyrics are too wide to fit on the display.  Just write "Lyrics"
     677        // at the bottom on the display to indicate they are available.
     678        QFontMetrics fm(p->font());
     679        QString l = "Lyrics";
     680        int width = fm.width(l);
     681        int height = m_font_height;
     682        int x = m_size.width() / 2 - width / 2;
     683        int y = m_size.height() - height;
     684        p->setPen(Qt::white);
     685        p->drawText(x, y, width, height, Qt::AlignCenter, l);
     686    }
     687    else
     688    {
     689        int textWidth = m_max_line_width;
     690        int textHeight = m_font_height * m_lyrics.size();
     691        int x = m_size.width() - m_max_line_width - m_indentx;
     692        int y = m_indenty;
     693   
     694        int line = m_start;
     695        for (int offset = 0;
     696             line <= m_start + m_visible_lines-1 && line < int(m_lyrics.size());
     697             offset += m_font_height, line++)
     698        {
     699            QString l = m_lyrics[line] + "\n";
     700            p->setPen(Qt::white);
     701            p->drawText(x, y + offset, textWidth, textHeight, Qt::AlignLeft, l);
     702        }
     703    }
     704
     705    // Store our new size
     706    m_cursize = m_size;
     707
     708    return true;
     709}
     710
     711static class LyricsFactory : public VisFactory
     712{
     713  public:
     714    const QString &name(void) const
     715    {
     716        static QString name("Lyrics");
     717        return name;
     718    }
     719
     720    uint plugins(QStringList *list) const
     721    {
     722        *list << name();
     723        return 1;
     724    }
     725
     726    VisualBase *create(MainVisual *parent, long int winid, const QString &pluginName) const
     727    {
     728        (void)winid;
     729        (void)pluginName;
     730        return new Lyrics(parent);
     731    }
     732}LyricsFactory;
     733
    458734Blank::Blank()
    459735    : VisualBase(true)
    460736{
  • metadata.cpp

     
    871871
    872872//--------------------------------------------------------------------------
    873873
     874QVector<QString> Metadata::getUnsynchronizedLyrics()
     875{
     876    QVector<QString> ulyrics;
     877
     878    ulyrics = MetaIOID3::getUnsynchronizedLyrics(m_filename);
     879
     880    return ulyrics;
     881}
     882
    874883MetadataLoadingThread::MetadataLoadingThread(AllMusic *parent_ptr)
    875884{
    876885    parent = parent_ptr;
  • metadata.h

     
    194194    QImage getAlbumArt(void);
    195195    // this looks only for the given image type
    196196    QImage getAlbumArt(ImageType type);
     197    QVector<QString> getUnsynchronizedLyrics();
    197198
    198199  private:
    199200    void setCompilationFormatting(bool cd = false);
  • metaioid3.cpp

     
    344344}
    345345
    346346/*!
     347 *
     348 */
     349QVector<QString> MetaIOID3::getUnsynchronizedLyrics(QString filename)
     350{
     351  QVector<QString> ulyrics;
     352
     353  TagLib::MPEG::File *taglib = new TagLib::MPEG::File(filename.local8Bit());
     354  if (taglib != NULL)
     355  {
     356      TagLib::ID3v2::Tag *tag = taglib->ID3v2Tag();
     357
     358      if (tag != NULL && !tag->frameListMap()["USLT"].isEmpty())
     359      {
     360          TagLib::ID3v2::FrameList ulyricframes = tag->frameListMap()["USLT"];
     361
     362          // No special support for multiple USLT frames.  Just concatenate
     363          // them all into one vector.
     364          for(TagLib::ID3v2::FrameList::Iterator it = ulyricframes.begin();
     365                                               it != ulyricframes.end(); ++it)
     366          {
     367              QString lstr = TStringToQString((*it)->toString());
     368              QStringList sl = QStringList::split("\n", lstr, TRUE);
     369              for (QStringList::Iterator it = sl.begin(); it != sl.end(); ++it)
     370                  ulyrics.push_back(*it);
     371          }
     372      }
     373      delete taglib;
     374  }
     375  if (ulyrics.size() == 1)
     376  {
     377      // It is useful to use only one line of the lyrics when it has no lyrics
     378      // (classical music for example) to quiet tools that look for missing
     379      // lyrics.  Just clear that line so it isn't displayed.
     380      ulyrics.clear();
     381  }
     382  return ulyrics;
     383}
     384
     385/*!
    347386 * \brief Find the a custom comment tag by description.
    348387 *        This is a copy of the same function in the
    349388 *        TagLib::ID3v2::UserTextIdentificationFrame Class with a static
  • visualize.h

     
    101101    QImage m_image;
    102102};
    103103
     104class Lyrics : public VisualBase
     105{
     106  public:
     107    Lyrics(MainVisual *parent);
     108    virtual ~Lyrics();
     109
     110    void resize(const QSize &size);
     111    bool process(VisualNode *node = 0);
     112    bool draw(QPainter *p, const QColor &back = Qt::black);
     113    void handleKeyPress(const QString &action);
     114
     115  private:
     116    bool needsUpdate(void);
     117    void findFrontCover(void);
     118    void calculateScreenInfo(QPainter *p);
     119
     120    QSize m_size, m_cursize;
     121    QString m_filename;
     122    ImageType m_currImageType;
     123    MainVisual *m_pParent;
     124    QImage m_image;
     125    QVector<QString> m_lyrics;
     126    int m_start;
     127    int m_page_amount;
     128    int m_indentx;
     129    int m_indenty;
     130    int m_visible_lines;
     131    int m_max_line_width;
     132    int m_font_height;
     133    bool m_lyrics_too_wide;
     134    bool m_image_too_small;
     135};
     136
    104137class Blank : public VisualBase
    105138{
    106139    // This draws ... well ... nothing 
  • metaioid3.h

     
    4141    bool write(Metadata* mdata);
    4242    Metadata* read(QString filename);
    4343    static QImage getAlbumArt(QString filename, ImageType type);
     44    static QVector<QString> getUnsynchronizedLyrics(QString filename);
    4445
    4546  private:
    4647    TagLib::MPEG::File *OpenFile(const QString &filename);