Support attaching format information to selected color variables

This commit is contained in:
Andrzej Rybczak
2016-12-22 16:31:41 +01:00
parent 9c13827b62
commit a488c2d89d
22 changed files with 492 additions and 175 deletions

View File

@@ -347,7 +347,13 @@ void SearchEngine::runAction()
found += 3; // don't count options inserted below
w.insertSeparator(ResetButton+1);
w.insertItem(ResetButton+2, SEItem(), NC::List::Properties::Bold | NC::List::Properties::Inactive);
w.at(ResetButton+2).value().mkBuffer() << Config.color1 << "Search results: " << Config.color2 << "Found " << found << (found > 1 ? " songs" : " song") << NC::Color::Default;
w.at(ResetButton+2).value().mkBuffer()
<< Config.color1
<< "Search results: "
<< NC::FormattedColor::End(Config.color1)
<< Config.color2
<< "Found " << found << (found > 1 ? " songs" : " song")
<< NC::FormattedColor::End(Config.color2);
w.insertSeparator(ResetButton+3);
markSongsInPlaylist(w);
Statusbar::print("Searching finished");

View File

@@ -95,11 +95,25 @@ void SongInfo::switchTo()
void SongInfo::PrepareSong(const MPD::Song &s)
{
w << NC::Format::Bold << Config.color1 << "Filename: " << NC::Format::NoBold << Config.color2 << s.getName() << '\n' << NC::Color::End;
w << NC::Format::Bold << "Directory: " << NC::Format::NoBold << Config.color2;
ShowTag(w, s.getDirectory());
w << "\n\n" << NC::Color::End;
w << NC::Format::Bold << "Length: " << NC::Format::NoBold << Config.color2 << s.getLength() << '\n' << NC::Color::End;
auto print_key_value = [this](const char *key, const auto &value) {
w << NC::Format::Bold
<< Config.color1
<< key
<< ":"
<< NC::FormattedColor::End(Config.color1)
<< NC::Format::NoBold
<< " "
<< Config.color2
<< value
<< NC::FormattedColor::End(Config.color2)
<< "\n";
};
print_key_value("Filename", s.getName());
print_key_value("Directory", ShowTag(s.getDirectory()));
w << "\n";
print_key_value("Length", s.getLength());
# ifdef HAVE_TAGLIB_H
if (!Config.mpd_music_dir.empty() && !s.isStream())
{
@@ -110,31 +124,23 @@ void SongInfo::PrepareSong(const MPD::Song &s)
TagLib::FileRef f(path_to_file.c_str());
if (!f.isNull())
{
std::string channels;
switch (f.audioProperties()->channels())
{
case 1:
channels = "Mono";
break;
case 2:
channels = "Stereo";
break;
default:
channels = boost::lexical_cast<std::string>(f.audioProperties()->channels());
break;
}
w << NC::Format::Bold << "Bitrate: " << NC::Format::NoBold << Config.color2 << f.audioProperties()->bitrate() << " kbps\n" << NC::Color::End;
w << NC::Format::Bold << "Sample rate: " << NC::Format::NoBold << Config.color2 << f.audioProperties()->sampleRate() << " Hz\n" << NC::Color::End;
w << NC::Format::Bold << "Channels: " << NC::Format::NoBold << Config.color2 << channels << NC::Color::End << "\n";
print_key_value(
"Bitrate",
boost::lexical_cast<std::string>(f.audioProperties()->bitrate()) + " kbps");
print_key_value(
"Sample rate",
boost::lexical_cast<std::string>(f.audioProperties()->sampleRate()) + " Hz");
print_key_value("Channels", channelsToString(f.audioProperties()->channels()));
auto rginfo = Tags::readReplayGain(f.file());
if (!rginfo.empty())
{
w << NC::Format::Bold << "\nReference loudness: " << NC::Format::NoBold << Config.color2 << rginfo.referenceLoudness() << NC::Color::End << "\n";
w << NC::Format::Bold << "Track gain: " << NC::Format::NoBold << Config.color2 << rginfo.trackGain() << NC::Color::End << "\n";
w << NC::Format::Bold << "Track peak: " << NC::Format::NoBold << Config.color2 << rginfo.trackPeak() << NC::Color::End << "\n";
w << NC::Format::Bold << "Album gain: " << NC::Format::NoBold << Config.color2 << rginfo.albumGain() << NC::Color::End << "\n";
w << NC::Format::Bold << "Album peak: " << NC::Format::NoBold << Config.color2 << rginfo.albumPeak() << NC::Color::End << "\n";
w << "\n";
print_key_value("Reference loudness", rginfo.referenceLoudness());
print_key_value("Track gain", rginfo.trackGain());
print_key_value("Track peak", rginfo.trackPeak());
print_key_value("Album gain", rginfo.albumGain());
print_key_value("Album peak", rginfo.albumPeak());
}
}
}
@@ -143,7 +149,7 @@ void SongInfo::PrepareSong(const MPD::Song &s)
for (const Metadata *m = Tags; m->Name; ++m)
{
w << NC::Format::Bold << '\n' << m->Name << ": " << NC::Format::NoBold;
w << NC::Format::Bold << "\n" << m->Name << ":" << NC::Format::NoBold << " ";
ShowTag(w, s.getTags(m->Get));
}
}

View File

@@ -551,7 +551,11 @@ void TagEditor::runAction()
*FParserLegend << "%C - comment\n\n";
*FParserLegend << NC::Format::Bold << "Files:\n" << NC::Format::NoBold;
for (auto it = EditedSongs.begin(); it != EditedSongs.end(); ++it)
*FParserLegend << Config.color2 << " * " << NC::Color::End << (*it)->getName() << '\n';
*FParserLegend << Config.color2
<< " * "
<< NC::FormattedColor::End(Config.color2)
<< (*it)->getName()
<< "\n";
FParserLegend->flush();
if (!Patterns.empty())
@@ -631,9 +635,14 @@ void TagEditor::runAction()
}
if (!FParserUsePreview)
s.setNewName(new_file + extension);
*FParserPreview << file << Config.color2 << " -> " << NC::Color::End;
*FParserPreview << file
<< Config.color2
<< " -> "
<< NC::FormattedColor::End(Config.color2);
if (new_file.empty())
*FParserPreview << Config.empty_tags_color << Config.empty_tag << NC::Color::End;
*FParserPreview << Config.empty_tags_color
<< Config.empty_tag
<< NC::FormattedColor::End(Config.empty_tags_color);
else
*FParserPreview << new_file << extension;
*FParserPreview << "\n\n";

View File

@@ -208,41 +208,69 @@ bool TinyTagEditor::getTags()
w.resizeList(24);
for (size_t i = 0; i < 7; ++i)
w.at(i).setInactive(true);
w[i].setInactive(true);
w.at(7).setSeparator(true);
w.at(19).setSeparator(true);
w.at(21).setSeparator(true);
w[7].setSeparator(true);
w[19].setSeparator(true);
w[21].setSeparator(true);
if (!Tags::extendedSetSupported(f.file()))
{
w.at(10).setInactive(true);
w[10].setInactive(true);
for (size_t i = 15; i <= 17; ++i)
w.at(i).setInactive(true);
w[i].setInactive(true);
}
w.highlight(8);
w.at(0).value() << NC::Format::Bold << Config.color1 << "Song name: " << NC::Format::NoBold << Config.color2 << itsEdited.getName() << NC::Color::End;
w.at(1).value() << NC::Format::Bold << Config.color1 << "Location in DB: " << NC::Format::NoBold << Config.color2;
ShowTag(w.at(1).value(), itsEdited.getDirectory());
w.at(1).value() << NC::Color::End;
w.at(3).value() << NC::Format::Bold << Config.color1 << "Length: " << NC::Format::NoBold << Config.color2 << itsEdited.getLength() << NC::Color::End;
w.at(4).value() << NC::Format::Bold << Config.color1 << "Bitrate: " << NC::Format::NoBold << Config.color2 << f.audioProperties()->bitrate() << " kbps" << NC::Color::End;
w.at(5).value() << NC::Format::Bold << Config.color1 << "Sample rate: " << NC::Format::NoBold << Config.color2 << f.audioProperties()->sampleRate() << " Hz" << NC::Color::End;
w.at(6).value() << NC::Format::Bold << Config.color1 << "Channels: " << NC::Format::NoBold << Config.color2 << (f.audioProperties()->channels() == 1 ? "Mono" : "Stereo") << NC::Color::Default;
auto print_key_value = [this](NC::Buffer &buf, const char *key, const auto &value) {
buf << NC::Format::Bold
<< Config.color1
<< key
<< ":"
<< NC::FormattedColor::End(Config.color1)
<< NC::Format::NoBold
<< " "
<< Config.color2
<< value
<< NC::FormattedColor::End(Config.color2);
};
print_key_value(w[0].value(), "Filename", itsEdited.getName());
print_key_value(w[1].value(), "Directory", ShowTag(itsEdited.getDirectory()));
print_key_value(w[3].value(), "Length", itsEdited.getLength());
print_key_value(
w[4].value(),
"Bitrate",
boost::lexical_cast<std::string>(f.audioProperties()->bitrate()) + " kbps");
print_key_value(
w[5].value(),
"Sample rate",
boost::lexical_cast<std::string>(f.audioProperties()->sampleRate()) + " Hz");
print_key_value(
w[6].value(),
"Channels",
channelsToString(f.audioProperties()->channels()));
unsigned pos = 8;
for (const SongInfo::Metadata *m = SongInfo::Tags; m->Name; ++m, ++pos)
{
w.at(pos).value() << NC::Format::Bold << m->Name << ":" << NC::Format::NoBold << ' ';
ShowTag(w.at(pos).value(), itsEdited.getTags(m->Get));
w[pos].value() << NC::Format::Bold
<< m->Name
<< ":"
<< NC::Format::NoBold
<< " ";
ShowTag(w[pos].value(), itsEdited.getTags(m->Get));
}
w.at(20).value() << NC::Format::Bold << "Filename:" << NC::Format::NoBold << ' ' << itsEdited.getName();
w[20].value() << NC::Format::Bold
<< "Filename:"
<< NC::Format::NoBold
<< " "
<< itsEdited.getName();
w.at(22).value() << "Save";
w.at(23).value() << "Cancel";
w[22].value() << "Save";
w[23].value() << "Cancel";
return true;
}

View File

