From 315dd3d7705d314b935a7a35007347a41e0f9bfd Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 25 Jan 2008 22:08:06 +0000 Subject: more rhythm ferret/transient detection/split region stuff, maybe it works now git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2969 d708f5d6-7413-0410-9779-e7cbd77b26cf --- SConstruct | 2 + gtk2_ardour/ardev_common.sh.in | 2 +- gtk2_ardour/editor.h | 3 +- gtk2_ardour/editor_ops.cc | 120 +++++++++++++++++++++----------- gtk2_ardour/public_editor.h | 1 + gtk2_ardour/rhythm_ferret.cc | 74 +------------------- libs/ardour/ardour/audioanalyser.h | 4 +- libs/ardour/ardour/audioregion.h | 2 + libs/ardour/ardour/transient_detector.h | 2 +- libs/ardour/audioanalyser.cc | 3 +- libs/ardour/audioregion.cc | 63 +++++++++++++++++ libs/ardour/transient_detector.cc | 6 +- 12 files changed, 160 insertions(+), 122 deletions(-) diff --git a/SConstruct b/SConstruct index 4f84f5384c..0113fd3466 100644 --- a/SConstruct +++ b/SConstruct @@ -1012,6 +1012,7 @@ if env['SYSLIBS']: 'libs/midi++2', 'libs/ardour', 'libs/vamp-sdk', + 'libs/vamp-plugins/', # these are unconditionally included but have # tests internally to avoid compilation etc # if VST is not set @@ -1077,6 +1078,7 @@ else: 'libs/midi++2', 'libs/ardour', 'libs/vamp-sdk', + 'libs/vamp-plugins/', # these are unconditionally included but have # tests internally to avoid compilation etc # if VST is not set diff --git a/gtk2_ardour/ardev_common.sh.in b/gtk2_ardour/ardev_common.sh.in index 332efc3271..a3d41a84b3 100644 --- a/gtk2_ardour/ardev_common.sh.in +++ b/gtk2_ardour/ardev_common.sh.in @@ -4,7 +4,7 @@ cd `dirname "$0"`/.. export ARDOUR_PATH=gtk2_ardour/icons:gtk2_ardour/pixmaps:gtk2_ardour:. export GTK_PATH=libs/clearlooks -export VAMP_PATH=libs/vamp-sdk:$VAMP_PATH +export VAMP_PATH=libs/vamp-plugins:$VAMP_PATH export LD_LIBRARY_PATH=libs/vamp-sdk:libs/surfaces/control_protocol:libs/ardour:libs/midi++2:libs/pbd:libs/rubberband:libs/soundtouch:libs/gtkmm2ext:libs/sigc++2:libs/glibmm2:libs/gtkmm2/atk:libs/gtkmm2/pango:libs/gtkmm2/gdk:libs/gtkmm2/gtk:libs/libgnomecanvasmm:libs/libsndfile:libs/appleutility:$LD_LIBRARY_PATH diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 5ce99636db..4c5dce6fad 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -959,6 +959,8 @@ class Editor : public PublicEditor void split_region (); void split_region_at (nframes_t); void split_regions_at (nframes_t, RegionSelection&); + void split_region_at_transients (); + void split_region_at_points (boost::shared_ptr, std::vector&); void crop_region_to_selection (); void crop_region_to (nframes_t start, nframes_t end); void set_sync_point (nframes64_t, const RegionSelection&); @@ -984,7 +986,6 @@ class Editor : public PublicEditor void normalize_region (); void denormalize_region (); void adjust_region_scale_amplitude (bool up); - void split_region_at_transients (); void use_region_as_bar (); void use_range_as_bar (); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 6485ce356e..da6774c560 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -5019,7 +5019,7 @@ Editor::define_one_bar (nframes64_t start, nframes64_t end) void Editor::split_region_at_transients () { - list transients; + vector positions; if (!session) { return; @@ -5031,7 +5031,7 @@ Editor::split_region_at_transients () return; } -#if 0 + session->begin_reversible_command (_("split regions")); for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ) { @@ -5040,52 +5040,90 @@ Editor::split_region_at_transients () tmp = i; ++tmp; - cerr << "working on " << (*i)->get_item_name() << endl; - boost::shared_ptr ar = boost::dynamic_pointer_cast ((*i)->region()); - if (!ar) { - continue; - } - - boost::shared_ptr pl = ar->playlist(); - - if (!pl) { - continue; + if (ar && (ar->get_transients (positions) == 0)) { + split_region_at_points ((*i)->region(), positions); + positions.clear (); } - - cerr << "getting transients\n"; - ar->get_transients (transients); - nframes64_t start = ar->start(); - nframes64_t pos = ar->position(); - - pl->freeze (); - pl->remove_region (ar); - - cerr << "creating new regions from " << transients.size() << " transients\n"; - - for (list::iterator x = transients.begin(); x != transients.end(); ++x) { - - nframes_t len = (*x) - start; + i = tmp; + } - string new_name; + session->commit_reversible_command (); - if (session->region_name (new_name, ar->name())) { - continue; - } +} - pl->add_region (RegionFactory::create (ar->get_sources(), start, len, new_name), pos); - - start = (*x); - pos += len; +void +Editor::split_region_at_points (boost::shared_ptr r, vector& positions) +{ + boost::shared_ptr ar = boost::dynamic_pointer_cast (r); + + if (!ar) { + return; + } + + boost::shared_ptr pl = ar->playlist(); + + if (!pl) { + return; + } + + if (positions.empty()) { + return; + } + + vector::const_iterator x; + + nframes64_t pos = ar->position(); + + XMLNode& before (pl->get_state()); + + x = positions.begin(); + + while (x != positions.end()) { + if ((*x) > pos) { + break; } - - pl->thaw (); - - transients.clear (); - - i = tmp; } -#endif + + if (x == positions.end()) { + return; + } + + pl->freeze (); + pl->remove_region (ar); + + do { + + /* file start = original start + how far we from the initial position ? + */ + + nframes64_t file_start = ar->start() + (pos - ar->position()); + + /* length = next position - current position + */ + + nframes64_t len = (*x) - pos; + + string new_name; + + if (session->region_name (new_name, ar->name())) { + continue; + } + + pl->add_region (RegionFactory::create (ar->get_sources(), file_start, len, new_name), pos); + + pos += len; + + ++x; + + } while (x != positions.end() && (*x) < ar->last_frame()); + + pl->thaw (); + + XMLNode& after (pl->get_state()); + + session->add_command (new MementoCommand(*pl, &before, &after)); } + diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index 8e666bdf7a..cf03942e13 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -157,6 +157,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulThingWithGoingAway virtual void restore_editing_space() = 0; virtual nframes64_t get_preferred_edit_position (bool ignore_playhead = false) = 0; virtual void toggle_meter_updating() = 0; + virtual void split_region_at_points (boost::shared_ptr, std::vector&) = 0; sigc::signal ZoomFocusChanged; sigc::signal ZoomChanged; diff --git a/gtk2_ardour/rhythm_ferret.cc b/gtk2_ardour/rhythm_ferret.cc index a52980167f..cc771a3f15 100644 --- a/gtk2_ardour/rhythm_ferret.cc +++ b/gtk2_ardour/rhythm_ferret.cc @@ -207,7 +207,7 @@ RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr readabl t.set_threshold (detection_threshold_adjustment.get_value()); t.set_sensitivity (sensitivity_adjustment.get_value()); - if (t.run ("", readable, i, these_results)) { + if (t.run ("", readable.get(), i, these_results)) { continue; } @@ -289,83 +289,13 @@ RhythmFerret::do_split_action () (*i)->get_time_axis_view().hide_temporary_lines (); - do_region_split ((*i), current_results); + editor.split_region_at_points ((*i)->region(), current_results); /* i is invalid at this point */ i = tmp; } - session->commit_reversible_command (); -} - -void -RhythmFerret::do_region_split (RegionView* rv, const vector& positions) -{ - boost::shared_ptr ar = boost::dynamic_pointer_cast (rv->region()); - - if (!ar) { - return; - } - - boost::shared_ptr pl = ar->playlist(); - - if (!pl) { - return; - } - - vector::const_iterator x; - - nframes64_t pos = ar->position(); - - XMLNode& before (pl->get_state()); - - x = positions.begin(); - - while (x != positions.end()) { - if ((*x) > pos) { - break; - } - } - - if (x == positions.end()) { - return; - } - - pl->freeze (); - pl->remove_region (ar); - - do { - - /* file start = original start + how far we from the initial position ? - */ - - nframes64_t file_start = ar->start() + (pos - ar->position()); - - /* length = next position - current position - */ - - nframes64_t len = (*x) - pos; - - string new_name; - - if (session->region_name (new_name, ar->name())) { - continue; - } - - pl->add_region (RegionFactory::create (ar->get_sources(), file_start, len, new_name), pos); - - pos += len; - - ++x; - - } while (x != positions.end() && (*x) < ar->last_frame()); - - pl->thaw (); - - XMLNode& after (pl->get_state()); - - session->add_command (new MementoCommand(*pl, &before, &after)); } void diff --git a/libs/ardour/ardour/audioanalyser.h b/libs/ardour/ardour/audioanalyser.h index aac2600ba6..dbd8a52d5a 100644 --- a/libs/ardour/ardour/audioanalyser.h +++ b/libs/ardour/ardour/audioanalyser.h @@ -43,7 +43,7 @@ class AudioAnalyser { /* analysis object should provide a run method that accepts a path to write the results to (optionally empty) - a boost::shared_ptr to read data from + a Readable* to read data from and a reference to a type-specific container to return the results. */ @@ -59,7 +59,7 @@ class AudioAnalyser { nframes64_t stepsize; int initialize_plugin (AnalysisPluginKey name, float sample_rate); - int analyse (const std::string& path, boost::shared_ptr, uint32_t channel); + int analyse (const std::string& path, Readable*, uint32_t channel); /* instances of an analysis object will have this method called whenever there are results to process. if out is non-null, diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index e35b041a08..5bc59a715a 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -148,6 +148,8 @@ class AudioRegion : public Region void set_playlist (boost::weak_ptr); + int get_transients (std::vector&); + private: friend class RegionFactory; diff --git a/libs/ardour/ardour/transient_detector.h b/libs/ardour/ardour/transient_detector.h index 45172d8f54..c65bae3ed5 100644 --- a/libs/ardour/ardour/transient_detector.h +++ b/libs/ardour/ardour/transient_detector.h @@ -40,7 +40,7 @@ class TransientDetector : public AudioAnalyser float get_threshold () const; float get_sensitivity () const; - int run (const std::string& path, boost::shared_ptr, uint32_t channel, std::vector& results); + int run (const std::string& path, Readable*, uint32_t channel, std::vector& results); protected: std::vector* current_results; diff --git a/libs/ardour/audioanalyser.cc b/libs/ardour/audioanalyser.cc index 86bf1c51be..4cc99a5d5e 100644 --- a/libs/ardour/audioanalyser.cc +++ b/libs/ardour/audioanalyser.cc @@ -37,6 +37,7 @@ AudioAnalyser::initialize_plugin (AnalysisPluginKey key, float sr) plugin = loader->loadPlugin (key, sr, PluginLoader::ADAPT_ALL); if (!plugin) { + error << string_compose (_("VAMP Plugin \"%1\" could not be loaded"), key) << endmsg; return -1; } @@ -69,7 +70,7 @@ AudioAnalyser::reset () } int -AudioAnalyser::analyse (const string& path, boost::shared_ptr src, uint32_t channel) +AudioAnalyser::analyse (const string& path, Readable* src, uint32_t channel) { ofstream ofile; Plugin::FeatureSet onsets; diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index ebf42255cc..01728a8c01 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -43,6 +43,7 @@ #include #include #include +#include #include "i18n.h" #include @@ -1502,6 +1503,68 @@ AudioRegion::set_playlist (boost::weak_ptr wpl) } } +int +AudioRegion::get_transients (vector& results) +{ + if (!playlist()) { + return -1; + } + + TransientDetector t (playlist()->session().frame_rate()); + bool existing_results = !results.empty(); + + for (uint32_t i = 0; i < n_channels(); ++i) { + + vector these_results; + + t.reset (); + + if (t.run ("", this, i, these_results)) { + return -1; + } + + /* translate all transients to give absolute position */ + + for (vector::iterator i = these_results.begin(); i != these_results.end(); ++i) { + (*i) += _position; + } + + /* merge */ + + results.insert (results.end(), these_results.begin(), these_results.end()); + } + + if (!results.empty() && (existing_results || n_channels() > 1)) { + + /* 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); + + /* XXX force a 3msec gap - use a config variable */ + + nframes64_t gap_frames = (nframes64_t) floor (3.0 * (playlist()->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; +} + + extern "C" { int region_read_peaks_from_c (void *arg, uint32_t npeaks, uint32_t start, uint32_t cnt, intptr_t data, uint32_t n_chan, double samples_per_unit) diff --git a/libs/ardour/transient_detector.cc b/libs/ardour/transient_detector.cc index cc554ee544..b85700dd90 100644 --- a/libs/ardour/transient_detector.cc +++ b/libs/ardour/transient_detector.cc @@ -7,7 +7,7 @@ using namespace ARDOUR; using namespace std; TransientDetector::TransientDetector (float sr) - : AudioAnalyser (sr, X_("ardour-vamp-plugins:percussiononsets")) + : AudioAnalyser (sr, X_("libardourvampplugins:percussiononsets")) { } @@ -16,7 +16,7 @@ TransientDetector::~TransientDetector() } int -TransientDetector::run (const std::string& path, boost::shared_ptr src, uint32_t channel, vector& results) +TransientDetector::run (const std::string& path, Readable* src, uint32_t channel, vector& results) { current_results = &results; int ret = analyse (path, src, channel); @@ -37,7 +37,7 @@ TransientDetector::use_features (Plugin::FeatureSet& features, ostream* out) (*out) << (*f).timestamp.toString() << endl; } - current_results->push_back (RealTime::realTime2Frame ((*f).timestamp, sample_rate)); + current_results->push_back (RealTime::realTime2Frame ((*f).timestamp, (nframes_t) floor(sample_rate))); } } -- cgit v1.2.3