1 /*
2  * Copyright (C) 2008-2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2009-2010 David Robillard <d@drobilla.net>
4  * Copyright (C) 2015-2016 Robin Gareus <robin@gareus.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include <cmath>
22 #include "ardour/onset_detector.h"
23 
24 #include "pbd/i18n.h"
25 
26 using namespace Vamp;
27 using namespace ARDOUR;
28 using namespace std;
29 
30 /* need a static initializer function for this */
31 
32 string OnsetDetector::_op_id = X_("aubio-onset");
33 
OnsetDetector(float sr)34 OnsetDetector::OnsetDetector (float sr)
35 	: AudioAnalyser (sr, X_("libardourvampplugins:aubioonset"))
36 	, current_results (0)
37 {
38 }
39 
~OnsetDetector()40 OnsetDetector::~OnsetDetector()
41 {
42 }
43 
44 string
operational_identifier()45 OnsetDetector::operational_identifier()
46 {
47 	return _op_id;
48 }
49 
50 int
run(const std::string & path,Readable * src,uint32_t channel,AnalysisFeatureList & results)51 OnsetDetector::run (const std::string& path, Readable* src, uint32_t channel, AnalysisFeatureList& results)
52 {
53 	current_results = &results;
54 	int ret = analyse (path, src, channel);
55 
56 	current_results = 0;
57 	return ret;
58 }
59 
60 int
use_features(Plugin::FeatureSet & features,ostream * out)61 OnsetDetector::use_features (Plugin::FeatureSet& features, ostream* out)
62 {
63 	const Plugin::FeatureList& fl (features[0]);
64 
65 	for (Plugin::FeatureList::const_iterator f = fl.begin(); f != fl.end(); ++f) {
66 
67 		if ((*f).hasTimestamp) {
68 
69 			if (out) {
70 				(*out) << (*f).timestamp.toString() << endl;
71 			}
72 
73 			current_results->push_back (RealTime::realTime2Frame ((*f).timestamp, (samplecnt_t) floor(sample_rate)));
74 		}
75 	}
76 
77 	return 0;
78 }
79 
80 void
set_silence_threshold(float val)81 OnsetDetector::set_silence_threshold (float val)
82 {
83 	if (plugin) {
84 		plugin->setParameter ("silencethreshold", val);
85 	}
86 }
87 
88 void
set_peak_threshold(float val)89 OnsetDetector::set_peak_threshold (float val)
90 {
91 	if (plugin) {
92 		plugin->setParameter ("peakpickthreshold", val);
93 	}
94 }
95 
96 void
set_minioi(float val)97 OnsetDetector::set_minioi (float val)
98 {
99 #ifdef HAVE_AUBIO4
100 	if (plugin) {
101 		plugin->setParameter ("minioi", val);
102 	}
103 #endif
104 }
105 
106 void
set_function(int val)107 OnsetDetector::set_function (int val)
108 {
109 	if (plugin) {
110 		plugin->setParameter ("onsettype", (float) val);
111 	}
112 }
113 
114 void
cleanup_onsets(AnalysisFeatureList & t,float sr,float gap_msecs)115 OnsetDetector::cleanup_onsets (AnalysisFeatureList& t, float sr, float gap_msecs)
116 {
117 	if (t.empty()) {
118 		return;
119 	}
120 
121 	t.sort ();
122 
123 	/* remove duplicates or other things that are too close */
124 
125 	AnalysisFeatureList::iterator i = t.begin();
126 	AnalysisFeatureList::iterator f, b;
127 	const samplecnt_t gap_samples = (samplecnt_t) floor (gap_msecs * (sr / 1000.0));
128 
129 	while (i != t.end()) {
130 
131 		// move front iterator to just past i, and back iterator the same place
132 
133 		f = i;
134 		++f;
135 		b = f;
136 
137 		// move f until we find a new value that is far enough away
138 
139 		while ((f != t.end()) && (((*f) - (*i)) < gap_samples)) {
140 			++f;
141 		}
142 
143 		i = f;
144 
145 		// if f moved forward from b, we had duplicates/too-close points: get rid of them
146 
147 		if (b != f) {
148 			t.erase (b, f);
149 		}
150 	}
151 }
152