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