2 Copyright (C) 2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <gtkmm/table.h>
23 #include <gtkmm/label.h>
24 #include <gtkmm/stock.h>
25 #include "ardour/audioregion.h"
26 #include "ardour/audiosource.h"
28 #include "ardour/dB.h"
29 #include "ardour_ui.h"
30 #include "ardour/session.h"
32 #include "gui_thread.h"
33 #include "strip_silence_dialog.h"
34 #include "canvas_impl.h"
35 #include "simpleline.h"
37 #include "simplerect.h"
38 #include "rgb_macros.h"
42 using namespace ARDOUR
;
44 using namespace ArdourCanvas
;
46 Glib::StaticMutex
StripSilenceDialog::run_lock
;
47 Glib::Cond
* StripSilenceDialog::thread_waiting
= 0;
48 Glib::Cond
* StripSilenceDialog::thread_run
= 0;
49 bool StripSilenceDialog::thread_should_exit
= false;
50 InterThreadInfo
StripSilenceDialog::itt
;
51 StripSilenceDialog
* StripSilenceDialog::current
= 0;
53 /** Construct Strip silence dialog box */
54 StripSilenceDialog::StripSilenceDialog (Session
* s
, list
<boost::shared_ptr
<ARDOUR::AudioRegion
> > const & regions
)
55 : ArdourDialog (_("Strip Silence"))
57 , _minimum_length (X_("silence duration"), true, "SilenceDurationClock", true, false, true, false)
58 , _fade_length (X_("silence duration"), true, "SilenceDurationClock", true, false, true, false)
61 , restart_queued (false)
62 , _peaks_ready_connection (0)
66 if (thread_waiting
== 0) {
67 thread_waiting
= new Glib::Cond
;
68 thread_run
= new Glib::Cond
;
71 Gtk::HBox
* hbox
= Gtk::manage (new Gtk::HBox
);
73 Gtk::Table
* table
= Gtk::manage (new Gtk::Table (3, 3));
74 table
->set_spacings (6);
78 table
->attach (*Gtk::manage (new Gtk::Label (_("Threshold"), 1, 0.5)), 0, 1, n
, n
+ 1, Gtk::FILL
);
79 table
->attach (_threshold
, 1, 2, n
, n
+ 1, Gtk::FILL
);
80 table
->attach (*Gtk::manage (new Gtk::Label (_("dbFS"))), 2, 3, n
, n
+ 1, Gtk::FILL
);
83 _threshold
.set_digits (1);
84 _threshold
.set_increments (1, 10);
85 _threshold
.set_range (-120, 0);
86 _threshold
.set_value (-60);
88 table
->attach (*Gtk::manage (new Gtk::Label (_("Minimum length"), 1, 0.5)), 0, 1, n
, n
+ 1, Gtk::FILL
);
89 table
->attach (_minimum_length
, 1, 2, n
, n
+ 1, Gtk::FILL
);
92 _minimum_length
.set_session (s
);
93 _minimum_length
.set_mode (AudioClock::Frames
);
94 _minimum_length
.set (1000, true);
96 table
->attach (*Gtk::manage (new Gtk::Label (_("Fade length"), 1, 0.5)), 0, 1, n
, n
+ 1, Gtk::FILL
);
97 table
->attach (_fade_length
, 1, 2, n
, n
+ 1, Gtk::FILL
);
100 _fade_length
.set_session (s
);
101 _fade_length
.set_mode (AudioClock::Frames
);
102 _fade_length
.set (64, true);
104 hbox
->pack_start (*table
);
106 table
= Gtk::manage (new Gtk::Table (3, 2));
107 table
->set_spacings (6);
111 table
->attach (*Gtk::manage (new Gtk::Label (_("Silent segments:"), 1, 0.5)), 3, 4, n
, n
+ 1, Gtk::FILL
);
112 table
->attach (_segment_count_label
, 5, 6, n
, n
+ 1, Gtk::FILL
);
113 _segment_count_label
.set_alignment (0, 0.5);
116 table
->attach (*Gtk::manage (new Gtk::Label (_("Shortest silence:"), 1, 0.5)), 3, 4, n
, n
+ 1, Gtk::FILL
);
117 table
->attach (_shortest_silence_label
, 5, 6, n
, n
+ 1, Gtk::FILL
);
118 _shortest_silence_label
.set_alignment (0, 0.5);
121 table
->attach (*Gtk::manage (new Gtk::Label (_("Shortest audible:"), 1, 0.5)), 3, 4, n
, n
+ 1, Gtk::FILL
);
122 table
->attach (_shortest_audible_label
, 5, 6, n
, n
+ 1, Gtk::FILL
);
123 _shortest_audible_label
.set_alignment (0, 0.5);
126 hbox
->pack_start (*table
);
128 /* dummy label for padding */
129 hbox
->pack_start (*Gtk::manage (new Gtk::Label ("")), true, true);
131 get_vbox()->pack_start (*hbox
, false, false);
133 add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
134 add_button (Gtk::Stock::APPLY
, Gtk::RESPONSE_OK
);
136 _canvas
= new CanvasAA ();
137 _canvas
->signal_size_allocate().connect (sigc::mem_fun (*this, &StripSilenceDialog::canvas_allocation
));
138 _canvas
->set_size_request (_wave_width
, _wave_height
* regions
.size());
140 for (list
<boost::shared_ptr
<ARDOUR::AudioRegion
> >::const_iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
141 Wave
* w
= new Wave (_canvas
->root(), *i
);
142 _waves
.push_back (w
);
145 get_vbox()->pack_start (*_canvas
, true, true);
147 get_vbox()->pack_start (_progress_bar
, true, true);
151 _threshold
.get_adjustment()->signal_value_changed().connect (sigc::mem_fun (*this, &StripSilenceDialog::threshold_changed
));
152 _minimum_length
.ValueChanged
.connect (sigc::mem_fun (*this, &StripSilenceDialog::maybe_start_silence_detection
));
155 update_silence_rects ();
156 update_threshold_line ();
158 maybe_start_silence_detection ();
162 StripSilenceDialog::~StripSilenceDialog ()
164 for (list
<Wave
*>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
170 delete _peaks_ready_connection
;
175 StripSilenceDialog::create_waves ()
179 delete _peaks_ready_connection
;
180 _peaks_ready_connection
= 0;
182 for (list
<Wave
*>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
183 if ((*i
)->region
->audio_source(0)->peaks_ready (boost::bind (&StripSilenceDialog::peaks_ready
, this), &_peaks_ready_connection
, gui_context())) {
184 (*i
)->view
= new WaveView (*(_canvas
->root()));
185 (*i
)->view
->property_data_src() = static_cast<gpointer
>((*i
)->region
.get());
186 (*i
)->view
->property_cache() = WaveView::create_cache ();
187 (*i
)->view
->property_cache_updater() = true;
188 (*i
)->view
->property_channel() = 0;
189 (*i
)->view
->property_length_function() = (void *) region_length_from_c
;
190 (*i
)->view
->property_sourcefile_length_function() = (void *) sourcefile_length_from_c
;
191 (*i
)->view
->property_peak_function() = (void *) region_read_peaks_from_c
;
192 (*i
)->view
->property_x() = 0;
193 (*i
)->view
->property_y() = n
* _wave_height
;
194 (*i
)->view
->property_height() = _wave_height
;
195 (*i
)->view
->property_samples_per_unit() = (*i
)->samples_per_unit
;
196 (*i
)->view
->property_region_start() = (*i
)->region
->start();
197 (*i
)->view
->property_wave_color() = ARDOUR_UI::config()->canvasvar_WaveForm
.get();
198 (*i
)->view
->property_fill_color() = ARDOUR_UI::config()->canvasvar_WaveFormFill
.get();
199 (*i
)->view
->property_logscaled() = true;
200 (*i
)->view
->property_rectified() = true;
208 StripSilenceDialog::peaks_ready ()
210 delete _peaks_ready_connection
;
211 _peaks_ready_connection
= 0;
216 StripSilenceDialog::canvas_allocation (Gtk::Allocation
& alloc
)
220 _canvas
->set_scroll_region (0.0, 0.0, alloc
.get_width(), alloc
.get_height());
221 _wave_width
= alloc
.get_width ();
222 _wave_height
= alloc
.get_height ();
224 for (list
<Wave
*>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
, ++n
) {
225 (*i
)->samples_per_unit
= ((double) (*i
)->region
->length() / _wave_width
);
228 (*i
)->view
->property_y() = n
* _wave_height
;
229 (*i
)->view
->property_samples_per_unit() = (*i
)->samples_per_unit
;
230 (*i
)->view
->property_height() = _wave_height
;
234 resize_silence_rects ();
235 update_threshold_line ();
239 StripSilenceDialog::resize_silence_rects ()
243 for (list
<Wave
*>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
245 list
<pair
<frameoffset_t
, framecnt_t
> >::const_iterator j
;
246 list
<SimpleRect
*>::iterator r
;
248 for (j
= (*i
)->silence
.begin(), r
= (*i
)->silence_rects
.begin();
249 j
!= (*i
)->silence
.end() && r
!= (*i
)->silence_rects
.end(); ++j
, ++r
) {
250 (*r
)->property_x1() = j
->first
/ (*i
)->samples_per_unit
;
251 (*r
)->property_x2() = j
->second
/ (*i
)->samples_per_unit
;
252 (*r
)->property_y1() = n
* _wave_height
;
253 (*r
)->property_y2() = (n
+ 1) * _wave_height
;
254 (*r
)->property_outline_pixels() = 0;
255 (*r
)->property_fill_color_rgba() = RGBA_TO_UINT (128, 128, 128, 128);
263 StripSilenceDialog::update_threshold_line ()
267 for (list
<Wave
*>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
268 (*i
)->threshold_line
->property_x1() = 0;
269 (*i
)->threshold_line
->property_x2() = _wave_width
;
271 double const y
= alt_log_meter (_threshold
.get_value());
273 (*i
)->threshold_line
->property_y1() = (n
+ 1 - y
) * _wave_height
;
274 (*i
)->threshold_line
->property_y2() = (n
+ 1 - y
) * _wave_height
;
281 StripSilenceDialog::update_silence_rects ()
284 uint32_t max_segments
= 0;
287 for (list
<Wave
*>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
288 for (list
<SimpleRect
*>::iterator j
= (*i
)->silence_rects
.begin(); j
!= (*i
)->silence_rects
.end(); ++j
) {
292 (*i
)->silence_rects
.clear ();
295 for (list
<pair
<frameoffset_t
, framecnt_t
> >::const_iterator j
= (*i
)->silence
.begin(); j
!= (*i
)->silence
.end(); ++j
) {
297 SimpleRect
* r
= new SimpleRect (*(_canvas
->root()));
298 r
->property_x1() = j
->first
/ (*i
)->samples_per_unit
;
299 r
->property_x2() = j
->second
/ (*i
)->samples_per_unit
;
300 r
->property_y1() = n
* _wave_height
;
301 r
->property_y2() = (n
+ 1) * _wave_height
;
302 r
->property_outline_pixels() = 0;
303 r
->property_fill_color_rgba() = RGBA_TO_UINT (128, 128, 128, 128);
304 (*i
)->silence_rects
.push_back (r
);
308 max_segments
= max (max_segments
, sc
);
312 if (min_audible
> 0) {
317 ma
= (float) min_audible
/_session
->frame_rate();
318 ms
= (float) min_silence
/_session
->frame_rate();
320 if (min_audible
< _session
->frame_rate()) {
327 if (min_silence
< _session
->frame_rate()) {
334 _segment_count_label
.set_text (string_compose ("%1", max_segments
));
335 if (max_segments
> 0) {
336 _shortest_silence_label
.set_text (string_compose ("%1 %2", ms
, sunits
));
337 _shortest_audible_label
.set_text (string_compose ("%1 %2", ma
, aunits
));
339 _shortest_silence_label
.set_text ("");
340 _shortest_audible_label
.set_text ("");
343 _segment_count_label
.set_text (_("Full silence"));
344 _shortest_silence_label
.set_text ("");
345 _shortest_audible_label
.set_text ("");
350 StripSilenceDialog::_detection_done (void* arg
)
352 StripSilenceDialog
* ssd
= (StripSilenceDialog
*) arg
;
353 return ssd
->detection_done ();
357 StripSilenceDialog::detection_done ()
359 get_window()->set_cursor (Gdk::Cursor (Gdk::LEFT_PTR
));
360 update_silence_rects ();
365 StripSilenceDialog::_detection_thread_work (void* arg
)
367 StripSilenceDialog
* ssd
= (StripSilenceDialog
*) arg
;
368 return ssd
->detection_thread_work ();
372 StripSilenceDialog::detection_thread_work ()
374 ARDOUR_UI::instance()->register_thread ("gui", pthread_self(), "silence", 32);
379 thread_waiting
->signal ();
380 thread_run
->wait (run_lock
);
382 if (thread_should_exit
) {
383 thread_waiting
->signal ();
389 StripSilenceDialog
* ssd
= current
;
392 for (list
<Wave
*>::iterator i
= ssd
->_waves
.begin(); i
!= ssd
->_waves
.end(); ++i
) {
393 (*i
)->silence
= (*i
)->region
->find_silence (dB_to_coefficient (ssd
->threshold ()), ssd
->minimum_length (), ssd
->itt
);
394 ssd
->update_stats ((*i
)->silence
);
397 if (!ssd
->itt
.cancel
) {
398 g_idle_add ((gboolean (*)(void*)) StripSilenceDialog::_detection_done
, ssd
);
410 StripSilenceDialog::threshold_changed ()
412 update_threshold_line ();
413 maybe_start_silence_detection ();
417 StripSilenceDialog::maybe_start_silence_detection ()
419 if (!restart_queued
) {
420 restart_queued
= true;
421 Glib::signal_idle().connect (sigc::mem_fun (*this, &StripSilenceDialog::start_silence_detection
));
426 StripSilenceDialog::start_silence_detection ()
428 Glib::Mutex::Lock
lm (run_lock
);
429 restart_queued
= false;
438 pthread_create (&itt
.thread
, 0, StripSilenceDialog::_detection_thread_work
, this);
439 /* wait for it to get started */
440 thread_waiting
->wait (run_lock
);
444 /* stop whatever the thread is doing */
450 thread_run
->signal ();
451 thread_waiting
->wait (run_lock
);
461 /* and start it up (again) */
463 thread_run
->signal ();
467 get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH
));
469 /* don't call again until needed */
475 StripSilenceDialog::stop_thread ()
477 Glib::Mutex::Lock
lm (run_lock
);
480 thread_should_exit
= true;
481 thread_run
->signal ();
482 thread_waiting
->wait (run_lock
);
487 StripSilenceDialog::update_stats (const SilenceResult
& res
)
494 min_silence
= max_framepos
;
496 min_audible
= max_framepos
;
498 SilenceResult::const_iterator cur
;
502 framepos_t start
= 0;
506 if (cur
->first
== 0) {
507 /* initial segment, starting at zero, is silent */
511 /* initial segment, starting at zero, is audible */
516 while (cur
!= res
.end()) {
518 framecnt_t interval_duration
;
520 interval_duration
= end
- start
;
524 max_silence
= max (max_silence
, interval_duration
);
525 min_silence
= min (min_silence
, interval_duration
);
528 max_audible
= max (max_audible
, interval_duration
);
529 min_audible
= min (min_audible
, interval_duration
);
535 in_silence
= !in_silence
;
540 StripSilenceDialog::minimum_length () const
542 return _minimum_length
.current_duration (_waves
.front()->region
->position());
546 StripSilenceDialog::fade_length () const
548 return _minimum_length
.current_duration (_waves
.front()->region
->position());
551 StripSilenceDialog::Wave::Wave (Group
* g
, boost::shared_ptr
<AudioRegion
> r
)
552 : region (r
), view (0), samples_per_unit (1)
554 threshold_line
= new ArdourCanvas::SimpleLine (*g
);
555 threshold_line
->property_color_rgba() = RGBA_TO_UINT (0, 0, 0, 128);
558 StripSilenceDialog::Wave::~Wave ()
561 delete threshold_line
;
562 for (list
<SimpleRect
*>::iterator i
= silence_rects
.begin(); i
!= silence_rects
.end(); ++i
) {
568 StripSilenceDialog::update_progress_gui (float p
)
570 _progress_bar
.set_fraction (p
);