Merge branch 'master' into mono
Conflicts: src/engines/gstenginepipeline.cpp
This commit is contained in:
commit
876cc0c4b6
|
@ -388,6 +388,7 @@
|
|||
<file>schema/schema-49.sql</file>
|
||||
<file>schema/schema-4.sql</file>
|
||||
<file>schema/schema-5.sql</file>
|
||||
<file>schema/schema-50.sql</file>
|
||||
<file>schema/schema-6.sql</file>
|
||||
<file>schema/schema-7.sql</file>
|
||||
<file>schema/schema-8.sql</file>
|
||||
|
|
|
@ -59,7 +59,10 @@ CREATE TABLE device_%deviceid_songs (
|
|||
|
||||
performer TEXT,
|
||||
grouping TEXT,
|
||||
lyrics TEXT
|
||||
lyrics TEXT,
|
||||
|
||||
originalyear INTEGER,
|
||||
effective_originalyear INTEGER
|
||||
);
|
||||
|
||||
CREATE INDEX idx_device_%deviceid_songs_album ON device_%deviceid_songs (album);
|
||||
|
|
|
@ -46,7 +46,10 @@ CREATE TABLE jamendo.songs (
|
|||
|
||||
performer TEXT,
|
||||
grouping TEXT,
|
||||
lyrics TEXT
|
||||
lyrics TEXT,
|
||||
|
||||
originalyear INTEGER,
|
||||
effective_originalyear INTEGER
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE jamendo.songs_fts USING fts3(
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
ALTER TABLE %allsongstables ADD COLUMN originalyear INTEGER;
|
||||
|
||||
ALTER TABLE %allsongstables ADD COLUMN effective_originalyear INTEGER;
|
||||
|
||||
UPDATE songs SET originalyear = -1;
|
||||
|
||||
UPDATE songs SET effective_originalyear = -1;
|
||||
|
||||
UPDATE schema_version SET version=50;
|
|
@ -107,6 +107,14 @@ const char* TagReader::kMP4_FMPS_Playcount_ID =
|
|||
const char* TagReader::kMP4_FMPS_Score_ID =
|
||||
"----:com.apple.iTunes:FMPS_Rating_Amarok_Score";
|
||||
|
||||
namespace {
|
||||
// Tags containing the year the album was originally released (in contrast to
|
||||
// other tags that contain the release year of the current edition)
|
||||
const char* kMP4_OriginalYear_ID = "----:com.apple.iTunes:ORIGINAL YEAR";
|
||||
const char* kASF_OriginalDate_ID = "WM/OriginalReleaseTime";
|
||||
const char* kASF_OriginalYear_ID = "WM/OriginalReleaseYear";
|
||||
}
|
||||
|
||||
TagReader::TagReader()
|
||||
: factory_(new TagLibFileRefFactory),
|
||||
network_(new QNetworkAccessManager),
|
||||
|
@ -190,6 +198,14 @@ void TagReader::ReadFile(const QString& filename,
|
|||
compilation =
|
||||
TStringToQString(map["TCMP"].front()->toString()).trimmed();
|
||||
|
||||
if (!map["TDOR"].isEmpty()) {
|
||||
song->set_originalyear(
|
||||
map["TDOR"].front()->toString().substr(0, 4).toInt());
|
||||
} else if (!map["TORY"].isEmpty()) {
|
||||
song->set_originalyear(
|
||||
map["TORY"].front()->toString().substr(0, 4).toInt());
|
||||
}
|
||||
|
||||
if (!map["USLT"].isEmpty()) {
|
||||
Decode(map["USLT"].front()->toString(), nullptr,
|
||||
song->mutable_lyrics());
|
||||
|
@ -313,6 +329,15 @@ void TagReader::ReadFile(const QString& filename,
|
|||
Decode(items["\251grp"].toStringList().toString(" "), nullptr,
|
||||
song->mutable_grouping());
|
||||
}
|
||||
|
||||
if (items.contains(kMP4_OriginalYear_ID)) {
|
||||
song->set_originalyear(
|
||||
TStringToQString(
|
||||
items[kMP4_OriginalYear_ID].toStringList().toString('\n'))
|
||||
.left(4)
|
||||
.toInt());
|
||||
}
|
||||
|
||||
Decode(mp4_tag->comment(), nullptr, song->mutable_comment());
|
||||
}
|
||||
}
|
||||
|
@ -353,6 +378,22 @@ void TagReader::ReadFile(const QString& filename,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (attributes_map.contains(kASF_OriginalDate_ID)) {
|
||||
const TagLib::ASF::AttributeList& attributes =
|
||||
attributes_map[kASF_OriginalDate_ID];
|
||||
if (!attributes.isEmpty()) {
|
||||
song->set_originalyear(
|
||||
TStringToQString(attributes.front().toString()).left(4).toInt());
|
||||
}
|
||||
} else if (attributes_map.contains(kASF_OriginalYear_ID)) {
|
||||
const TagLib::ASF::AttributeList& attributes =
|
||||
attributes_map[kASF_OriginalYear_ID];
|
||||
if (!attributes.isEmpty()) {
|
||||
song->set_originalyear(
|
||||
TStringToQString(attributes.front().toString()).left(4).toInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (tag) {
|
||||
|
@ -489,6 +530,13 @@ void TagReader::ParseOggTag(const TagLib::Ogg::FieldListMap& map,
|
|||
Decode(map["ALBUM ARTIST"].front(), codec, song->mutable_albumartist());
|
||||
}
|
||||
|
||||
if (!map["ORIGINALDATE"].isEmpty())
|
||||
song->set_originalyear(
|
||||
TStringToQString(map["ORIGINALDATE"].front()).left(4).toInt());
|
||||
else if (!map["ORIGINALYEAR"].isEmpty())
|
||||
song->set_originalyear(
|
||||
TStringToQString(map["ORIGINALYEAR"].front()).toInt());
|
||||
|
||||
if (!map["BPM"].isEmpty())
|
||||
song->set_bpm(TStringToQString(map["BPM"].front()).trimmed().toFloat());
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ message SongMetadata {
|
|||
optional string performer = 31;
|
||||
optional string grouping = 32;
|
||||
optional string lyrics = 33;
|
||||
optional int32 originalyear = 34;
|
||||
}
|
||||
|
||||
message ReadFileRequest {
|
||||
|
|
|
@ -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_ = !psychedelic_colors_on_;
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
#include <QVariant>
|
||||
|
||||
const char* Database::kDatabaseFilename = "clementine.db";
|
||||
const int Database::kSchemaVersion = 49;
|
||||
const int Database::kSchemaVersion = 50;
|
||||
const char* Database::kMagicAllSongsTables = "%allsongstables";
|
||||
|
||||
int Database::sNextConnectionId = 1;
|
||||
|
|
|
@ -51,7 +51,8 @@ const QStringList OrganiseFormat::kKnownTags = QStringList() << "title"
|
|||
<< "extension"
|
||||
<< "performer"
|
||||
<< "grouping"
|
||||
<< "lyrics";
|
||||
<< "lyrics"
|
||||
<< "originalyear";
|
||||
|
||||
// From http://en.wikipedia.org/wiki/8.3_filename#Directory_table
|
||||
const char OrganiseFormat::kInvalidFatCharacters[] = "\"*/\\:<>?|";
|
||||
|
@ -200,6 +201,8 @@ QString OrganiseFormat::TagValue(const QString& tag, const Song& song) const {
|
|||
value = song.comment();
|
||||
else if (tag == "year")
|
||||
value = QString::number(song.year());
|
||||
else if (tag == "originalyear")
|
||||
value = QString::number(song.effective_originalyear());
|
||||
else if (tag == "track")
|
||||
value = QString::number(song.track());
|
||||
else if (tag == "disc")
|
||||
|
|
|
@ -53,6 +53,10 @@ using std::shared_ptr;
|
|||
|
||||
const char* Player::kSettingsGroup = "Player";
|
||||
|
||||
namespace {
|
||||
const int kSeekStepSec = 10;
|
||||
}
|
||||
|
||||
Player::Player(Application* app, QObject* parent)
|
||||
: PlayerInterface(parent),
|
||||
app_(app),
|
||||
|
@ -444,11 +448,11 @@ void Player::SeekTo(int seconds) {
|
|||
}
|
||||
|
||||
void Player::SeekForward() {
|
||||
SeekTo(engine()->position_nanosec() / kNsecPerSec + 10);
|
||||
SeekTo(engine()->position_nanosec() / kNsecPerSec + kSeekStepSec);
|
||||
}
|
||||
|
||||
void Player::SeekBackward() {
|
||||
SeekTo(engine()->position_nanosec() / kNsecPerSec - 10);
|
||||
SeekTo(engine()->position_nanosec() / kNsecPerSec - kSeekStepSec);
|
||||
}
|
||||
|
||||
void Player::EngineMetadataReceived(const Engine::SimpleMetaBundle& bundle) {
|
||||
|
|
|
@ -112,7 +112,9 @@ const QStringList Song::kColumns = QStringList() << "title"
|
|||
<< "etag"
|
||||
<< "performer"
|
||||
<< "grouping"
|
||||
<< "lyrics";
|
||||
<< "lyrics"
|
||||
<< "originalyear"
|
||||
<< "effective_originalyear";
|
||||
|
||||
const QString Song::kColumnSpec = Song::kColumns.join(", ");
|
||||
const QString Song::kBindSpec =
|
||||
|
@ -157,6 +159,7 @@ struct Song::Private : public QSharedData {
|
|||
int disc_;
|
||||
float bpm_;
|
||||
int year_;
|
||||
int originalyear_;
|
||||
QString genre_;
|
||||
QString comment_;
|
||||
bool compilation_; // From the file tag
|
||||
|
@ -230,6 +233,7 @@ Song::Private::Private()
|
|||
disc_(-1),
|
||||
bpm_(-1),
|
||||
year_(-1),
|
||||
originalyear_(-1),
|
||||
compilation_(false),
|
||||
sampler_(false),
|
||||
forced_compilation_on_(false),
|
||||
|
@ -285,6 +289,10 @@ int Song::track() const { return d->track_; }
|
|||
int Song::disc() const { return d->disc_; }
|
||||
float Song::bpm() const { return d->bpm_; }
|
||||
int Song::year() const { return d->year_; }
|
||||
int Song::originalyear() const { return d->originalyear_; }
|
||||
int Song::effective_originalyear() const {
|
||||
return d->originalyear_ < 0 ? d->year_ : d->originalyear_;
|
||||
}
|
||||
const QString& Song::genre() const { return d->genre_; }
|
||||
const QString& Song::comment() const { return d->comment_; }
|
||||
bool Song::is_compilation() const {
|
||||
|
@ -342,6 +350,7 @@ void Song::set_track(int v) { d->track_ = v; }
|
|||
void Song::set_disc(int v) { d->disc_ = v; }
|
||||
void Song::set_bpm(float v) { d->bpm_ = v; }
|
||||
void Song::set_year(int v) { d->year_ = v; }
|
||||
void Song::set_originalyear(int v) { d->originalyear_ = v; }
|
||||
void Song::set_genre(const QString& v) { d->genre_ = v; }
|
||||
void Song::set_comment(const QString& v) { d->comment_ = v; }
|
||||
void Song::set_compilation(bool v) { d->compilation_ = v; }
|
||||
|
@ -499,6 +508,7 @@ void Song::InitFromProtobuf(const pb::tagreader::SongMetadata& pb) {
|
|||
d->disc_ = pb.disc();
|
||||
d->bpm_ = pb.bpm();
|
||||
d->year_ = pb.year();
|
||||
d->originalyear_ = pb.originalyear();
|
||||
d->genre_ = QStringFromStdString(pb.genre());
|
||||
d->comment_ = QStringFromStdString(pb.comment());
|
||||
d->compilation_ = pb.compilation();
|
||||
|
@ -545,6 +555,7 @@ void Song::ToProtobuf(pb::tagreader::SongMetadata* pb) const {
|
|||
pb->set_disc(d->disc_);
|
||||
pb->set_bpm(d->bpm_);
|
||||
pb->set_year(d->year_);
|
||||
pb->set_originalyear(d->originalyear_);
|
||||
pb->set_genre(DataCommaSizeFromQString(d->genre_));
|
||||
pb->set_comment(DataCommaSizeFromQString(d->comment_));
|
||||
pb->set_compilation(d->compilation_);
|
||||
|
@ -585,6 +596,7 @@ void Song::InitFromQuery(const SqlRow& q, bool reliable_metadata, int col) {
|
|||
d->disc_ = toint(col + 7);
|
||||
d->bpm_ = tofloat(col + 8);
|
||||
d->year_ = toint(col + 9);
|
||||
d->originalyear_ = toint(col + 41);
|
||||
d->genre_ = tostr(col + 10);
|
||||
d->comment_ = tostr(col + 11);
|
||||
d->compilation_ = q.value(col + 12).toBool();
|
||||
|
@ -957,6 +969,8 @@ void Song::BindToQuery(QSqlQuery* query) const {
|
|||
query->bindValue(":performer", strval(d->performer_));
|
||||
query->bindValue(":grouping", strval(d->grouping_));
|
||||
query->bindValue(":lyrics", strval(d->lyrics_));
|
||||
query->bindValue(":originalyear", intval(d->originalyear_));
|
||||
query->bindValue(":effective_originalyear", intval(this->effective_originalyear()));
|
||||
|
||||
#undef intval
|
||||
#undef notnullintval
|
||||
|
@ -1056,7 +1070,8 @@ bool Song::IsMetadataEqual(const Song& other) const {
|
|||
d->performer_ == other.d->performer_ &&
|
||||
d->grouping_ == other.d->grouping_ && d->track_ == other.d->track_ &&
|
||||
d->disc_ == other.d->disc_ && qFuzzyCompare(d->bpm_, other.d->bpm_) &&
|
||||
d->year_ == other.d->year_ && d->genre_ == other.d->genre_ &&
|
||||
d->year_ == other.d->year_ && d->originalyear_ == other.d->originalyear_ &&
|
||||
d->genre_ == other.d->genre_ &&
|
||||
d->comment_ == other.d->comment_ &&
|
||||
d->compilation_ == other.d->compilation_ &&
|
||||
d->beginning_ == other.d->beginning_ &&
|
||||
|
|
|
@ -176,6 +176,8 @@ class Song {
|
|||
int disc() const;
|
||||
float bpm() const;
|
||||
int year() const;
|
||||
int originalyear() const;
|
||||
int effective_originalyear() const;
|
||||
const QString& genre() const;
|
||||
const QString& comment() const;
|
||||
bool is_compilation() const;
|
||||
|
@ -255,6 +257,7 @@ class Song {
|
|||
void set_disc(int v);
|
||||
void set_bpm(float v);
|
||||
void set_year(int v);
|
||||
void set_originalyear(int v);
|
||||
void set_genre(const QString& v);
|
||||
void set_genre_id3(int id);
|
||||
void set_comment(const QString& v);
|
||||
|
|
|
@ -258,6 +258,13 @@ signals:
|
|||
bool pipeline_is_connected_;
|
||||
qint64 pending_seek_nanosec_;
|
||||
|
||||
// We can only use gst_element_query_position() when the pipeline is in
|
||||
// PAUSED nor PLAYING state. Whenever we get a new position (e.g. after a
|
||||
// correct call to gst_element_query_position() or after a seek), we store
|
||||
// it here so that we can use it when using gst_element_query_position() is
|
||||
// not possible.
|
||||
mutable gint64 last_known_position_ns_;
|
||||
|
||||
int volume_percent_;
|
||||
qreal volume_modifier_;
|
||||
|
||||
|
|
|
@ -120,12 +120,26 @@ QStandardItem* GlobalSearchModel::BuildContainers(const Song& s,
|
|||
has_album_icon = true;
|
||||
break;
|
||||
|
||||
case LibraryModel::GroupBy_OriginalYearAlbum:
|
||||
year = qMax(0, s.effective_originalyear());
|
||||
display_text = LibraryModel::PrettyYearAlbum(year, s.album());
|
||||
sort_text = LibraryModel::SortTextForNumber(year) + s.album();
|
||||
unique_tag = s.album_id();
|
||||
has_album_icon = true;
|
||||
break;
|
||||
|
||||
case LibraryModel::GroupBy_Year:
|
||||
year = qMax(0, s.year());
|
||||
display_text = QString::number(year);
|
||||
sort_text = LibraryModel::SortTextForNumber(year) + " ";
|
||||
break;
|
||||
|
||||
case LibraryModel::GroupBy_OriginalYear:
|
||||
year = qMax(0, s.effective_originalyear());
|
||||
display_text = QString::number(year);
|
||||
sort_text = LibraryModel::SortTextForNumber(year) + " ";
|
||||
break;
|
||||
|
||||
case LibraryModel::GroupBy_Composer:
|
||||
display_text = s.composer();
|
||||
case LibraryModel::GroupBy_Performer:
|
||||
|
|
|
@ -337,7 +337,8 @@ void GlobalSearchView::LazyLoadArt(const QModelIndex& proxy_index) {
|
|||
proxy_index.data(LibraryModel::Role_ContainerType).toInt());
|
||||
if (container_type != LibraryModel::GroupBy_Album &&
|
||||
container_type != LibraryModel::GroupBy_AlbumArtist &&
|
||||
container_type != LibraryModel::GroupBy_YearAlbum) {
|
||||
container_type != LibraryModel::GroupBy_YearAlbum &&
|
||||
container_type != LibraryModel::GroupBy_OriginalYearAlbum) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,11 +76,13 @@ GroupByDialog::GroupByDialog(QWidget* parent)
|
|||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_FileType, 5));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_Genre, 6));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_Year, 7));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_YearAlbum, 8));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_Bitrate, 9));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_Disc, 10));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_Performer, 11));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_Grouping, 12));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_OriginalYear, 8));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_YearAlbum, 9));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_OriginalYearAlbum, 10));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_Bitrate, 11));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_Disc, 12));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_Performer, 13));
|
||||
p_->mapping_.insert(Mapping(LibraryModel::GroupBy_Grouping, 14));
|
||||
|
||||
connect(ui_->button_box->button(QDialogButtonBox::Reset), SIGNAL(clicked()),
|
||||
SLOT(Reset()));
|
||||
|
|
|
@ -83,11 +83,21 @@
|
|||
<string>Year</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Original year</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Year - Album</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Original year - Album</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Bitrate</string>
|
||||
|
@ -159,11 +169,21 @@
|
|||
<string>Year</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Original year</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Year - Album</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Original year - Album</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Bitrate</string>
|
||||
|
@ -235,11 +255,21 @@
|
|||
<string>Year</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Original year</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Year - Album</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Original year - Album</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Bitrate</string>
|
||||
|
|
|
@ -115,6 +115,7 @@ Library::Library(Application* app, QObject* parent)
|
|||
|
||||
// full rescan revisions
|
||||
full_rescan_revisions_[26] = tr("CUE sheet support");
|
||||
full_rescan_revisions_[50] = tr("Original year tag support");
|
||||
|
||||
ReloadSettings();
|
||||
}
|
||||
|
|
|
@ -221,9 +221,15 @@ void LibraryModel::SongsDiscovered(const SongList& songs) {
|
|||
case GroupBy_Year:
|
||||
key = QString::number(qMax(0, song.year()));
|
||||
break;
|
||||
case GroupBy_OriginalYear:
|
||||
key = QString::number(qMax(0, song.effective_originalyear()));
|
||||
break;
|
||||
case GroupBy_YearAlbum:
|
||||
key = PrettyYearAlbum(qMax(0, song.year()), song.album());
|
||||
break;
|
||||
case GroupBy_OriginalYearAlbum:
|
||||
key = PrettyYearAlbum(qMax(0, song.effective_originalyear()), song.album());
|
||||
break;
|
||||
case GroupBy_FileType:
|
||||
key = song.filetype();
|
||||
break;
|
||||
|
@ -313,11 +319,15 @@ QString LibraryModel::DividerKey(GroupBy type, LibraryItem* item) const {
|
|||
}
|
||||
|
||||
case GroupBy_Year:
|
||||
case GroupBy_OriginalYear:
|
||||
return SortTextForNumber(item->sort_text.toInt() / 10 * 10);
|
||||
|
||||
case GroupBy_YearAlbum:
|
||||
return SortTextForNumber(item->metadata.year());
|
||||
|
||||
case GroupBy_OriginalYearAlbum:
|
||||
return SortTextForNumber(item->metadata.effective_originalyear());
|
||||
|
||||
case GroupBy_Bitrate:
|
||||
return SortTextForNumber(item->metadata.bitrate());
|
||||
|
||||
|
@ -347,10 +357,12 @@ QString LibraryModel::DividerDisplayText(GroupBy type,
|
|||
return key.toUpper();
|
||||
|
||||
case GroupBy_YearAlbum:
|
||||
case GroupBy_OriginalYearAlbum:
|
||||
if (key == "0000") return tr("Unknown");
|
||||
return key.toUpper();
|
||||
|
||||
case GroupBy_Year:
|
||||
case GroupBy_OriginalYear:
|
||||
if (key == "0000") return tr("Unknown");
|
||||
return QString::number(key.toInt()); // To remove leading 0s
|
||||
|
||||
|
@ -543,7 +555,8 @@ QVariant LibraryModel::data(const QModelIndex& index, int role) const {
|
|||
item->type == LibraryItem::Type_Container) {
|
||||
GroupBy container_type = group_by_[item->container_level];
|
||||
is_album_node = container_type == GroupBy_Album ||
|
||||
container_type == GroupBy_YearAlbum;
|
||||
container_type == GroupBy_YearAlbum ||
|
||||
container_type == GroupBy_OriginalYearAlbum;
|
||||
}
|
||||
if (is_album_node) {
|
||||
// It has const behaviour some of the time - that's ok right?
|
||||
|
@ -572,6 +585,7 @@ QVariant LibraryModel::data(const LibraryItem* item, int role) const {
|
|||
switch (container_type) {
|
||||
case GroupBy_Album:
|
||||
case GroupBy_YearAlbum:
|
||||
case GroupBy_OriginalYearAlbum:
|
||||
return album_icon_;
|
||||
case GroupBy_Artist:
|
||||
case GroupBy_AlbumArtist:
|
||||
|
@ -797,9 +811,15 @@ void LibraryModel::InitQuery(GroupBy type, LibraryQuery* q) {
|
|||
case GroupBy_YearAlbum:
|
||||
q->SetColumnSpec("DISTINCT year, album, grouping");
|
||||
break;
|
||||
case GroupBy_OriginalYearAlbum:
|
||||
q->SetColumnSpec("DISTINCT year, originalyear, album, grouping");
|
||||
break;
|
||||
case GroupBy_Year:
|
||||
q->SetColumnSpec("DISTINCT year");
|
||||
break;
|
||||
case GroupBy_OriginalYear:
|
||||
q->SetColumnSpec("DISTINCT effective_originalyear");
|
||||
break;
|
||||
case GroupBy_Genre:
|
||||
q->SetColumnSpec("DISTINCT genre");
|
||||
break;
|
||||
|
@ -841,9 +861,19 @@ void LibraryModel::FilterQuery(GroupBy type, LibraryItem* item,
|
|||
q->AddWhere("album", item->metadata.album());
|
||||
q->AddWhere("grouping", item->metadata.grouping());
|
||||
break;
|
||||
case GroupBy_OriginalYearAlbum:
|
||||
q->AddWhere("year", item->metadata.year());
|
||||
q->AddWhere("originalyear", item->metadata.originalyear());
|
||||
q->AddWhere("album", item->metadata.album());
|
||||
q->AddWhere("grouping", item->metadata.grouping());
|
||||
break;
|
||||
|
||||
case GroupBy_Year:
|
||||
q->AddWhere("year", item->key);
|
||||
break;
|
||||
case GroupBy_OriginalYear:
|
||||
q->AddWhere("effective_originalyear", item->key);
|
||||
break;
|
||||
case GroupBy_Composer:
|
||||
q->AddWhere("composer", item->key);
|
||||
break;
|
||||
|
@ -903,6 +933,7 @@ LibraryItem* LibraryModel::ItemFromQuery(GroupBy type, bool signal,
|
|||
int container_level) {
|
||||
LibraryItem* item = InitItem(type, signal, parent, container_level);
|
||||
int year = 0;
|
||||
int effective_originalyear = 0;
|
||||
int bitrate = 0;
|
||||
int disc = 0;
|
||||
|
||||
|
@ -923,12 +954,29 @@ LibraryItem* LibraryModel::ItemFromQuery(GroupBy type, bool signal,
|
|||
item->metadata.album();
|
||||
break;
|
||||
|
||||
case GroupBy_OriginalYearAlbum:
|
||||
item->metadata.set_year(row.value(0).toInt());
|
||||
item->metadata.set_originalyear(row.value(1).toInt());
|
||||
item->metadata.set_album(row.value(2).toString());
|
||||
item->metadata.set_grouping(row.value(3).toString());
|
||||
effective_originalyear = qMax(0, item->metadata.effective_originalyear());
|
||||
item->key = PrettyYearAlbum(effective_originalyear, item->metadata.album());
|
||||
item->sort_text = SortTextForNumber(effective_originalyear) + item->metadata.grouping()
|
||||
+ item->metadata.album();
|
||||
break;
|
||||
|
||||
case GroupBy_Year:
|
||||
year = qMax(0, row.value(0).toInt());
|
||||
item->key = QString::number(year);
|
||||
item->sort_text = SortTextForNumber(year) + " ";
|
||||
break;
|
||||
|
||||
case GroupBy_OriginalYear:
|
||||
year = qMax(0, row.value(0).toInt());
|
||||
item->key = QString::number(year);
|
||||
item->sort_text = SortTextForNumber(year) + " ";
|
||||
break;
|
||||
|
||||
case GroupBy_Composer:
|
||||
case GroupBy_Performer:
|
||||
case GroupBy_Grouping:
|
||||
|
@ -975,6 +1023,8 @@ LibraryItem* LibraryModel::ItemFromSong(GroupBy type, bool signal,
|
|||
int container_level) {
|
||||
LibraryItem* item = InitItem(type, signal, parent, container_level);
|
||||
int year = 0;
|
||||
int originalyear = 0;
|
||||
int effective_originalyear = 0;
|
||||
int bitrate = 0;
|
||||
|
||||
switch (type) {
|
||||
|
@ -992,12 +1042,29 @@ LibraryItem* LibraryModel::ItemFromSong(GroupBy type, bool signal,
|
|||
item->sort_text = SortTextForNumber(year) + s.grouping() + s.album();
|
||||
break;
|
||||
|
||||
case GroupBy_OriginalYearAlbum:
|
||||
year = qMax(0, s.year());
|
||||
originalyear = qMax(0, s.originalyear());
|
||||
effective_originalyear = qMax(0, s.effective_originalyear());
|
||||
item->metadata.set_year(year);
|
||||
item->metadata.set_originalyear(originalyear);
|
||||
item->metadata.set_album(s.album());
|
||||
item->key = PrettyYearAlbum(effective_originalyear, s.album());
|
||||
item->sort_text = SortTextForNumber(effective_originalyear) + s.grouping() + s.album();
|
||||
break;
|
||||
|
||||
case GroupBy_Year:
|
||||
year = qMax(0, s.year());
|
||||
item->key = QString::number(year);
|
||||
item->sort_text = SortTextForNumber(year) + " ";
|
||||
break;
|
||||
|
||||
case GroupBy_OriginalYear:
|
||||
year = qMax(0, s.effective_originalyear());
|
||||
item->key = QString::number(year);
|
||||
item->sort_text = SortTextForNumber(year) + " ";
|
||||
break;
|
||||
|
||||
case GroupBy_Composer:
|
||||
item->key = s.composer();
|
||||
case GroupBy_Performer:
|
||||
|
|
|
@ -85,6 +85,8 @@ class LibraryModel : public SimpleTreeModel<LibraryItem> {
|
|||
GroupBy_Grouping = 10,
|
||||
GroupBy_Bitrate = 11,
|
||||
GroupBy_Disc = 12,
|
||||
GroupBy_OriginalYearAlbum = 13,
|
||||
GroupBy_OriginalYear = 14,
|
||||
};
|
||||
|
||||
struct Grouping {
|
||||
|
|
|
@ -285,6 +285,8 @@ QVariant Playlist::data(const QModelIndex& index, int role) const {
|
|||
return song.disc();
|
||||
case Column_Year:
|
||||
return song.year();
|
||||
case Column_OriginalYear:
|
||||
return song.effective_originalyear();
|
||||
case Column_Genre:
|
||||
return song.genre();
|
||||
case Column_AlbumArtist:
|
||||
|
@ -1252,6 +1254,8 @@ bool Playlist::CompareItems(int column, Qt::SortOrder order,
|
|||
cmp(disc);
|
||||
case Column_Year:
|
||||
cmp(year);
|
||||
case Column_OriginalYear:
|
||||
cmp(originalyear);
|
||||
case Column_Genre:
|
||||
strcmp(genre);
|
||||
case Column_AlbumArtist:
|
||||
|
@ -1321,6 +1325,8 @@ QString Playlist::column_name(Column column) {
|
|||
return tr("Disc");
|
||||
case Column_Year:
|
||||
return tr("Year");
|
||||
case Column_OriginalYear:
|
||||
return tr("Original year");
|
||||
case Column_Genre:
|
||||
return tr("Genre");
|
||||
case Column_AlbumArtist:
|
||||
|
|
|
@ -114,6 +114,7 @@ class Playlist : public QAbstractListModel {
|
|||
Column_Mood,
|
||||
Column_Performer,
|
||||
Column_Grouping,
|
||||
Column_OriginalYear,
|
||||
ColumnCount
|
||||
};
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ PlaylistFilter::PlaylistFilter(QObject* parent)
|
|||
column_names_["track"] = Playlist::Column_Track;
|
||||
column_names_["disc"] = Playlist::Column_Disc;
|
||||
column_names_["year"] = Playlist::Column_Year;
|
||||
column_names_["originalyear"] = Playlist::Column_OriginalYear;
|
||||
column_names_["genre"] = Playlist::Column_Genre;
|
||||
column_names_["score"] = Playlist::Column_Score;
|
||||
column_names_["comment"] = Playlist::Column_Comment;
|
||||
|
@ -48,8 +49,9 @@ PlaylistFilter::PlaylistFilter(QObject* parent)
|
|||
|
||||
numerical_columns_ << Playlist::Column_Length << Playlist::Column_Track
|
||||
<< Playlist::Column_Disc << Playlist::Column_Year
|
||||
<< Playlist::Column_Score << Playlist::Column_BPM
|
||||
<< Playlist::Column_Bitrate << Playlist::Column_Rating;
|
||||
<< Playlist::Column_OriginalYear << Playlist::Column_Score
|
||||
<< Playlist::Column_BPM << Playlist::Column_Bitrate
|
||||
<< Playlist::Column_Rating;
|
||||
}
|
||||
|
||||
PlaylistFilter::~PlaylistFilter() {}
|
||||
|
|
|
@ -320,6 +320,7 @@ void PlaylistView::LoadGeometry() {
|
|||
if (!header_->restoreState(state)) {
|
||||
header_->HideSection(Playlist::Column_Disc);
|
||||
header_->HideSection(Playlist::Column_Year);
|
||||
header_->HideSection(Playlist::Column_OriginalYear);
|
||||
header_->HideSection(Playlist::Column_Genre);
|
||||
header_->HideSection(Playlist::Column_BPM);
|
||||
header_->HideSection(Playlist::Column_Bitrate);
|
||||
|
@ -585,10 +586,10 @@ void PlaylistView::keyPressEvent(QKeyEvent* event) {
|
|||
emit PlayPause();
|
||||
event->accept();
|
||||
} else if (event->key() == Qt::Key_Left) {
|
||||
emit SeekTrack(-1);
|
||||
emit SeekBackward();
|
||||
event->accept();
|
||||
} else if (event->key() == Qt::Key_Right) {
|
||||
emit SeekTrack(1);
|
||||
emit SeekForward();
|
||||
event->accept();
|
||||
} else if (event->modifiers() ==
|
||||
Qt::NoModifier // No modifier keys currently pressed...
|
||||
|
@ -1190,7 +1191,8 @@ ColumnAlignmentMap PlaylistView::DefaultColumnAlignment() {
|
|||
ret[Playlist::Column_Filesize] =
|
||||
ret[Playlist::Column_PlayCount] =
|
||||
ret[Playlist::Column_SkipCount] =
|
||||
(Qt::AlignRight | Qt::AlignVCenter);
|
||||
ret[Playlist::Column_OriginalYear] =
|
||||
(Qt::AlignRight | Qt::AlignVCenter);
|
||||
ret[Playlist::Column_Score] = (Qt::AlignCenter);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -109,7 +109,8 @@ signals:
|
|||
void PlayItem(const QModelIndex& index);
|
||||
void PlayPause();
|
||||
void RightClicked(const QPoint& global_pos, const QModelIndex& index);
|
||||
void SeekTrack(int gap);
|
||||
void SeekForward();
|
||||
void SeekBackward();
|
||||
void FocusOnFilterSignal(QKeyEvent* event);
|
||||
void BackgroundPropertyChanged();
|
||||
void ColumnAlignmentChanged(const ColumnAlignmentMap& alignment);
|
||||
|
|
|
@ -160,6 +160,7 @@ SearchTerm::Type SearchTerm::TypeOf(Field field) {
|
|||
case Field_Track:
|
||||
case Field_Disc:
|
||||
case Field_Year:
|
||||
case Field_OriginalYear:
|
||||
case Field_BPM:
|
||||
case Field_Bitrate:
|
||||
case Field_Samplerate:
|
||||
|
@ -253,6 +254,8 @@ QString SearchTerm::FieldColumnName(Field field) {
|
|||
return "disc";
|
||||
case Field_Year:
|
||||
return "year";
|
||||
case Field_OriginalYear:
|
||||
return "originalyear";
|
||||
case Field_BPM:
|
||||
return "bpm";
|
||||
case Field_Bitrate:
|
||||
|
@ -311,6 +314,8 @@ QString SearchTerm::FieldName(Field field) {
|
|||
return Playlist::column_name(Playlist::Column_Disc);
|
||||
case Field_Year:
|
||||
return Playlist::column_name(Playlist::Column_Year);
|
||||
case Field_OriginalYear:
|
||||
return Playlist::column_name(Playlist::Column_OriginalYear);
|
||||
case Field_BPM:
|
||||
return Playlist::column_name(Playlist::Column_BPM);
|
||||
case Field_Bitrate:
|
||||
|
|
|
@ -52,6 +52,7 @@ class SearchTerm {
|
|||
Field_Filepath,
|
||||
Field_Performer,
|
||||
Field_Grouping,
|
||||
Field_OriginalYear,
|
||||
FieldCount
|
||||
};
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Clementine Music Player\n"
|
||||
"PO-Revision-Date: 2015-06-17 14:55+0000\n"
|
||||
"Last-Translator: Clementine Buildbot <clementinebuildbot@davidsansome.com>\n"
|
||||
"PO-Revision-Date: 2015-06-26 14:32+0000\n"
|
||||
"Last-Translator: Peter Jespersen <flywheeldk@gmail.com>\n"
|
||||
"Language-Team: Danish (http://www.transifex.com/projects/p/clementine/language/da/)\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
@ -72,7 +72,7 @@ msgstr " sange"
|
|||
#: internet/vk/vkservice.cpp:148
|
||||
#, qt-format
|
||||
msgid "%1 (%2 songs)"
|
||||
msgstr ""
|
||||
msgstr "%1 (%2 sange)"
|
||||
|
||||
#: widgets/osd.cpp:194
|
||||
#, qt-format
|
||||
|
@ -422,7 +422,7 @@ msgstr "Aktiver/deaktiver Wiiremote"
|
|||
|
||||
#: internet/soundcloud/soundcloudservice.cpp:125
|
||||
msgid "Activities stream"
|
||||
msgstr ""
|
||||
msgstr "Aktivitetsstrøm"
|
||||
|
||||
#: internet/podcasts/addpodcastdialog.cpp:62
|
||||
msgid "Add Podcast"
|
||||
|
@ -2906,7 +2906,7 @@ msgstr "Stort albumomslag (detaljer nedenfor)"
|
|||
|
||||
#: widgets/nowplayingwidget.cpp:102
|
||||
msgid "Large album cover (no details)"
|
||||
msgstr ""
|
||||
msgstr "Stort albumomslag (ingen detaljer)"
|
||||
|
||||
#: widgets/fancytabwidget.cpp:662
|
||||
msgid "Large sidebar"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
# This file is distributed under the same license as the Clementine package.
|
||||
#
|
||||
# Translators:
|
||||
# Chen Kasirer <chen902@gmail.com>, 2015
|
||||
# Elia Shreidler <elia.shreidler@gmail.com>, 2013
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2010
|
||||
# matanya <matanya.moses@gmail.com>, 2012
|
||||
|
@ -13,8 +14,8 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Clementine Music Player\n"
|
||||
"PO-Revision-Date: 2015-06-17 14:55+0000\n"
|
||||
"Last-Translator: Clementine Buildbot <clementinebuildbot@davidsansome.com>\n"
|
||||
"PO-Revision-Date: 2015-06-25 22:51+0000\n"
|
||||
"Last-Translator: Chen Kasirer <chen902@gmail.com>\n"
|
||||
"Language-Team: Hebrew (http://www.transifex.com/projects/p/clementine/language/he/)\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
@ -438,7 +439,7 @@ msgstr "הוספת פעולה"
|
|||
|
||||
#: ../bin/src/ui_transcodedialog.h:218
|
||||
msgid "Add all tracks from a directory and all its subdirectories"
|
||||
msgstr ""
|
||||
msgstr "הוסף את כל הרצועות מהתיקייה ומתתי התיקיות שלה "
|
||||
|
||||
#: internet/internetradio/savedradio.cpp:112
|
||||
msgid "Add another stream..."
|
||||
|
@ -579,11 +580,11 @@ msgstr "הוסף לשירים שלי"
|
|||
|
||||
#: internet/spotify/spotifyservice.cpp:617
|
||||
msgid "Add to Spotify playlists"
|
||||
msgstr ""
|
||||
msgstr "הוסף לרשימת ההשמעה של Spotify"
|
||||
|
||||
#: internet/spotify/spotifyservice.cpp:610
|
||||
msgid "Add to Spotify starred"
|
||||
msgstr ""
|
||||
msgstr "הוסף למועדפים של Spotify"
|
||||
|
||||
#: ui/mainwindow.cpp:1679
|
||||
msgid "Add to another playlist"
|
||||
|
@ -603,7 +604,7 @@ msgstr "הוספה לתור"
|
|||
|
||||
#: internet/vk/vkservice.cpp:328
|
||||
msgid "Add user/group to bookmarks"
|
||||
msgstr ""
|
||||
msgstr "הוסף משתמש\\קבוצה לסימניות"
|
||||
|
||||
#: ../bin/src/ui_wiimoteshortcutgrabber.h:123
|
||||
msgid "Add wiimotedev action"
|
||||
|
@ -675,7 +676,7 @@ msgstr "מידע על האלבום ב־jamendo.com..."
|
|||
|
||||
#: internet/vk/vkservice.cpp:827
|
||||
msgid "Albums"
|
||||
msgstr ""
|
||||
msgstr "כל האלבומים"
|
||||
|
||||
#: ui/albumcovermanager.cpp:135
|
||||
msgid "Albums with covers"
|
||||
|
@ -687,7 +688,7 @@ msgstr "אלבומים ללא עטיפה"
|
|||
|
||||
#: ../bin/src/ui_podcastsettingspage.h:279
|
||||
msgid "All"
|
||||
msgstr ""
|
||||
msgstr "הכל"
|
||||
|
||||
#: ui/mainwindow.cpp:161
|
||||
msgid "All Files (*)"
|
||||
|
@ -1058,7 +1059,7 @@ msgstr "ביטול"
|
|||
|
||||
#: internet/podcasts/podcastservice.cpp:439
|
||||
msgid "Cancel download"
|
||||
msgstr ""
|
||||
msgstr "בטל הורדה"
|
||||
|
||||
#: internet/vk/vkservice.cpp:626
|
||||
msgid ""
|
||||
|
@ -1102,7 +1103,7 @@ msgstr "בדיקת פרקים חדשים"
|
|||
|
||||
#: internet/googledrive/googledriveservice.cpp:220
|
||||
msgid "Check for updates"
|
||||
msgstr ""
|
||||
msgstr "בדוק עדכונים"
|
||||
|
||||
#: ui/mainwindow.cpp:736
|
||||
msgid "Check for updates..."
|
||||
|
@ -1142,7 +1143,7 @@ msgstr "בחירת תיקיית יעד להורדת פודקאסט"
|
|||
|
||||
#: ../bin/src/ui_internetshowsettingspage.h:89
|
||||
msgid "Choose the internet services you want to show."
|
||||
msgstr ""
|
||||
msgstr "בחר שירות אינטרנט להצגה"
|
||||
|
||||
#: ../bin/src/ui_songinfosettingspage.h:160
|
||||
msgid ""
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Clementine Music Player\n"
|
||||
"PO-Revision-Date: 2015-06-17 14:55+0000\n"
|
||||
"Last-Translator: Clementine Buildbot <clementinebuildbot@davidsansome.com>\n"
|
||||
"PO-Revision-Date: 2015-06-24 18:26+0000\n"
|
||||
"Last-Translator: miku84\n"
|
||||
"Language-Team: Hungarian (http://www.transifex.com/projects/p/clementine/language/hu/)\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
@ -939,7 +939,7 @@ msgstr "Bal - jobb egyensúly"
|
|||
|
||||
#: core/globalshortcuts.cpp:80
|
||||
msgid "Ban (Last.fm scrobbling)"
|
||||
msgstr ""
|
||||
msgstr "Last.fm scrobbling tiltása"
|
||||
|
||||
#: analyzers/baranalyzer.cpp:35
|
||||
msgid "Bar analyzer"
|
||||
|
@ -2788,7 +2788,7 @@ msgstr "Internet szolgáltatások"
|
|||
|
||||
#: widgets/osd.cpp:321 ../bin/src/ui_playlistsequence.h:116
|
||||
msgid "Intro tracks"
|
||||
msgstr ""
|
||||
msgstr "A számokhoz"
|
||||
|
||||
#: internet/lastfm/lastfmservice.cpp:240
|
||||
msgid "Invalid API key"
|
||||
|
@ -3088,7 +3088,7 @@ msgstr "Kedvenc"
|
|||
|
||||
#: core/globalshortcuts.cpp:78
|
||||
msgid "Love (Last.fm scrobbling)"
|
||||
msgstr ""
|
||||
msgstr "Last.fm scrobbling engedélyezése"
|
||||
|
||||
#: analyzers/analyzercontainer.cpp:67
|
||||
#: visualisations/visualisationcontainer.cpp:107
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Clementine Music Player\n"
|
||||
"PO-Revision-Date: 2015-06-21 19:25+0000\n"
|
||||
"PO-Revision-Date: 2015-06-27 11:43+0000\n"
|
||||
"Last-Translator: Andrei Stepanov\n"
|
||||
"Language-Team: Russian (http://www.transifex.com/projects/p/clementine/language/ru/)\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
@ -5164,11 +5164,11 @@ msgstr "Всего выполнено сетевых запросов"
|
|||
#: ../bin/src/ui_edittagdialog.h:735 ../bin/src/ui_trackselectiondialog.h:213
|
||||
#: ../bin/src/ui_ripcddialog.h:305
|
||||
msgid "Track"
|
||||
msgstr "Композиция"
|
||||
msgstr "Трек"
|
||||
|
||||
#: internet/soundcloud/soundcloudservice.cpp:133
|
||||
msgid "Tracks"
|
||||
msgstr "Композиции"
|
||||
msgstr "Треки"
|
||||
|
||||
#: ../bin/src/ui_transcodedialog.h:210 ../bin/src/ui_mainwindow.h:687
|
||||
msgid "Transcode Music"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
# Kristian <kristianm24@gmail.com>, 2013-2015
|
||||
# Kristian <kristianm24@gmail.com>, 2012
|
||||
# Kristoffer Grundström <kristoffer.grundstrom1983@gmail.com>, 2014
|
||||
# paperbagcorner <mandersson444@gmail.com>, 2014
|
||||
# paperbagcorner <mandersson444@gmail.com>, 2014-2015
|
||||
# Patrik Nilsson <asavartzeth@gmail.com>, 2014-2015
|
||||
# pieorpaj <pie.or.paj@gmail.com>, 2013
|
||||
# pieorpaj <pie.or.paj@gmail.com>, 2012
|
||||
|
@ -20,8 +20,8 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Clementine Music Player\n"
|
||||
"PO-Revision-Date: 2015-06-20 11:26+0000\n"
|
||||
"Last-Translator: Kristian <kristianm24@gmail.com>\n"
|
||||
"PO-Revision-Date: 2015-06-22 18:56+0000\n"
|
||||
"Last-Translator: paperbagcorner <mandersson444@gmail.com>\n"
|
||||
"Language-Team: Swedish (http://www.transifex.com/projects/p/clementine/language/sv/)\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
@ -115,7 +115,7 @@ msgstr "%1 låt"
|
|||
#: devices/deviceview.cpp:127
|
||||
#, qt-format
|
||||
msgid "%1 songs"
|
||||
msgstr "%1 låtarna"
|
||||
msgstr "%1 låtar"
|
||||
|
||||
#: smartplaylists/searchpreview.cpp:132
|
||||
#, qt-format
|
||||
|
@ -4528,7 +4528,7 @@ msgstr "Visa alla låtar"
|
|||
|
||||
#: ../bin/src/ui_querysortpage.h:142
|
||||
msgid "Show all the songs"
|
||||
msgstr "Visa alla låtarna"
|
||||
msgstr "Visa alla låtar"
|
||||
|
||||
#: ../bin/src/ui_librarysettingspage.h:209
|
||||
msgid "Show cover art in library"
|
||||
|
|
|
@ -536,13 +536,19 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd,
|
|||
SLOT(PlayPause()));
|
||||
connect(ui_->playlist->view(), SIGNAL(RightClicked(QPoint, QModelIndex)),
|
||||
SLOT(PlaylistRightClick(QPoint, QModelIndex)));
|
||||
connect(ui_->playlist->view(), SIGNAL(SeekTrack(int)), ui_->track_slider,
|
||||
SLOT(Seek(int)));
|
||||
connect(ui_->playlist->view(), SIGNAL(SeekForward()), app_->player(),
|
||||
SLOT(SeekForward()));
|
||||
connect(ui_->playlist->view(), SIGNAL(SeekBackward()), app_->player(),
|
||||
SLOT(SeekBackward()));
|
||||
connect(ui_->playlist->view(), SIGNAL(BackgroundPropertyChanged()),
|
||||
SLOT(RefreshStyleSheet()));
|
||||
|
||||
connect(ui_->track_slider, SIGNAL(ValueChangedSeconds(int)), app_->player(),
|
||||
SLOT(SeekTo(int)));
|
||||
connect(ui_->track_slider, SIGNAL(SeekForward()), app_->player(),
|
||||
SLOT(SeekForward()));
|
||||
connect(ui_->track_slider, SIGNAL(SeekBackward()), app_->player(),
|
||||
SLOT(SeekBackward()));
|
||||
|
||||
// Library connections
|
||||
connect(library_view_->view(), SIGNAL(AddToPlaylistSignal(QMimeData*)),
|
||||
|
@ -1342,7 +1348,8 @@ void MainWindow::UpdateTrackPosition() {
|
|||
}
|
||||
}
|
||||
|
||||
// (just after) the scrobble point is a good point to change tracks in intro mode
|
||||
// (just after) the scrobble point is a good point to change tracks in intro
|
||||
// mode
|
||||
if (position >= scrobble_point + 5) {
|
||||
if (playlist->sequence()->repeat_mode() == PlaylistSequence::Repeat_Intro) {
|
||||
emit IntroPointReached();
|
||||
|
@ -2727,10 +2734,10 @@ void MainWindow::keyPressEvent(QKeyEvent* event) {
|
|||
app_->player()->PlayPause();
|
||||
event->accept();
|
||||
} else if (event->key() == Qt::Key_Left) {
|
||||
ui_->track_slider->Seek(-1);
|
||||
app_->player()->SeekBackward();
|
||||
event->accept();
|
||||
} else if (event->key() == Qt::Key_Right) {
|
||||
ui_->track_slider->Seek(1);
|
||||
app_->player()->SeekForward();
|
||||
event->accept();
|
||||
} else {
|
||||
QMainWindow::keyPressEvent(event);
|
||||
|
|
|
@ -70,6 +70,7 @@ OrganiseDialog::OrganiseDialog(TaskManager* task_manager, QWidget* parent)
|
|||
tags[tr("Disc")] = "disc";
|
||||
tags[tr("BPM")] = "bpm";
|
||||
tags[tr("Year")] = "year";
|
||||
tags[tr("Original year")] = "originalyear";
|
||||
tags[tr("Genre")] = "genre";
|
||||
tags[tr("Comment")] = "comment";
|
||||
tags[tr("Length")] = "length";
|
||||
|
|
|
@ -47,6 +47,8 @@ TrackSlider::TrackSlider(QWidget* parent)
|
|||
|
||||
connect(ui_->slider, SIGNAL(sliderMoved(int)), SIGNAL(ValueChanged(int)));
|
||||
connect(ui_->slider, SIGNAL(valueChanged(int)), SLOT(ValueMaybeChanged(int)));
|
||||
connect(ui_->slider, SIGNAL(SeekForward()), SIGNAL(SeekForward()));
|
||||
connect(ui_->slider, SIGNAL(SeekBackward()), SIGNAL(SeekBackward()));
|
||||
connect(ui_->remaining, SIGNAL(Clicked()), SLOT(ToggleTimeDisplay()));
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,9 @@ signals:
|
|||
void ValueChanged(int value);
|
||||
void ValueChangedSeconds(int value);
|
||||
|
||||
void SeekForward();
|
||||
void SeekBackward();
|
||||
|
||||
private slots:
|
||||
void ValueMaybeChanged(int value);
|
||||
void ToggleTimeDisplay();
|
||||
|
|
|
@ -98,6 +98,18 @@ void TrackSliderSlider::leaveEvent(QEvent* e) {
|
|||
popup_->hide();
|
||||
}
|
||||
|
||||
void TrackSliderSlider::keyPressEvent(QKeyEvent* event) {
|
||||
if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Down) {
|
||||
emit SeekBackward();
|
||||
event->accept();
|
||||
} else if (event->key() == Qt::Key_Right || event->key() == Qt::Key_Up) {
|
||||
emit SeekForward();
|
||||
event->accept();
|
||||
} else {
|
||||
QSlider::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackSliderSlider::UpdateDeltaTime() {
|
||||
if (popup_->isVisible()) {
|
||||
int delta_seconds = mouse_hover_seconds_ - (value() / kMsecPerSec);
|
||||
|
|
|
@ -29,12 +29,17 @@ class TrackSliderSlider : public QSlider {
|
|||
public:
|
||||
TrackSliderSlider(QWidget* parent = nullptr);
|
||||
|
||||
signals:
|
||||
void SeekForward();
|
||||
void SeekBackward();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent* e);
|
||||
void mouseReleaseEvent(QMouseEvent* e);
|
||||
void mouseMoveEvent(QMouseEvent* e);
|
||||
void enterEvent(QEvent*);
|
||||
void leaveEvent(QEvent*);
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
|
||||
private slots:
|
||||
void UpdateDeltaTime();
|
||||
|
|
Loading…
Reference in New Issue