diff --git a/src/analyzers/analyzerbase.cpp b/src/analyzers/analyzerbase.cpp index 5346694a1..71c0b7ff0 100644 --- a/src/analyzers/analyzerbase.cpp +++ b/src/analyzers/analyzerbase.cpp @@ -2,7 +2,7 @@ Copyright 2003, Max Howell Copyright 2009, 2011-2012, David Sansome Copyright 2010, 2012, 2014, John Maguire - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof Sobiecki Clementine is free software: you can redistribute it and/or modify @@ -33,6 +33,7 @@ #include #include "engines/enginebase.h" +#include "core/arraysize.h" // INSTRUCTIONS Base2D // 1. do anything that depends on height() in init(), Base2D will call it before @@ -45,7 +46,8 @@ // TODO(David Sansome): make an INSTRUCTIONS file // can't mod scope in analyze you have to use transform -// TODO(John Maguire): for 2D use setErasePixmap Qt function insetead of m_background +// TODO(John Maguire): for 2D use setErasePixmap Qt function insetead of +// m_background // make the linker happy only for gcc < 4.0 #if !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 0)) && \ @@ -53,20 +55,29 @@ template class Analyzer::Base; #endif +static const int sBarkBands[] = { + 100, 200, 300, 400, 510, 630, 770, 920, 1080, 1270, 1480, 1720, + 2000, 2320, 2700, 3150, 3700, 4400, 5300, 6400, 7700, 9500, 12000, 15500}; + +static const int sBarkBandCount = arraysize(sBarkBands); + Analyzer::Base::Base(QWidget* parent, uint scopeSize) : QWidget(parent), - m_timeout(40) // msec + timeout_(40) // msec , - m_fht(new FHT(scopeSize)), - m_engine(nullptr), - m_lastScope(512), - current_chunk_(0), + fht_(new FHT(scopeSize)), + engine_(nullptr), + lastScope_(512), new_frame_(false), - is_playing_(false) {} + is_playing_(false), + barkband_table_(QList()), + prev_color_index_(0), + bands_(0), + psychedelic_enabled_(false) {} -void Analyzer::Base::hideEvent(QHideEvent*) { m_timer.stop(); } +void Analyzer::Base::hideEvent(QHideEvent*) { timer_.stop(); } -void Analyzer::Base::showEvent(QShowEvent*) { m_timer.start(timeout(), this); } +void Analyzer::Base::showEvent(QShowEvent*) { timer_.start(timeout(), this); } void Analyzer::Base::transform(Scope& scope) { // this is a standard transformation that should give @@ -74,16 +85,16 @@ void Analyzer::Base::transform(Scope& scope) { // NOTE resizing here is redundant as FHT routines only calculate FHT::size() // values - // scope.resize( m_fht->size() ); + // scope.resize( fht_->size() ); float* front = static_cast(&scope.front()); - float* f = new float[m_fht->size()]; - m_fht->copy(&f[0], front); - m_fht->logSpectrum(front, &f[0]); - m_fht->scale(front, 1.0 / 20); + float* f = new float[fht_->size()]; + fht_->copy(&f[0], front); + fht_->logSpectrum(front, &f[0]); + fht_->scale(front, 1.0 / 20); - scope.resize(m_fht->size() / 2); // second half of values are rubbish + scope.resize(fht_->size() / 2); // second half of values are rubbish delete[] f; } @@ -91,30 +102,30 @@ void Analyzer::Base::paintEvent(QPaintEvent* e) { QPainter p(this); p.fillRect(e->rect(), palette().color(QPalette::Window)); - switch (m_engine->state()) { + switch (engine_->state()) { case Engine::Playing: { - const Engine::Scope& thescope = m_engine->scope(m_timeout); + const Engine::Scope& thescope = engine_->scope(timeout_); int i = 0; // convert to mono here - our built in analyzers need mono, but the // engines provide interleaved pcm - for (uint x = 0; static_cast(x) < m_fht->size(); ++x) { - m_lastScope[x] = - static_cast(thescope[i] + thescope[i + 1]) / (2 * (1 << 15)); + for (uint x = 0; static_cast(x) < fht_->size(); ++x) { + lastScope_[x] = static_cast(thescope[i] + thescope[i + 1]) / + (2 * (1 << 15)); i += 2; } is_playing_ = true; - transform(m_lastScope); - analyze(p, m_lastScope, new_frame_); + transform(lastScope_); + analyze(p, lastScope_, new_frame_); - // scope.resize( m_fht->size() ); + // scope.resize( fht_->size() ); break; } case Engine::Paused: is_playing_ = false; - analyze(p, m_lastScope, new_frame_); + analyze(p, lastScope_, new_frame_); break; default: @@ -131,9 +142,9 @@ int Analyzer::Base::resizeExponent(int exp) { else if (exp > 9) exp = 9; - if (exp != m_fht->sizeExp()) { - delete m_fht; - m_fht = new FHT(exp); + if (exp != fht_->sizeExp()) { + delete fht_; + fht_ = new FHT(exp); } return exp; } @@ -154,7 +165,7 @@ int Analyzer::Base::resizeForBands(int bands) { exp = 9; resizeExponent(exp); - return m_fht->size() / 2; + return fht_->size() / 2; } void Analyzer::Base::demo(QPainter& p) { @@ -175,6 +186,67 @@ void Analyzer::Base::demo(QPainter& p) { ++t; } +void Analyzer::Base::psychedelicModeChanged(bool enabled) { + psychedelic_enabled_ = enabled; +} + +int Analyzer::Base::BandFrequency(int band) const { + return ((kSampleRate / 2) * band + kSampleRate / 4) / bands_; +} + +void Analyzer::Base::updateBandSize(const int scopeSize) { + // prevent possible dbz in BandFrequency + if (scopeSize == 0) { + return; + } + + bands_ = scopeSize; + + barkband_table_.clear(); + barkband_table_.reserve(bands_ + 1); + + int barkband = 0; + for (int i = 0; i < bands_ + 1; ++i) { + if (barkband < sBarkBandCount - 1 && + BandFrequency(i) >= sBarkBands[barkband]) { + barkband++; + } + + barkband_table_.append(barkband); + } +} + +QColor Analyzer::Base::getPsychedelicColor(const Scope& scope, + const int ampFactor, + const int bias) { + if (scope.size() > barkband_table_.length()) { + return palette().color(QPalette::Highlight); + } + + // Calculate total magnitudes for different bark bands. + double bands[sBarkBandCount]{}; + + for (int i = 0; i < barkband_table_.size(); ++i) { + bands[barkband_table_[i]] += scope[i]; + } + + // Now divide the bark bands into thirds and compute their total amplitudes. + double rgb[3]{}; + for (int i = 0; i < sBarkBandCount - 1; ++i) { + rgb[(i * 3) / sBarkBandCount] += bands[i] * bands[i]; + } + + for (int i = 0; i < 3; ++i) { + // bias colours for a threshold around normally amplified audio + rgb[i] = (int)((sqrt(rgb[i]) * ampFactor) + bias); + if (rgb[i] > 255) { + rgb[i] = 255; + } + } + + return QColor::fromRgb(rgb[0], rgb[1], rgb[2]); +} + void Analyzer::Base::polishEvent() { init(); // virtual } @@ -211,7 +283,7 @@ void Analyzer::initSin(Scope& v, const uint size) { void Analyzer::Base::timerEvent(QTimerEvent* e) { QWidget::timerEvent(e); - if (e->timerId() != m_timer.timerId()) return; + if (e->timerId() != timer_.timerId()) return; new_frame_ = true; update(); diff --git a/src/analyzers/analyzerbase.h b/src/analyzers/analyzerbase.h index 503fc4604..73895caee 100644 --- a/src/analyzers/analyzerbase.h +++ b/src/analyzers/analyzerbase.h @@ -3,7 +3,7 @@ Copyright 2009-2010, David Sansome Copyright 2010, 2014, John Maguire Copyright 2011, Arnaud Bienner - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof Sobiecki Clementine is free software: you can redistribute it and/or modify @@ -58,21 +58,22 @@ class Base : public QWidget { Q_OBJECT public: - ~Base() { delete m_fht; } + ~Base() { delete fht_; } - uint timeout() const { return m_timeout; } + uint timeout() const { return timeout_; } - void set_engine(EngineBase* engine) { m_engine = engine; } + void set_engine(EngineBase* engine) { engine_ = engine; } void changeTimeout(uint newTimeout) { - m_timeout = newTimeout; - if (m_timer.isActive()) { - m_timer.stop(); - m_timer.start(m_timeout, this); + timeout_ = newTimeout; + if (timer_.isActive()) { + timer_.stop(); + timer_.start(timeout_, this); } } virtual void framerateChanged() {} + virtual void psychedelicModeChanged(bool); protected: explicit Base(QWidget*, uint scopeSize = 7); @@ -86,21 +87,32 @@ class Base : public QWidget { int resizeExponent(int); int resizeForBands(int); + int BandFrequency(int) const; + void updateBandSize(const int); + QColor getPsychedelicColor(const Scope&, const int, const int); virtual void init() {} virtual void transform(Scope&); virtual void analyze(QPainter& p, const Scope&, bool new_frame) = 0; virtual void demo(QPainter& p); protected: - QBasicTimer m_timer; - uint m_timeout; - FHT* m_fht; - EngineBase* m_engine; - Scope m_lastScope; - int current_chunk_; + static const int kSampleRate = + 44100; // we shouldn't need to care about ultrasonics + + QBasicTimer timer_; + uint timeout_; + FHT* fht_; + EngineBase* engine_; + Scope lastScope_; bool new_frame_; bool is_playing_; + + QList barkband_table_; + double prev_colors_[10][3]; + int prev_color_index_; + int bands_; + bool psychedelic_enabled_; }; void interpolate(const Scope&, Scope&); diff --git a/src/analyzers/analyzercontainer.cpp b/src/analyzers/analyzercontainer.cpp index 03037740a..676dd3cb7 100644 --- a/src/analyzers/analyzercontainer.cpp +++ b/src/analyzers/analyzercontainer.cpp @@ -3,7 +3,7 @@ Copyright 2010, 2014, John Maguire Copyright 2011-2012, Arnaud Bienner Copyright 2013, Vasily Fomin - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof Sobiecki Clementine is free software: you can redistribute it and/or modify @@ -57,6 +57,7 @@ AnalyzerContainer::AnalyzerContainer(QWidget* parent) visualisation_action_(nullptr), double_click_timer_(new QTimer(this)), ignore_next_click_(false), + psychedelic_colors_on_(false), current_analyzer_(nullptr), engine_(nullptr) { QHBoxLayout* layout = new QHBoxLayout(this); @@ -88,6 +89,11 @@ AnalyzerContainer::AnalyzerContainer(QWidget* parent) disable_action_->setCheckable(true); group_->addAction(disable_action_); + context_menu_->addSeparator(); + psychedelic_enable_ = context_menu_->addAction( + tr("Use Psychedelic Colors"), this, SLOT(TogglePsychedelicColors())); + psychedelic_enable_->setCheckable(true); + context_menu_->addSeparator(); // Visualisation action gets added in SetActions @@ -145,6 +151,12 @@ void AnalyzerContainer::DisableAnalyzer() { Save(); } +void AnalyzerContainer::TogglePsychedelicColors() { + psychedelic_colors_on_ ^= true; + current_analyzer_->psychedelicModeChanged(psychedelic_colors_on_); + SavePsychedelic(); +} + void AnalyzerContainer::ChangeAnalyzer(int id) { QObject* instance = analyzer_types_[id]->newInstance(Q_ARG(QWidget*, this)); @@ -161,6 +173,7 @@ void AnalyzerContainer::ChangeAnalyzer(int id) { current_framerate_ = current_framerate_ == 0 ? kMediumFramerate : current_framerate_; current_analyzer_->changeTimeout(1000 / current_framerate_); + current_analyzer_->psychedelicModeChanged(psychedelic_colors_on_); layout()->addWidget(current_analyzer_); @@ -183,6 +196,10 @@ void AnalyzerContainer::Load() { QSettings s; s.beginGroup(kSettingsGroup); + // Colours + psychedelic_colors_on_ = s.value("psychedelic", false).toBool(); + psychedelic_enable_->setChecked(psychedelic_colors_on_); + // Analyzer QString type = s.value("type", "BlockAnalyzer").toString(); if (type.isEmpty()) { @@ -227,6 +244,13 @@ void AnalyzerContainer::Save() { : QVariant()); } +void AnalyzerContainer::SavePsychedelic() { + QSettings s; + s.beginGroup(kSettingsGroup); + + s.setValue("psychedelic", psychedelic_colors_on_); +} + void AnalyzerContainer::AddFramerate(const QString& name, int framerate) { QAction* action = context_menu_framerate_->addAction(name, mapper_framerate_, SLOT(map())); diff --git a/src/analyzers/analyzercontainer.h b/src/analyzers/analyzercontainer.h index 46f0e942e..1a91c6d3d 100644 --- a/src/analyzers/analyzercontainer.h +++ b/src/analyzers/analyzercontainer.h @@ -4,6 +4,7 @@ Copyright 2011-2012, Arnaud Bienner Copyright 2013, Vasily Fomin Copyright 2014, Krzysztof Sobiecki + Copyright 2015, Mark Furneaux Clementine is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -40,7 +41,7 @@ class AnalyzerContainer : public QWidget { static const char* kSettingsGroup; static const char* kSettingsFramerate; - signals: +signals: void WheelEvent(int delta); protected: @@ -53,6 +54,7 @@ class AnalyzerContainer : public QWidget { void ChangeFramerate(int new_framerate); void DisableAnalyzer(); void ShowPopupMenu(); + void TogglePsychedelicColors(); private: static const int kLowFramerate; @@ -63,6 +65,7 @@ class AnalyzerContainer : public QWidget { void Load(); void Save(); void SaveFramerate(int framerate); + void SavePsychedelic(); template void AddAnalyzerType(); void AddFramerate(const QString& name, int framerate); @@ -80,11 +83,13 @@ class AnalyzerContainer : public QWidget { QList framerate_list_; QList actions_; QAction* disable_action_; + QAction* psychedelic_enable_; QAction* visualisation_action_; QTimer* double_click_timer_; QPoint last_click_pos_; bool ignore_next_click_; + bool psychedelic_colors_on_; Analyzer::Base* current_analyzer_; EngineBase* engine_; diff --git a/src/analyzers/baranalyzer.cpp b/src/analyzers/baranalyzer.cpp index effa439be..3992227c9 100644 --- a/src/analyzers/baranalyzer.cpp +++ b/src/analyzers/baranalyzer.cpp @@ -2,7 +2,7 @@ Copyright 2003, Mark Kretschmann Copyright 2009-2010, David Sansome Copyright 2014, Alibek Omarov - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof Sobiecki Copyright 2014, John Maguire @@ -23,7 +23,6 @@ /* Original Author: Mark Kretschmann 2003 */ - #include "baranalyzer.h" #include #include @@ -36,19 +35,20 @@ const char* BarAnalyzer::kName = BarAnalyzer::BarAnalyzer(QWidget* parent) : Analyzer::Base(parent, 8) { // roof pixmaps don't depend on size() so we do in the ctor - m_bg = parent->palette().color(QPalette::Background); + bg_ = parent->palette().color(QPalette::Background); QColor fg(parent->palette().color(QPalette::Highlight).lighter(150)); - double dr = static_cast(m_bg.red() - fg.red()) / - (NUM_ROOFS - 1); // -1 because we start loop below at 0 - double dg = static_cast(m_bg.green() - fg.green()) / (NUM_ROOFS - 1); - double db = static_cast(m_bg.blue() - fg.blue()) / (NUM_ROOFS - 1); + double dr = static_cast(bg_.red() - fg.red()) / + (kNumRoofs - 1); // -1 because we start loop below at 0 + double dg = static_cast(bg_.green() - fg.green()) / (kNumRoofs - 1); + double db = static_cast(bg_.blue() - fg.blue()) / (kNumRoofs - 1); - for (uint i = 0; i < NUM_ROOFS; ++i) { - m_pixRoof[i] = QPixmap(COLUMN_WIDTH, 1); - m_pixRoof[i].fill(QColor(fg.red() + static_cast(dr * i), fg.green() + static_cast(dg * i), - fg.blue() + static_cast(db * i))); + for (uint i = 0; i < kNumRoofs; ++i) { + pixRoof_[i] = QPixmap(kColumnWidth, 1); + pixRoof_[i].fill(QColor(fg.red() + static_cast(dr * i), + fg.green() + static_cast(dg * i), + fg.blue() + static_cast(db * i))); } } @@ -58,46 +58,66 @@ void BarAnalyzer::resizeEvent(QResizeEvent* e) { init(); } void BarAnalyzer::init() { const double MAX_AMPLITUDE = 1.0; - const double F = static_cast(height() - 2) / (log10(255) * MAX_AMPLITUDE); + const double F = + static_cast(height() - 2) / (log10(255) * MAX_AMPLITUDE); - BAND_COUNT = width() / 5; - MAX_DOWN = static_cast(0 - (qMax(1, height() / 50))); - MAX_UP = static_cast(qMax(1, height() / 25)); + band_count_ = width() / 5; + max_down_ = static_cast(0 - (qMax(1, height() / 50))); + max_up_ = static_cast(qMax(1, height() / 25)); - barVector.resize(BAND_COUNT, 0); - roofVector.resize(BAND_COUNT, height() - 5); - roofVelocityVector.resize(BAND_COUNT, ROOF_VELOCITY_REDUCTION_FACTOR); - m_roofMem.resize(BAND_COUNT); - m_scope.resize(BAND_COUNT); + barVector_.resize(band_count_, 0); + roofVector_.resize(band_count_, height() - 5); + roofVelocityVector_.resize(band_count_, kRoofVelocityReductionFactor); + roofMem_.resize(band_count_); + scope_.resize(band_count_); // generate a list of values that express amplitudes in range 0-MAX_AMP as // ints from 0-height() on log scale for (uint x = 0; x < 256; ++x) { - m_lvlMapper[x] = static_cast(F * log10(x + 1)); + lvlMapper_[x] = static_cast(F * log10(x + 1)); } - m_pixBarGradient = QPixmap(height() * COLUMN_WIDTH, height()); - m_pixCompose = QPixmap(size()); + pixBarGradient_ = QPixmap(height() * kColumnWidth, height()); + pixCompose_ = QPixmap(size()); canvas_ = QPixmap(size()); canvas_.fill(palette().color(QPalette::Background)); - QPainter p(&m_pixBarGradient); - QColor rgb(palette().color(QPalette::Highlight)); + updateBandSize(band_count_); + colorChanged(); + setMinimumSize(QSize(band_count_ * kColumnWidth, 10)); +} - for (int x = 0, r = rgb.red(), g = rgb.green(), b = rgb.blue(), r2 = 255 - r; x < height(); - ++x) { +void BarAnalyzer::colorChanged() { + if (pixBarGradient_.isNull()) { + return; + } + + QPainter p(&pixBarGradient_); + QColor rgb; + if (psychedelic_enabled_) { + rgb = getPsychedelicColor(scope_, 50, 100); + } else { + rgb = palette().color(QPalette::Highlight); + } + + for (int x = 0, r = rgb.red(), g = rgb.green(), b = rgb.blue(), r2 = 255 - r; + x < height(); ++x) { for (int y = x; y > 0; --y) { const double fraction = static_cast(y) / height(); // p.setPen( QColor( r + (int)(r2 * fraction), g, b - (int)(255 * // fraction) ) ); p.setPen(QColor(r + static_cast(r2 * fraction), g, b)); - p.drawLine(x * COLUMN_WIDTH, height() - y, (x + 1) * COLUMN_WIDTH, + p.drawLine(x * kColumnWidth, height() - y, (x + 1) * kColumnWidth, height() - y); } } +} - setMinimumSize(QSize(BAND_COUNT * COLUMN_WIDTH, 10)); +void BarAnalyzer::psychedelicModeChanged(bool enabled) { + psychedelic_enabled_ = enabled; + // reset colours back to normal + colorChanged(); } void BarAnalyzer::analyze(QPainter& p, const Scope& s, bool new_frame) { @@ -107,20 +127,25 @@ void BarAnalyzer::analyze(QPainter& p, const Scope& s, bool new_frame) { } // Analyzer::interpolate( s, m_bands ); - Scope& v = m_scope; - Analyzer::interpolate(s, v); + Analyzer::interpolate(s, scope_); QPainter canvas_painter(&canvas_); + // update the graphics with the new colour + if (psychedelic_enabled_) { + colorChanged(); + } + canvas_.fill(palette().color(QPalette::Background)); - for (uint i = 0, x = 0, y2; i < v.size(); ++i, x += COLUMN_WIDTH + 1) { + for (uint i = 0, x = 0, y2; i < scope_.size(); ++i, x += kColumnWidth + 1) { // assign pre[log10]'d value - y2 = static_cast(v[i] * - 256); // 256 will be optimised to a bitshift //no, it's a float - y2 = m_lvlMapper[(y2 > 255) ? 255 : y2]; // lvlMapper is array of ints with - // values 0 to height() + y2 = static_cast( + scope_[i] * + 256); // 256 will be optimised to a bitshift //no, it's a float + y2 = lvlMapper_[(y2 > 255) ? 255 : y2]; // lvlMapper is array of ints with + // values 0 to height() - int change = y2 - barVector[i]; + int change = y2 - barVector_[i]; // using the best of Markey's, piggz and Max's ideas on the way to shift the // bars @@ -129,54 +154,52 @@ void BarAnalyzer::analyze(QPainter& p, const Scope& s, bool new_frame) { // 2. shift large upwards with a bias towards last value // 3. fall downwards at a constant pace - /*if ( change > MAX_UP ) //anything too much greater than 2 gives "jitter" + /*if ( change > max_up_ ) //anything too much greater than 2 gives "jitter" //add some dynamics - makes the value slightly closer to what it was last time - y2 = ( barVector[i] + MAX_UP ); - //y2 = ( barVector[i] * 2 + y2 ) / 3; + y2 = ( barVector_[i] + max_up_ ); + //y2 = ( barVector_[i] * 2 + y2 ) / 3; else*/ if (change < - MAX_DOWN) - y2 = barVector[i] + MAX_DOWN; + max_down_) + y2 = barVector_[i] + max_down_; - if (static_cast(y2) > roofVector[i]) { - roofVector[i] = static_cast(y2); - roofVelocityVector[i] = 1; + if (static_cast(y2) > roofVector_[i]) { + roofVector_[i] = static_cast(y2); + roofVelocityVector_[i] = 1; } // remember where we are - barVector[i] = y2; + barVector_[i] = y2; - if (m_roofMem[i].size() > NUM_ROOFS) - m_roofMem[i].erase(m_roofMem[i].begin()); + if (roofMem_[i].size() > kNumRoofs) roofMem_[i].erase(roofMem_[i].begin()); // blt last n roofs, a.k.a motion blur - for (uint c = 0; c < m_roofMem[i].size(); ++c) - // bitBlt( m_pComposePixmap, x, m_roofMem[i]->at( c ), m_roofPixmaps[ c ] + for (uint c = 0; c < roofMem_[i].size(); ++c) + // bitBlt( m_pComposePixmap, x, roofMem_[i]->at( c ), m_roofPixmaps[ c ] // ); - // bitBlt( canvas(), x, m_roofMem[i][c], &m_pixRoof[ NUM_ROOFS - 1 - c ] + // bitBlt( canvas(), x, roofMem_[i][c], &pixRoof_[ kNumRoofs - 1 - c ] // ); - canvas_painter.drawPixmap(x, m_roofMem[i][c], - m_pixRoof[NUM_ROOFS - 1 - c]); + canvas_painter.drawPixmap(x, roofMem_[i][c], pixRoof_[kNumRoofs - 1 - c]); // blt the bar - canvas_painter.drawPixmap(x, height() - y2, *gradient(), y2 * COLUMN_WIDTH, - height() - y2, COLUMN_WIDTH, y2); + canvas_painter.drawPixmap(x, height() - y2, *gradient(), y2 * kColumnWidth, + height() - y2, kColumnWidth, y2); /*bitBlt( canvas(), x, height() - y2, - gradient(), y2 * COLUMN_WIDTH, height() - y2, COLUMN_WIDTH, y2, + gradient(), y2 * kColumnWidth, height() - y2, kColumnWidth, y2, Qt::CopyROP );*/ - m_roofMem[i].push_back(height() - roofVector[i] - 2); + roofMem_[i].push_back(height() - roofVector_[i] - 2); // set roof parameters for the NEXT draw - if (roofVelocityVector[i] != 0) { - if (roofVelocityVector[i] > 32) // no reason to do == 32 - roofVector[i] -= - (roofVelocityVector[i] - 32) / 20; // trivial calculation + if (roofVelocityVector_[i] != 0) { + if (roofVelocityVector_[i] > 32) // no reason to do == 32 + roofVector_[i] -= + (roofVelocityVector_[i] - 32) / 20; // trivial calculation - if (roofVector[i] < 0) { - roofVector[i] = 0; // not strictly necessary - roofVelocityVector[i] = 0; + if (roofVector_[i] < 0) { + roofVector_[i] = 0; // not strictly necessary + roofVelocityVector_[i] = 0; } else { - ++roofVelocityVector[i]; + ++roofVelocityVector_[i]; } } } diff --git a/src/analyzers/baranalyzer.h b/src/analyzers/baranalyzer.h index c3e0411af..37159a47e 100644 --- a/src/analyzers/baranalyzer.h +++ b/src/analyzers/baranalyzer.h @@ -2,7 +2,7 @@ Copyright 2003-2005, Max Howell Copyright 2005, Mark Kretschmann Copyright 2009-2010, David Sansome - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof A. Sobiecki Copyright 2014, John Maguire @@ -39,44 +39,45 @@ class BarAnalyzer : public Analyzer::Base { void init(); virtual void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame); - // virtual void transform( Scope& ); + virtual void psychedelicModeChanged(bool); /** * Resizes the widget to a new geometry according to @p e * @param e The resize-event */ void resizeEvent(QResizeEvent* e); + void colorChanged(); - uint BAND_COUNT; - int MAX_DOWN; - int MAX_UP; - static const uint ROOF_HOLD_TIME = 48; - static const int ROOF_VELOCITY_REDUCTION_FACTOR = 32; - static const uint NUM_ROOFS = 16; - static const uint COLUMN_WIDTH = 4; + uint band_count_; + int max_down_; + int max_up_; + static const uint kRoofHoldTime = 48; + static const int kRoofVelocityReductionFactor = 32; + static const uint kNumRoofs = 16; + static const uint kColumnWidth = 4; static const char* kName; protected: - QPixmap m_pixRoof[NUM_ROOFS]; - // vector m_roofMem[BAND_COUNT]; + QPixmap pixRoof_[kNumRoofs]; + // vector roofMem_[band_count_]; // Scope m_bands; //copy of the Scope to prevent creating/destroying a Scope // every iteration - uint m_lvlMapper[256]; - std::vector m_roofMem; - std::vector barVector; // positions of bars - std::vector roofVector; // positions of roofs - std::vector roofVelocityVector; // speed that roofs falls + uint lvlMapper_[256]; + std::vector roofMem_; + std::vector barVector_; // positions of bars + std::vector roofVector_; // positions of roofs + std::vector roofVelocityVector_; // speed that roofs falls - const QPixmap* gradient() const { return &m_pixBarGradient; } + const QPixmap* gradient() const { return &pixBarGradient_; } private: - QPixmap m_pixBarGradient; - QPixmap m_pixCompose; + QPixmap pixBarGradient_; + QPixmap pixCompose_; QPixmap canvas_; - Analyzer::Scope m_scope; // so we don't create a vector every frame - QColor m_bg; + Analyzer::Scope scope_; // so we don't create a vector every frame + QColor bg_; }; #endif // ANALYZERS_BARANALYZER_H_ diff --git a/src/analyzers/blockanalyzer.cpp b/src/analyzers/blockanalyzer.cpp index bb6807a63..e31e81d1a 100644 --- a/src/analyzers/blockanalyzer.cpp +++ b/src/analyzers/blockanalyzer.cpp @@ -3,7 +3,7 @@ Copyright 2005, Mark Kretschmann Copyright 2009-2010, David Sansome Copyright 2010, 2014, John Maguire - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof Sobiecki Clementine is free software: you can redistribute it and/or modify @@ -33,35 +33,34 @@ #include #include -const uint BlockAnalyzer::HEIGHT = 2; -const uint BlockAnalyzer::WIDTH = 4; -const uint BlockAnalyzer::MIN_ROWS = 3; // arbituary -const uint BlockAnalyzer::MIN_COLUMNS = 32; // arbituary -const uint BlockAnalyzer::MAX_COLUMNS = 256; // must be 2**n -const uint BlockAnalyzer::FADE_SIZE = 90; +const uint BlockAnalyzer::kHeight = 2; +const uint BlockAnalyzer::kWidth = 4; +const uint BlockAnalyzer::kMinRows = 3; // arbituary +const uint BlockAnalyzer::kMinColumns = 32; // arbituary +const uint BlockAnalyzer::kMaxColumns = 256; // must be 2**n +const uint BlockAnalyzer::kFadeSize = 90; const char* BlockAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer"); BlockAnalyzer::BlockAnalyzer(QWidget* parent) : Analyzer::Base(parent, 9), - m_columns(0), - m_rows(0), - m_y(0), - m_barPixmap(1, 1), - m_topBarPixmap(WIDTH, HEIGHT), - m_scope(MIN_COLUMNS), - m_store(1 << 8, 0), - m_fade_bars(FADE_SIZE), - m_fade_pos(1 << 8, 50), - m_fade_intensity(1 << 8, 32) { - setMinimumSize(MIN_COLUMNS * (WIDTH + 1) - 1, - MIN_ROWS * (HEIGHT + 1) - 1); + columns_(0), + rows_(0), + y_(0), + barPixmap_(1, 1), + topBarPixmap_(kWidth, kHeight), + scope_(kMinColumns), + store_(1 << 8, 0), + fade_bars_(kFadeSize), + fade_pos_(1 << 8, 50), + fade_intensity_(1 << 8, 32) { + setMinimumSize(kMinColumns * (kWidth + 1) - 1, kMinRows * (kHeight + 1) - 1); // -1 is padding, no drawing takes place there - setMaximumWidth(MAX_COLUMNS * (WIDTH + 1) - 1); + setMaximumWidth(kMaxColumns * (kWidth + 1) - 1); // mxcl says null pixmaps cause crashes, so let's play it safe - for (uint i = 0; i < FADE_SIZE; ++i) m_fade_bars[i] = QPixmap(1, 1); + for (uint i = 0; i < kFadeSize; ++i) fade_bars_[i] = QPixmap(1, 1); } BlockAnalyzer::~BlockAnalyzer() {} @@ -69,41 +68,44 @@ BlockAnalyzer::~BlockAnalyzer() {} void BlockAnalyzer::resizeEvent(QResizeEvent* e) { QWidget::resizeEvent(e); - m_background = QPixmap(size()); + background_ = QPixmap(size()); canvas_ = QPixmap(size()); - const uint oldRows = m_rows; + const uint oldRows = rows_; // all is explained in analyze().. // +1 to counter -1 in maxSizes, trust me we need this! - m_columns = qMin(static_cast(static_cast(width() + 1) / (WIDTH + 1)) + 1, MAX_COLUMNS); - m_rows = static_cast(static_cast(height() + 1) / (HEIGHT + 1)); + columns_ = qMin( + static_cast(static_cast(width() + 1) / (kWidth + 1)) + 1, + kMaxColumns); + rows_ = static_cast(static_cast(height() + 1) / (kHeight + 1)); // this is the y-offset for drawing from the top of the widget - m_y = (height() - (m_rows * (HEIGHT + 1)) + 2) / 2; + y_ = (height() - (rows_ * (kHeight + 1)) + 2) / 2; - m_scope.resize(m_columns); + scope_.resize(columns_); - if (m_rows != oldRows) { - m_barPixmap = QPixmap(WIDTH, m_rows * (HEIGHT + 1)); + if (rows_ != oldRows) { + barPixmap_ = QPixmap(kWidth, rows_ * (kHeight + 1)); - for (uint i = 0; i < FADE_SIZE; ++i) - m_fade_bars[i] = QPixmap(WIDTH, m_rows * (HEIGHT + 1)); + for (uint i = 0; i < kFadeSize; ++i) + fade_bars_[i] = QPixmap(kWidth, rows_ * (kHeight + 1)); - m_yscale.resize(m_rows + 1); + yscale_.resize(rows_ + 1); const uint PRE = 1, PRO = 1; // PRE and PRO allow us to restrict the range somewhat - for (uint z = 0; z < m_rows; ++z) - m_yscale[z] = 1 - (log10(PRE + z) / log10(PRE + m_rows + PRO)); + for (uint z = 0; z < rows_; ++z) + yscale_[z] = 1 - (log10(PRE + z) / log10(PRE + rows_ + PRO)); - m_yscale[m_rows] = 0; + yscale_[rows_] = 0; determineStep(); paletteChange(palette()); } + updateBandSize(columns_); drawBackground(); } @@ -113,9 +115,9 @@ void BlockAnalyzer::determineStep() { // I calculated the value 30 based on some trial and error // the fall time of 30 is too slow on framerates above 50fps - const double fallTime = timeout() < 20 ? 20 * m_rows : 30 * m_rows; + const double fallTime = timeout() < 20 ? 20 * rows_ : 30 * rows_; - m_step = static_cast(m_rows * timeout()) / fallTime; + step_ = static_cast(rows_ * timeout()) / fallTime; } void BlockAnalyzer::framerateChanged() { // virtual @@ -127,15 +129,14 @@ void BlockAnalyzer::transform(Analyzer::Scope& s) { float* front = static_cast(&s.front()); - m_fht->spectrum(front); - m_fht->scale(front, 1.0 / 20); + fht_->spectrum(front); + fht_->scale(front, 1.0 / 20); // the second half is pretty dull, so only show it if the user has a large // analyzer - // by setting to m_scope.size() if large we prevent interpolation of large + // by setting to scope_.size() if large we prevent interpolation of large // analyzers, this is good! - s.resize(m_scope.size() <= MAX_COLUMNS / 2 ? MAX_COLUMNS / 2 - : m_scope.size()); + s.resize(scope_.size() <= kMaxColumns / 2 ? kMaxColumns / 2 : scope_.size()); } void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, @@ -150,7 +151,7 @@ void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, // y represents the number of blanks // y starts from the top and increases in units of blocks - // m_yscale looks similar to: { 0.7, 0.5, 0.25, 0.15, 0.1, 0 } + // yscale_ looks similar to: { 0.7, 0.5, 0.25, 0.15, 0.1, 0 } // if it contains 6 elements there are 5 rows in the analyzer if (!new_frame) { @@ -160,51 +161,55 @@ void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, QPainter canvas_painter(&canvas_); - Analyzer::interpolate(s, m_scope); + Analyzer::interpolate(s, scope_); + + // update the graphics with the new colour + if (psychedelic_enabled_) { + paletteChange(QPalette()); + } // Paint the background - canvas_painter.drawPixmap(0, 0, m_background); + canvas_painter.drawPixmap(0, 0, background_); - for (uint y, x = 0; x < m_scope.size(); ++x) { + for (uint y, x = 0; x < scope_.size(); ++x) { // determine y - for (y = 0; m_scope[x] < m_yscale[y]; ++y) - continue; + for (y = 0; scope_[x] < yscale_[y]; ++y) continue; // this is opposite to what you'd think, higher than y // means the bar is lower than y (physically) - if (static_cast(y) > m_store[x]) - y = static_cast(m_store[x] += m_step); + if (static_cast(y) > store_[x]) + y = static_cast(store_[x] += step_); else - m_store[x] = y; + store_[x] = y; - // if y is lower than m_fade_pos, then the bar has exceeded the height of + // if y is lower than fade_pos_, then the bar has exceeded the kHeight of // the fadeout // if the fadeout is quite faded now, then display the new one - if (y <= m_fade_pos[x] /*|| m_fade_intensity[x] < FADE_SIZE / 3*/) { - m_fade_pos[x] = y; - m_fade_intensity[x] = FADE_SIZE; + if (y <= fade_pos_[x] /*|| fade_intensity_[x] < kFadeSize / 3*/) { + fade_pos_[x] = y; + fade_intensity_[x] = kFadeSize; } - if (m_fade_intensity[x] > 0) { - const uint offset = --m_fade_intensity[x]; - const uint y = m_y + (m_fade_pos[x] * (HEIGHT + 1)); - canvas_painter.drawPixmap(x * (WIDTH + 1), y, m_fade_bars[offset], 0, 0, - WIDTH, height() - y); + if (fade_intensity_[x] > 0) { + const uint offset = --fade_intensity_[x]; + const uint y = y_ + (fade_pos_[x] * (kHeight + 1)); + canvas_painter.drawPixmap(x * (kWidth + 1), y, fade_bars_[offset], 0, 0, + kWidth, height() - y); } - if (m_fade_intensity[x] == 0) m_fade_pos[x] = m_rows; + if (fade_intensity_[x] == 0) fade_pos_[x] = rows_; - // REMEMBER: y is a number from 0 to m_rows, 0 means all blocks are glowing, - // m_rows means none are - canvas_painter.drawPixmap(x * (WIDTH + 1), y * (HEIGHT + 1) + m_y, *bar(), - 0, y * (HEIGHT + 1), bar()->width(), + // REMEMBER: y is a number from 0 to rows_, 0 means all blocks are glowing, + // rows_ means none are + canvas_painter.drawPixmap(x * (kWidth + 1), y * (kHeight + 1) + y_, *bar(), + 0, y * (kHeight + 1), bar()->width(), bar()->height()); } - for (uint x = 0; x < m_store.size(); ++x) - canvas_painter.drawPixmap(x * (WIDTH + 1), - static_cast(m_store[x]) * (HEIGHT + 1) + m_y, - m_topBarPixmap); + for (uint x = 0; x < store_.size(); ++x) + canvas_painter.drawPixmap(x * (kWidth + 1), + static_cast(store_[x]) * (kHeight + 1) + y_, + topBarPixmap_); p.drawPixmap(0, 0, canvas_); } @@ -232,6 +237,12 @@ static inline void adjustToLimits(int& b, int& f, uint& amount) { } } +void BlockAnalyzer::psychedelicModeChanged(bool enabled) { + psychedelic_enabled_ = enabled; + // reset colours back to normal + paletteChange(QPalette()); +} + /** * Clever contrast function * @@ -305,7 +316,8 @@ QColor ensureContrast(const QColor& bg, const QColor& fg, uint _amount = 150) { if (static_cast(_amount) > 0) adjustToLimits(bs, fs, _amount); // see if we need to adjust the hue - if (static_cast(_amount) > 0) fh += static_cast(_amount); // cycles around; + if (static_cast(_amount) > 0) + fh += static_cast(_amount); // cycles around; return QColor::fromHsv(fh, fs, fv); } @@ -327,23 +339,34 @@ QColor ensureContrast(const QColor& bg, const QColor& fg, uint _amount = 150) { void BlockAnalyzer::paletteChange(const QPalette&) { const QColor bg = palette().color(QPalette::Background); - const QColor fg = ensureContrast(bg, palette().color(QPalette::Highlight)); + QColor fg; - m_topBarPixmap.fill(fg); + if (psychedelic_enabled_) { + fg = getPsychedelicColor(scope_, 10, 75); + } else { + fg = ensureContrast(bg, palette().color(QPalette::Highlight)); + } - const double dr = 15 * static_cast(bg.red() - fg.red()) / (m_rows * 16); - const double dg = 15 * static_cast(bg.green() - fg.green()) / (m_rows * 16); - const double db = 15 * static_cast(bg.blue() - fg.blue()) / (m_rows * 16); + topBarPixmap_.fill(fg); + + const double dr = + 15 * static_cast(bg.red() - fg.red()) / (rows_ * 16); + const double dg = + 15 * static_cast(bg.green() - fg.green()) / (rows_ * 16); + const double db = + 15 * static_cast(bg.blue() - fg.blue()) / (rows_ * 16); const int r = fg.red(), g = fg.green(), b = fg.blue(); bar()->fill(bg); QPainter p(bar()); - for (int y = 0; static_cast(y) < m_rows; ++y) + + for (int y = 0; static_cast(y) < rows_; ++y) // graduate the fg color - p.fillRect(0, y * (HEIGHT + 1), WIDTH, HEIGHT, - QColor(r + static_cast(dr * y), g + static_cast(dg * y), - b + static_cast(db * y))); + p.fillRect( + 0, y * (kHeight + 1), kWidth, kHeight, + QColor(r + static_cast(dr * y), g + static_cast(dg * y), + b + static_cast(db * y))); { const QColor bg = palette().color(QPalette::Background).dark(112); @@ -360,13 +383,15 @@ void BlockAnalyzer::paletteChange(const QPalette&) { const int r = bg.red(), g = bg.green(), b = bg.blue(); // Precalculate all fade-bar pixmaps - for (uint y = 0; y < FADE_SIZE; ++y) { - m_fade_bars[y].fill(palette().color(QPalette::Background)); - QPainter f(&m_fade_bars[y]); - for (int z = 0; static_cast(z) < m_rows; ++z) { - const double Y = 1.0 - (log10(FADE_SIZE - y) / log10(FADE_SIZE)); - f.fillRect(0, z * (HEIGHT + 1), WIDTH, HEIGHT, - QColor(r + static_cast(dr * Y), g + static_cast(dg * Y), b + static_cast(db * Y))); + for (uint y = 0; y < kFadeSize; ++y) { + fade_bars_[y].fill(palette().color(QPalette::Background)); + QPainter f(&fade_bars_[y]); + for (int z = 0; static_cast(z) < rows_; ++z) { + const double Y = 1.0 - (log10(kFadeSize - y) / log10(kFadeSize)); + f.fillRect( + 0, z * (kHeight + 1), kWidth, kHeight, + QColor(r + static_cast(dr * Y), g + static_cast(dg * Y), + b + static_cast(db * Y))); } } } @@ -378,11 +403,16 @@ void BlockAnalyzer::drawBackground() { const QColor bg = palette().color(QPalette::Background); const QColor bgdark = bg.dark(112); - m_background.fill(bg); + background_.fill(bg); - QPainter p(&m_background); - for (int x = 0; (uint)x < m_columns; ++x) - for (int y = 0; (uint)y < m_rows; ++y) - p.fillRect(x * (WIDTH + 1), y * (HEIGHT + 1) + m_y, WIDTH, HEIGHT, + QPainter p(&background_); + + if (p.paintEngine() == 0) { + return; + } + + for (int x = 0; (uint)x < columns_; ++x) + for (int y = 0; (uint)y < rows_; ++y) + p.fillRect(x * (kWidth + 1), y * (kHeight + 1) + y_, kWidth, kHeight, bgdark); } diff --git a/src/analyzers/blockanalyzer.h b/src/analyzers/blockanalyzer.h index b055cb86d..04a9dcb38 100644 --- a/src/analyzers/blockanalyzer.h +++ b/src/analyzers/blockanalyzer.h @@ -2,7 +2,7 @@ Copyright 2003-2005, Max Howell Copyright 2009-2010, David Sansome Copyright 2010, 2014, John Maguire - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof A. Sobiecki Clementine is free software: you can redistribute it and/or modify @@ -39,12 +39,12 @@ class BlockAnalyzer : public Analyzer::Base { Q_INVOKABLE BlockAnalyzer(QWidget*); ~BlockAnalyzer(); - static const uint HEIGHT; - static const uint WIDTH; - static const uint MIN_ROWS; - static const uint MIN_COLUMNS; - static const uint MAX_COLUMNS; - static const uint FADE_SIZE; + static const uint kHeight; + static const uint kWidth; + static const uint kMinRows; + static const uint kMinColumns; + static const uint kMaxColumns; + static const uint kFadeSize; static const char* kName; @@ -54,29 +54,30 @@ class BlockAnalyzer : public Analyzer::Base { virtual void resizeEvent(QResizeEvent*); virtual void paletteChange(const QPalette&); virtual void framerateChanged(); + virtual void psychedelicModeChanged(bool); void drawBackground(); void determineStep(); private: - QPixmap* bar() { return &m_barPixmap; } + QPixmap* bar() { return &barPixmap_; } - uint m_columns, m_rows; // number of rows and columns of blocks - uint m_y; // y-offset from top of widget - QPixmap m_barPixmap; - QPixmap m_topBarPixmap; - QPixmap m_background; + uint columns_, rows_; // number of rows and columns of blocks + uint y_; // y-offset from top of widget + QPixmap barPixmap_; + QPixmap topBarPixmap_; + QPixmap background_; QPixmap canvas_; - Analyzer::Scope m_scope; // so we don't create a vector every frame - std::vector m_store; // current bar heights - std::vector m_yscale; + Analyzer::Scope scope_; // so we don't create a vector every frame + std::vector store_; // current bar kHeights + std::vector yscale_; // FIXME why can't I namespace these? c++ issue? - std::vector m_fade_bars; - std::vector m_fade_pos; - std::vector m_fade_intensity; + std::vector fade_bars_; + std::vector fade_pos_; + std::vector fade_intensity_; - float m_step; // rows to fall per frame + float step_; // rows to fall per frame }; #endif // ANALYZERS_BLOCKANALYZER_H_ diff --git a/src/analyzers/boomanalyzer.cpp b/src/analyzers/boomanalyzer.cpp index 94c8dfc86..93df2e48a 100644 --- a/src/analyzers/boomanalyzer.cpp +++ b/src/analyzers/boomanalyzer.cpp @@ -2,7 +2,7 @@ Copyright 2004, Max Howell Copyright 2009-2010, David Sansome Copyright 2010, 2014, John Maguire - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof Sobiecki Clementine is free software: you can redistribute it and/or modify @@ -28,69 +28,78 @@ using Analyzer::Scope; +const uint BoomAnalyzer::kColumnWidth = 4; +const uint BoomAnalyzer::kMaxBandCount = 256; +const uint BoomAnalyzer::kMinBandCount = 32; + const char* BoomAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Boom analyzer"); BoomAnalyzer::BoomAnalyzer(QWidget* parent) : Analyzer::Base(parent, 9), - K_barHeight(1.271) // 1.471 + bands_(0), + scope_(kMinBandCount), + fg_(palette().color(QPalette::Highlight)), + K_barHeight_(1.271) // 1.471 , - F_peakSpeed(1.103) // 1.122 + F_peakSpeed_(1.103) // 1.122 , - F(1.0), - bar_height(BAND_COUNT, 0), - peak_height(BAND_COUNT, 0), - peak_speed(BAND_COUNT, 0.01), - barPixmap(COLUMN_WIDTH, 50) {} + F_(1.0), + bar_height_(kMaxBandCount, 0), + peak_height_(kMaxBandCount, 0), + peak_speed_(kMaxBandCount, 0.01), + barPixmap_(kColumnWidth, 50) { + setMinimumWidth(kMinBandCount * (kColumnWidth + 1) - 1); + setMaximumWidth(kMaxBandCount * (kColumnWidth + 1) - 1); +} void BoomAnalyzer::changeK_barHeight(int newValue) { - K_barHeight = static_cast(newValue) / 1000; + K_barHeight_ = static_cast(newValue) / 1000; } void BoomAnalyzer::changeF_peakSpeed(int newValue) { - F_peakSpeed = static_cast(newValue) / 1000; + F_peakSpeed_ = static_cast(newValue) / 1000; } -void BoomAnalyzer::resizeEvent(QResizeEvent*) { init(); } +void BoomAnalyzer::resizeEvent(QResizeEvent* e) { + QWidget::resizeEvent(e); -void BoomAnalyzer::init() { const uint HEIGHT = height() - 2; const double h = 1.2 / HEIGHT; - F = static_cast(HEIGHT) / (log10(256) * 1.1 /*<- max. amplitude*/); + bands_ = qMin( + static_cast(static_cast(width() + 1) / (kColumnWidth + 1)) + + 1, + kMaxBandCount); + scope_.resize(bands_); - barPixmap = QPixmap(COLUMN_WIDTH - 2, HEIGHT); + F_ = static_cast(HEIGHT) / (log10(256) * 1.1 /*<- max. amplitude*/); + + barPixmap_ = QPixmap(kColumnWidth - 2, HEIGHT); canvas_ = QPixmap(size()); canvas_.fill(palette().color(QPalette::Background)); - QPainter p(&barPixmap); + QPainter p(&barPixmap_); for (uint y = 0; y < HEIGHT; ++y) { const double F = static_cast(y) * h; p.setPen(QColor(qMax(0, 255 - static_cast(229.0 * F)), qMax(0, 255 - static_cast(229.0 * F)), qMax(0, 255 - static_cast(191.0 * F)))); - p.drawLine(0, y, COLUMN_WIDTH - 2, y); + p.drawLine(0, y, kColumnWidth - 2, y); } + + updateBandSize(bands_); } void BoomAnalyzer::transform(Scope& s) { float* front = static_cast(&s.front()); - m_fht->spectrum(front); - m_fht->scale(front, 1.0 / 60); + fht_->spectrum(front); + fht_->scale(front, 1.0 / 50); - Scope scope(32, 0); - - const uint xscale[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 19, 24, 29, 36, - 43, 52, 63, 76, 91, 108, 129, 153, 182, 216, 255}; - - for (uint j, i = 0; i < 32; i++) - for (j = xscale[i]; j < xscale[i + 1]; j++) - if (s[j] > scope[i]) scope[i] = s[j]; - - s = scope; + s.resize(scope_.size() <= kMaxBandCount / 2 ? kMaxBandCount / 2 + : scope_.size()); } void BoomAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) { @@ -104,47 +113,70 @@ void BoomAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) { QPainter canvas_painter(&canvas_); canvas_.fill(palette().color(QPalette::Background)); - for (uint i = 0, x = 0, y; i < BAND_COUNT; ++i, x += COLUMN_WIDTH + 1) { - h = log10(scope[i] * 256.0) * F; + Analyzer::interpolate(scope, scope_); + + // update the graphics with the new colour + if (psychedelic_enabled_) { + paletteChange(QPalette()); + } + + for (uint i = 0, x = 0, y; i < bands_; ++i, x += kColumnWidth + 1) { + h = log10(scope_[i] * 256.0) * F_; if (h > MAX_HEIGHT) h = MAX_HEIGHT; - if (h > bar_height[i]) { - bar_height[i] = h; + if (h > bar_height_[i]) { + bar_height_[i] = h; - if (h > peak_height[i]) { - peak_height[i] = h; - peak_speed[i] = 0.01; + if (h > peak_height_[i]) { + peak_height_[i] = h; + peak_speed_[i] = 0.01; } else { goto peak_handling; } } else { - if (bar_height[i] > 0.0) { - bar_height[i] -= K_barHeight; // 1.4 - if (bar_height[i] < 0.0) bar_height[i] = 0.0; + if (bar_height_[i] > 0.0) { + bar_height_[i] -= K_barHeight_; // 1.4 + if (bar_height_[i] < 0.0) bar_height_[i] = 0.0; } peak_handling: - if (peak_height[i] > 0.0) { - peak_height[i] -= peak_speed[i]; - peak_speed[i] *= F_peakSpeed; // 1.12 + if (peak_height_[i] > 0.0) { + peak_height_[i] -= peak_speed_[i]; + peak_speed_[i] *= F_peakSpeed_; // 1.12 - if (peak_height[i] < bar_height[i]) peak_height[i] = bar_height[i]; - if (peak_height[i] < 0.0) peak_height[i] = 0.0; + if (peak_height_[i] < bar_height_[i]) peak_height_[i] = bar_height_[i]; + if (peak_height_[i] < 0.0) peak_height_[i] = 0.0; } } - y = height() - uint(bar_height[i]); - canvas_painter.drawPixmap(x + 1, y, barPixmap, 0, y, -1, -1); - canvas_painter.setPen(palette().color(QPalette::Highlight)); - if (bar_height[i] > 0) - canvas_painter.drawRect(x, y, COLUMN_WIDTH - 1, height() - y - 1); + y = height() - uint(bar_height_[i]); + canvas_painter.drawPixmap(x + 1, y, barPixmap_, 0, y, -1, -1); + canvas_painter.setPen(fg_); + if (bar_height_[i] > 0) + canvas_painter.drawRect(x, y, kColumnWidth - 1, height() - y - 1); - y = height() - uint(peak_height[i]); - canvas_painter.setPen(palette().color(QPalette::Base)); - canvas_painter.drawLine(x, y, x + COLUMN_WIDTH - 1, y); + y = height() - uint(peak_height_[i]); + canvas_painter.setPen(palette().color(QPalette::Midlight)); + canvas_painter.drawLine(x, y, x + kColumnWidth - 1, y); } p.drawPixmap(0, 0, canvas_); } + +void BoomAnalyzer::psychedelicModeChanged(bool enabled) { + psychedelic_enabled_ = enabled; + // reset colours back to normal + paletteChange(QPalette()); +} + +void BoomAnalyzer::paletteChange(const QPalette&) { + if (psychedelic_enabled_) { + fg_ = getPsychedelicColor(scope_, 50, 100); + } else { + // the highlight colour changes when the main window loses focus, + // so we use save and use the focused colour + fg_ = palette().color(QPalette::Highlight); + } +} diff --git a/src/analyzers/boomanalyzer.h b/src/analyzers/boomanalyzer.h index 5f087c339..d25a3abae 100644 --- a/src/analyzers/boomanalyzer.h +++ b/src/analyzers/boomanalyzer.h @@ -1,7 +1,7 @@ /* This file is part of Clementine. Copyright 2004, Max Howell Copyright 2009-2010, David Sansome - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof Sobiecki Copyright 2014, John Maguire @@ -27,10 +27,6 @@ #include "analyzerbase.h" -/** -@author Max Howell -*/ - class BoomAnalyzer : public Analyzer::Base { Q_OBJECT @@ -39,9 +35,9 @@ class BoomAnalyzer : public Analyzer::Base { static const char* kName; - virtual void init(); virtual void transform(Analyzer::Scope& s); virtual void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame); + virtual void psychedelicModeChanged(bool); public slots: void changeK_barHeight(int); @@ -49,17 +45,23 @@ class BoomAnalyzer : public Analyzer::Base { protected: void resizeEvent(QResizeEvent* e); + void paletteChange(const QPalette&); - static const uint COLUMN_WIDTH = 4; - static const uint BAND_COUNT = 32; + static const uint kColumnWidth; + static const uint kMaxBandCount; + static const uint kMinBandCount; - double K_barHeight, F_peakSpeed, F; + uint bands_; + Analyzer::Scope scope_; + QColor fg_; - std::vector bar_height; - std::vector peak_height; - std::vector peak_speed; + double K_barHeight_, F_peakSpeed_, F_; - QPixmap barPixmap; + std::vector bar_height_; + std::vector peak_height_; + std::vector peak_speed_; + + QPixmap barPixmap_; QPixmap canvas_; }; diff --git a/src/analyzers/fht.cpp b/src/analyzers/fht.cpp index 5ad262ad5..38e9b7c5a 100644 --- a/src/analyzers/fht.cpp +++ b/src/analyzers/fht.cpp @@ -24,70 +24,69 @@ #include #include "fht.h" -FHT::FHT(int n) : m_buf(0), m_tab(0), m_log(0) { +FHT::FHT(int n) : buf_(0), tab_(0), log_(0) { if (n < 3) { - m_num = 0; - m_exp2 = -1; + num_ = 0; + exp2_ = -1; return; } - m_exp2 = n; - m_num = 1 << n; + exp2_ = n; + num_ = 1 << n; if (n > 3) { - m_buf = new float[m_num]; - m_tab = new float[m_num * 2]; + buf_ = new float[num_]; + tab_ = new float[num_ * 2]; makeCasTable(); } } FHT::~FHT() { - delete[] m_buf; - delete[] m_tab; - delete[] m_log; + delete[] buf_; + delete[] tab_; + delete[] log_; } void FHT::makeCasTable(void) { float d, *costab, *sintab; - int ul, ndiv2 = m_num / 2; + int ul, ndiv2 = num_ / 2; - for (costab = m_tab, sintab = m_tab + m_num / 2 + 1, ul = 0; ul < m_num; - ul++) { + for (costab = tab_, sintab = tab_ + num_ / 2 + 1, ul = 0; ul < num_; ul++) { d = M_PI * ul / ndiv2; *costab = *sintab = cos(d); costab += 2, sintab += 2; - if (sintab > m_tab + m_num * 2) sintab = m_tab + 1; + if (sintab > tab_ + num_ * 2) sintab = tab_ + 1; } } float* FHT::copy(float* d, float* s) { - return static_cast(memcpy(d, s, m_num * sizeof(float))); + return static_cast(memcpy(d, s, num_ * sizeof(float))); } float* FHT::clear(float* d) { - return static_cast(memset(d, 0, m_num * sizeof(float))); + return static_cast(memset(d, 0, num_ * sizeof(float))); } void FHT::scale(float* p, float d) { - for (int i = 0; i < (m_num / 2); i++) *p++ *= d; + for (int i = 0; i < (num_ / 2); i++) *p++ *= d; } void FHT::ewma(float* d, float* s, float w) { - for (int i = 0; i < (m_num / 2); i++, d++, s++) *d = *d * w + *s * (1 - w); + for (int i = 0; i < (num_ / 2); i++, d++, s++) *d = *d * w + *s * (1 - w); } void FHT::logSpectrum(float* out, float* p) { - int n = m_num / 2, i, j, k, *r; - if (!m_log) { - m_log = new int[n]; + int n = num_ / 2, i, j, k, *r; + if (!log_) { + log_ = new int[n]; float f = n / log10(static_cast(n)); - for (i = 0, r = m_log; i < n; i++, r++) { + for (i = 0, r = log_; i < n; i++, r++) { j = static_cast(rint(log10(i + 1.0) * f)); *r = j >= n ? n - 1 : j; } } semiLogSpectrum(p); *out++ = *p = *p / 100; - for (k = i = 1, r = m_log; i < n; i++) { + for (k = i = 1, r = log_; i < n; i++) { j = *r++; if (i == j) { *out++ = p[i]; @@ -102,7 +101,7 @@ void FHT::logSpectrum(float* out, float* p) { void FHT::semiLogSpectrum(float* p) { float e; power2(p); - for (int i = 0; i < (m_num / 2); i++, p++) { + for (int i = 0; i < (num_ / 2); i++, p++) { e = 10.0 * log10(sqrt(*p * .5)); *p = e < 0 ? 0 : e; } @@ -110,31 +109,31 @@ void FHT::semiLogSpectrum(float* p) { void FHT::spectrum(float* p) { power2(p); - for (int i = 0; i < (m_num / 2); i++, p++) + for (int i = 0; i < (num_ / 2); i++, p++) *p = static_cast(sqrt(*p * .5)); } void FHT::power(float* p) { power2(p); - for (int i = 0; i < (m_num / 2); i++) *p++ *= .5; + for (int i = 0; i < (num_ / 2); i++) *p++ *= .5; } void FHT::power2(float* p) { int i; float* q; - _transform(p, m_num, 0); + _transform(p, num_, 0); *p = (*p * *p), *p += *p, p++; - for (i = 1, q = p + m_num - 2; i < (m_num / 2); i++, --q) + for (i = 1, q = p + num_ - 2; i < (num_ / 2); i++, --q) *p = (*p * *p) + (*q * *q), p++; } void FHT::transform(float* p) { - if (m_num == 8) + if (num_ == 8) transform8(p); else - _transform(p, m_num, 0); + _transform(p, num_, 0); } void FHT::transform8(float* p) { @@ -173,19 +172,19 @@ void FHT::_transform(float* p, int n, int k) { int i, j, ndiv2 = n / 2; float a, *t1, *t2, *t3, *t4, *ptab, *pp; - for (i = 0, t1 = m_buf, t2 = m_buf + ndiv2, pp = &p[k]; i < ndiv2; i++) + for (i = 0, t1 = buf_, t2 = buf_ + ndiv2, pp = &p[k]; i < ndiv2; i++) *t1++ = *pp++, *t2++ = *pp++; - memcpy(p + k, m_buf, sizeof(float) * n); + memcpy(p + k, buf_, sizeof(float) * n); _transform(p, ndiv2, k); _transform(p, ndiv2, k + ndiv2); - j = m_num / ndiv2 - 1; - t1 = m_buf; + j = num_ / ndiv2 - 1; + t1 = buf_; t2 = t1 + ndiv2; t3 = p + k + ndiv2; - ptab = m_tab; + ptab = tab_; pp = p + k; a = *ptab++ * *t3++; @@ -202,5 +201,5 @@ void FHT::_transform(float* p, int n, int k) { *t1++ = *pp + a; *t2++ = *pp++ - a; } - memcpy(p + k, m_buf, sizeof(float) * n); + memcpy(p + k, buf_, sizeof(float) * n); } diff --git a/src/analyzers/fht.h b/src/analyzers/fht.h index 77703b04f..6e37fee2c 100644 --- a/src/analyzers/fht.h +++ b/src/analyzers/fht.h @@ -32,11 +32,11 @@ * [1] Computer in Physics, Vol. 9, No. 4, Jul/Aug 1995 pp 373-379 */ class FHT { - int m_exp2; - int m_num; - float* m_buf; - float* m_tab; - int* m_log; + int exp2_; + int num_; + float* buf_; + float* tab_; + int* log_; /** * Create a table of "cas" (cosine and sine) values. @@ -59,8 +59,8 @@ class FHT { explicit FHT(int); ~FHT(); - inline int sizeExp() const { return m_exp2; } - inline int size() const { return m_num; } + inline int sizeExp() const { return exp2_; } + inline int size() const { return num_; } float* copy(float*, float*); float* clear(float*); void scale(float*, float); diff --git a/src/analyzers/nyancatanalyzer.cpp b/src/analyzers/nyancatanalyzer.cpp index 890d55f44..2424f5635 100644 --- a/src/analyzers/nyancatanalyzer.cpp +++ b/src/analyzers/nyancatanalyzer.cpp @@ -57,7 +57,7 @@ NyanCatAnalyzer::NyanCatAnalyzer(QWidget* parent) } } -void NyanCatAnalyzer::transform(Scope& s) { m_fht->spectrum(&s.front()); } +void NyanCatAnalyzer::transform(Scope& s) { fht_->spectrum(&s.front()); } void NyanCatAnalyzer::timerEvent(QTimerEvent* e) { if (e->timerId() == timer_id_) { @@ -74,7 +74,8 @@ void NyanCatAnalyzer::resizeEvent(QResizeEvent* e) { buffer_[1] = QPixmap(); available_rainbow_width_ = width() - kCatWidth + kRainbowOverlap; - px_per_frame_ = static_cast(available_rainbow_width_) / (kHistorySize - 1) + 1; + px_per_frame_ = + static_cast(available_rainbow_width_) / (kHistorySize - 1) + 1; x_offset_ = px_per_frame_ * (kHistorySize - 1) - available_rainbow_width_; } @@ -112,11 +113,13 @@ void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, QPointF* dest = polyline; float* source = history_; - const float top_of_cat = static_cast(height()) / 2 - static_cast(kCatHeight) / 2; + const float top_of_cat = + static_cast(height()) / 2 - static_cast(kCatHeight) / 2; for (int band = 0; band < kRainbowBands; ++band) { // Calculate the Y position of this band. const float y = - static_cast(kCatHeight) / (kRainbowBands + 1) * (band + 0.5) + top_of_cat; + static_cast(kCatHeight) / (kRainbowBands + 1) * (band + 0.5) + + top_of_cat; // Add each point in the line. for (int x = 0; x < kHistorySize; ++x) { diff --git a/src/analyzers/rainbowdashanalyzer.cpp b/src/analyzers/rainbowdashanalyzer.cpp index 29c968cc4..c7182163d 100644 --- a/src/analyzers/rainbowdashanalyzer.cpp +++ b/src/analyzers/rainbowdashanalyzer.cpp @@ -1,6 +1,6 @@ /* This file is part of Clementine. Copyright 2014, Alibek Omarov - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof Sobiecki Copyright 2014, David Sansome @@ -57,7 +57,7 @@ RainbowDashAnalyzer::RainbowDashAnalyzer(QWidget* parent) } } -void RainbowDashAnalyzer::transform(Scope& s) { m_fht->spectrum(&s.front()); } +void RainbowDashAnalyzer::transform(Scope& s) { fht_->spectrum(&s.front()); } void RainbowDashAnalyzer::timerEvent(QTimerEvent* e) { if (e->timerId() == timer_id_) { @@ -74,7 +74,8 @@ void RainbowDashAnalyzer::resizeEvent(QResizeEvent* e) { buffer_[1] = QPixmap(); available_rainbow_width_ = width() - kDashWidth + kRainbowOverlap; - px_per_frame_ = static_cast(available_rainbow_width_) / (kHistorySize - 1) + 1; + px_per_frame_ = + static_cast(available_rainbow_width_) / (kHistorySize - 1) + 1; x_offset_ = px_per_frame_ * (kHistorySize - 1) - available_rainbow_width_; } @@ -111,12 +112,13 @@ void RainbowDashAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s, QPointF* dest = polyline; float* source = history_; - const float top_of_Dash = static_cast(height()) / 2 - static_cast(kRainbowHeight) / 2; + const float top_of_Dash = static_cast(height()) / 2 - + static_cast(kRainbowHeight) / 2; for (int band = 0; band < kRainbowBands; ++band) { // Calculate the Y position of this band. - const float y = - static_cast(kRainbowHeight) / (kRainbowBands + 1) * (band + 0.5) + - top_of_Dash; + const float y = static_cast(kRainbowHeight) / (kRainbowBands + 1) * + (band + 0.5) + + top_of_Dash; // Add each point in the line. for (int x = 0; x < kHistorySize; ++x) { diff --git a/src/analyzers/rainbowdashanalyzer.h b/src/analyzers/rainbowdashanalyzer.h index b5a73b8cf..d8d97c11c 100644 --- a/src/analyzers/rainbowdashanalyzer.h +++ b/src/analyzers/rainbowdashanalyzer.h @@ -1,6 +1,6 @@ /* This file is part of Clementine. Copyright 2014, Alibek Omarov - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof Sobiecki Clementine is free software: you can redistribute it and/or modify diff --git a/src/analyzers/sonogram.cpp b/src/analyzers/sonogram.cpp index 879414586..ae2068069 100644 --- a/src/analyzers/sonogram.cpp +++ b/src/analyzers/sonogram.cpp @@ -2,7 +2,7 @@ Copyright 2004, Melchior FRANZ Copyright 2009-2010, David Sansome Copyright 2010, 2014, John Maguire - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof Sobiecki Clementine is free software: you can redistribute it and/or modify @@ -31,7 +31,8 @@ using Analyzer::Scope; const char* Sonogram::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Sonogram"); -Sonogram::Sonogram(QWidget* parent) : Analyzer::Base(parent, 9) {} +Sonogram::Sonogram(QWidget* parent) + : Analyzer::Base(parent, 9), scope_size_(128) {} Sonogram::~Sonogram() {} @@ -45,6 +46,12 @@ void Sonogram::resizeEvent(QResizeEvent* e) { canvas_ = QPixmap(size()); canvas_.fill(palette().color(QPalette::Background)); + updateBandSize(scope_size_); +} + +void Sonogram::psychedelicModeChanged(bool enabled) { + psychedelic_enabled_ = enabled; + updateBandSize(scope_size_); } void Sonogram::analyze(QPainter& p, const Scope& s, bool new_frame) { @@ -60,20 +67,45 @@ void Sonogram::analyze(QPainter& p, const Scope& s, bool new_frame) { canvas_painter.drawPixmap(0, 0, canvas_, 1, 0, x, -1); Scope::const_iterator it = s.begin(), end = s.end(); - for (int y = height() - 1; y;) { - if (it >= end || *it < .005) - c = palette().color(QPalette::Background); - else if (*it < .05) - c.setHsv(95, 255, 255 - static_cast(*it * 4000.0)); - else if (*it < 1.0) - c.setHsv(95 - static_cast(*it * 90.0), 255, 255); - else - c = Qt::red; + if (scope_size_ != s.size()) { + scope_size_ = s.size(); + updateBandSize(scope_size_); + } - canvas_painter.setPen(c); - canvas_painter.drawPoint(x, y--); + if (psychedelic_enabled_) { + c = getPsychedelicColor(s, 20, 100); + for (int y = height() - 1; y;) { + if (it >= end || *it < .005) { + c = palette().color(QPalette::Background); + } else if (*it < .05) { + c.setHsv(c.hue(), c.saturation(), 255 - static_cast(*it * 4000.0)); + } else if (*it < 1.0) { + c.setHsv((c.hue() + static_cast(*it * 90.0)) % 255, 255, 255); + } else { + c = getPsychedelicColor(s, 10, 50); + } - if (it < end) ++it; + canvas_painter.setPen(c); + canvas_painter.drawPoint(x, y--); + + if (it < end) ++it; + } + } else { + for (int y = height() - 1; y;) { + if (it >= end || *it < .005) + c = palette().color(QPalette::Background); + else if (*it < .05) + c.setHsv(95, 255, 255 - static_cast(*it * 4000.0)); + else if (*it < 1.0) + c.setHsv(95 - static_cast(*it * 90.0), 255, 255); + else + c = Qt::red; + + canvas_painter.setPen(c); + canvas_painter.drawPoint(x, y--); + + if (it < end) ++it; + } } canvas_painter.end(); @@ -83,11 +115,11 @@ void Sonogram::analyze(QPainter& p, const Scope& s, bool new_frame) { void Sonogram::transform(Scope& scope) { float* front = static_cast(&scope.front()); - m_fht->power2(front); - m_fht->scale(front, 1.0 / 256); - scope.resize(m_fht->size() / 2); + fht_->power2(front); + fht_->scale(front, 1.0 / 256); + scope.resize(fht_->size() / 2); } void Sonogram::demo(QPainter& p) { - analyze(p, Scope(m_fht->size(), 0), new_frame_); + analyze(p, Scope(fht_->size(), 0), new_frame_); } diff --git a/src/analyzers/sonogram.h b/src/analyzers/sonogram.h index 73fe9307d..7588c5264 100644 --- a/src/analyzers/sonogram.h +++ b/src/analyzers/sonogram.h @@ -3,6 +3,7 @@ Copyright 2009-2010, David Sansome Copyright 2014, Krzysztof Sobiecki Copyright 2014, John Maguire + Copyright 2015, Mark Furneaux Clementine is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,10 +27,6 @@ #include "analyzerbase.h" -/** -@author Melchior FRANZ -*/ - class Sonogram : public Analyzer::Base { Q_OBJECT public: @@ -43,8 +40,10 @@ class Sonogram : public Analyzer::Base { void transform(Analyzer::Scope&); void demo(QPainter& p); void resizeEvent(QResizeEvent*); + void psychedelicModeChanged(bool); QPixmap canvas_; + int scope_size_; }; #endif // ANALYZERS_SONOGRAM_H_ diff --git a/src/analyzers/turbine.cpp b/src/analyzers/turbine.cpp index 7d409a5d9..0572bc270 100644 --- a/src/analyzers/turbine.cpp +++ b/src/analyzers/turbine.cpp @@ -2,7 +2,7 @@ Copyright 2003, Stanislav Karchebny Copyright 2003, Max Howell Copyright 2009-2010, David Sansome - Copyright 2014, Mark Furneaux + Copyright 2014-2015, Mark Furneaux Copyright 2014, Krzysztof Sobiecki Copyright 2014, John Maguire @@ -21,7 +21,7 @@ */ /* Original Author: Stanislav Karchebny 2003 - * Original Author: Max Howell 2003 + * Original Author: Max Howell 2003 */ #include @@ -42,58 +42,64 @@ void TurbineAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) { float h; const uint hd2 = height() / 2; - const uint MAX_HEIGHT = hd2 - 1; + const uint kMaxHeight = hd2 - 1; QPainter canvas_painter(&canvas_); canvas_.fill(palette().color(QPalette::Background)); - for (uint i = 0, x = 0, y; i < BAND_COUNT; ++i, x += COLUMN_WIDTH + 1) { - h = log10(scope[i] * 256.0) * F * 0.5; + Analyzer::interpolate(scope, scope_); - if (h > MAX_HEIGHT) h = MAX_HEIGHT; + // update the graphics with the new colour + if (psychedelic_enabled_) { + paletteChange(QPalette()); + } - if (h > bar_height[i]) { - bar_height[i] = h; + for (uint i = 0, x = 0, y; i < bands_; ++i, x += kColumnWidth + 1) { + h = log10(scope_[i] * 256.0) * F_ * 0.5; - if (h > peak_height[i]) { - peak_height[i] = h; - peak_speed[i] = 0.01; + if (h > kMaxHeight) h = kMaxHeight; + + if (h > bar_height_[i]) { + bar_height_[i] = h; + + if (h > peak_height_[i]) { + peak_height_[i] = h; + peak_speed_[i] = 0.01; } else { goto peak_handling; } } else { - if (bar_height[i] > 0.0) { - bar_height[i] -= K_barHeight; // 1.4 - if (bar_height[i] < 0.0) bar_height[i] = 0.0; + if (bar_height_[i] > 0.0) { + bar_height_[i] -= K_barHeight_; // 1.4 + if (bar_height_[i] < 0.0) bar_height_[i] = 0.0; } peak_handling: - if (peak_height[i] > 0.0) { - peak_height[i] -= peak_speed[i]; - peak_speed[i] *= F_peakSpeed; // 1.12 + if (peak_height_[i] > 0.0) { + peak_height_[i] -= peak_speed_[i]; + peak_speed_[i] *= F_peakSpeed_; // 1.12 - if (peak_height[i] < bar_height[i]) peak_height[i] = bar_height[i]; - if (peak_height[i] < 0.0) peak_height[i] = 0.0; + if (peak_height_[i] < bar_height_[i]) peak_height_[i] = bar_height_[i]; + if (peak_height_[i] < 0.0) peak_height_[i] = 0.0; } } - y = hd2 - static_cast(bar_height[i]); - canvas_painter.drawPixmap(x + 1, y, barPixmap, 0, y, -1, -1); - canvas_painter.drawPixmap(x + 1, hd2, barPixmap, 0, - static_cast(bar_height[i]), - -1, -1); + y = hd2 - static_cast(bar_height_[i]); + canvas_painter.drawPixmap(x + 1, y, barPixmap_, 0, y, -1, -1); + canvas_painter.drawPixmap(x + 1, hd2, barPixmap_, 0, + static_cast(bar_height_[i]), -1, -1); - canvas_painter.setPen(palette().color(QPalette::Highlight)); - if (bar_height[i] > 0) - canvas_painter.drawRect(x, y, COLUMN_WIDTH - 1, - static_cast(bar_height[i]) * 2 - 1); + canvas_painter.setPen(fg_); + if (bar_height_[i] > 0) + canvas_painter.drawRect(x, y, kColumnWidth - 1, + static_cast(bar_height_[i]) * 2 - 1); - const uint x2 = x + COLUMN_WIDTH - 1; - canvas_painter.setPen(palette().color(QPalette::Base)); - y = hd2 - uint(peak_height[i]); + const uint x2 = x + kColumnWidth - 1; + canvas_painter.setPen(palette().color(QPalette::Midlight)); + y = hd2 - uint(peak_height_[i]); canvas_painter.drawLine(x, y, x2, y); - y = hd2 + uint(peak_height[i]); + y = hd2 + uint(peak_height_[i]); canvas_painter.drawLine(x, y, x2, y); }