From 9f63ab9931e6478472853bdda58da47ea29ac125 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 2 Feb 2008 03:57:35 +0000 Subject: Merge with trunk R2978. git-svn-id: svn://localhost/ardour2/branches/3.0@2988 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/rhythm_ferret.cc | 305 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 gtk2_ardour/rhythm_ferret.cc (limited to 'gtk2_ardour/rhythm_ferret.cc') diff --git a/gtk2_ardour/rhythm_ferret.cc b/gtk2_ardour/rhythm_ferret.cc new file mode 100644 index 0000000000..980b36e1d1 --- /dev/null +++ b/gtk2_ardour/rhythm_ferret.cc @@ -0,0 +1,305 @@ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "rhythm_ferret.h" +#include "audio_region_view.h" +#include "public_editor.h" + +#include "i18n.h" + +using namespace std; +using namespace Gtk; +using namespace Gdk; +using namespace PBD; +using namespace ARDOUR; + +/* order of these must match the AnalysisMode enums + in rhythm_ferret.h +*/ +static const gchar * _analysis_mode_strings[] = { + N_("Percussive Onset"), + N_("Note Onset"), + 0 +}; + +RhythmFerret::RhythmFerret (PublicEditor& e) + : ArdourDialog (_("Rhythm Ferret")) + , editor (e) + , operation_frame (_("Operation")) + , selection_frame (_("Selection")) + , ferret_frame (_("Analysis")) + , logo (0) + , region_split_button (operation_button_group, _("Split Region")) + , tempo_button (operation_button_group, _("Set Tempo Map")) + , region_conform_button (operation_button_group, _("Conform Region")) + , analysis_mode_label (_("Mode")) + , detection_threshold_adjustment (3, 0, 20, 1, 4) + , detection_threshold_scale (detection_threshold_adjustment) + , detection_threshold_label (_("Threshold")) + , sensitivity_adjustment (40, 0, 100, 1, 10) + , sensitivity_scale (sensitivity_adjustment) + , sensitivity_label (_("Sensitivity")) + , analyze_button (_("Analyze")) + , trigger_gap_adjustment (3, 0, 100, 1, 10) + , trigger_gap_spinner (trigger_gap_adjustment) + , trigger_gap_label (_("Trigger gap (msecs)")) + , action_button (Stock::APPLY) + +{ + upper_hpacker.set_spacing (6); + + upper_hpacker.pack_start (operation_frame, true, true); + upper_hpacker.pack_start (selection_frame, true, true); + upper_hpacker.pack_start (ferret_frame, true, true); + + op_packer.pack_start (region_split_button, false, false); + op_packer.pack_start (tempo_button, false, false); + op_packer.pack_start (region_conform_button, false, false); + + operation_frame.add (op_packer); + + HBox* box; + + ferret_packer.set_spacing (6); + ferret_packer.set_border_width (6); + + vector strings; + + analysis_mode_strings = I18N (_analysis_mode_strings); + Gtkmm2ext::set_popdown_strings (analysis_mode_selector, analysis_mode_strings); + analysis_mode_selector.set_active_text (analysis_mode_strings.front()); + + box = manage (new HBox); + box->set_spacing (6); + box->pack_start (analysis_mode_label, false, false); + box->pack_start (analysis_mode_selector, true, true); + ferret_packer.pack_start (*box, false, false); + + box = manage (new HBox); + box->set_spacing (6); + box->pack_start (detection_threshold_label, false, false); + box->pack_start (detection_threshold_scale, true, true); + ferret_packer.pack_start (*box, false, false); + + box = manage (new HBox); + box->set_spacing (6); + box->pack_start (sensitivity_label, false, false); + box->pack_start (sensitivity_scale, true, true); + ferret_packer.pack_start (*box, false, false); + + box = manage (new HBox); + box->set_spacing (6); + box->pack_start (trigger_gap_label, false, false); + box->pack_start (trigger_gap_spinner, false, false); + ferret_packer.pack_start (*box, false, false); + + ferret_packer.pack_start (analyze_button, false, false); + + analyze_button.signal_clicked().connect (mem_fun (*this, &RhythmFerret::run_analysis)); + + ferret_frame.add (ferret_packer); + + // Glib::RefPtr logo_pixbuf ("somefile"); + + if (logo) { + lower_hpacker.pack_start (*logo, false, false); + } + + lower_hpacker.pack_start (operation_clarification_label, false, false); + lower_hpacker.pack_start (action_button, false, false); + + action_button.signal_clicked().connect (mem_fun (*this, &RhythmFerret::do_action)); + + get_vbox()->set_border_width (6); + get_vbox()->set_spacing (6); + get_vbox()->pack_start (upper_hpacker, true, true); + get_vbox()->pack_start (lower_hpacker, false, false); + + show_all (); +} + +RhythmFerret::~RhythmFerret() +{ + if (logo) { + delete logo; + } +} + +RhythmFerret::AnalysisMode +RhythmFerret::get_analysis_mode () const +{ + string str = analysis_mode_selector.get_active_text (); + + if (str == _(_analysis_mode_strings[(int) NoteOnset])) { + return NoteOnset; + } + + return PercussionOnset; +} + +RhythmFerret::Action +RhythmFerret::get_action () const +{ + if (tempo_button.get_active()) { + return DefineTempoMap; + } else if (region_conform_button.get_active()) { + return ConformRegion; + } + + return SplitRegion; +} + +void +RhythmFerret::run_analysis () +{ + if (!session) { + return; + } + + RegionSelection& regions (editor.get_selection().regions); + + current_results.clear (); + + if (regions.empty()) { + return; + } + + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + + boost::shared_ptr rd = boost::static_pointer_cast ((*i)->region()); + + switch (get_analysis_mode()) { + case PercussionOnset: + run_percussion_onset_analysis (rd, (*i)->region()->position(), current_results); + break; + default: + break; + } + + } + + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + (*i)->get_time_axis_view().show_temporary_lines (current_results); + } + +} + +int +RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr readable, nframes64_t offset, vector& results) +{ + TransientDetector t (session->frame_rate()); + + for (uint32_t i = 0; i < readable->n_channels(); ++i) { + + vector these_results; + + t.reset (); + t.set_threshold (detection_threshold_adjustment.get_value()); + t.set_sensitivity (sensitivity_adjustment.get_value()); + + if (t.run ("", readable.get(), i, these_results)) { + continue; + } + + /* translate all transients to give absolute position */ + + for (vector::iterator i = these_results.begin(); i != these_results.end(); ++i) { + (*i) += offset; + } + + /* merge */ + + results.insert (results.end(), these_results.begin(), these_results.end()); + } + + if (!results.empty()) { + + /* now resort to bring transients from different channels together */ + + sort (results.begin(), results.end()); + + /* remove duplicates or other things that are too close */ + + vector::iterator i = results.begin(); + nframes64_t curr = (*i); + nframes64_t gap_frames = (nframes64_t) floor (trigger_gap_adjustment.get_value() * (session->frame_rate() / 1000.0)); + + ++i; + + while (i != results.end()) { + if (((*i) == curr) || (((*i) - curr) < gap_frames)) { + i = results.erase (i); + } else { + ++i; + curr = *i; + } + } + + } + + return 0; +} + +void +RhythmFerret::do_action () +{ + if (!session || current_results.empty()) { + return; + } + + switch (get_action()) { + case SplitRegion: + do_split_action (); + 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); + + if (regions.empty()) { + return; + } + + session->begin_reversible_command (_("split regions (rhythm ferret)")); + + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ) { + + RegionSelection::iterator tmp; + + tmp = i; + ++tmp; + + (*i)->get_time_axis_view().hide_temporary_lines (); + + editor.split_region_at_points ((*i)->region(), current_results); + + /* i is invalid at this point */ + + i = tmp; + } + +} + +void +RhythmFerret::set_session (Session* s) +{ + ArdourDialog::set_session (s); + current_results.clear (); +} -- cgit v1.2.3