Merge with 2.0-ongoing R2988
[ardour.git] / libs / ardour / audioanalyser.cc
1 #include <vamp-sdk/hostext/PluginLoader.h>
2 #include <glibmm/miscutils.h>
3 #include <glibmm/fileutils.h>
4 #include <glib/gstdio.h> // for g_remove()
5
6 #include <pbd/error.h>
7
8 #include <ardour/audioanalyser.h>
9 #include <ardour/readable.h>
10 #include <ardour/readable.h>
11
12 #include "i18n.h"
13
14 using namespace std;
15 using namespace Vamp;
16 using namespace PBD;
17 using namespace ARDOUR;
18
19 AudioAnalyser::AudioAnalyser (float sr, AnalysisPluginKey key)
20         : sample_rate (sr)
21         , plugin_key (key)
22 {
23         /* create VAMP plugin and initialize */
24         
25         if (initialize_plugin (plugin_key, sample_rate)) {
26                 error << string_compose (_("cannot load VAMP plugin \"%1\""), key) << endmsg;
27                 throw failed_constructor();
28         } 
29 }
30
31 AudioAnalyser::~AudioAnalyser ()
32 {
33         delete plugin;
34 }
35
36 int
37 AudioAnalyser::initialize_plugin (AnalysisPluginKey key, float sr)
38 {
39         using namespace Vamp::HostExt;
40
41         PluginLoader* loader (PluginLoader::getInstance());
42
43         plugin = loader->loadPlugin (key, sr, PluginLoader::ADAPT_ALL);
44
45         if (!plugin) {
46                 error << string_compose (_("VAMP Plugin \"%1\" could not be loaded"), key) << endmsg;
47                 return -1;
48         } 
49
50         /* we asked for the buffering adapter, so set the blocksize to
51            something that makes for efficient disk i/o
52         */
53
54         bufsize = 65536;
55         stepsize = bufsize;
56
57         if (plugin->getMinChannelCount() > 1) {
58                 delete plugin;
59                 return -1;
60         }
61
62         if (!plugin->initialise (1, stepsize, bufsize)) {
63                 delete plugin;
64                 return -1;
65         }
66
67         return 0;
68 }
69
70 void
71 AudioAnalyser::reset ()
72 {
73         if (plugin) {
74                 plugin->reset ();
75         }
76 }
77         
78 int
79 AudioAnalyser::analyse (const string& path, Readable* src, uint32_t channel)
80 {
81         ofstream ofile;
82         Plugin::FeatureSet features;
83         int ret = -1;
84         bool done = false;
85         Sample* data = 0;
86         nframes64_t len = src->readable_length();
87         nframes64_t pos = 0;
88         float* bufs[1] = { 0 };
89         string tmp_path;
90
91         if (!path.empty()) {
92
93                 /* store data in tmp file, not the real one */
94                 
95                 tmp_path = path;
96                 tmp_path += ".tmp";
97
98                 ofile.open (tmp_path.c_str());
99                 if (!ofile) {
100                         goto out;
101                 }
102         }
103
104         data = new Sample[bufsize];
105         bufs[0] = data;
106
107         while (!done) {
108
109                 nframes64_t to_read;
110                 
111                 /* read from source */
112
113                 to_read = min ((len - pos), bufsize);
114                 
115                 if (src->read (data, pos, to_read, channel) != to_read) {
116                         goto out;
117                 }
118
119                 /* zero fill buffer if necessary */
120
121                 if (to_read != bufsize) {
122                         memset (data + to_read, 0, (bufsize - to_read));
123                 }
124                 
125                 features = plugin->process (bufs, RealTime::fromSeconds ((double) pos / sample_rate));
126
127                 if (use_features (features, (path.empty() ? 0 : &ofile))) {
128                         goto out;
129                 }
130
131                 pos += stepsize;
132
133                 if (pos >= len) {
134                         done = true;
135                 }
136         }
137
138         /* finish up VAMP plugin */
139
140         features = plugin->getRemainingFeatures ();
141
142         if (use_features (features, (path.empty() ? &ofile : 0))) {
143                 goto out;
144         }
145
146         ret = 0;
147
148   out:
149         /* works even if it has not been opened */
150         ofile.close ();
151
152         if (ret) {
153                 g_remove (tmp_path.c_str());
154         } else if (!path.empty()) {
155                 /* move the data file to the requested path */
156                 g_rename (tmp_path.c_str(), path.c_str());
157         }
158
159         if (data) {
160                 delete [] data;
161         }
162
163         return ret;
164 }
165