X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Frhythm_ferret.cc;h=4a4f3d4ec477a367cdf2497c40c53c73c7856485;hb=e11b3f90c2d02735a071d526d67cfd0de90cbac3;hp=980b36e1d13274a2b3994e2b10babe754f44a8c5;hpb=9f63ab9931e6478472853bdda58da47ea29ac125;p=ardour.git diff --git a/gtk2_ardour/rhythm_ferret.cc b/gtk2_ardour/rhythm_ferret.cc index 980b36e1d1..4a4f3d4ec4 100644 --- a/gtk2_ardour/rhythm_ferret.cc +++ b/gtk2_ardour/rhythm_ferret.cc @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -13,6 +14,7 @@ #include "rhythm_ferret.h" #include "audio_region_view.h" #include "public_editor.h" +#include "utils.h" #include "i18n.h" @@ -31,6 +33,17 @@ static const gchar * _analysis_mode_strings[] = { 0 }; +static const gchar * _onset_function_strings[] = { + N_("Energy Based"), + N_("Spectral Difference"), + N_("High-Frequency Content"), + N_("Complex Domain"), + N_("Phase Deviation"), + N_("Kullback-Liebler"), + N_("Modified Kullback-Liebler"), + 0 +}; + RhythmFerret::RhythmFerret (PublicEditor& e) : ArdourDialog (_("Rhythm Ferret")) , editor (e) @@ -49,6 +62,13 @@ RhythmFerret::RhythmFerret (PublicEditor& e) , sensitivity_scale (sensitivity_adjustment) , sensitivity_label (_("Sensitivity")) , analyze_button (_("Analyze")) + , onset_function_label (_("Detection function")) + , peak_picker_threshold_adjustment (0.3, 0.0, 1.0, 0.01, 0.1) + , peak_picker_threshold_scale (peak_picker_threshold_adjustment) + , peak_picker_label (_("Peak Threshold")) + , silence_threshold_adjustment (-90.0, -120.0, 0.0, 1, 10) + , silence_threshold_scale (silence_threshold_adjustment) + , silence_label (_("Silent Threshold (dB)")) , trigger_gap_adjustment (3, 0, 100, 1, 10) , trigger_gap_spinner (trigger_gap_adjustment) , trigger_gap_label (_("Trigger gap (msecs)")) @@ -57,9 +77,9 @@ RhythmFerret::RhythmFerret (PublicEditor& e) { 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); + upper_hpacker.pack_start (selection_frame, true, true); + upper_hpacker.pack_start (operation_frame, true, true); op_packer.pack_start (region_split_button, false, false); op_packer.pack_start (tempo_button, false, false); @@ -77,6 +97,14 @@ RhythmFerret::RhythmFerret (PublicEditor& e) 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()); + analysis_mode_selector.signal_changed().connect (mem_fun (*this, &RhythmFerret::analysis_mode_changed)); + + onset_function_strings = I18N (_onset_function_strings); + Gtkmm2ext::set_popdown_strings (onset_detection_function_selector, onset_function_strings); + /* Onset plugin uses complex domain as default function + XXX there should be a non-hacky way to set this + */ + onset_detection_function_selector.set_active_text (onset_function_strings[3]); box = manage (new HBox); box->set_spacing (6); @@ -84,38 +112,62 @@ RhythmFerret::RhythmFerret (PublicEditor& e) box->pack_start (analysis_mode_selector, true, true); ferret_packer.pack_start (*box, false, false); + ferret_packer.pack_start (analysis_packer, 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); + 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)); + + box = manage (new HBox); + box->set_spacing (6); + box->pack_start (detection_threshold_label, false, false); + box->pack_start (detection_threshold_scale, true, true); + perc_onset_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); + perc_onset_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); + box->pack_start (onset_function_label, false, false); + box->pack_start (onset_detection_function_selector, true, true); + note_onset_packer.pack_start (*box, false, false); + + box = manage (new HBox); + box->set_spacing (6); + box->pack_start (peak_picker_label, false, false); + box->pack_start (peak_picker_threshold_scale, true, true); + note_onset_packer.pack_start (*box, false, false); + + box = manage (new HBox); + box->set_spacing (6); + box->pack_start (silence_label, false, false); + box->pack_start (silence_threshold_scale, true, true); + note_onset_packer.pack_start (*box, false, false); - ferret_packer.pack_start (analyze_button, false, false); + analysis_mode_changed (); - analyze_button.signal_clicked().connect (mem_fun (*this, &RhythmFerret::run_analysis)); - ferret_frame.add (ferret_packer); - - // Glib::RefPtr logo_pixbuf ("somefile"); + logo = manage (new Gtk::Image (::get_icon (X_("ferret_02")))); + if (logo) { lower_hpacker.pack_start (*logo, false, false); } - lower_hpacker.pack_start (operation_clarification_label, false, false); + lower_hpacker.pack_start (operation_clarification_label, true, true); lower_hpacker.pack_start (action_button, false, false); + lower_hpacker.set_border_width (6); + lower_hpacker.set_spacing (6); action_button.signal_clicked().connect (mem_fun (*this, &RhythmFerret::do_action)); @@ -134,12 +186,30 @@ RhythmFerret::~RhythmFerret() } } +void +RhythmFerret::analysis_mode_changed () +{ + analysis_packer.children().clear (); + + switch (get_analysis_mode()) { + case PercussionOnset: + analysis_packer.pack_start (perc_onset_packer); + break; + + case NoteOnset: + analysis_packer.pack_start (note_onset_packer); + break; + } + + analysis_packer.show_all (); +} + RhythmFerret::AnalysisMode RhythmFerret::get_analysis_mode () const { string str = analysis_mode_selector.get_active_text (); - if (str == _(_analysis_mode_strings[(int) NoteOnset])) { + if (str == analysis_mode_strings[(int) NoteOnset]) { return NoteOnset; } @@ -181,6 +251,9 @@ RhythmFerret::run_analysis () case PercussionOnset: run_percussion_onset_analysis (rd, (*i)->region()->position(), current_results); break; + case NoteOnset: + run_note_onset_analysis (rd, (*i)->region()->position(), current_results); + break; default: break; } @@ -188,19 +261,19 @@ RhythmFerret::run_analysis () } for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { - (*i)->get_time_axis_view().show_temporary_lines (current_results); + (*i)->get_time_axis_view().show_feature_lines (current_results); } } int -RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr readable, nframes64_t offset, vector& results) +RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr readable, nframes64_t offset, AnalysisFeatureList& results) { TransientDetector t (session->frame_rate()); for (uint32_t i = 0; i < readable->n_channels(); ++i) { - vector these_results; + AnalysisFeatureList these_results; t.reset (); t.set_threshold (detection_threshold_adjustment.get_value()); @@ -212,38 +285,79 @@ RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr readabl /* translate all transients to give absolute position */ - for (vector::iterator i = these_results.begin(); i != these_results.end(); ++i) { - (*i) += offset; + 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()) { - - /* now resort to bring transients from different channels together */ - - sort (results.begin(), results.end()); + TransientDetector::cleanup_transients (results, session->frame_rate(), trigger_gap_adjustment.get_value()); + } - /* remove duplicates or other things that are too close */ + return 0; +} - 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)); +int +RhythmFerret::get_note_onset_function () +{ + string txt = onset_detection_function_selector.get_active_text(); - ++i; + for (int n = 0; _onset_function_strings[n]; ++n) { + /* compare translated versions */ + if (txt == onset_function_strings[n]) { + return n; + } + } + fatal << string_compose (_("programming error: %1 (%2)"), X_("illegal note onset function string"), txt) + << endmsg; + /*NOTREACHED*/ + return -1; +} - while (i != results.end()) { - if (((*i) == curr) || (((*i) - curr) < gap_frames)) { - i = results.erase (i); - } else { - ++i; - curr = *i; +int +RhythmFerret::run_note_onset_analysis (boost::shared_ptr readable, nframes64_t offset, AnalysisFeatureList& results) +{ + try { + OnsetDetector t (session->frame_rate()); + + for (uint32_t i = 0; i < readable->n_channels(); ++i) { + + AnalysisFeatureList these_results; + + t.reset (); + + t.set_function (get_note_onset_function()); + t.set_silence_threshold (silence_threshold_adjustment.get_value()); + t.set_peak_threshold (peak_picker_threshold_adjustment.get_value()); + + if (t.run ("", readable.get(), i, these_results)) { + 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 (); } + } catch (failed_constructor& err) { + error << "Could not load note onset detection plugin" << endmsg; + return -1; + } + + if (!results.empty()) { + OnsetDetector::cleanup_onsets (results, session->frame_rate(), trigger_gap_adjustment.get_value()); } return 0; @@ -286,14 +400,15 @@ RhythmFerret::do_split_action () tmp = i; ++tmp; - (*i)->get_time_axis_view().hide_temporary_lines (); + (*i)->get_time_axis_view().hide_feature_lines (); - editor.split_region_at_points ((*i)->region(), current_results); + editor.split_region_at_points ((*i)->region(), current_results, false); /* i is invalid at this point */ i = tmp; } + session->commit_reversible_command (); } @@ -303,3 +418,16 @@ RhythmFerret::set_session (Session* s) ArdourDialog::set_session (s); current_results.clear (); } + +static void hide_time_axis_features (TimeAxisView& tav) +{ + tav.hide_feature_lines (); +} + +void +RhythmFerret::on_hide () +{ + editor.foreach_time_axis_view (sigc::ptr_fun (hide_time_axis_features)); + ArdourDialog::on_hide (); +} +