Add "Psychedelic Colour" mode to all analyzers
(Well, except Nyanalyzer and Rainbow dash because they are already colourful enough.) I have added functionality for any 2D analyzer to change any part of its colour palatte with the frequency content of the music, in the same way that Moodbars do. I find this gives the analyzer a sort of "third dimention". This is built into Analyzer::Base, so all analyzers can use it and override it as they please. I have thus added support for Block, Boom, Turbine, Sonogram, and Bar, however Boom and Block seem to look the best in my opinion. This is of course all optional and is toggled by a checkbox in the context menu for the analyzer, disabled by default. I have not been able to measure any increase in CPU activity with this enabled, even at 60fps.
This commit is contained in:
parent
73ae416534
commit
c102bf7fe6
|
@ -2,7 +2,7 @@
|
|||
Copyright 2003, Max Howell <max.howell@methylblue.com>
|
||||
Copyright 2009, 2011-2012, David Sansome <me@davidsansome.com>
|
||||
Copyright 2010, 2012, 2014, John Maguire <john.maguire@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
|
||||
Clementine is free software: you can redistribute it and/or modify
|
||||
|
@ -33,6 +33,7 @@
|
|||
#include <QtDebug>
|
||||
|
||||
#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<QWidget>;
|
||||
#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<uint>()),
|
||||
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<float*>(&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<int>(x) < m_fht->size(); ++x) {
|
||||
m_lastScope[x] =
|
||||
static_cast<double>(thescope[i] + thescope[i + 1]) / (2 * (1 << 15));
|
||||
for (uint x = 0; static_cast<int>(x) < fht_->size(); ++x) {
|
||||
lastScope_[x] = static_cast<double>(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();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||
Copyright 2011, Arnaud Bienner <arnaud.bienner@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
|
||||
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<uint> barkband_table_;
|
||||
double prev_colors_[10][3];
|
||||
int prev_color_index_;
|
||||
int bands_;
|
||||
bool psychedelic_enabled_;
|
||||
};
|
||||
|
||||
void interpolate(const Scope&, Scope&);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||
Copyright 2011-2012, Arnaud Bienner <arnaud.bienner@gmail.com>
|
||||
Copyright 2013, Vasily Fomin <vasili.fomin@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
|
||||
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()));
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
Copyright 2011-2012, Arnaud Bienner <arnaud.bienner@gmail.com>
|
||||
Copyright 2013, Vasily Fomin <vasili.fomin@gmail.com>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
Copyright 2015, Mark Furneaux <mark@furneaux.ca>
|
||||
|
||||
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 <typename T>
|
||||
void AddAnalyzerType();
|
||||
void AddFramerate(const QString& name, int framerate);
|
||||
|
@ -80,11 +83,13 @@ class AnalyzerContainer : public QWidget {
|
|||
QList<int> framerate_list_;
|
||||
QList<QAction*> 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_;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Copyright 2003, Mark Kretschmann <markey@web.de>
|
||||
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||
Copyright 2014, Alibek Omarov <a1ba.omarov@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
Copyright 2014, John Maguire <john.maguire@gmail.com>
|
||||
|
||||
|
@ -23,7 +23,6 @@
|
|||
/* Original Author: Mark Kretschmann <markey@web.de> 2003
|
||||
*/
|
||||
|
||||
|
||||
#include "baranalyzer.h"
|
||||
#include <cmath>
|
||||
#include <QtDebug>
|
||||
|
@ -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<double>(m_bg.red() - fg.red()) /
|
||||
(NUM_ROOFS - 1); // -1 because we start loop below at 0
|
||||
double dg = static_cast<double>(m_bg.green() - fg.green()) / (NUM_ROOFS - 1);
|
||||
double db = static_cast<double>(m_bg.blue() - fg.blue()) / (NUM_ROOFS - 1);
|
||||
double dr = static_cast<double>(bg_.red() - fg.red()) /
|
||||
(kNumRoofs - 1); // -1 because we start loop below at 0
|
||||
double dg = static_cast<double>(bg_.green() - fg.green()) / (kNumRoofs - 1);
|
||||
double db = static_cast<double>(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<int>(dr * i), fg.green() + static_cast<int>(dg * i),
|
||||
fg.blue() + static_cast<int>(db * i)));
|
||||
for (uint i = 0; i < kNumRoofs; ++i) {
|
||||
pixRoof_[i] = QPixmap(kColumnWidth, 1);
|
||||
pixRoof_[i].fill(QColor(fg.red() + static_cast<int>(dr * i),
|
||||
fg.green() + static_cast<int>(dg * i),
|
||||
fg.blue() + static_cast<int>(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<double>(height() - 2) / (log10(255) * MAX_AMPLITUDE);
|
||||
const double F =
|
||||
static_cast<double>(height() - 2) / (log10(255) * MAX_AMPLITUDE);
|
||||
|
||||
BAND_COUNT = width() / 5;
|
||||
MAX_DOWN = static_cast<int>(0 - (qMax(1, height() / 50)));
|
||||
MAX_UP = static_cast<int>(qMax(1, height() / 25));
|
||||
band_count_ = width() / 5;
|
||||
max_down_ = static_cast<int>(0 - (qMax(1, height() / 50)));
|
||||
max_up_ = static_cast<int>(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<uint>(F * log10(x + 1));
|
||||
lvlMapper_[x] = static_cast<uint>(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<double>(y) / height();
|
||||
|
||||
// p.setPen( QColor( r + (int)(r2 * fraction), g, b - (int)(255 *
|
||||
// fraction) ) );
|
||||
p.setPen(QColor(r + static_cast<int>(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<uint>(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<uint>(
|
||||
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<int>(y2) > roofVector[i]) {
|
||||
roofVector[i] = static_cast<int>(y2);
|
||||
roofVelocityVector[i] = 1;
|
||||
if (static_cast<int>(y2) > roofVector_[i]) {
|
||||
roofVector_[i] = static_cast<int>(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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Copyright 2003-2005, Max Howell <max.howell@methylblue.com>
|
||||
Copyright 2005, Mark Kretschmann <markey@web.de>
|
||||
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof A. Sobiecki <sobkas@gmail.com>
|
||||
Copyright 2014, John Maguire <john.maguire@gmail.com>
|
||||
|
||||
|
@ -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<uint> m_roofMem[BAND_COUNT];
|
||||
QPixmap pixRoof_[kNumRoofs];
|
||||
// vector<uint> roofMem_[band_count_];
|
||||
|
||||
// Scope m_bands; //copy of the Scope to prevent creating/destroying a Scope
|
||||
// every iteration
|
||||
uint m_lvlMapper[256];
|
||||
std::vector<aroofMemVec> m_roofMem;
|
||||
std::vector<uint> barVector; // positions of bars
|
||||
std::vector<int> roofVector; // positions of roofs
|
||||
std::vector<uint> roofVelocityVector; // speed that roofs falls
|
||||
uint lvlMapper_[256];
|
||||
std::vector<aroofMemVec> roofMem_;
|
||||
std::vector<uint> barVector_; // positions of bars
|
||||
std::vector<int> roofVector_; // positions of roofs
|
||||
std::vector<uint> 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_
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
Copyright 2005, Mark Kretschmann <markey@web.de>
|
||||
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
|
||||
Clementine is free software: you can redistribute it and/or modify
|
||||
|
@ -33,35 +33,34 @@
|
|||
#include <cstdlib>
|
||||
#include <QPainter>
|
||||
|
||||
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<uint>(static_cast<double>(width() + 1) / (WIDTH + 1)) + 1, MAX_COLUMNS);
|
||||
m_rows = static_cast<uint>(static_cast<double>(height() + 1) / (HEIGHT + 1));
|
||||
columns_ = qMin(
|
||||
static_cast<uint>(static_cast<double>(width() + 1) / (kWidth + 1)) + 1,
|
||||
kMaxColumns);
|
||||
rows_ = static_cast<uint>(static_cast<double>(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<double>(m_rows * timeout()) / fallTime;
|
||||
step_ = static_cast<double>(rows_ * timeout()) / fallTime;
|
||||
}
|
||||
|
||||
void BlockAnalyzer::framerateChanged() { // virtual
|
||||
|
@ -127,15 +129,14 @@ void BlockAnalyzer::transform(Analyzer::Scope& s) {
|
|||
|
||||
float* front = static_cast<float*>(&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<float>(y) > m_store[x])
|
||||
y = static_cast<int>(m_store[x] += m_step);
|
||||
if (static_cast<float>(y) > store_[x])
|
||||
y = static_cast<int>(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<int>(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<int>(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<int>(_amount) > 0) adjustToLimits(bs, fs, _amount);
|
||||
|
||||
// see if we need to adjust the hue
|
||||
if (static_cast<int>(_amount) > 0) fh += static_cast<int>(_amount); // cycles around;
|
||||
if (static_cast<int>(_amount) > 0)
|
||||
fh += static_cast<int>(_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<double>(bg.red() - fg.red()) / (m_rows * 16);
|
||||
const double dg = 15 * static_cast<double>(bg.green() - fg.green()) / (m_rows * 16);
|
||||
const double db = 15 * static_cast<double>(bg.blue() - fg.blue()) / (m_rows * 16);
|
||||
topBarPixmap_.fill(fg);
|
||||
|
||||
const double dr =
|
||||
15 * static_cast<double>(bg.red() - fg.red()) / (rows_ * 16);
|
||||
const double dg =
|
||||
15 * static_cast<double>(bg.green() - fg.green()) / (rows_ * 16);
|
||||
const double db =
|
||||
15 * static_cast<double>(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<uint>(y) < m_rows; ++y)
|
||||
|
||||
for (int y = 0; static_cast<uint>(y) < rows_; ++y)
|
||||
// graduate the fg color
|
||||
p.fillRect(0, y * (HEIGHT + 1), WIDTH, HEIGHT,
|
||||
QColor(r + static_cast<int>(dr * y), g + static_cast<int>(dg * y),
|
||||
b + static_cast<int>(db * y)));
|
||||
p.fillRect(
|
||||
0, y * (kHeight + 1), kWidth, kHeight,
|
||||
QColor(r + static_cast<int>(dr * y), g + static_cast<int>(dg * y),
|
||||
b + static_cast<int>(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<uint>(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<int>(dr * Y), g + static_cast<int>(dg * Y), b + static_cast<int>(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<uint>(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<int>(dr * Y), g + static_cast<int>(dg * Y),
|
||||
b + static_cast<int>(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);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Copyright 2003-2005, Max Howell <max.howell@methylblue.com>
|
||||
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof A. Sobiecki <sobkas@gmail.com>
|
||||
|
||||
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<float> m_store; // current bar heights
|
||||
std::vector<float> m_yscale;
|
||||
Analyzer::Scope scope_; // so we don't create a vector every frame
|
||||
std::vector<float> store_; // current bar kHeights
|
||||
std::vector<float> yscale_;
|
||||
|
||||
// FIXME why can't I namespace these? c++ issue?
|
||||
std::vector<QPixmap> m_fade_bars;
|
||||
std::vector<uint> m_fade_pos;
|
||||
std::vector<int> m_fade_intensity;
|
||||
std::vector<QPixmap> fade_bars_;
|
||||
std::vector<uint> fade_pos_;
|
||||
std::vector<int> fade_intensity_;
|
||||
|
||||
float m_step; // rows to fall per frame
|
||||
float step_; // rows to fall per frame
|
||||
};
|
||||
|
||||
#endif // ANALYZERS_BLOCKANALYZER_H_
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Copyright 2004, Max Howell <max.howell@methylblue.com>
|
||||
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
|
||||
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<double>(newValue) / 1000;
|
||||
K_barHeight_ = static_cast<double>(newValue) / 1000;
|
||||
}
|
||||
|
||||
void BoomAnalyzer::changeF_peakSpeed(int newValue) {
|
||||
F_peakSpeed = static_cast<double>(newValue) / 1000;
|
||||
F_peakSpeed_ = static_cast<double>(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<double>(HEIGHT) / (log10(256) * 1.1 /*<- max. amplitude*/);
|
||||
bands_ = qMin(
|
||||
static_cast<uint>(static_cast<double>(width() + 1) / (kColumnWidth + 1)) +
|
||||
1,
|
||||
kMaxBandCount);
|
||||
scope_.resize(bands_);
|
||||
|
||||
barPixmap = QPixmap(COLUMN_WIDTH - 2, HEIGHT);
|
||||
F_ = static_cast<double>(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<double>(y) * h;
|
||||
|
||||
p.setPen(QColor(qMax(0, 255 - static_cast<int>(229.0 * F)),
|
||||
qMax(0, 255 - static_cast<int>(229.0 * F)),
|
||||
qMax(0, 255 - static_cast<int>(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<float*>(&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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* This file is part of Clementine.
|
||||
Copyright 2004, Max Howell <max.howell@methylblue.com>
|
||||
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
Copyright 2014, John Maguire <john.maguire@gmail.com>
|
||||
|
||||
|
@ -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<float> bar_height;
|
||||
std::vector<float> peak_height;
|
||||
std::vector<float> peak_speed;
|
||||
double K_barHeight_, F_peakSpeed_, F_;
|
||||
|
||||
QPixmap barPixmap;
|
||||
std::vector<float> bar_height_;
|
||||
std::vector<float> peak_height_;
|
||||
std::vector<float> peak_speed_;
|
||||
|
||||
QPixmap barPixmap_;
|
||||
QPixmap canvas_;
|
||||
};
|
||||
|
||||
|
|
|
@ -24,70 +24,69 @@
|
|||
#include <string.h>
|
||||
#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<float*>(memcpy(d, s, m_num * sizeof(float)));
|
||||
return static_cast<float*>(memcpy(d, s, num_ * sizeof(float)));
|
||||
}
|
||||
|
||||
float* FHT::clear(float* d) {
|
||||
return static_cast<float*>(memset(d, 0, m_num * sizeof(float)));
|
||||
return static_cast<float*>(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<double>(n));
|
||||
for (i = 0, r = m_log; i < n; i++, r++) {
|
||||
for (i = 0, r = log_; i < n; i++, r++) {
|
||||
j = static_cast<int>(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<float>(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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<float>(available_rainbow_width_) / (kHistorySize - 1) + 1;
|
||||
px_per_frame_ =
|
||||
static_cast<float>(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<float>(height()) / 2 - static_cast<float>(kCatHeight) / 2;
|
||||
const float top_of_cat =
|
||||
static_cast<float>(height()) / 2 - static_cast<float>(kCatHeight) / 2;
|
||||
for (int band = 0; band < kRainbowBands; ++band) {
|
||||
// Calculate the Y position of this band.
|
||||
const float y =
|
||||
static_cast<float>(kCatHeight) / (kRainbowBands + 1) * (band + 0.5) + top_of_cat;
|
||||
static_cast<float>(kCatHeight) / (kRainbowBands + 1) * (band + 0.5) +
|
||||
top_of_cat;
|
||||
|
||||
// Add each point in the line.
|
||||
for (int x = 0; x < kHistorySize; ++x) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* This file is part of Clementine.
|
||||
Copyright 2014, Alibek Omarov <a1ba.omarov@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
Copyright 2014, David Sansome <me@davidsansome.com>
|
||||
|
||||
|
@ -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<float>(available_rainbow_width_) / (kHistorySize - 1) + 1;
|
||||
px_per_frame_ =
|
||||
static_cast<float>(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<float>(height()) / 2 - static_cast<float>(kRainbowHeight) / 2;
|
||||
const float top_of_Dash = static_cast<float>(height()) / 2 -
|
||||
static_cast<float>(kRainbowHeight) / 2;
|
||||
for (int band = 0; band < kRainbowBands; ++band) {
|
||||
// Calculate the Y position of this band.
|
||||
const float y =
|
||||
static_cast<float>(kRainbowHeight) / (kRainbowBands + 1) * (band + 0.5) +
|
||||
top_of_Dash;
|
||||
const float y = static_cast<float>(kRainbowHeight) / (kRainbowBands + 1) *
|
||||
(band + 0.5) +
|
||||
top_of_Dash;
|
||||
|
||||
// Add each point in the line.
|
||||
for (int x = 0; x < kHistorySize; ++x) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* This file is part of Clementine.
|
||||
Copyright 2014, Alibek Omarov <a1ba.omarov@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
|
||||
Clementine is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Copyright 2004, Melchior FRANZ <mfranz@kde.org>
|
||||
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
|
||||
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<int>(*it * 4000.0));
|
||||
else if (*it < 1.0)
|
||||
c.setHsv(95 - static_cast<int>(*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<int>(*it * 4000.0));
|
||||
} else if (*it < 1.0) {
|
||||
c.setHsv((c.hue() + static_cast<int>(*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<int>(*it * 4000.0));
|
||||
else if (*it < 1.0)
|
||||
c.setHsv(95 - static_cast<int>(*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<float*>(&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_);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
Copyright 2014, John Maguire <john.maguire@gmail.com>
|
||||
Copyright 2015, Mark Furneaux <mark@furneaux.ca>
|
||||
|
||||
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_
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Copyright 2003, Stanislav Karchebny <berkus@users.sf.net>
|
||||
Copyright 2003, Max Howell <max.howell@methylblue.com>
|
||||
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
|
||||
Copyright 2014, Mark Furneaux <mark@romaco.ca>
|
||||
Copyright 2014-2015, Mark Furneaux <mark@furneaux.ca>
|
||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
||||
Copyright 2014, John Maguire <john.maguire@gmail.com>
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
|
||||
/* Original Author: Stanislav Karchebny <berkus@users.sf.net> 2003
|
||||
* Original Author: Max Howell <max.howell@methylblue.com> 2003
|
||||
* Original Author: Max Howell <max.howell@methylblue.com> 2003
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
|
@ -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<uint>(bar_height[i]);
|
||||
canvas_painter.drawPixmap(x + 1, y, barPixmap, 0, y, -1, -1);
|
||||
canvas_painter.drawPixmap(x + 1, hd2, barPixmap, 0,
|
||||
static_cast<int>(bar_height[i]),
|
||||
-1, -1);
|
||||
y = hd2 - static_cast<uint>(bar_height_[i]);
|
||||
canvas_painter.drawPixmap(x + 1, y, barPixmap_, 0, y, -1, -1);
|
||||
canvas_painter.drawPixmap(x + 1, hd2, barPixmap_, 0,
|
||||
static_cast<int>(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<int>(bar_height[i]) * 2 - 1);
|
||||
canvas_painter.setPen(fg_);
|
||||
if (bar_height_[i] > 0)
|
||||
canvas_painter.drawRect(x, y, kColumnWidth - 1,
|
||||
static_cast<int>(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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue