visualizer: add filled wave visualizer

This commit is contained in:
Darby Payne
2014-10-20 23:09:55 -07:00
committed by Andrzej Rybczak
parent 9bab03e4b2
commit 1f2daaa08c
7 changed files with 119 additions and 46 deletions

View File

@@ -39,4 +39,6 @@ enum class Design { Classic, Alternative };
std::ostream &operator<<(std::ostream &os, Design ui);
std::istream &operator>>(std::istream &is, Design &ui);
enum class VisualizerType { Wave, WaveFilled, Spectrum };
#endif // NCMPCPP_ENUMS_H

View File

@@ -231,13 +231,8 @@ bool Configuration::read(const std::string &config_path)
return boost::posix_time::seconds(v);
}));
p.add("visualizer_type", option_parser::worker([this](std::string &&v) {
if (v == "wave")
visualizer_use_wave = true;
else if (v == "spectrum")
visualizer_use_wave = false;
else
throw std::runtime_error("invalid argument: " + v);
}, defaults_to(visualizer_use_wave, true)
visualizer_type = stringToVisualizerType( v );
}, defaults_to(visualizer_type, VisualizerType::Wave)
));
p.add("visualizer_look", assign_default<std::string>(
visualizer_chars, "●▮", [](std::string &&s) {
@@ -649,3 +644,5 @@ bool Configuration::read(const std::string &config_path)
std::ifstream f(config_path);
return p.run(f);
}
/* vim: set tabstop=4 softtabstop=4 shiftwidth=4 noexpandtab : */

View File

@@ -34,7 +34,7 @@
struct Column
{
Column() : stretch_limit(-1), right_alignment(0), display_empty_tag(1) { }
std::wstring name;
std::string type;
int width;
@@ -50,12 +50,12 @@ struct Configuration
Configuration()
: playlist_disable_highlight_delay(0), visualizer_sync_interval(0)
{ }
bool read(const std::string &config_path);
std::string ncmpcpp_directory;
std::string lyrics_directory;
std::string mpd_music_dir;
std::string visualizer_fifo_path;
std::string visualizer_output_name;
@@ -78,7 +78,7 @@ struct Configuration
std::string lastfm_preferred_language;
std::wstring progressbar;
std::wstring visualizer_chars;
std::string pattern;
std::vector<Column> columns;
@@ -94,7 +94,7 @@ struct Configuration
NC::Buffer now_playing_prefix;
NC::Buffer now_playing_suffix;
NC::Buffer modified_item_prefix;
NC::Color color1;
NC::Color color2;
NC::Color empty_tags_color;
@@ -109,17 +109,19 @@ struct Configuration
NC::Color statusbar_color;
NC::Color alternative_ui_separator_color;
NC::Color active_column_color;
std::vector<NC::Color> visualizer_colors;
VisualizerType visualizer_type;
NC::Border window_border;
NC::Border active_window_border;
Design design;
SpaceAddMode space_add_mode;
mpd_tag_type media_lib_primary_tag;
bool colors_enabled;
bool playlist_show_remaining_time;
bool playlist_shorten_total_times;
@@ -151,7 +153,6 @@ struct Configuration
bool ask_before_clearing_playlists;
bool mouse_support;
bool mouse_list_scroll_whole_page;
bool visualizer_use_wave;
bool visualizer_in_stereo;
bool data_fetching_delay;
bool media_library_sort_by_mtime;
@@ -162,7 +163,7 @@ struct Configuration
bool ask_for_locked_screen_width_part;
bool allow_for_physical_item_deletion;
bool progressbar_boldness;
unsigned mpd_connection_timeout;
unsigned crossfade_time;
unsigned seek_time;
@@ -173,21 +174,21 @@ struct Configuration
unsigned search_engine_default_search_mode;
boost::regex::flag_type regex_type;
boost::posix_time::seconds playlist_disable_highlight_delay;
boost::posix_time::seconds visualizer_sync_interval;
double visualizer_sample_multiplier;
double locked_screen_width_part;
size_t selected_item_prefix_length;
size_t selected_item_suffix_length;
size_t now_playing_prefix_length;
size_t now_playing_suffix_length;
ScreenType startup_screen_type;
std::list<ScreenType> screen_sequence;
SortMode browser_sort_mode;
};

View File

@@ -43,6 +43,18 @@ NC::Color stringToColor(const std::string &color)
return result;
}
VisualizerType stringToVisualizerType(const std::string &visualizerType)
{
VisualizerType result = VisualizerType::Wave;
if (visualizerType == "wave")
result = VisualizerType::Wave;
else if (visualizerType == "spectrum")
result = VisualizerType::Spectrum;
else if (visualizerType == "wave_filled")
result = VisualizerType::WaveFilled;
return result;
}
NC::Border stringToBorder(const std::string &border)
{
NC::Border result = NC::Border::None;

View File

@@ -24,8 +24,10 @@
#include "mpdpp.h"
#include "mutable_song.h"
#include "window.h"
#include "enums.h"
NC::Color stringToColor(const std::string &color);
VisualizerType stringToVisualizerType(const std::string &visualizerType);
NC::Border stringToBorder(const std::string &border);
std::string tagTypeToString(mpd_tag_type tag);

View File

@@ -37,6 +37,7 @@
#include "title.h"
#include "screen_switcher.h"
#include "status.h"
#include "enums.h"
using Global::MainStartY;
using Global::MainHeight;
@@ -92,13 +93,13 @@ void Visualizer::update()
{
if (m_fifo < 0)
return;
// PCM in format 44100:16:1 (for mono visualization) and 44100:16:2 (for stereo visualization) is supported
int16_t buf[m_samples];
ssize_t data = read(m_fifo, buf, sizeof(buf));
if (data < 0) // no data available in fifo
return;
if (m_output_id != -1 && Global::Timer - m_timer > Config.visualizer_sync_interval)
{
Mpd.DisableOutput(m_output_id);
@@ -106,13 +107,16 @@ void Visualizer::update()
Mpd.EnableOutput(m_output_id);
m_timer = Global::Timer;
}
void (Visualizer::*draw)(int16_t *, ssize_t, size_t, size_t);
# ifdef HAVE_FFTW3_H
if (!Config.visualizer_use_wave)
if (Config.visualizer_type == VisualizerType::Spectrum)
draw = &Visualizer::DrawFrequencySpectrum;
else
# endif // HAVE_FFTW3_H
if (Config.visualizer_type == VisualizerType::WaveFilled)
draw = &Visualizer::DrawSoundWaveFill;
else
draw = &Visualizer::DrawSoundWave;
const ssize_t samples_read = data/sizeof(int16_t);
@@ -137,7 +141,7 @@ void Visualizer::update()
}
size_t half_height = MainHeight/2;
(this->*draw)(buf_left, samples_read/2, 0, half_height);
(this->*draw)(buf_right, samples_read/2, half_height+(draw == &Visualizer::DrawSoundWave ? 1 : 0), half_height+(draw != &Visualizer::DrawSoundWave ? 1 : 0));
(this->*draw)(buf_right, samples_read/2, half_height+(draw == &Visualizer::DrawFrequencySpectrum ? 0 : 1), half_height+(draw != &Visualizer::DrawFrequencySpectrum ? 0 : 1));
}
else
(this->*draw)(buf, samples_read, 0, MainHeight);
@@ -154,12 +158,63 @@ int Visualizer::windowTimeout()
void Visualizer::spacePressed()
{
std::string visualizerName;
if (Config.visualizer_type == VisualizerType::Wave)
{
Config.visualizer_type = VisualizerType::WaveFilled;
visualizerName = "sound wave filled";
}
# ifdef HAVE_FFTW3_H
Config.visualizer_use_wave = !Config.visualizer_use_wave;
Statusbar::printf("Visualization type: %1%",
Config.visualizer_use_wave ? "sound wave" : "frequency spectrum"
);
else if (Config.visualizer_type == VisualizerType::WaveFilled)
{
Config.visualizer_type = VisualizerType::Spectrum;
visualizerName = "frequency spectrum";
}
# endif // HAVE_FFTW3_H
else
{
Config.visualizer_type = VisualizerType::Wave;
visualizerName = "sound wave";
}
Statusbar::printf("Visualization type: %1%", visualizerName.c_str());
}
NC::Color Visualizer::toColor( int number, int max )
{
const int colorMapSize = Config.visualizer_colors.size();
const int normalizedNumber = ( ( number * colorMapSize ) / max ) % colorMapSize;
return Config.visualizer_colors[normalizedNumber];
}
void Visualizer::DrawSoundWaveFill(int16_t *buf, ssize_t samples, size_t y_offset, size_t height)
{
const int samples_per_col = samples/w.getWidth();
const int half_height = height/2;
double prev_point_pos = 0;
const size_t win_width = w.getWidth();
const bool left = y_offset > 0;
int x = 0;
for (size_t i = 0; i < win_width; ++i)
{
double point_pos = 0;
for (int j = 0; j < samples_per_col; ++j)
point_pos += buf[i*samples_per_col+j];
point_pos /= samples_per_col;
point_pos /= std::numeric_limits<int16_t>::max();
point_pos *= half_height;
for (int k = 0; k < point_pos * 2; k += 1)
{
x = left ? height + k : height - k;
if ( x > 0 && x < w.getHeight() && (i-(k < half_height + point_pos)) > 0 && (i-(k < half_height + point_pos)) < w.getWidth() )
{
w << toColor( k, height )
<< NC::XY(i-(k < half_height + point_pos), x)
<< Config.visualizer_chars[1]
<< NC::Color::End;
}
}
}
}
void Visualizer::DrawSoundWave(int16_t *buf, ssize_t samples, size_t y_offset, size_t height)
@@ -183,7 +238,7 @@ void Visualizer::DrawSoundWave(int16_t *buf, ssize_t samples, size_t y_offset, s
Config.visualizer_colors.size()), Config.visualizer_colors.size() - 1)]
<< Config.visualizer_chars[0]
<< NC::Color::End;
if (i && abs(prev_point_pos-point_pos) > 2)
{
// if gap is too big. intermediate values are needed
@@ -211,13 +266,13 @@ void Visualizer::DrawFrequencySpectrum(int16_t *buf, ssize_t samples, size_t y_o
else
m_fftw_input[i] = 0;
}
fftw_execute(m_fftw_plan);
// count magnitude of each frequency and scale it to fit the screen
for (unsigned i = 0; i < m_fftw_results; ++i)
m_freq_magnitudes[i] = sqrt(m_fftw_output[i][0]*m_fftw_output[i][0] + m_fftw_output[i][1]*m_fftw_output[i][1])/2e4*height;
const size_t win_width = w.getWidth();
// cut bandwidth a little to achieve better look
const int freqs_per_col = m_fftw_results/win_width * 7/10;
@@ -282,3 +337,4 @@ void Visualizer::FindOutputID()
#endif // ENABLE_VISUALIZER
/* vim: set tabstop=4 softtabstop=4 shiftwidth=4 noexpandtab : */

View File

@@ -37,41 +37,43 @@
struct Visualizer: Screen<NC::Window>, Tabbable
{
Visualizer();
virtual void switchTo() OVERRIDE;
virtual void resize() OVERRIDE;
virtual std::wstring title() OVERRIDE;
virtual ScreenType type() OVERRIDE { return ScreenType::Visualizer; }
virtual void update() OVERRIDE;
virtual void scroll(NC::Scroll) OVERRIDE { }
virtual int windowTimeout() OVERRIDE;
virtual void enterPressed() OVERRIDE { }
virtual void spacePressed() OVERRIDE;
virtual void mouseButtonPressed(MEVENT) OVERRIDE { }
virtual bool isMergable() OVERRIDE { return true; }
// private members
void SetFD();
void ResetFD();
void FindOutputID();
protected:
virtual bool isLockable() OVERRIDE { return true; }
private:
NC::Color toColor(int, int);
void DrawSoundWave(int16_t *, ssize_t, size_t, size_t);
void DrawSoundWaveFill(int16_t *, ssize_t, size_t, size_t);
# ifdef HAVE_FFTW3_H
void DrawFrequencySpectrum(int16_t *, ssize_t, size_t, size_t);
# endif // HAVE_FFTW3_H
int m_output_id;
boost::posix_time::ptime m_timer;
int m_fifo;
unsigned m_samples;
# ifdef HAVE_FFTW3_H
@@ -89,3 +91,4 @@ extern Visualizer *myVisualizer;
#endif // NCMPCPP_VISUALIZER_H
/* vim: set tabstop=4 softtabstop=4 shiftwidth=4 noexpandtab : */