lincoln's patch to use QM onset detection in RFerret, and other tweaks
git-svn-id: svn://localhost/ardour2/branches/3.0@9031 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
730cdb38bc
commit
5fb296cd6b
@ -56,7 +56,7 @@ static const gchar * _operation_strings[] = {
|
|||||||
RhythmFerret::RhythmFerret (Editor& e)
|
RhythmFerret::RhythmFerret (Editor& e)
|
||||||
: ArdourDialog (_("Rhythm Ferret"))
|
: ArdourDialog (_("Rhythm Ferret"))
|
||||||
, editor (e)
|
, 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)
|
, detection_threshold_scale (detection_threshold_adjustment)
|
||||||
, sensitivity_adjustment (40, 0, 100, 1, 10)
|
, sensitivity_adjustment (40, 0, 100, 1, 10)
|
||||||
, sensitivity_scale (sensitivity_adjustment)
|
, sensitivity_scale (sensitivity_adjustment)
|
||||||
@ -84,6 +84,7 @@ RhythmFerret::RhythmFerret (Editor& e)
|
|||||||
XXX there should be a non-hacky way to set this
|
XXX there should be a non-hacky way to set this
|
||||||
*/
|
*/
|
||||||
onset_detection_function_selector.set_active_text (onset_function_strings[3]);
|
onset_detection_function_selector.set_active_text (onset_function_strings[3]);
|
||||||
|
detection_threshold_scale.set_digits (3);
|
||||||
|
|
||||||
Table* t = manage (new Table (7, 3));
|
Table* t = manage (new Table (7, 3));
|
||||||
t->set_spacings (12);
|
t->set_spacings (12);
|
||||||
@ -145,6 +146,7 @@ RhythmFerret::analysis_mode_changed ()
|
|||||||
{
|
{
|
||||||
bool const perc = get_analysis_mode() == PercussionOnset;
|
bool const perc = get_analysis_mode() == PercussionOnset;
|
||||||
|
|
||||||
|
trigger_gap_spinner.set_sensitive (!perc);
|
||||||
detection_threshold_scale.set_sensitive (perc);
|
detection_threshold_scale.set_sensitive (perc);
|
||||||
sensitivity_scale.set_sensitive (perc);
|
sensitivity_scale.set_sensitive (perc);
|
||||||
onset_detection_function_selector.set_sensitive (!perc);
|
onset_detection_function_selector.set_sensitive (!perc);
|
||||||
@ -230,20 +232,12 @@ RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr<Readable> readabl
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* translate all transients to give absolute position */
|
|
||||||
|
|
||||||
//for (AnalysisFeatureList::iterator x = these_results.begin(); x != these_results.end(); ++x) {
|
|
||||||
// (*x) += offset;
|
|
||||||
//}
|
|
||||||
|
|
||||||
/* merge */
|
/* merge */
|
||||||
|
|
||||||
results.insert (results.end(), these_results.begin(), these_results.end());
|
results.insert (results.end(), these_results.begin(), these_results.end());
|
||||||
these_results.clear ();
|
these_results.clear ();
|
||||||
}
|
|
||||||
|
|
||||||
if (!results.empty()) {
|
t.update_positions (readable.get(), i, results);
|
||||||
TransientDetector::cleanup_transients (results, _session->frame_rate(), trigger_gap_adjustment.get_value());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -260,8 +254,10 @@ RhythmFerret::get_note_onset_function ()
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fatal << string_compose (_("programming error: %1 (%2)"), X_("illegal note onset function string"), txt)
|
fatal << string_compose (_("programming error: %1 (%2)"), X_("illegal note onset function string"), txt)
|
||||||
<< endmsg;
|
<< endmsg;
|
||||||
|
|
||||||
/*NOTREACHED*/
|
/*NOTREACHED*/
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -286,12 +282,6 @@ RhythmFerret::run_note_onset_analysis (boost::shared_ptr<Readable> readable, fra
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* translate all transients to give absolute position */
|
|
||||||
|
|
||||||
//for (AnalysisFeatureList::iterator x = these_results.begin(); x != these_results.end(); ++x) {
|
|
||||||
// (*x) += offset;
|
|
||||||
//}
|
|
||||||
|
|
||||||
/* merge */
|
/* merge */
|
||||||
|
|
||||||
results.insert (results.end(), these_results.begin(), these_results.end());
|
results.insert (results.end(), these_results.begin(), these_results.end());
|
||||||
@ -345,6 +335,8 @@ RhythmFerret::do_split_action ()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editor.EditorFreeze(); /* Emit signal */
|
||||||
|
|
||||||
_session->begin_reversible_command (_("split regions (rhythm ferret)"));
|
_session->begin_reversible_command (_("split regions (rhythm ferret)"));
|
||||||
|
|
||||||
/* Merge the transient positions for regions in consideration */
|
/* Merge the transient positions for regions in consideration */
|
||||||
@ -368,16 +360,15 @@ RhythmFerret::do_split_action ()
|
|||||||
tmp = i;
|
tmp = i;
|
||||||
++tmp;
|
++tmp;
|
||||||
|
|
||||||
AnalysisFeatureList features;
|
editor.split_region_at_points ((*i)->region(), merged_features, false, false);
|
||||||
features = (*i)->region()->transients();
|
|
||||||
editor.split_region_at_points ((*i)->region(), merged_features, false, true);
|
|
||||||
|
|
||||||
/* i is invalid at this point */
|
/* i is invalid at this point */
|
||||||
|
|
||||||
i = tmp;
|
i = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
_session->commit_reversible_command ();
|
_session->commit_reversible_command ();
|
||||||
|
|
||||||
|
editor.EditorThaw(); /* Emit signal */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -399,9 +390,11 @@ void
|
|||||||
RhythmFerret::clear_transients ()
|
RhythmFerret::clear_transients ()
|
||||||
{
|
{
|
||||||
current_results.clear ();
|
current_results.clear ();
|
||||||
|
|
||||||
for (RegionSelection::iterator i = regions_with_transients.begin(); i != regions_with_transients.end(); ++i) {
|
for (RegionSelection::iterator i = regions_with_transients.begin(); i != regions_with_transients.end(); ++i) {
|
||||||
(*i)->region()->set_transients (current_results);
|
(*i)->region()->set_transients (current_results);
|
||||||
}
|
}
|
||||||
|
|
||||||
regions_with_transients.clear ();
|
regions_with_transients.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
class AudioSource;
|
class AudioSource;
|
||||||
|
class Readable;
|
||||||
class Session;
|
class Session;
|
||||||
|
|
||||||
class TransientDetector : public AudioAnalyser
|
class TransientDetector : public AudioAnalyser
|
||||||
@ -43,14 +44,17 @@ class TransientDetector : public AudioAnalyser
|
|||||||
float get_sensitivity () const;
|
float get_sensitivity () const;
|
||||||
|
|
||||||
int run (const std::string& path, Readable*, uint32_t channel, AnalysisFeatureList& results);
|
int run (const std::string& path, Readable*, uint32_t channel, AnalysisFeatureList& results);
|
||||||
|
void update_positions (Readable* src, uint32_t channel, AnalysisFeatureList& results);
|
||||||
|
|
||||||
static void cleanup_transients (AnalysisFeatureList&, float sr, float gap_msecs);
|
static void cleanup_transients (AnalysisFeatureList&, float sr, float gap_msecs);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AnalysisFeatureList* current_results;
|
AnalysisFeatureList* current_results;
|
||||||
int use_features (Vamp::Plugin::FeatureSet&, std::ostream*);
|
int use_features (Vamp::Plugin::FeatureSet&, std::ostream*);
|
||||||
|
|
||||||
static std::string _op_id;
|
static std::string _op_id;
|
||||||
|
float threshold;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace */
|
} /* namespace */
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "ardour/readable.h"
|
||||||
#include "ardour/transient_detector.h"
|
#include "ardour/transient_detector.h"
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
@ -9,18 +11,20 @@ using namespace std;
|
|||||||
|
|
||||||
/* need a static initializer function for this */
|
/* need a static initializer function for this */
|
||||||
|
|
||||||
string TransientDetector::_op_id = X_("libardourvampplugins:percussiononsets:2");
|
string TransientDetector::_op_id = X_("libardourvampplugins:qm-onsetdetector:2");
|
||||||
|
|
||||||
TransientDetector::TransientDetector (float sr)
|
TransientDetector::TransientDetector (float sr)
|
||||||
: AudioAnalyser (sr, X_("libardourvampplugins:percussiononsets"))
|
: AudioAnalyser (sr, X_("libardourvampplugins:qm-onsetdetector"))
|
||||||
{
|
{
|
||||||
/* update the op_id */
|
/* update the op_id */
|
||||||
|
|
||||||
_op_id = X_("libardourvampplugins:percussiononsets");
|
_op_id = X_("libardourvampplugins:qm-onsetdetector");
|
||||||
|
|
||||||
// XXX this should load the above-named plugin and get the current version
|
// XXX this should load the above-named plugin and get the current version
|
||||||
|
|
||||||
_op_id += ":2";
|
_op_id += ":2";
|
||||||
|
|
||||||
|
threshold = 0.00;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransientDetector::~TransientDetector()
|
TransientDetector::~TransientDetector()
|
||||||
@ -40,6 +44,7 @@ TransientDetector::run (const std::string& path, Readable* src, uint32_t channel
|
|||||||
int ret = analyse (path, src, channel);
|
int ret = analyse (path, src, channel);
|
||||||
|
|
||||||
current_results = 0;
|
current_results = 0;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,15 +71,14 @@ TransientDetector::use_features (Plugin::FeatureSet& features, ostream* out)
|
|||||||
void
|
void
|
||||||
TransientDetector::set_threshold (float val)
|
TransientDetector::set_threshold (float val)
|
||||||
{
|
{
|
||||||
if (plugin) {
|
threshold = val;
|
||||||
plugin->setParameter ("threshold", val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TransientDetector::set_sensitivity (float val)
|
TransientDetector::set_sensitivity (float val)
|
||||||
{
|
{
|
||||||
if (plugin) {
|
if (plugin) {
|
||||||
|
plugin->selectProgram ("Percussive onsets");
|
||||||
plugin->setParameter ("sensitivity", val);
|
plugin->setParameter ("sensitivity", val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,3 +121,52 @@ TransientDetector::cleanup_transients (AnalysisFeatureList& t, float sr, float g
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TransientDetector::update_positions (Readable* src, uint32_t channel, AnalysisFeatureList& positions)
|
||||||
|
{
|
||||||
|
Plugin::FeatureSet features;
|
||||||
|
|
||||||
|
Sample* data = 0;
|
||||||
|
float* bufs[1] = { 0 };
|
||||||
|
|
||||||
|
int buff_size = 1024;
|
||||||
|
int step_size = 64;
|
||||||
|
|
||||||
|
data = new Sample[buff_size];
|
||||||
|
bufs[0] = data;
|
||||||
|
|
||||||
|
AnalysisFeatureList::iterator i = positions.begin();
|
||||||
|
|
||||||
|
while (i != positions.end()) {
|
||||||
|
|
||||||
|
framecnt_t to_read;
|
||||||
|
|
||||||
|
/* read from source */
|
||||||
|
to_read = buff_size;
|
||||||
|
|
||||||
|
if (src->read (data, (*i) - buff_size, to_read, channel) != to_read) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple heuristic for locating approx correct cut position.
|
||||||
|
|
||||||
|
for (int j = 0; j < buff_size;){
|
||||||
|
|
||||||
|
Sample s = abs (data[j]);
|
||||||
|
Sample s2 = abs (data[j + step_size]);
|
||||||
|
|
||||||
|
if ((s2 - s) > threshold){
|
||||||
|
//cerr << "Thresh exceeded. Moving pos from: " << (*i) << " to: " << (*i) - buff_size + (j + 16) << endl;
|
||||||
|
(*i) = (*i) - buff_size + (j + 24);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
j = j + step_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] data;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user