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"))
56 , _minimum_length (X_("silence duration"), true, "SilenceDurationClock", true, false, true, false)
57 , _fade_length (X_("silence duration"), true, "SilenceDurationClock", true, false, true, false)
60 , restart_queued (false)
61 , _peaks_ready_connection (0)
65 if (thread_waiting
== 0) {
66 thread_waiting
= new Glib::Cond
;
67 thread_run
= new Glib::Cond
;
70 Gtk::HBox
* hbox
= Gtk::manage (new Gtk::HBox
);
72 Gtk::Table
* table
= Gtk::manage (new Gtk::Table (3, 3));
73 table
->set_spacings (6);
77 table
->attach (*Gtk::manage (new Gtk::Label (_("Threshold"), 1, 0.5)), 0, 1, n
, n
+ 1, Gtk::FILL
);
78 table
->attach (_threshold
, 1, 2, n
, n
+ 1, Gtk::FILL
);
79 table
->attach (*Gtk::manage (new Gtk::Label (_("dbFS"))), 2, 3, n
, n
+ 1, Gtk::FILL
);
82 _threshold
.set_digits (1);
83 _threshold
.set_increments (1, 10);
84 _threshold
.set_range (-120, 0);
85 _threshold
.set_value (-60);
87 table
->attach (*Gtk::manage (new Gtk::Label (_("Minimum length"), 1, 0.5)), 0, 1, n
, n
+ 1, Gtk::FILL
);
88 table
->attach (_minimum_length
, 1, 2, n
, n
+ 1, Gtk::FILL
);
91 _minimum_length
.set_session (s
);
92 _minimum_length
.set_mode (AudioClock::Frames
);
93 _minimum_length
.set (1000, true);
95 table
->attach (*Gtk::manage (new Gtk::Label (_("Fade length"), 1, 0.5)), 0, 1, n
, n
+ 1, Gtk::FILL
);
96 table
->attach (_fade_length
, 1, 2, n
, n
+ 1, Gtk::FILL
);
99 _fade_length
.set_session (s
);
100 _fade_length
.set_mode (AudioClock::Frames
);
101 _fade_length
.set (64, true);
103 hbox
->pack_start (*table
);
105 table
= Gtk::manage (new Gtk::Table (3, 2));
106 table
->set_spacings (6);
110 table
->attach (*Gtk::manage (new Gtk::Label (_("Silent segments:"), 1, 0.5)), 3, 4, n
, n
+ 1, Gtk::FILL
);
111 table
->attach (_segment_count_label
, 5, 6, n
, n
+ 1, Gtk::FILL
);
112 _segment_count_label
.set_alignment (0, 0.5);
115 table
->attach (*Gtk::manage (new Gtk::Label (_("Shortest silence:"), 1, 0.5)), 3, 4, n
, n
+ 1, Gtk::FILL
);
116 table
->attach (_shortest_silence_label
, 5, 6, n
, n
+ 1, Gtk::FILL
);
117 _shortest_silence_label
.set_alignment (0, 0.5);
120 table
->attach (*Gtk::manage (new Gtk::Label (_("Shortest audible:"), 1, 0.5)), 3, 4, n
, n
+ 1, Gtk::FILL
);
121 table
->attach (_shortest_audible_label
, 5, 6, n
, n
+ 1, Gtk::FILL
);
122 _shortest_audible_label
.set_alignment (0, 0.5);
125 hbox
->pack_start (*table
);
127 /* dummy label for padding */
128 hbox
->pack_start (*Gtk::manage (new Gtk::Label ("")), true, true);
130 get_vbox()->pack_start (*hbox
, false, false);
132 add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
133 add_button (Gtk::Stock::APPLY
, Gtk::RESPONSE_OK
);
135 _canvas
= new CanvasAA ();
136 _canvas
->signal_size_allocate().connect (sigc::mem_fun (*this, &StripSilenceDialog::canvas_allocation
));
137 _canvas
->set_size_request (_wave_width
, _wave_height
* regions
.size());
139 for (list
<boost::shared_ptr
<ARDOUR::AudioRegion
> >::const_iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
140 Wave
* w
= new Wave (_canvas
->root(), *i
);
141 _waves
.push_back (w
);
144 get_vbox()->pack_start (*_canvas
, true, true);
148 _threshold
.get_adjustment()->signal_value_changed().connect (sigc::mem_fun (*this, &StripSilenceDialog::threshold_changed
));
149 _minimum_length
.ValueChanged
.connect (sigc::mem_fun (*this, &StripSilenceDialog::maybe_start_silence_detection
));
152 update_silence_rects ();
153 update_threshold_line ();
155 maybe_start_silence_detection ();
159 StripSilenceDialog::~StripSilenceDialog ()
161 for (list
<Wave
*>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
167 delete _peaks_ready_connection
;
172 StripSilenceDialog::create_waves ()
176 delete _peaks_ready_connection
;
177 _peaks_ready_connection
= 0;
179 for (list
<Wave
*>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
180 if ((*i
)->region
->audio_source(0)->peaks_ready (boost::bind (&StripSilenceDialog::peaks_ready
, this), &_peaks_ready_connection
, gui_context())) {
181 (*i
)->view
= new WaveView (*(_canvas
->root()));
182 (*i
)->view
->property_data_src() = static_cast<gpointer
>((*i
)->region
.get());
183 (*i
)->view
->property_cache() = WaveView::create_cache ();
184 (*i
)->view
->property_cache_updater() = true;
185 (*i
)->view
->property_channel() = 0;
186 (*i
)->view
->property_length_function() = (void *) region_length_from_c
;
187 (*i
)->view
->property_sourcefile_length_function() = (void *) sourcefile_length_from_c
;
188 (*i
)->view
->property_peak_function() = (void *) region_read_peaks_from_c
;
189 (*i
)->view
->property_x() = 0;
190 (*i
)->view
->property_y() = n
* _wave_height
;
191 (*i
)->view
->property_height() = _wave_height
;
192 (*i
)->view
->property_samples_per_unit() = (*i
)->samples_per_unit
;
193 (*i
)->view
->property_region_start() = (*i
)->region
->start();
194 (*i
)->view
->property_wave_color() = ARDOUR_UI::config()->canvasvar_WaveForm
.get();
195 (*i
)->view
->property_fill_color() = ARDOUR_UI::config()->canvasvar_WaveFormFill
.get();
196 (*i
)->view
->property_logscaled() = true;
197 (*i
)->view
->property_rectified() = true;
205 StripSilenceDialog::peaks_ready ()
207 delete _peaks_ready_connection
;
208 _peaks_ready_connection
= 0;
213 StripSilenceDialog::canvas_allocation (Gtk::Allocation
& alloc
)
217 _canvas
->set_scroll_region (0.0, 0.0, alloc
.get_width(), alloc
.get_height());
218 _wave_width
= alloc
.get_width ();
219 _wave_height
= alloc
.get_height ();
221 for (list
<Wave
*>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
, ++n
) {
222 (*i
)->samples_per_unit
= ((double) (*i
)->region
->length() / _wave_width
);
225 (*i
)->view
->property_y() = n
* _wave_height
;
226 (*i
)->view
->property_samples_per_unit() = (*i
)->samples_per_unit
;
227 (*i
)->view
->property_height() = _wave_height
;
231 resize_silence_rects ();
232 update_threshold_line ();
236 StripSilenceDialog::resize_silence_rects ()
240 for (list
<Wave
*>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
242 list
<pair
<frameoffset_t
, framecnt_t
> >::const_iterator j
;
243 list
<SimpleRect
*>::iterator r
;
245 for (j
= (*i
)->silence
.begin(), r
= (*i
)->silence_rects
.begin();
246 j
!= (*i
)->silence
.end() && r
!= (*i
)->silence_rects
.end(); ++j
, ++r
) {
247 (*r
)->property_x1() = j
->first
/ (*i
)->samples_per_unit
;
248 (*r
)->property_x2() = j
->second
/ (*i
)->samples_per_unit
;
249 (*r
)->property_y1() = n
* _wave_height
;
250 (*r
)->property_y2() = (n
+ 1) * _wave_height
;
251 (*r
)->property_outline_pixels() = 0;
252 (*r
)->property_fill_color_rgba() = RGBA_TO_UINT (128, 128, 128, 128);
260 StripSilenceDialog::update_threshold_line ()
264 for (list
<Wave
*>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
265 (*i
)->threshold_line
->property_x1() = 0;
266 (*i
)->threshold_line
->property_x2() = _wave_width
;
268 double const y
= alt_log_meter (_threshold
.get_value());
270 (*i
)->threshold_line
->property_y1() = (n
+ 1 - y
) * _wave_height
;
271 (*i
)->threshold_line
->property_y2() = (n
+ 1 - y
) * _wave_height
;
278 StripSilenceDialog::update_silence_rects ()
281 uint32_t max_segments
= 0;
284 for (list
<Wave
*>::iterator i
= _waves
.begin(); i
!= _waves
.end(); ++i
) {
285 for (list
<SimpleRect
*>::iterator j
= (*i
)->silence_rects
.begin(); j
!= (*i
)->silence_rects
.end(); ++j
) {
289 (*i
)->silence_rects
.clear ();
292 for (list
<pair
<frameoffset_t
, framecnt_t
> >::const_iterator j
= (*i
)->silence
.begin(); j
!= (*i
)->silence
.end(); ++j
) {
294 SimpleRect
* r
= new SimpleRect (*(_canvas
->root()));
295 r
->property_x1() = j
->first
/ (*i
)->samples_per_unit
;
296 r
->property_x2() = j
->second
/ (*i
)->samples_per_unit
;
297 r
->property_y1() = n
* _wave_height
;
298 r
->property_y2() = (n
+ 1) * _wave_height
;
299 r
->property_outline_pixels() = 0;
300 r
->property_fill_color_rgba() = RGBA_TO_UINT (128, 128, 128, 128);
301 (*i
)->silence_rects
.push_back (r
);
305 max_segments
= max (max_segments
, sc
);
309 if (min_audible
> 0) {
314 ma
= (float) min_audible
/_session
->frame_rate();
315 ms
= (float) min_silence
/_session
->frame_rate();
317 if (min_audible
< _session
->frame_rate()) {
324 if (min_silence
< _session
->frame_rate()) {
331 _segment_count_label
.set_text (string_compose ("%1", max_segments
));
332 if (max_segments
> 0) {
333 _shortest_silence_label
.set_text (string_compose ("%1 %2", ms
, sunits
));
334 _shortest_audible_label
.set_text (string_compose ("%1 %2", ma
, aunits
));
336 _shortest_silence_label
.set_text ("");
337 _shortest_audible_label
.set_text ("");
340 _segment_count_label
.set_text (_("Full silence"));
341 _shortest_silence_label
.set_text ("");
342 _shortest_audible_label
.set_text ("");
347 StripSilenceDialog::_detection_done (void* arg
)
349 StripSilenceDialog
* ssd
= (StripSilenceDialog
*) arg
;
350 return ssd
->detection_done ();
354 StripSilenceDialog::detection_done ()
356 get_window()->set_cursor (Gdk::Cursor (Gdk::LEFT_PTR
));
357 update_silence_rects ();
362 StripSilenceDialog::_detection_thread_work (void* arg
)
364 StripSilenceDialog
* ssd
= (StripSilenceDialog
*) arg
;
365 return ssd
->detection_thread_work ();
369 StripSilenceDialog::detection_thread_work ()
371 ARDOUR_UI::instance()->register_thread ("gui", pthread_self(), "silence", 32);
376 thread_waiting
->signal ();
377 thread_run
->wait (run_lock
);
379 if (thread_should_exit
) {
380 thread_waiting
->signal ();
386 StripSilenceDialog
* ssd
= current
;
389 for (list
<Wave
*>::iterator i
= ssd
->_waves
.begin(); i
!= ssd
->_waves
.end(); ++i
) {
390 (*i
)->silence
= (*i
)->region
->find_silence (dB_to_coefficient (ssd
->threshold ()), ssd
->minimum_length (), ssd
->itt
);
391 ssd
->update_stats ((*i
)->silence
);
394 if (!ssd
->itt
.cancel
) {
395 g_idle_add ((gboolean (*)(void*)) StripSilenceDialog::_detection_done
, ssd
);
407 StripSilenceDialog::threshold_changed ()
409 update_threshold_line ();
410 maybe_start_silence_detection ();
414 StripSilenceDialog::maybe_start_silence_detection ()
416 if (!restart_queued
) {
417 restart_queued
= true;
418 Glib::signal_idle().connect (sigc::mem_fun (*this, &StripSilenceDialog::start_silence_detection
));
423 StripSilenceDialog::start_silence_detection ()
425 Glib::Mutex::Lock
lm (run_lock
);
426 restart_queued
= false;
435 pthread_create (&itt
.thread
, 0, StripSilenceDialog::_detection_thread_work
, this);
436 /* wait for it to get started */
437 thread_waiting
->wait (run_lock
);
441 /* stop whatever the thread is doing */
447 thread_run
->signal ();
448 thread_waiting
->wait (run_lock
);
458 /* and start it up (again) */
460 thread_run
->signal ();
464 get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH
));
466 /* don't call again until needed */
472 StripSilenceDialog::stop_thread ()
474 Glib::Mutex::Lock
lm (run_lock
);
477 thread_should_exit
= true;
478 thread_run
->signal ();
479 thread_waiting
->wait (run_lock
);
484 StripSilenceDialog::update_stats (const SilenceResult
& res
)
491 min_silence
= max_frames
;
493 min_audible
= max_frames
;
495 SilenceResult::const_iterator cur
;
499 framepos_t start
= 0;
503 if (cur
->first
== 0) {
504 /* initial segment, starting at zero, is silent */
508 /* initial segment, starting at zero, is audible */
513 while (cur
!= res
.end()) {
515 framecnt_t interval_duration
;
517 interval_duration
= end
- start
;
521 max_silence
= max (max_silence
, interval_duration
);
522 min_silence
= min (min_silence
, interval_duration
);
525 max_audible
= max (max_audible
, interval_duration
);
526 min_audible
= min (min_audible
, interval_duration
);
532 in_silence
= !in_silence
;
537 StripSilenceDialog::minimum_length () const
539 return _minimum_length
.current_duration (_waves
.front()->region
->position());
543 StripSilenceDialog::fade_length () const
545 return _minimum_length
.current_duration (_waves
.front()->region
->position());
548 StripSilenceDialog::Wave::Wave (Group
* g
, boost::shared_ptr
<AudioRegion
> r
)
549 : region (r
), view (0), samples_per_unit (1)
551 threshold_line
= new ArdourCanvas::SimpleLine (*g
);
552 threshold_line
->property_color_rgba() = RGBA_TO_UINT (0, 0, 0, 128);
555 StripSilenceDialog::Wave::~Wave ()
558 delete threshold_line
;
559 for (list
<SimpleRect
*>::iterator i
= silence_rects
.begin(); i
!= silence_rects
.end(); ++i
) {