/*************************************************************************** * Copyright (C) 2007-2012 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include "skin.h" #include "fft.h" #include "inlines.h" #include "mainvisual.h" #define VISUAL_NODE_SIZE 512 //samples #define VISUAL_BUFFER_SIZE (5*VISUAL_NODE_SIZE) MainVisual *MainVisual::m_instance = 0; MainVisual *MainVisual::instance() { if (!m_instance) qFatal ("MainVisual: this object is not created!"); return m_instance; } MainVisual::MainVisual (QWidget *parent) : Visual (parent), m_vis (0) { m_skin = Skin::instance(); m_ratio = m_skin->ratio(); connect(m_skin, SIGNAL(skinChanged()), this, SLOT(readSettings())); m_timer = new QTimer (this); connect(m_timer, SIGNAL (timeout()), this, SLOT (timeout())); m_buffer = new float[VISUAL_BUFFER_SIZE]; m_buffer_at = 0; m_instance = this; m_update = false; createMenu(); readSettings(); } MainVisual::~MainVisual() { writeSettings(); if (m_vis) { delete m_vis; m_vis = 0; } delete [] m_buffer; m_instance = 0; } void MainVisual::setVisual (VisualBase *newvis) { m_timer->stop(); if (m_vis) delete m_vis; m_vis = newvis; if (m_vis) m_timer->start(); else { m_pixmap.fill (Qt::transparent); update(); } } void MainVisual::clear() { m_buffer_at = 0; if (m_vis) m_vis->clear(); m_pixmap = m_bg; update(); } void MainVisual::add (float *data, size_t samples, int chan) { if (!m_timer->isActive () || !m_vis) return; if(VISUAL_BUFFER_SIZE == m_buffer_at) { m_buffer_at -= VISUAL_NODE_SIZE; memmove(m_buffer, m_buffer + VISUAL_NODE_SIZE, m_buffer_at * sizeof(float)); return; } int frames = qMin(int(samples/chan), VISUAL_BUFFER_SIZE - m_buffer_at); mono16_from_multichannel(m_buffer + m_buffer_at, data, frames, chan); m_buffer_at += frames; } void MainVisual::timeout() { mutex()->lock (); if(m_buffer_at < VISUAL_NODE_SIZE) { mutex()->unlock (); return; } if (m_vis) { m_vis->process (m_buffer); m_buffer_at -= VISUAL_NODE_SIZE; memmove(m_buffer, m_buffer + VISUAL_NODE_SIZE, m_buffer_at*sizeof(float)); m_pixmap = m_bg; QPainter p(&m_pixmap); m_vis->draw (&p); } mutex()->unlock (); update(); } void MainVisual::paintEvent (QPaintEvent *) { QPainter painter (this); painter.drawPixmap (0,0, m_pixmap); } void MainVisual::hideEvent (QHideEvent *) { m_timer->stop(); } void MainVisual::showEvent (QShowEvent *) { if (m_vis) m_timer->start(); } void MainVisual::mousePressEvent (QMouseEvent *e) { if (e->button() == Qt::RightButton) m_menu->exec(e->globalPos()); else { m_pixmap = m_bg; if (!m_vis) setVisual(new mainvisual::Analyzer); else if (m_vis->name() == "Analyzer") setVisual(new mainvisual::Scope); else if (m_vis->name() == "Scope") setVisual(0); QString str = m_vis ? m_vis->name() : "Off"; foreach(QAction *act, m_visModeGroup->actions ()) { if (str == act->data().toString()) { act->setChecked(true); break; } } writeSettings(); } } void MainVisual::drawBackGround() { m_bg = QPixmap (76 * m_ratio, 16 * m_ratio); if (m_transparentAction->isChecked()) { m_bg.fill (Qt::transparent); return; } QPainter painter(&m_bg); for (int x = 0; x < 76 * m_ratio; x += 2) { painter.setPen(m_skin->getVisColor(0)); painter.drawLine(x + 1, 0, x + 1, 16 *m_ratio); for (int y = 0; y < 16 *m_ratio; y += 2) { painter.setPen(m_skin->getVisColor(0)); painter.drawPoint(x,y); painter.setPen(m_skin->getVisColor(1)); painter.drawPoint(x,y + 1); } } } void MainVisual::writeSettings() { QSettings settings(Qmmp::configFile(), QSettings::IniFormat); settings.beginGroup("Skinned"); QAction *act = m_peaksFalloffGroup->checkedAction (); settings.setValue("vis_peaks_falloff", act ? act->data().toDouble() : 0.2); act = m_analyzerFalloffGroup->checkedAction (); settings.setValue("vis_analyzer_falloff", act ? act->data().toDouble() : 2.2); settings.setValue("vis_show_peaks", m_peaksAction->isChecked()); act = m_analyzerModeGroup->checkedAction(); settings.setValue("vis_analyzer_mode", act ? act->data().toInt() : 0); act = m_analyzerTypeGroup->checkedAction(); settings.setValue("vis_analyzer_type", act ? act->data().toInt() : 1); settings.setValue("vis_transparent_bg", m_transparentAction->isChecked()); act = m_visModeGroup->checkedAction (); settings.setValue("vis_type", act ? act->data().toString() : "Off"); act = m_fpsGroup->checkedAction(); settings.setValue("vis_rate", act ? act->data().toInt() : 25); } void MainVisual::createMenu() { m_menu = new QMenu (this); connect(m_menu, SIGNAL(triggered (QAction *)),SLOT(writeSettings())); connect(m_menu, SIGNAL(triggered (QAction *)),SLOT(readSettings())); QMenu *visMode = m_menu->addMenu(tr("Visualization Mode")); m_visModeGroup = new QActionGroup(this); m_visModeGroup->setExclusive(true); m_visModeGroup->addAction(tr("Analyzer"))->setData("Analyzer"); m_visModeGroup->addAction(tr("Scope"))->setData("Scope"); m_visModeGroup->addAction(tr("Off"))->setData("Off"); foreach(QAction *act, m_visModeGroup->actions ()) { act->setCheckable(true); visMode->addAction(act); } QMenu *analyzerMode = m_menu->addMenu(tr("Analyzer Mode")); m_analyzerModeGroup = new QActionGroup(this); m_analyzerTypeGroup = new QActionGroup(this); m_analyzerModeGroup->addAction(tr("Normal"))->setData(0); m_analyzerModeGroup->addAction(tr("Fire"))->setData(1); m_analyzerModeGroup->addAction(tr("Vertical Lines"))->setData(2); m_analyzerTypeGroup->addAction(tr("Lines"))->setData(0); m_analyzerTypeGroup->addAction(tr("Bars"))->setData(1); foreach(QAction *act, m_analyzerModeGroup->actions ()) { act->setCheckable(true); analyzerMode->addAction(act); } analyzerMode->addSeparator (); foreach(QAction *act, m_analyzerTypeGroup->actions ()) { act->setCheckable(true); analyzerMode->addAction(act); } analyzerMode->addSeparator (); m_peaksAction = analyzerMode->addAction(tr("Peaks")); m_peaksAction->setCheckable(true); QMenu *refreshRate = m_menu->addMenu(tr("Refresh Rate")); m_fpsGroup = new QActionGroup(this); m_fpsGroup->setExclusive(true); m_fpsGroup->addAction(tr("50 fps"))->setData(50); m_fpsGroup->addAction(tr("25 fps"))->setData(25); m_fpsGroup->addAction(tr("10 fps"))->setData(10); m_fpsGroup->addAction(tr("5 fps"))->setData(5); foreach(QAction *act, m_fpsGroup->actions ()) { act->setCheckable(true); refreshRate->addAction(act); } QMenu *analyzerFalloff = m_menu->addMenu(tr("Analyzer Falloff")); m_analyzerFalloffGroup = new QActionGroup(this); m_analyzerFalloffGroup->setExclusive(true); m_analyzerFalloffGroup->addAction(tr("Slowest"))->setData(1.2); m_analyzerFalloffGroup->addAction(tr("Slow"))->setData(1.8); m_analyzerFalloffGroup->addAction(tr("Medium"))->setData(2.2); m_analyzerFalloffGroup->addAction(tr("Fast"))->setData(2.4); m_analyzerFalloffGroup->addAction(tr("Fastest"))->setData(2.8); foreach(QAction *act, m_analyzerFalloffGroup->actions ()) { act->setCheckable(true); analyzerFalloff->addAction(act); } QMenu *peaksFalloff = m_menu->addMenu(tr("Peaks Falloff")); m_peaksFalloffGroup = new QActionGroup(this); m_peaksFalloffGroup->setExclusive(true); m_peaksFalloffGroup->addAction(tr("Slowest"))->setData(0.05); m_peaksFalloffGroup->addAction(tr("Slow"))->setData(0.1); m_peaksFalloffGroup->addAction(tr("Medium"))->setData(0.2); m_peaksFalloffGroup->addAction(tr("Fast"))->setData(0.4); m_peaksFalloffGroup->addAction(tr("Fastest"))->setData(0.8); foreach(QAction *act, m_peaksFalloffGroup->actions ()) { act->setCheckable(true #include "opusfile.h" #include "replaygainreader.h" #include "decoder_opus.h" #include "opusmetadatamodel.h" #include "decoderopusfactory.h" // DecoderOpusFactory bool DecoderOpusFactory::supports(const QString &source) const { return source.right(5).toLower() == ".opus"; } bool DecoderOpusFactory::canDecode(QIODevice *input) const { char buf[36]; if (input->peek(buf, 36) == 36 && !memcmp(buf, "OggS", 4) && !memcmp(buf + 28, "OpusHead", 8)) return true; return false; } const DecoderProperties DecoderOpusFactory::properties() const { DecoderProperties properties; properties.name = tr("Opus Plugin"); properties.shortName = "opus"; properties.filters << "*.opus"; properties.description = tr("Ogg Opus Files"); properties.contentTypes << "audio/opus"; properties.hasAbout = true; properties.hasSettings = false; properties.noInput = false; return properties; } Decoder *DecoderOpusFactory::create(const QString &url, QIODevice *input) { Decoder *d = new DecoderOpus(url, input); if(!url.contains("://")) //local file { ReplayGainReader rg(url); d->setReplayGainInfo(rg.replayGainInfo()); } return d; } MetaDataModel* DecoderOpusFactory::createMetaDataModel(const QString &path, QObject *parent) { return new OpusMetaDataModel(path, parent); } QList<FileInfo *> DecoderOpusFactory::createPlayList(const QString &fileName, bool useMetaData, QStringList *) { FileInfo *info = new FileInfo(fileName); TagLib::Ogg::Opus::File fileRef(fileName.toLocal8Bit().constData()); TagLib::Ogg::XiphComment *tag = useMetaData ? fileRef.tag() : 0; if (tag && !tag