+/*
+ Copyright (C) 2012 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
#include <gtkmm/stock.h>
#include <gtkmm2ext/utils.h>
#include "pbd/memento_command.h"
#include "pbd/convert.h"
-#include "ardour/transient_detector.h"
-#include "ardour/onset_detector.h"
-#include "ardour/audiosource.h"
#include "ardour/audioregion.h"
-#include "ardour/playlist.h"
-#include "ardour/region_factory.h"
+#include "ardour/onset_detector.h"
#include "ardour/session.h"
+#include "ardour/transient_detector.h"
#include "rhythm_ferret.h"
#include "audio_region_view.h"
-#include "public_editor.h"
+#include "editor.h"
#include "utils.h"
#include "time_axis_view.h"
static const gchar * _operation_strings[] = {
N_("Split region"),
- N_("Set tempo map"),
- N_("Conform region"),
+ N_("Snap regions"),
+ N_("Conform regions"),
0
};
-RhythmFerret::RhythmFerret (PublicEditor& e)
+RhythmFerret::RhythmFerret (Editor& e)
: ArdourDialog (_("Rhythm Ferret"))
, editor (e)
- , detection_threshold_adjustment (3, 0, 20, 1, 4)
+ , detection_threshold_adjustment (0.015, 0.0, 0.1, 0.001, 0.1)
, detection_threshold_scale (detection_threshold_adjustment)
, sensitivity_adjustment (40, 0, 100, 1, 10)
, sensitivity_scale (sensitivity_adjustment)
XXX there should be a non-hacky way to set this
*/
onset_detection_function_selector.set_active_text (onset_function_strings[3]);
+ detection_threshold_scale.set_digits (3);
Table* t = manage (new Table (7, 3));
t->set_spacings (12);
t->attach (peak_picker_threshold_scale, 1, 2, n, n + 1, FILL);
t->attach (*manage (new Label (_("dB"))), 2, 3, n, n + 1, FILL);
++n;
-
+
t->attach (*manage (new Label (_("Silence threshold"), 1, 0.5)), 0, 1, n, n + 1, FILL);
t->attach (silence_threshold_scale, 1, 2, n, n + 1, FILL);
t->attach (*manage (new Label (_("dB"))), 2, 3, n, n + 1, FILL);
RhythmFerret::analysis_mode_changed ()
{
bool const perc = get_analysis_mode() == PercussionOnset;
-
+
+ trigger_gap_spinner.set_sensitive (!perc);
detection_threshold_scale.set_sensitive (perc);
sensitivity_scale.set_sensitive (perc);
onset_detection_function_selector.set_sensitive (!perc);
RhythmFerret::get_action () const
{
if (operation_selector.get_active_row_number() == 1) {
- return DefineTempoMap;
+ return SnapRegionsToGrid;
} else if (operation_selector.get_active_row_number() == 2) {
return ConformRegion;
}
return;
}
- RegionSelection& regions (editor.get_selection().regions);
+ clear_transients ();
+
+ regions_with_transients = editor.get_selection().regions;
current_results.clear ();
- if (regions.empty()) {
+ if (regions_with_transients.empty()) {
return;
}
- for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
+ for (RegionSelection::iterator i = regions_with_transients.begin(); i != regions_with_transients.end(); ++i) {
boost::shared_ptr<Readable> rd = boost::static_pointer_cast<AudioRegion> ((*i)->region());
break;
}
+ (*i)->region()->set_transients (current_results);
+ current_results.clear();
}
-
- for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
- (*i)->get_time_axis_view().show_feature_lines (current_results);
- }
-
}
int
-RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr<Readable> readable, nframes64_t offset, AnalysisFeatureList& results)
+RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr<Readable> readable, frameoffset_t /*offset*/, AnalysisFeatureList& results)
{
TransientDetector t (_session->frame_rate());
continue;
}
- /* translate all transients to give absolute position */
-
- for (AnalysisFeatureList::iterator x = these_results.begin(); x != these_results.end(); ++x) {
- (*x) += offset;
- }
-
/* merge */
results.insert (results.end(), these_results.begin(), these_results.end());
these_results.clear ();
- }
- if (!results.empty()) {
- TransientDetector::cleanup_transients (results, _session->frame_rate(), trigger_gap_adjustment.get_value());
+ t.update_positions (readable.get(), i, results);
}
return 0;
return n;
}
}
+
fatal << string_compose (_("programming error: %1 (%2)"), X_("illegal note onset function string"), txt)
<< endmsg;
+
/*NOTREACHED*/
return -1;
}
int
-RhythmFerret::run_note_onset_analysis (boost::shared_ptr<Readable> readable, nframes64_t offset, AnalysisFeatureList& results)
+RhythmFerret::run_note_onset_analysis (boost::shared_ptr<Readable> readable, frameoffset_t /*offset*/, AnalysisFeatureList& results)
{
try {
OnsetDetector t (_session->frame_rate());
continue;
}
- /* translate all transients to give absolute position */
-
- for (AnalysisFeatureList::iterator x = these_results.begin(); x != these_results.end(); ++x) {
- (*x) += offset;
- }
-
/* merge */
results.insert (results.end(), these_results.begin(), these_results.end());
void
RhythmFerret::do_action ()
{
- if (!_session || current_results.empty()) {
+ if (!_session) {
return;
}
case SplitRegion:
do_split_action ();
break;
-
+ case SnapRegionsToGrid:
+ editor.snap_regions_to_grid();
+ break;
+ case ConformRegion:
+ editor.close_region_gaps();
+ break;
default:
break;
}
void
RhythmFerret::do_split_action ()
{
- /* this can/will change the current selection, so work with a copy */
-
- RegionSelection& regions (editor.get_selection().regions);
+ /* XXX: this is quite a special-case; (currently) the only operation which is
+ performed on the selection only (without entered_regionview or the edit point
+ being considered)
+ */
+ RegionSelection regions = editor.selection->regions;
if (regions.empty()) {
return;
}
+ editor.EditorFreeze(); /* Emit signal */
+
_session->begin_reversible_command (_("split regions (rhythm ferret)"));
+ /* Merge the transient positions for regions in consideration */
+ AnalysisFeatureList merged_features;
+
+ for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
+
+ AnalysisFeatureList features;
+ features = (*i)->region()->transients();
+
+ merged_features.insert (merged_features.end(), features.begin(), features.end());
+ }
+
+ merged_features.sort();
+ merged_features.unique();
+
for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ) {
RegionSelection::iterator tmp;
tmp = i;
++tmp;
- (*i)->get_time_axis_view().hide_feature_lines ();
-
- editor.split_region_at_points ((*i)->region(), current_results, false);
+ editor.split_region_at_points ((*i)->region(), merged_features, false, false);
/* i is invalid at this point */
-
i = tmp;
}
_session->commit_reversible_command ();
+
+ editor.EditorThaw(); /* Emit signal */
}
void
current_results.clear ();
}
-static void hide_time_axis_features (TimeAxisView& tav)
+void
+RhythmFerret::on_hide ()
{
- tav.hide_feature_lines ();
+ ArdourDialog::on_hide ();
+ clear_transients ();
}
+/* Clear any transients that we have added */
void
-RhythmFerret::on_hide ()
+RhythmFerret::clear_transients ()
{
- editor.foreach_time_axis_view (sigc::ptr_fun (hide_time_axis_features));
- ArdourDialog::on_hide ();
+ current_results.clear ();
+
+ for (RegionSelection::iterator i = regions_with_transients.begin(); i != regions_with_transients.end(); ++i) {
+ (*i)->region()->set_transients (current_results);
+ }
+
+ regions_with_transients.clear ();
}