ardour
transient_detector.cc
Go to the documentation of this file.
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 
22 #include "ardour/readable.h"
24 
25 #include "i18n.h"
26 
27 using namespace Vamp;
28 using namespace ARDOUR;
29 using namespace std;
30 
31 /* need a static initializer function for this */
32 
33 string TransientDetector::_op_id = X_("libardourvampplugins:qm-onsetdetector:2");
34 
35 TransientDetector::TransientDetector (float sr)
36  : AudioAnalyser (sr, X_("libardourvampplugins:qm-onsetdetector"))
37 {
38  /* update the op_id */
39 
40  _op_id = X_("libardourvampplugins:qm-onsetdetector");
41 
42  // XXX this should load the above-named plugin and get the current version
43 
44  _op_id += ":2";
45 
46  threshold = 0.00;
47 }
48 
50 {
51 }
52 
53 string
55 {
56  return _op_id;
57 }
58 
59 int
60 TransientDetector::run (const std::string& path, Readable* src, uint32_t channel, AnalysisFeatureList& results)
61 {
62  current_results = &results;
63  int ret = analyse (path, src, channel);
64 
65  current_results = 0;
66 
67  return ret;
68 }
69 
70 int
71 TransientDetector::use_features (Plugin::FeatureSet& features, ostream* out)
72 {
73  const Plugin::FeatureList& fl (features[0]);
74 
75  for (Plugin::FeatureList::const_iterator f = fl.begin(); f != fl.end(); ++f) {
76 
77  if (f->hasTimestamp) {
78 
79  if (out) {
80  (*out) << (*f).timestamp.toString() << endl;
81  }
82 
83  current_results->push_back (RealTime::realTime2Frame (f->timestamp, (framecnt_t) floor(sample_rate)));
84  }
85  }
86 
87  return 0;
88 }
89 
90 void
92 {
93  threshold = val;
94 }
95 
96 void
98 {
99  if (plugin) {
100  plugin->selectProgram ("Percussive onsets");
101  plugin->setParameter ("sensitivity", val);
102  }
103 }
104 
105 void
107 {
108  if (t.empty()) {
109  return;
110  }
111 
112  t.sort ();
113 
114  /* remove duplicates or other things that are too close */
115 
116  AnalysisFeatureList::iterator i = t.begin();
117  AnalysisFeatureList::iterator f, b;
118  const framecnt_t gap_frames = (framecnt_t) floor (gap_msecs * (sr / 1000.0));
119 
120  while (i != t.end()) {
121 
122  // move front iterator to just past i, and back iterator the same place
123 
124  f = i;
125  ++f;
126  b = f;
127 
128  // move f until we find a new value that is far enough away
129 
130  while ((f != t.end()) && (((*f) - (*i)) < gap_frames)) {
131  ++f;
132  }
133 
134  i = f;
135 
136  // if f moved forward from b, we had duplicates/too-close points: get rid of them
137 
138  if (b != f) {
139  t.erase (b, f);
140  }
141  }
142 }
143 
144 void
146 {
147  int const buff_size = 1024;
148  int const step_size = 64;
149 
150  Sample* data = new Sample[buff_size];
151 
152  AnalysisFeatureList::iterator i = positions.begin();
153 
154  while (i != positions.end()) {
155 
156  /* read from source */
157  framecnt_t const to_read = buff_size;
158 
159  if (src->read (data, (*i) - buff_size, to_read, channel) != to_read) {
160  break;
161  }
162 
163  // Simple heuristic for locating approx correct cut position.
164 
165  for (int j = 0; j < (buff_size - step_size); ) {
166 
167  Sample const s = abs (data[j]);
168  Sample const s2 = abs (data[j + step_size]);
169 
170  if ((s2 - s) > threshold) {
171  //cerr << "Thresh exceeded. Moving pos from: " << (*i) << " to: " << (*i) - buff_size + (j + 16) << endl;
172  (*i) = (*i) - buff_size + (j + 24);
173  break;
174  }
175 
176  j += step_size;
177  }
178 
179  ++i;
180  }
181 
182  delete [] data;
183 }
int use_features(Vamp::Plugin::FeatureSet &, std::ostream *)
static void cleanup_transients(AnalysisFeatureList &, float sr, float gap_msecs)
int analyse(const std::string &path, Readable *, uint32_t channel)
tuple f
Definition: signals.py:35
AnalysisFeatureList * current_results
Definition: Beats.hpp:239
virtual framecnt_t read(Sample *, framepos_t pos, framecnt_t cnt, int channel) const =0
#define X_(Text)
Definition: i18n.h:13
int64_t framecnt_t
Definition: types.h:76
float Sample
Definition: types.h:54
std::list< framepos_t > AnalysisFeatureList
Definition: types.h:530
Definition: amp.h:29
AnalysisPlugin * plugin
Definition: audioanalyser.h:57
int run(const std::string &path, Readable *, uint32_t channel, AnalysisFeatureList &results)
void update_positions(Readable *src, uint32_t channel, AnalysisFeatureList &results)
static std::string operational_identifier()