diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index 1e1a9f2c395..652601b0300 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -1750,6 +1750,30 @@ AudioRegionView::remove_transient (float pos) } } +samplepos_t +AudioRegionView::get_transient_position(float pos){ + list >::iterator l; + for (l = feature_lines.begin(); l != feature_lines.end(); ++l) { + float *line_pos = (float*) (*l).second->get_data ("position"); + if (rint(pos) == (rint(*line_pos))) { + return (*l).first; + } + } + return 0; +} + +void +AudioRegionView::get_transient_feature_line(samplepos_t pos, std::list& equivalent_transient_items) +{ + list >::iterator l; + for (l = feature_lines.begin(); l != feature_lines.end(); ++l) { + if (pos == (*l).first) { + equivalent_transient_items.push_back((*l).second); + break; + } + } +} + void AudioRegionView::thaw_after_trim () { diff --git a/gtk2_ardour/audio_region_view.h b/gtk2_ardour/audio_region_view.h index d12d8ff0868..048afaed78c 100644 --- a/gtk2_ardour/audio_region_view.h +++ b/gtk2_ardour/audio_region_view.h @@ -108,6 +108,8 @@ class AudioRegionView : public RegionView void update_transient(float old_pos, float new_pos); void remove_transient(float pos); + samplepos_t get_transient_position(float pos); + void get_transient_feature_line(samplepos_t pos, std::list& equivalent_transient_items); void show_region_editor (); diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 25098898537..612078d6b7f 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -964,14 +964,39 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case FeatureLineItem: { + std::list equivalent_transient_items; + ArdourCanvas::Line* line = reinterpret_cast (item); + assert (line); + + RegionView* tmp_rv = reinterpret_cast (item->get_data ("regionview")); + + vector all_equivalent_regions; + get_equivalent_regions(tmp_rv, all_equivalent_regions, ARDOUR::Properties::group_select.property_id); + + AudioRegionView* tmp_arv = dynamic_cast (tmp_rv); + samplepos_t transient_position = tmp_arv->get_transient_position(*(float*) line->get_data("position")); +// boost::shared_ptr arv; + for (vector::iterator i = all_equivalent_regions.begin(); i != all_equivalent_regions.end(); ++i){ + AudioRegionView* arv = dynamic_cast (*i); + arv->get_transient_feature_line(transient_position, equivalent_transient_items); + } + + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) { + equivalent_transient_items.clear(); + equivalent_transient_items.push_back(item); + } + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::TertiaryModifier)) { - remove_transient(item); + for (std::list::iterator i = equivalent_transient_items.begin(); i != equivalent_transient_items.end(); ++i){ + remove_transient(*i); + } return true; } - - _drags->set (new FeatureLineDrag (this, item), event); + + for (std::list::iterator i = equivalent_transient_items.begin(); i != equivalent_transient_items.end(); ++i){ + _drags->set (new FeatureLineDrag (this, *i), event); + } return true; - break; } case RegionItem: diff --git a/gtk2_ardour/rhythm_ferret.cc b/gtk2_ardour/rhythm_ferret.cc index 8eb64840f6a..c4b526c1321 100644 --- a/gtk2_ardour/rhythm_ferret.cc +++ b/gtk2_ardour/rhythm_ferret.cc @@ -109,6 +109,7 @@ RhythmFerret::RhythmFerret (Editor& e) */ onset_detection_function_selector.set_active_text (onset_function_strings[3]); detection_threshold_scale.set_digits (3); + filter_to_grid.set_active(true); Table* t = manage (new Table (7, 3)); t->set_spacings (12); @@ -153,7 +154,11 @@ RhythmFerret::RhythmFerret (Editor& e) t->attach (detection_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 (_("Filter results on grid"), 1, 0.5)), 0, 1, n, n + 1, FILL); + t->attach (filter_to_grid, 1, 2, n, n + 1, FILL); + ++n; + t->attach (*manage (new Label (_("Operation"), 1, 0.5)), 0, 1, n, n + 1, FILL); t->attach (operation_selector, 1, 2, n, n + 1, FILL); ++n; @@ -235,7 +240,10 @@ RhythmFerret::run_analysis () if (regions_with_transients.empty()) { return; } - + + bool active_filter = filter_to_grid.get_active(); + vector filter_list; + for (RegionSelection::iterator i = regions_with_transients.begin(); i != regions_with_transients.end(); ++i) { boost::shared_ptr rd = boost::static_pointer_cast ((*i)->region()); @@ -250,10 +258,56 @@ RhythmFerret::run_analysis () default: break; } - - (*i)->region()->set_onsets (current_results); + for (AnalysisFeatureList::iterator j = current_results.begin(); j != current_results.end(); ++j) { + MusicSample snaped_transient(*j + (*i)->region()->position(), 0); + editor.snap_to(snaped_transient, ARDOUR::RoundNearest, false, true); + + GridFilterElement gfe((*i), *j, snaped_transient.sample); + filter_list.push_back(gfe); + } current_results.clear(); } + + std::sort(begin(filter_list), end(filter_list), [](GridFilterElement const &gf1, + GridFilterElement const &gf2 ) { + if (gf1.snaped_sample != gf2.snaped_sample){ + return gf1.snaped_sample < gf2.snaped_sample; + } + + return gf1.distance < gf2.distance; + } + ); + + for (RegionSelection::iterator r = regions_with_transients.begin(); r != regions_with_transients.end(); ++r) { + current_results.clear(); + samplepos_t last_snaped_sample = -1; + + for (vector::iterator f = filter_list.begin(); f != filter_list.end(); ++f){ + if (active_filter && (*f).snaped_sample == last_snaped_sample){ + continue; + } + last_snaped_sample = (*f).snaped_sample; + + if ((*f).region_view == (*r)) { + current_results.push_back((*f).sample); + } else { +// if onset is on an equivalent region, we put it on this region too. + vector all_equivalent_regions; + editor.get_equivalent_regions((*f).region_view, all_equivalent_regions, ARDOUR::Properties::group_select.property_id); + + for (vector::iterator eqr = all_equivalent_regions.begin(); eqr!= all_equivalent_regions.end(); ++eqr){ + if ((*eqr) == (*r)){ + current_results.push_back((*f).sample + ((*f).region_view->region()->position() - (*r)->region()->position())); + break; + } + } + } + } + + (*r)->region()->set_onsets (current_results); + } + current_results.clear(); + } int @@ -452,3 +506,9 @@ RhythmFerret::clear_transients () regions_with_transients.clear (); } +GridFilterElement::GridFilterElement(RegionView* reg_view, samplepos_t onset, samplepos_t snaped){ + region_view = reg_view; + sample = onset; + snaped_sample = snaped; + distance = std::abs((region_view->region()->position() + sample) - snaped_sample); +} diff --git a/gtk2_ardour/rhythm_ferret.h b/gtk2_ardour/rhythm_ferret.h index 5f14509a184..d8448974366 100644 --- a/gtk2_ardour/rhythm_ferret.h +++ b/gtk2_ardour/rhythm_ferret.h @@ -96,7 +96,8 @@ class RhythmFerret : public ArdourDialog Gtk::Adjustment trigger_gap_adjustment; Gtk::SpinButton trigger_gap_spinner; - + Gtk::CheckButton filter_to_grid; + Gtk::Button action_button; std::vector analysis_mode_strings; @@ -123,4 +124,12 @@ class RhythmFerret : public ArdourDialog void do_region_split (RegionView* rv, const ARDOUR::AnalysisFeatureList&); }; +struct GridFilterElement { + GridFilterElement(RegionView* reg_view, samplepos_t onset, samplepos_t snaped); + samplepos_t snaped_sample; + samplepos_t sample; + samplepos_t distance; + RegionView* region_view; +}; + #endif /* __gtk2_ardour_rhythm_ferret_h__ */