@@ -9,134 +9,42 @@ std::shared_ptr<waybar::modules::cava::CavaBackend> waybar::modules::cava::CavaB
99 return backend_ptr;
1010}
1111
12- waybar::modules::cava::CavaBackend::CavaBackend (const Json::Value& config) {
12+ waybar::modules::cava::CavaBackend::CavaBackend (const Json::Value& config) : config_(config) {
1313 // Load waybar module config
14- char cfgPath[PATH_MAX];
15- cfgPath[0 ] = ' \0 ' ;
16-
17- if (config[" cava_config" ].isString ()) strcpy (cfgPath, config[" cava_config" ].asString ().data ());
18- // Load cava config
19- error_.length = 0 ;
20-
21- if (!load_config (cfgPath, &prm_, false , &error_, 0 )) {
22- spdlog::error (" cava backend. Error loading config. {0}" , error_.message );
23- exit (EXIT_FAILURE);
24- }
25-
26- // Override cava parameters by the user config
27- prm_.inAtty = 0 ;
28- prm_.output = ::cava::output_method::OUTPUT_RAW;
29- if (prm_.data_format ) free (prm_.data_format );
30- prm_.data_format = strdup (" ascii" );
31- if (prm_.raw_target ) free (prm_.raw_target );
32- prm_.raw_target = strdup (" /dev/stdout" );
33- prm_.ascii_range = config[" format-icons" ].size () - 1 ;
34-
35- prm_.bar_width = 2 ;
36- prm_.bar_spacing = 0 ;
37- prm_.bar_height = 32 ;
38- prm_.bar_width = 1 ;
39- prm_.orientation = ::cava::ORIENT_TOP;
40- prm_.xaxis = ::cava::xaxis_scale::NONE;
41- prm_.mono_opt = ::cava::AVERAGE;
42- prm_.autobars = 0 ;
43- prm_.gravity = 0 ;
44- prm_.integral = 1 ;
45-
46- if (config[" framerate" ].isInt ()) prm_.framerate = config[" framerate" ].asInt ();
47- // Calculate delay for Update() thread
48- frame_time_milsec_ = std::chrono::milliseconds ((int )(1e3 / prm_.framerate ));
49- if (config[" autosens" ].isInt ()) prm_.autosens = config[" autosens" ].asInt ();
50- if (config[" sensitivity" ].isInt ()) prm_.sens = config[" sensitivity" ].asInt ();
51- if (config[" bars" ].isInt ()) prm_.fixedbars = config[" bars" ].asInt ();
52- if (config[" lower_cutoff_freq" ].isNumeric ())
53- prm_.lower_cut_off = config[" lower_cutoff_freq" ].asLargestInt ();
54- if (config[" higher_cutoff_freq" ].isNumeric ())
55- prm_.upper_cut_off = config[" higher_cutoff_freq" ].asLargestInt ();
56- if (config[" sleep_timer" ].isInt ()) prm_.sleep_timer = config[" sleep_timer" ].asInt ();
57- if (config[" method" ].isString ())
58- prm_.input = ::cava::input_method_by_name (config[" method" ].asString ().c_str ());
59- if (config[" source" ].isString ()) {
60- if (prm_.audio_source ) free (prm_.audio_source );
61- prm_.audio_source = config[" source" ].asString ().data ();
62- }
63- if (config[" sample_rate" ].isNumeric ()) prm_.samplerate = config[" sample_rate" ].asLargestInt ();
64- if (config[" sample_bits" ].isInt ()) prm_.samplebits = config[" sample_bits" ].asInt ();
65- if (config[" stereo" ].isBool ()) prm_.stereo = config[" stereo" ].asBool ();
66- if (config[" reverse" ].isBool ()) prm_.reverse = config[" reverse" ].asBool ();
67- if (config[" bar_delimiter" ].isInt ()) prm_.bar_delim = config[" bar_delimiter" ].asInt ();
68- if (config[" monstercat" ].isBool ()) prm_.monstercat = config[" monstercat" ].asBool ();
69- if (config[" waves" ].isBool ()) prm_.waves = config[" waves" ].asBool ();
70- if (config[" noise_reduction" ].isDouble ())
71- prm_.noise_reduction = config[" noise_reduction" ].asDouble ();
72- if (config[" input_delay" ].isInt ())
73- fetch_input_delay_ = std::chrono::seconds (config[" input_delay" ].asInt ());
74-
75- audio_raw_.height = prm_.ascii_range ;
76- audio_data_.format = -1 ;
77- audio_data_.rate = 0 ;
78- audio_data_.samples_counter = 0 ;
79- audio_data_.channels = 2 ;
80- audio_data_.IEEE_FLOAT = 0 ;
81- audio_data_.input_buffer_size = BUFFER_SIZE * audio_data_.channels ;
82- audio_data_.cava_buffer_size = audio_data_.input_buffer_size * 8 ;
83- audio_data_.terminate = 0 ;
84- audio_data_.suspendFlag = false ;
85- input_source_ = get_input (&audio_data_, &prm_);
86-
87- if (!input_source_) {
88- spdlog::error (" cava backend API didn't provide input audio source method" );
89- exit (EXIT_FAILURE);
90- }
91-
92- // Make cava parameters configuration
93- // Init cava plan, audio_raw structure
94- audio_raw_init (&audio_data_, &audio_raw_, &prm_, &plan_);
95- if (!plan_) spdlog::error (" cava backend plan is not provided" );
96- audio_raw_.previous_frame [0 ] = -1 ; // For first Update() call need to rePaint text message
14+ loadConfig ();
9715 // Read audio source trough cava API. Cava orginizes this process via infinity loop
9816 read_thread_ = [this ] {
17+ // Thread safe reading incoming source and do callbacks
18+ doOutReadConnect ();
19+
9920 try {
10021 input_source_ (&audio_data_);
10122 } catch (const std::runtime_error& e) {
10223 spdlog::warn (" Cava backend. Read source error: {0}" , e.what ());
10324 }
10425 read_thread_.sleep_for (fetch_input_delay_);
105- };
106-
107- thread_ = [this ] {
108- doUpdate ();
109- thread_.sleep_for (frame_time_milsec_);
26+ loadConfig ();
11027 };
11128}
11229
113- waybar::modules::cava::CavaBackend::~CavaBackend () {
114- thread_.stop ();
115- read_thread_.stop ();
116- cava_destroy (plan_);
117- delete plan_;
118- plan_ = nullptr ;
119- audio_raw_clean (&audio_raw_);
120- pthread_mutex_lock (&audio_data_.lock );
121- audio_data_.terminate = 1 ;
122- pthread_mutex_unlock (&audio_data_.lock );
123- config_clean (&prm_);
124- free (audio_data_.source );
125- free (audio_data_.cava_in );
126- }
30+ waybar::modules::cava::CavaBackend::~CavaBackend () { freeBackend (); }
12731
128- static void upThreadDelay (std::chrono::milliseconds& delay, std::chrono::seconds& delta) {
32+ static bool upThreadDelay (std::chrono::milliseconds& delay, std::chrono::seconds& delta) {
12933 if (delta == std::chrono::seconds{0 }) {
13034 delta += std::chrono::seconds{1 };
13135 delay += delta;
36+ return true ;
13237 }
38+ return false ;
13339}
13440
135- static void downThreadDelay (std::chrono::milliseconds& delay, std::chrono::seconds& delta) {
41+ static bool downThreadDelay (std::chrono::milliseconds& delay, std::chrono::seconds& delta) {
13642 if (delta > std::chrono::seconds{0 }) {
13743 delay -= delta;
13844 delta -= std::chrono::seconds{1 };
45+ return true ;
13946 }
47+ return false ;
14048}
14149
14250bool waybar::modules::cava::CavaBackend::isSilence () {
@@ -186,6 +94,7 @@ void waybar::modules::cava::CavaBackend::doPauseResume() {
18694 upThreadDelay (frame_time_milsec_, suspend_silence_delay_);
18795 }
18896 pthread_mutex_unlock (&audio_data_.lock );
97+ doOutReadConnect ();
18998}
19099
191100waybar::modules::cava::CavaBackend::type_signal_update
@@ -215,12 +124,129 @@ void waybar::modules::cava::CavaBackend::doUpdate(bool force) {
215124 }
216125
217126 if (!silence_ || prm_.sleep_timer == 0 ) {
218- downThreadDelay (frame_time_milsec_, suspend_silence_delay_);
127+ if ( downThreadDelay (frame_time_milsec_, suspend_silence_delay_)) doOutReadConnect ( );
219128 execute ();
220129 if (re_paint_ == 1 || force) m_signal_update_.emit (output_);
221130 } else {
222- upThreadDelay (frame_time_milsec_, suspend_silence_delay_);
131+ if ( upThreadDelay (frame_time_milsec_, suspend_silence_delay_)) doOutReadConnect ( );
223132 if (silence_ != silence_prev_ || force) m_signal_silence_.emit ();
224133 }
225134 silence_prev_ = silence_;
226135}
136+
137+ void waybar::modules::cava::CavaBackend::freeBackend () {
138+ out_thread_.disconnect ();
139+
140+ if (plan_ != NULL ) {
141+ cava_destroy (plan_);
142+ delete plan_;
143+ plan_ = NULL ;
144+ }
145+
146+ audio_raw_clean (&audio_raw_);
147+ pthread_mutex_lock (&audio_data_.lock );
148+ audio_data_.terminate = 1 ;
149+ pthread_mutex_unlock (&audio_data_.lock );
150+ free_config (&prm_);
151+ free (audio_data_.source );
152+ free (audio_data_.cava_in );
153+ }
154+
155+ void waybar::modules::cava::CavaBackend::loadConfig () {
156+ freeBackend ();
157+ // Load waybar module config
158+ char cfgPath[PATH_MAX];
159+ cfgPath[0 ] = ' \0 ' ;
160+
161+ if (config_[" cava_config" ].isString ()) strcpy (cfgPath, config_[" cava_config" ].asString ().data ());
162+ // Load cava config
163+ error_.length = 0 ;
164+
165+ if (!load_config (cfgPath, &prm_, &error_)) {
166+ spdlog::error (" cava backend. Error loading config. {0}" , error_.message );
167+ exit (EXIT_FAILURE);
168+ }
169+
170+ // Override cava parameters by the user config
171+ prm_.inAtty = 0 ;
172+ prm_.output = ::cava::output_method::OUTPUT_RAW;
173+ if (prm_.data_format ) free (prm_.data_format );
174+ prm_.data_format = strdup (" ascii" );
175+ if (prm_.raw_target ) free (prm_.raw_target );
176+ prm_.raw_target = strdup (" /dev/stdout" );
177+ prm_.ascii_range = config_[" format-icons" ].size () - 1 ;
178+
179+ prm_.bar_width = 2 ;
180+ prm_.bar_spacing = 0 ;
181+ prm_.bar_height = 32 ;
182+ prm_.bar_width = 1 ;
183+ prm_.orientation = ::cava::ORIENT_TOP;
184+ prm_.xaxis = ::cava::xaxis_scale::NONE;
185+ prm_.mono_opt = ::cava::AVERAGE;
186+ prm_.autobars = 0 ;
187+ prm_.gravity = 0 ;
188+ prm_.integral = 1 ;
189+
190+ if (config_[" framerate" ].isInt ()) prm_.framerate = config_[" framerate" ].asInt ();
191+ // Calculate delay for Update() thread
192+ frame_time_milsec_ = std::chrono::milliseconds ((int )(1e3 / prm_.framerate ));
193+ if (config_[" autosens" ].isInt ()) prm_.autosens = config_[" autosens" ].asInt ();
194+ if (config_[" sensitivity" ].isInt ()) prm_.sens = config_[" sensitivity" ].asInt ();
195+ if (config_[" bars" ].isInt ()) prm_.fixedbars = config_[" bars" ].asInt ();
196+ if (config_[" lower_cutoff_freq" ].isNumeric ())
197+ prm_.lower_cut_off = config_[" lower_cutoff_freq" ].asLargestInt ();
198+ if (config_[" higher_cutoff_freq" ].isNumeric ())
199+ prm_.upper_cut_off = config_[" higher_cutoff_freq" ].asLargestInt ();
200+ if (config_[" sleep_timer" ].isInt ()) prm_.sleep_timer = config_[" sleep_timer" ].asInt ();
201+ if (config_[" method" ].isString ())
202+ prm_.input = ::cava::input_method_by_name (config_[" method" ].asString ().c_str ());
203+ if (config_[" source" ].isString ()) {
204+ if (prm_.audio_source ) free (prm_.audio_source );
205+ prm_.audio_source = config_[" source" ].asString ().data ();
206+ }
207+ if (config_[" sample_rate" ].isNumeric ()) prm_.samplerate = config_[" sample_rate" ].asLargestInt ();
208+ if (config_[" sample_bits" ].isInt ()) prm_.samplebits = config_[" sample_bits" ].asInt ();
209+ if (config_[" stereo" ].isBool ()) prm_.stereo = config_[" stereo" ].asBool ();
210+ if (config_[" reverse" ].isBool ()) prm_.reverse = config_[" reverse" ].asBool ();
211+ if (config_[" bar_delimiter" ].isInt ()) prm_.bar_delim = config_[" bar_delimiter" ].asInt ();
212+ if (config_[" monstercat" ].isBool ()) prm_.monstercat = config_[" monstercat" ].asBool ();
213+ if (config_[" waves" ].isBool ()) prm_.waves = config_[" waves" ].asBool ();
214+ if (config_[" noise_reduction" ].isDouble ())
215+ prm_.noise_reduction = config_[" noise_reduction" ].asDouble ();
216+ if (config_[" input_delay" ].isInt ())
217+ fetch_input_delay_ = std::chrono::seconds (config_[" input_delay" ].asInt ());
218+
219+ audio_raw_.height = prm_.ascii_range ;
220+ audio_data_.format = -1 ;
221+ audio_data_.rate = 0 ;
222+ audio_data_.samples_counter = 0 ;
223+ audio_data_.channels = 2 ;
224+ audio_data_.IEEE_FLOAT = 0 ;
225+ audio_data_.input_buffer_size = BUFFER_SIZE * audio_data_.channels ;
226+ audio_data_.cava_buffer_size = audio_data_.input_buffer_size * 8 ;
227+ audio_data_.terminate = 0 ;
228+ audio_data_.suspendFlag = false ;
229+ input_source_ = get_input (&audio_data_, &prm_);
230+
231+ if (!input_source_) {
232+ spdlog::error (" cava backend API didn't provide input audio source method" );
233+ exit (EXIT_FAILURE);
234+ }
235+
236+ // Make cava parameters configuration
237+ // Init cava plan, audio_raw structure
238+ audio_raw_init (&audio_data_, &audio_raw_, &prm_, &plan_);
239+ if (!plan_) spdlog::error (" cava backend plan is not provided" );
240+ audio_raw_.previous_frame [0 ] = -1 ; // For first Update() call need to rePaint text message
241+ }
242+
243+ void waybar::modules::cava::CavaBackend::doOutReadConnect () {
244+ out_thread_.disconnect ();
245+ // Thread safe reading incoming source and do callbacks
246+ out_thread_ = Glib::signal_timeout ().connect (
247+ [&]() {
248+ Update ();
249+ return true ;
250+ },
251+ frame_time_milsec_.count ());
252+ }
0 commit comments