@@ -51,9 +51,10 @@ namespace {
const int fps = 25;
// toColor: a scaling function for coloring. For numbers 0 to max this function returns
// a coloring from the lowest color to the highest, and colors will not loop from 0 to max.
const NC::Color &toColor(size_t number, size_t max, bool wrap = true)
// toColor: a scaling function for coloring. For numbers 0 to max this function
// returns a coloring from the lowest color to the highest, and colors will not
// loop from 0 to max.
const NC::FormattedColor &toColor(size_t number, size_t max, bool wrap = true)
{
const auto colors_size = Config.visualizer_colors.size();
const auto index = (number * colors_size) / max;
@@ -216,10 +217,11 @@ void Visualizer::DrawSoundWave(int16_t *buf, ssize_t samples, size_t y_offset, s
return;
auto draw_point = [&](size_t x, int32_t y) {
auto c = toColor(std::abs(y), half_height, false);
w << NC::XY(x, base_y+y)
<< toColor(std::abs(y), half_height, false)
<< Config.visualizer_chars[0]
<< NC::Color::End;
<< c
<< Config.visualizer_chars[0]
<< NC::FormattedColor::End(c);
};
int32_t point_y, prev_point_y = 0;
@@ -263,9 +265,10 @@ void Visualizer::DrawSoundWaveStereo(int16_t *buf_left, int16_t *buf_right, ssiz
/**********************************************************************/
// DrawSoundWaveFill: This visualizer is very similar to DrawSoundWave, but instead of
// a single line the entire height is filled. In stereo mode, the top half of the screen
// is dedicated to the right channel, the bottom the left channel.
// DrawSoundWaveFill: This visualizer is very similar to DrawSoundWave, but
// instead of a single line the entire height is filled. In stereo mode, the top
// half of the screen is dedicated to the right channel, the bottom the left
// channel.
void Visualizer::DrawSoundWaveFill(int16_t *buf, ssize_t samples, size_t y_offset, size_t height)
{
// if right channel is drawn, bars descend from the top to the bottom
@@ -291,11 +294,12 @@ void Visualizer::DrawSoundWaveFill(int16_t *buf, ssize_t samples, size_t y_offse
for (int32_t j = 0; j < point_y; ++j)
{
auto c = toColor(j, height);
size_t y = flipped ? y_offset+j : y_offset+height-j-1;
w << NC::XY(x, y)
<< toColor(j, height)
<< Config.visualizer_chars[1]
<< NC::Color::End;
<< c
<< Config.visualizer_chars[1]
<< NC::FormattedColor::End(c);
}
}
}
@@ -308,13 +312,13 @@ void Visualizer::DrawSoundWaveFillStereo(int16_t *buf_left, int16_t *buf_right,
/**********************************************************************/
// draws the sound wave as an ellipse with origin in the center of the screen
// Draws the sound wave as an ellipse with origin in the center of the screen.
void Visualizer::DrawSoundEllipse(int16_t *buf, ssize_t samples, size_t, size_t height)
{
const size_t half_width = w.getWidth()/2;
const size_t half_height = height/2;
// make it so that the loop goes around the ellipse exactly once
// Make it so that the loop goes around the ellipse exactly once.
const double deg_multiplier = 2*boost::math::constants::pi<double>()/samples;
int32_t x, y;
@@ -325,30 +329,33 @@ void Visualizer::DrawSoundEllipse(int16_t *buf, ssize_t samples, size_t, size_t
y = half_height * std::sin(i*deg_multiplier);
max_radius = sqrt(x*x + y*y);
// calculate the distance of the sample from the center,
// where 0 is the center of the ellipse and 1 is its border
// Calculate the distance of the sample from the center, where 0 is the
// center of the ellipse and 1 is its border.
radius = std::abs(buf[i]);
radius /= 32768.0;
// appropriately scale the position
// Appropriately scale the position.
x *= radius;
y *= radius;
auto c = toColor(sqrt(x*x + y*y), max_radius, false);
w << NC::XY(half_width + x, half_height + y)
<< toColor(sqrt(x*x + y*y), max_radius, false)
<< Config.visualizer_chars[0]
<< NC::Color::End;
<< c
<< Config.visualizer_chars[0]
<< NC::FormattedColor::End(c);
}
}
// DrawSoundEllipseStereo: This visualizer only works in stereo. The colors form concentric
// rings originating from the center (width/2, height/2). For any given point, the width is
// scaled with the left channel and height is scaled with the right channel. For example,
// if a song is entirely in the right channel, then it would just be a vertical line.
// DrawSoundEllipseStereo: This visualizer only works in stereo. The colors form
// concentric rings originating from the center (width/2, height/2). For any
// given point, the width is scaled with the left channel and height is scaled
// with the right channel. For example, if a song is entirely in the right
// channel, then it would just be a vertical line.
//
// Since every font/terminal is different, the visualizer is never a perfect circle. This
// visualizer assume the font height is twice the length of the font's width. If the font
// is skinner or wider than this, instead of a circle it will be an ellipse.
// Since every font/terminal is different, the visualizer is never a perfect
// circle. This visualizer assume the font height is twice the length of the
// font's width. If the font is skinner or wider than this, instead of a circle
// it will be an ellipse.
void Visualizer::DrawSoundEllipseStereo(int16_t *buf_left, int16_t *buf_right, ssize_t samples, size_t half_height)
{
const size_t width = w.getWidth();
@@ -365,14 +372,16 @@ void Visualizer::DrawSoundEllipseStereo(int16_t *buf_left, int16_t *buf_right, s
x = buf_left[i]/32768.0 * (buf_left[i] < 0 ? left_half_width : right_half_width);
y = buf_right[i]/32768.0 * (buf_right[i] < 0 ? top_half_height : bottom_half_height);
// The arguments to the toColor function roughly follow a circle equation where
// the center is not centered around (0,0). For example (x - w)^2 + (y-h)+2 = r^2
// centers the circle around the point (w,h). Because fonts are not all the same
// size, this will not always generate a perfect circle.
w << toColor(sqrt(x*x + 4*y*y), radius)
<< NC::XY(left_half_width + x, top_half_height + y)
<< Config.visualizer_chars[1]
<< NC::Color::End;
// The arguments to the toColor function roughly follow a circle equation
// where the center is not centered around (0,0). For example (x - w)^2 +
// (y-h)+2 = r^2 centers the circle around the point (w,h). Because fonts
// are not all the same size, this will not always generate a perfect
// circle.
auto c = toColor(sqrt(x*x + 4*y*y), radius);
w << NC::XY(left_half_width + x, top_half_height + y)
<< c
<< Config.visualizer_chars[1]
<< NC::FormattedColor::End(c);
}
}
@@ -381,7 +390,7 @@ void Visualizer::DrawSoundEllipseStereo(int16_t *buf_left, int16_t *buf_right, s
#ifdef HAVE_FFTW3_H
void Visualizer::DrawFrequencySpectrum(int16_t *buf, ssize_t samples, size_t y_offset, size_t height)
{
// if right channel is drawn, bars descend from the top to the bottom
// If right channel is drawn, bars descend from the top to the bottom.
const bool flipped = y_offset > 0;
// copy samples to fftw input array
@@ -389,7 +398,7 @@ void Visualizer::DrawFrequencySpectrum(int16_t *buf, ssize_t samples, size_t y_o
m_fftw_input[i] = i < samples ? buf[i] : 0;
fftw_execute(m_fftw_plan);
// count magnitude of each frequency and scale it to fit the screen
// Count magnitude of each frequency and scale it to fit the screen.
for (size_t i = 0; i < m_fftw_results; ++i)
m_freq_magnitudes[i] = sqrt(
m_fftw_output[i][0]*m_fftw_output[i][0]
@@ -397,7 +406,7 @@ void Visualizer::DrawFrequencySpectrum(int16_t *buf, ssize_t samples, size_t y_o
)/2e4*height;
const size_t win_width = w.getWidth();
// cut bandwidth a little to achieve better look
// Cut bandwidth a little to achieve better look.
const double bins_per_bar = m_fftw_results/win_width * 7/10;
double bar_height;
size_t bar_bound_height;
@@ -406,19 +415,20 @@ void Visualizer::DrawFrequencySpectrum(int16_t *buf, ssize_t samples, size_t y_o
bar_height = 0;
for (int j = 0; j < bins_per_bar; ++j)
bar_height += m_freq_magnitudes[x*bins_per_bar+j];
// buff higher frequencies
// Buff higher frequencies.
bar_height *= log2(2 + x) * 100.0/win_width;
// moderately normalize the heights
// Moderately normalize the heights.
bar_height = pow(bar_height, 0.5);
bar_bound_height = std::min(std::size_t(bar_height/bins_per_bar), height);
for (size_t j = 0; j < bar_bound_height; ++j)
{
size_t y = flipped ? y_offset+j : y_offset+height-j-1;
auto c = toColor(j, height);
w << NC::XY(x, y)
<< toColor(j, height)
<< Config.visualizer_chars[1]
<< NC::Color::End;
<< c
<< Config.visualizer_chars[1]
<< NC::FormattedColor::End(c);
}
}
}
@@ -495,5 +505,3 @@ void Visualizer::ResetAutoScaleMultiplier()
}
#endif // ENABLE_VISUALIZER
/* vim: set tabstop=4 softtabstop=4 shiftwidth=4 noexpandtab : */