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"
36 #include "simplerect.h"
37 #include "rgb_macros.h"
40 using namespace ARDOUR
;
42 using namespace ArdourCanvas
;
44 Glib::StaticMutex
StripSilenceDialog::run_lock
;
45 Glib::Cond
* StripSilenceDialog::thread_waiting
= 0;
46 Glib::Cond
* StripSilenceDialog::thread_run
= 0;
47 bool StripSilenceDialog::thread_should_exit
= false;
48 InterThreadInfo
StripSilenceDialog::itt
;
49 StripSilenceDialog
* StripSilenceDialog::current
= 0;
51 /** Construct Strip silence dialog box */
52 StripSilenceDialog::StripSilenceDialog (Session
* s
, std::list
<boost::shared_ptr
<ARDOUR::AudioRegion
> > const & regions
)
53 : ArdourDialog (_("Strip Silence"))
54 , _minimum_length (X_("silence duration"), true, "SilenceDurationClock", true, false, true, false)
55 , _fade_length (X_("silence duration"), true, "SilenceDurationClock", true, false, true, false)
58 , restart_queued (false)
62 if (thread_waiting
== 0) {
63 thread_waiting
= new Glib::Cond
;
64 thread_run
= new Glib::Cond
;
67 for (std::list
<boost::shared_ptr
<ARDOUR::AudioRegion
> >::const_iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
75 Gtk::HBox
* hbox
= Gtk::manage (new Gtk::HBox
);
76 hbox
->set_spacing (16);
78 Gtk::Table
* table
= Gtk::manage (new Gtk::Table (4, 3));
79 table
->set_spacings (4);
81 Gtk::Label
* l
= Gtk::manage (new Gtk::Label (_("Threshold:")));
82 l
->set_alignment (1, 0.5);
84 hbox
->pack_start (*l
, false, false);
85 hbox
->pack_start (_threshold
, true, true);
87 _threshold
.set_digits (1);
88 _threshold
.set_increments (1, 10);
89 _threshold
.set_range (-120, 0);
90 _threshold
.set_value (-60);
92 l
= Gtk::manage (new Gtk::Label (_("dBFS")));
93 l
->set_alignment (0, 0.5);
95 hbox
->pack_start (*l
, false, false);
97 l
= Gtk::manage (new Gtk::Label (_("Minimum length:")));
98 l
->set_alignment (1, 0.5);
100 hbox
->pack_start (*l
, false, false);
101 hbox
->pack_start (_minimum_length
, true, true);
103 _minimum_length
.set_session (s
);
104 _minimum_length
.set_mode (AudioClock::Frames
);
105 _minimum_length
.set (1000, true);
107 l
= Gtk::manage (new Gtk::Label (_("Fade length:")));
108 l
->set_alignment (1, 0.5);
110 hbox
->pack_start (*l
, false, false);
111 hbox
->pack_start (_fade_length
, true, true);
113 _fade_length
.set_session (s
);
114 _fade_length
.set_mode (AudioClock::Frames
);
115 _fade_length
.set (64, true);
117 _segment_count_label
.set_text (_("Silent segments: none"));
119 get_vbox()->pack_start (*hbox
, false, false);
122 add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
123 add_button (Gtk::Stock::APPLY
, Gtk::RESPONSE_OK
);
125 _canvas
= new CanvasAA ();
126 _canvas
->signal_size_allocate().connect (sigc::mem_fun (*this, &StripSilenceDialog::canvas_allocation
));
127 _canvas
->set_size_request (_wave_width
, _wave_height
* _waves
.size ());
129 get_vbox()->pack_start (*_canvas
, true, true);
130 get_vbox()->pack_start (_segment_count_label
, false, false);
134 _threshold
.get_adjustment()->signal_value_changed().connect (sigc::mem_fun (*this, &StripSilenceDialog::maybe_start_silence_detection
));
135 _minimum_length
.ValueChanged
.connect (sigc::mem_fun (*this, &StripSilenceDialog::maybe_start_silence_detection
));
138 update_silence_rects ();
142 StripSilenceDialog::~StripSilenceDialog ()
144 for (std::list
<Wave
>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
146 for (std::list
<SimpleRect
*>::iterator j
= i
->silence_rects
.begin(); j
!= i
->silence_rects
.end(); ++j
) {
155 StripSilenceDialog::create_waves ()
159 for (std::list
<Wave
>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
160 if (i
->region
->audio_source(0)->peaks_ready (boost::bind (&StripSilenceDialog::peaks_ready
, this), _peaks_ready_connection
, gui_context())) {
161 i
->view
= new WaveView (*(_canvas
->root()));
162 i
->view
->property_data_src() = static_cast<gpointer
>(i
->region
.get());
163 i
->view
->property_cache() = WaveView::create_cache ();
164 i
->view
->property_cache_updater() = true;
165 i
->view
->property_channel() = 0;
166 i
->view
->property_length_function() = (void *) region_length_from_c
;
167 i
->view
->property_sourcefile_length_function() = (void *) sourcefile_length_from_c
;
168 i
->view
->property_peak_function() = (void *) region_read_peaks_from_c
;
169 i
->view
->property_x() = 0;
170 i
->view
->property_y() = n
* _wave_height
;
171 i
->view
->property_height() = _wave_height
;
172 i
->view
->property_samples_per_unit() = i
->samples_per_unit
;
173 i
->view
->property_region_start() = i
->region
->start();
174 i
->view
->property_wave_color() = ARDOUR_UI::config()->canvasvar_WaveForm
.get();
175 i
->view
->property_fill_color() = ARDOUR_UI::config()->canvasvar_WaveFormFill
.get();
183 StripSilenceDialog::peaks_ready ()
185 _peaks_ready_connection
.disconnect ();
190 StripSilenceDialog::canvas_allocation (Gtk::Allocation
& alloc
)
194 _canvas
->set_scroll_region (0.0, 0.0, alloc
.get_width(), alloc
.get_height());
195 _wave_width
= alloc
.get_width ();
196 _wave_height
= alloc
.get_height ();
198 for (std::list
<Wave
>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
, ++n
) {
199 i
->samples_per_unit
= ((double) i
->region
->length() / _wave_width
);
202 i
->view
->property_y() = n
* _wave_height
;
203 i
->view
->property_samples_per_unit() = i
->samples_per_unit
;
204 i
->view
->property_height() = _wave_height
;
208 redraw_silence_rects ();
212 StripSilenceDialog::redraw_silence_rects ()
216 for (std::list
<Wave
>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
218 std::list
<std::pair
<frameoffset_t
, framecnt_t
> >::const_iterator j
;
219 std::list
<SimpleRect
*>::iterator r
;
221 for (j
= i
->silence
.begin(), r
= i
->silence_rects
.begin();
222 j
!= i
->silence
.end() && r
!= i
->silence_rects
.end(); ++j
, ++r
) {
223 (*r
)->property_x1() = j
->first
/ i
->samples_per_unit
;
224 (*r
)->property_x2() = j
->second
/ i
->samples_per_unit
;
225 (*r
)->property_y1() = n
* _wave_height
;
226 (*r
)->property_y2() = (n
+ 1) * _wave_height
;
227 (*r
)->property_outline_pixels() = 0;
228 (*r
)->property_fill_color_rgba() = RGBA_TO_UINT (128, 128, 128, 128);
236 StripSilenceDialog::update_silence_rects ()
239 uint32_t max_segments
= 0;
242 for (std::list
<Wave
>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
243 for (std::list
<SimpleRect
*>::iterator j
= i
->silence_rects
.begin(); j
!= i
->silence_rects
.end(); ++j
) {
247 i
->silence_rects
.clear ();
250 for (std::list
<std::pair
<frameoffset_t
, framecnt_t
> >::const_iterator j
= i
->silence
.begin(); j
!= i
->silence
.end(); ++j
) {
252 SimpleRect
* r
= new SimpleRect (*(_canvas
->root()));
253 r
->property_x1() = j
->first
/ i
->samples_per_unit
;
254 r
->property_x2() = j
->second
/ i
->samples_per_unit
;
255 r
->property_y1() = n
* _wave_height
;
256 r
->property_y2() = (n
+ 1) * _wave_height
;
257 r
->property_outline_pixels() = 0;
258 r
->property_fill_color_rgba() = RGBA_TO_UINT (128, 128, 128, 128);
259 i
->silence_rects
.push_back (r
);
263 max_segments
= max (max_segments
, sc
);
267 if (min_audible
> 0) {
272 ma
= (float) min_audible
/_session
->frame_rate();
273 ms
= (float) min_silence
/_session
->frame_rate();
275 if (min_audible
> _session
->frame_rate()) {
282 if (min_silence
> _session
->frame_rate()) {
289 _segment_count_label
.set_text (string_compose (_("Silent segments: %1\nShortest silence %2 %3 Shortest audible %4 %5"),
290 max_segments
, ms
, sunits
, ma
, aunits
));
292 _segment_count_label
.set_text (_("Full silence"));
297 StripSilenceDialog::_detection_done (void* arg
)
299 StripSilenceDialog
* ssd
= (StripSilenceDialog
*) arg
;
300 return ssd
->detection_done ();
304 StripSilenceDialog::detection_done ()
306 get_window()->set_cursor (Gdk::Cursor (Gdk::LEFT_PTR
));
307 update_silence_rects ();
312 StripSilenceDialog::_detection_thread_work (void* arg
)
314 StripSilenceDialog
* ssd
= (StripSilenceDialog
*) arg
;
315 return ssd
->detection_thread_work ();
319 StripSilenceDialog::detection_thread_work ()
321 ARDOUR_UI::instance()->register_thread ("gui", pthread_self(), "silence", 32);
326 thread_waiting
->signal ();
327 thread_run
->wait (run_lock
);
329 if (thread_should_exit
) {
330 thread_waiting
->signal ();
336 StripSilenceDialog
* ssd
= current
;
339 for (std::list
<Wave
>::iterator i
= ssd
->_waves
.begin(); i
!= ssd
->_waves
.end(); ++i
) {
340 i
->silence
= i
->region
->find_silence (dB_to_coefficient (ssd
->threshold ()), ssd
->minimum_length (), ssd
->itt
);
341 ssd
->update_stats (i
->silence
);
344 if (!ssd
->itt
.cancel
) {
345 g_idle_add ((gboolean (*)(void*)) StripSilenceDialog::_detection_done
, ssd
);
357 StripSilenceDialog::maybe_start_silence_detection ()
359 if (!restart_queued
) {
360 restart_queued
= true;
361 Glib::signal_idle().connect (sigc::mem_fun (*this, &StripSilenceDialog::start_silence_detection
));
366 StripSilenceDialog::start_silence_detection ()
368 Glib::Mutex::Lock
lm (run_lock
);
369 restart_queued
= false;
378 pthread_create (&itt
.thread
, 0, StripSilenceDialog::_detection_thread_work
, this);
379 /* wait for it to get started */
380 thread_waiting
->wait (run_lock
);
384 /* stop whatever the thread is doing */
390 thread_run
->signal ();
391 thread_waiting
->wait (run_lock
);
401 /* and start it up (again) */
403 thread_run
->signal ();
407 get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH
));
409 /* don't call again until needed */
415 StripSilenceDialog::stop_thread ()
417 Glib::Mutex::Lock
lm (run_lock
);
420 thread_should_exit
= true;
421 thread_run
->signal ();
422 thread_waiting
->wait (run_lock
);
427 StripSilenceDialog::update_stats (const SilenceResult
& res
)
434 min_silence
= max_frames
;
436 min_audible
= max_frames
;
438 SilenceResult::const_iterator cur
;
442 framepos_t start
= 0;
446 if (cur
->first
== 0) {
447 /* initial segment, starting at zero, is silent */
451 /* initial segment, starting at zero, is audible */
456 while (cur
!= res
.end()) {
458 framecnt_t interval_duration
;
460 interval_duration
= end
- start
;
464 max_silence
= max (max_silence
, interval_duration
);
465 min_silence
= min (min_silence
, interval_duration
);
468 max_audible
= max (max_audible
, interval_duration
);
469 min_audible
= min (min_audible
, interval_duration
);
475 in_silence
= !in_silence
;
480 StripSilenceDialog::minimum_length () const
482 return _minimum_length
.current_duration (_waves
.front().region
->position());
486 StripSilenceDialog::fade_length () const
488 return _minimum_length
.current_duration (_waves
.front().region
->position());