diff --git a/doc/bindings b/doc/bindings index 8ac4ffbb..e623b53d 100644 --- a/doc/bindings +++ b/doc/bindings @@ -439,6 +439,9 @@ #def_key "m" # toggle_media_library_sort_mode # +#def_key "m" +# set_visualizer_sample_multiplier +# #def_key "n" # move_sort_order_down # diff --git a/doc/config b/doc/config index b6d926b7..f306d8c1 100644 --- a/doc/config +++ b/doc/config @@ -70,6 +70,12 @@ #visualizer_in_stereo = yes # ## +## Multiply received samples by given value. Very +## useful for proper visualization of quiet music. +## +#visualizer_sample_multipler = 1 +# +## ## Note: Below parameter defines how often ncmpcpp ## has to "synchronize" visualizer and audio outputs. ## 30 seconds is optimal value, but if you experience diff --git a/doc/ncmpcpp.1 b/doc/ncmpcpp.1 index 5bc2ddd5..ececc552 100644 --- a/doc/ncmpcpp.1 +++ b/doc/ncmpcpp.1 @@ -66,6 +66,9 @@ Path to mpd fifo output. This is needed to make music visualizer work (note that .B visualizer_output_name = NAME Name of output that provides data for visualizer. Needed to keep sound and visualization in sync. .TP +.B visualizer_sample_multiplier = NUMBER +Multiply received samples by given value. Very useful for proper visualization of quiet music. +.TP .B visualizer_sync_interval = SECONDS Defines interval between syncing visualizer and audio outputs. .TP diff --git a/src/actions.cpp b/src/actions.cpp index be8bb825..e7e5e710 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -2184,6 +2184,31 @@ void SetSelectedItemsPriority::run() myPlaylist->SetSelectedItemsPriority(prio); } +bool SetVisualizerSampleMultiplier::canBeRun() const +{ +# ifdef ENABLE_VISUALIZER + return myScreen == myVisualizer; +# else + return false; +# endif // ENABLE_VISUALIZER +} + +void SetVisualizerSampleMultiplier::run() +{ +# ifdef ENABLE_VISUALIZER + using Global::wFooter; + + Statusbar::lock(); + Statusbar::put() << "Set visualizer sample multiplier: "; + std::string smultiplier = wFooter->getString(); + Statusbar::unlock(); + + double multiplier = fromString(smultiplier); + lowerBoundCheck(multiplier, 1.0); + Config.visualizer_sample_multiplier = multiplier; +# endif // ENABLE_VISUALIZER +} + bool FilterPlaylistOnPriorities::canBeRun() const { return myScreen == myPlaylist; @@ -2612,6 +2637,7 @@ void populateActions() insert_action(new Actions::ToggleMediaLibrarySortMode()); insert_action(new Actions::RefetchLyrics()); insert_action(new Actions::SetSelectedItemsPriority()); + insert_action(new Actions::SetVisualizerSampleMultiplier()); insert_action(new Actions::FilterPlaylistOnPriorities()); insert_action(new Actions::ShowSongInfo()); insert_action(new Actions::ShowArtistInfo()); diff --git a/src/actions.h b/src/actions.h index 9f10a6ac..d828c2eb 100644 --- a/src/actions.h +++ b/src/actions.h @@ -52,9 +52,9 @@ enum class Type ToggleSpaceMode, ToggleAddMode, ToggleMouse, ToggleBitrateVisibility, AddRandomItems, ToggleBrowserSortMode, ToggleLibraryTagType, ToggleMediaLibrarySortMode, RefetchLyrics, - SetSelectedItemsPriority, FilterPlaylistOnPriorities, ShowSongInfo, - ShowArtistInfo, ShowLyrics, Quit, NextScreen, PreviousScreen, ShowHelp, - ShowPlaylist, ShowBrowser, ChangeBrowseMode, ShowSearchEngine, + SetSelectedItemsPriority, SetVisualizerSampleMultiplier, FilterPlaylistOnPriorities, + ShowSongInfo, ShowArtistInfo, ShowLyrics, Quit, NextScreen, PreviousScreen, + ShowHelp, ShowPlaylist, ShowBrowser, ChangeBrowseMode, ShowSearchEngine, ResetSearchEngine, ShowMediaLibrary, ToggleMediaLibraryColumnsMode, ShowPlaylistEditor, ShowTagEditor, ShowOutputs, ShowVisualizer, ShowClock, ShowServerInfo, @@ -959,6 +959,16 @@ protected: virtual void run(); }; +struct SetVisualizerSampleMultiplier : public BaseAction +{ + SetVisualizerSampleMultiplier() + : BaseAction(Type::SetVisualizerSampleMultiplier, "set_visualizer_sample_multiplier") { } + +protected: + virtual bool canBeRun() const; + virtual void run(); +}; + struct FilterPlaylistOnPriorities : public BaseAction { FilterPlaylistOnPriorities() diff --git a/src/bindings.cpp b/src/bindings.cpp index 1af815d2..d70f83f0 100644 --- a/src/bindings.cpp +++ b/src/bindings.cpp @@ -540,6 +540,7 @@ void BindingsConfiguration::generateDefaults() bind(k, Actions::Type::MoveSortOrderUp); bind(k, Actions::Type::MoveSelectedItemsUp); bind(k, Actions::Type::ToggleMediaLibrarySortMode); + bind(k, Actions::Type::SetVisualizerSampleMultiplier); } if (notBound(k = stringToKey("n"))) { diff --git a/src/help.cpp b/src/help.cpp index cccec8d7..a490c922 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -374,6 +374,7 @@ void write_bindings(NC::Scrollpad &w) # if defined(ENABLE_VISUALIZER) && defined(HAVE_FFTW3_H) key_section(w, "Music visualizer"); key(w, Type::PressSpace, "Toggle visualization type"); + key(w, Type::SetVisualizerSampleMultiplier, "Set visualizer sample multiplier"); # endif // ENABLE_VISUALIZER && HAVE_FFTW3_H mouse_section(w, "Global"); diff --git a/src/settings.cpp b/src/settings.cpp index 04cd9b77..3b85c2b7 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -221,6 +221,11 @@ bool Configuration::read(const std::string &config_path) p.add("visualizer_in_stereo", yes_no( visualizer_in_stereo, true )); + p.add("visualizer_sample_multiplier", assign_default( + visualizer_sample_multiplier, 1.0, [](double v) { + lowerBoundCheck(v, 1.0); + return v; + })); p.add("visualizer_sync_interval", assign_default( visualizer_sync_interval, 30, [](unsigned v) { return boost::posix_time::seconds(v); diff --git a/src/settings.h b/src/settings.h index 88d92e91..ddb812ba 100644 --- a/src/settings.h +++ b/src/settings.h @@ -176,6 +176,7 @@ struct Configuration 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; diff --git a/src/visualizer.cpp b/src/visualizer.cpp index 3c54ea98..56161b82 100644 --- a/src/visualizer.cpp +++ b/src/visualizer.cpp @@ -113,9 +113,19 @@ void Visualizer::update() else # endif // HAVE_FFTW3_H draw = &Visualizer::DrawSoundWave; - + + const ssize_t samples_read = data/sizeof(int16_t); + std::for_each(buf, buf+samples_read, [](int16_t &sample) { + int32_t tmp = sample * Config.visualizer_sample_multiplier; + if (tmp < std::numeric_limits::min()) + sample = std::numeric_limits::min(); + else if (tmp > std::numeric_limits::max()) + sample = std::numeric_limits::max(); + else + sample = tmp; + }); + w.clear(); - ssize_t samples_read = data/sizeof(int16_t); if (Config.visualizer_in_stereo) { int16_t buf_left[samples_read/2], buf_right[samples_read/2];