~ubuntu-branches/ubuntu/gutsy/audacity/gutsy-backports

« back to all changes in this revision

Viewing changes to lib-src/libvamp/host/vamp-simple-host.cpp

  • Committer: Bazaar Package Importer
  • Author(s): John Dong
  • Date: 2008-02-18 21:58:19 UTC
  • mfrom: (13.1.2 hardy)
  • Revision ID: james.westby@ubuntu.com-20080218215819-tmbcf1rx238r8gdv
Tags: 1.3.4-1.1ubuntu1~gutsy1
Automated backport upload; no source changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
 
2
 
 
3
/*
 
4
    Vamp
 
5
 
 
6
    An API for audio analysis and feature extraction plugins.
 
7
 
 
8
    Centre for Digital Music, Queen Mary, University of London.
 
9
    Copyright 2006 Chris Cannam.
 
10
    FFT code from Don Cross's public domain FFT implementation.
 
11
  
 
12
    Permission is hereby granted, free of charge, to any person
 
13
    obtaining a copy of this software and associated documentation
 
14
    files (the "Software"), to deal in the Software without
 
15
    restriction, including without limitation the rights to use, copy,
 
16
    modify, merge, publish, distribute, sublicense, and/or sell copies
 
17
    of the Software, and to permit persons to whom the Software is
 
18
    furnished to do so, subject to the following conditions:
 
19
 
 
20
    The above copyright notice and this permission notice shall be
 
21
    included in all copies or substantial portions of the Software.
 
22
 
 
23
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
24
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
25
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
26
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
 
27
    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 
28
    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
29
    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
30
 
 
31
    Except as contained in this notice, the names of the Centre for
 
32
    Digital Music; Queen Mary, University of London; and Chris Cannam
 
33
    shall not be used in advertising or otherwise to promote the sale,
 
34
    use or other dealings in this Software without prior written
 
35
    authorization.
 
36
*/
 
37
 
 
38
#include "vamp-sdk/PluginHostAdapter.h"
 
39
#include "vamp-sdk/hostext/PluginChannelAdapter.h"
 
40
#include "vamp-sdk/hostext/PluginInputDomainAdapter.h"
 
41
#include "vamp-sdk/hostext/PluginLoader.h"
 
42
#include "vamp/vamp.h"
 
43
 
 
44
#include <iostream>
 
45
#include <sndfile.h>
 
46
 
 
47
#include "system.h"
 
48
 
 
49
#include <cmath>
 
50
 
 
51
using std::cout;
 
52
using std::cerr;
 
53
using std::endl;
 
54
using std::string;
 
55
using std::vector;
 
56
 
 
57
using Vamp::HostExt::PluginLoader;
 
58
 
 
59
#define HOST_VERSION "1.1"
 
60
 
 
61
void printFeatures(int, int, int, Vamp::Plugin::FeatureSet);
 
62
void transformInput(float *, size_t);
 
63
void fft(unsigned int, bool, double *, double *, double *, double *);
 
64
void printPluginPath(bool verbose);
 
65
void enumeratePlugins();
 
66
void listPluginsInLibrary(string soname);
 
67
int runPlugin(string myname, string soname, string id, string output,
 
68
              int outputNo, string inputFile);
 
69
 
 
70
void usage(const char *name)
 
71
{
 
72
    cerr << "\n"
 
73
         << name << ": A simple Vamp plugin host.\n\n"
 
74
        "Centre for Digital Music, Queen Mary, University of London.\n"
 
75
        "Copyright 2006-2007 Chris Cannam and QMUL.\n"
 
76
        "Freely redistributable; published under a BSD-style license.\n\n"
 
77
        "Usage:\n\n"
 
78
        "  " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav\n"
 
79
        "  " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno]\n\n"
 
80
        "    -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n"
 
81
        "       audio data in \"file.wav\", retrieving the named \"output\", or output\n"
 
82
        "       number \"outputno\" (the first output by default) and dumping it to\n"
 
83
        "       standard output.\n\n"
 
84
        "       \"pluginlibrary\" should be a library name, not a file path; the\n"
 
85
        "       standard Vamp library search path will be used to locate it.  If\n"
 
86
        "       a file path is supplied, the directory part(s) will be ignored.\n\n"
 
87
        "  " << name << " -l\n\n"
 
88
        "    -- List the plugin libraries and Vamp plugins in the library search path.\n\n"
 
89
        "  " << name << " -p\n\n"
 
90
        "    -- Print out the Vamp library search path.\n\n"
 
91
        "  " << name << " -v\n\n"
 
92
        "    -- Display version information only.\n\n"
 
93
         << endl;
 
94
    exit(2);
 
95
}
 
96
 
 
97
int main(int argc, char **argv)
 
98
{
 
99
    char *scooter = argv[0];
 
100
    char *name = 0;
 
101
    while (scooter && *scooter) {
 
102
        if (*scooter == '/' || *scooter == '\\') name = ++scooter;
 
103
        else ++scooter;
 
104
    }
 
105
    if (!name || !*name) name = argv[0];
 
106
    
 
107
    if (argc < 2 || argc > 4 ||
 
108
        (argc == 2 &&
 
109
         (!strcmp(argv[1], "-?") ||
 
110
          !strcmp(argv[1], "-h") ||
 
111
          !strcmp(argv[1], "--help")))) {
 
112
 
 
113
        usage(name); // does not return
 
114
    }
 
115
 
 
116
    if (argc == 2 && !strcmp(argv[1], "-v")) {
 
117
        cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl
 
118
             << "Vamp API version: " << VAMP_API_VERSION << endl
 
119
             << "Vamp SDK version: " << VAMP_SDK_VERSION << endl;
 
120
        return 0;
 
121
    }
 
122
    
 
123
    if (argc == 2 && !strcmp(argv[1], "-l")) {
 
124
        printPluginPath(true);
 
125
        enumeratePlugins();
 
126
        return 0;
 
127
    }
 
128
    if (argc == 2 && !strcmp(argv[1], "-p")) {
 
129
        printPluginPath(false);
 
130
        return 0;
 
131
    }
 
132
 
 
133
    cerr << endl << name << ": Running..." << endl;
 
134
 
 
135
    string soname = argv[1];
 
136
    string plugid = "";
 
137
    string output = "";
 
138
    int outputNo = -1;
 
139
    string wavname;
 
140
    if (argc >= 3) wavname = argv[2];
 
141
 
 
142
    string::size_type sep = soname.find(':');
 
143
 
 
144
    if (sep != string::npos) {
 
145
        plugid = soname.substr(sep + 1);
 
146
        soname = soname.substr(0, sep);
 
147
 
 
148
        sep = plugid.find(':');
 
149
        if (sep != string::npos) {
 
150
            output = plugid.substr(sep + 1);
 
151
            plugid = plugid.substr(0, sep);
 
152
        }
 
153
    }
 
154
 
 
155
    if (plugid == "") {
 
156
        usage(name);
 
157
    }
 
158
 
 
159
    if (argc == 4) outputNo = atoi(argv[3]);
 
160
 
 
161
    if (output != "" && outputNo != -1) {
 
162
        usage(name);
 
163
    }
 
164
 
 
165
    return runPlugin(name, soname, plugid, output, outputNo, wavname);
 
166
}
 
167
 
 
168
 
 
169
int runPlugin(string myname, string soname, string id,
 
170
              string output, int outputNo, string wavname)
 
171
{
 
172
    PluginLoader *loader = PluginLoader::getInstance();
 
173
 
 
174
    PluginLoader::PluginKey key = loader->composePluginKey(soname, id);
 
175
    
 
176
    SNDFILE *sndfile;
 
177
    SF_INFO sfinfo;
 
178
    memset(&sfinfo, 0, sizeof(SF_INFO));
 
179
 
 
180
    sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
 
181
    if (!sndfile) {
 
182
        cerr << myname << ": ERROR: Failed to open input file \""
 
183
             << wavname << "\": " << sf_strerror(sndfile) << endl;
 
184
        return 1;
 
185
    }
 
186
 
 
187
    Vamp::Plugin *plugin = loader->loadPlugin
 
188
        (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL);
 
189
    if (!plugin) {
 
190
        cerr << myname << ": ERROR: Failed to load plugin \"" << id
 
191
             << "\" from library \"" << soname << "\"" << endl;
 
192
        sf_close(sndfile);
 
193
        return 1;
 
194
    }
 
195
 
 
196
    cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
 
197
 
 
198
    int blockSize = plugin->getPreferredBlockSize();
 
199
    int stepSize = plugin->getPreferredStepSize();
 
200
 
 
201
    int channels = sfinfo.channels;
 
202
 
 
203
    float *filebuf = new float[blockSize * channels];
 
204
    float **plugbuf = new float*[channels];
 
205
    for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2];
 
206
 
 
207
    cerr << "Using block size = " << blockSize << ", step size = "
 
208
              << stepSize << endl;
 
209
 
 
210
    int minch = plugin->getMinChannelCount();
 
211
    int maxch = plugin->getMaxChannelCount();
 
212
    cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
 
213
    cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
 
214
 
 
215
    Vamp::Plugin::OutputList outputs = plugin->getOutputDescriptors();
 
216
    Vamp::Plugin::OutputDescriptor od;
 
217
 
 
218
    int returnValue = 1;
 
219
 
 
220
    if (outputs.empty()) {
 
221
        cerr << "ERROR: Plugin has no outputs!" << endl;
 
222
        goto done;
 
223
    }
 
224
 
 
225
    if (outputNo < 0) {
 
226
 
 
227
        for (size_t oi = 0; oi < outputs.size(); ++oi) {
 
228
            if (outputs[oi].identifier == output) {
 
229
                outputNo = oi;
 
230
                break;
 
231
            }
 
232
        }
 
233
 
 
234
        if (outputNo < 0) {
 
235
            cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
 
236
            goto done;
 
237
        }
 
238
 
 
239
    } else {
 
240
 
 
241
        if (int(outputs.size()) <= outputNo) {
 
242
            cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
 
243
            goto done;
 
244
        }        
 
245
    }
 
246
 
 
247
    od = outputs[outputNo];
 
248
    cerr << "Output is: \"" << od.identifier << "\"" << endl;
 
249
 
 
250
    if (!plugin->initialise(channels, stepSize, blockSize)) {
 
251
        cerr << "ERROR: Plugin initialise (channels = " << channels
 
252
             << ", stepSize = " << stepSize << ", blockSize = "
 
253
             << blockSize << ") failed." << endl;
 
254
        goto done;
 
255
    }
 
256
 
 
257
    for (size_t i = 0; i < sfinfo.frames; i += stepSize) {
 
258
 
 
259
        int count;
 
260
 
 
261
        if (sf_seek(sndfile, i, SEEK_SET) < 0) {
 
262
            cerr << "ERROR: sf_seek failed: " << sf_strerror(sndfile) << endl;
 
263
            break;
 
264
        }
 
265
        
 
266
        if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) {
 
267
            cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
 
268
            break;
 
269
        }
 
270
 
 
271
        for (int c = 0; c < channels; ++c) {
 
272
            int j = 0;
 
273
            while (j < count) {
 
274
                plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
 
275
                ++j;
 
276
            }
 
277
            while (j < blockSize) {
 
278
                plugbuf[c][j] = 0.0f;
 
279
                ++j;
 
280
            }
 
281
        }
 
282
 
 
283
        printFeatures
 
284
            (i, sfinfo.samplerate, outputNo, plugin->process
 
285
             (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate)));
 
286
    }
 
287
 
 
288
    printFeatures(sfinfo.frames, sfinfo.samplerate, outputNo,
 
289
                  plugin->getRemainingFeatures());
 
290
 
 
291
    returnValue = 0;
 
292
 
 
293
done:
 
294
    delete plugin;
 
295
    sf_close(sndfile);
 
296
    return returnValue;
 
297
}
 
298
 
 
299
void
 
300
printPluginPath(bool verbose)
 
301
{
 
302
    if (verbose) {
 
303
        cout << "\nVamp plugin search path: ";
 
304
    }
 
305
 
 
306
    vector<string> path = Vamp::PluginHostAdapter::getPluginPath();
 
307
    for (size_t i = 0; i < path.size(); ++i) {
 
308
        if (verbose) {
 
309
            cout << "[" << path[i] << "]";
 
310
        } else {
 
311
            cout << path[i] << endl;
 
312
        }
 
313
    }
 
314
 
 
315
    if (verbose) cout << endl;
 
316
}
 
317
 
 
318
void
 
319
enumeratePlugins()
 
320
{
 
321
    PluginLoader *loader = PluginLoader::getInstance();
 
322
 
 
323
    cout << "\nVamp plugin libraries found in search path:" << endl;
 
324
 
 
325
    std::vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
 
326
    typedef std::multimap<std::string, PluginLoader::PluginKey>
 
327
        LibraryMap;
 
328
    LibraryMap libraryMap;
 
329
 
 
330
    for (size_t i = 0; i < plugins.size(); ++i) {
 
331
        std::string path = loader->getLibraryPathForPlugin(plugins[i]);
 
332
        libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
 
333
    }
 
334
 
 
335
    std::string prevPath = "";
 
336
    int index = 0;
 
337
 
 
338
    for (LibraryMap::iterator i = libraryMap.begin();
 
339
         i != libraryMap.end(); ++i) {
 
340
        
 
341
        std::string path = i->first;
 
342
        PluginLoader::PluginKey key = i->second;
 
343
 
 
344
        if (path != prevPath) {
 
345
            prevPath = path;
 
346
            index = 0;
 
347
            cout << "\n  " << path << ":" << endl;
 
348
        }
 
349
 
 
350
        Vamp::Plugin *plugin = loader->loadPlugin(key, 48000);
 
351
        if (plugin) {
 
352
 
 
353
            char c = char('A' + index);
 
354
            if (c > 'Z') c = char('a' + (index - 26));
 
355
 
 
356
            cout << "    [" << c << "] [v"
 
357
                 << plugin->getVampApiVersion() << "] "
 
358
                 << plugin->getName() << ", \""
 
359
                 << plugin->getIdentifier() << "\"" << " ["
 
360
                 << plugin->getMaker() << "]" << endl;
 
361
 
 
362
            PluginLoader::PluginCategoryHierarchy category =
 
363
                loader->getPluginCategory(key);
 
364
            if (!category.empty()) {
 
365
                cout << "       ";
 
366
                for (size_t ci = 0; ci < category.size(); ++ci) {
 
367
                    cout << " > " << category[ci];
 
368
                }
 
369
                cout << endl;
 
370
            }
 
371
 
 
372
            if (plugin->getDescription() != "") {
 
373
                cout << "        - " << plugin->getDescription() << endl;
 
374
            }
 
375
 
 
376
            Vamp::Plugin::OutputList outputs =
 
377
                plugin->getOutputDescriptors();
 
378
 
 
379
            if (outputs.size() > 1) {
 
380
                for (size_t j = 0; j < outputs.size(); ++j) {
 
381
                    cout << "         (" << j << ") "
 
382
                         << outputs[j].name << ", \""
 
383
                         << outputs[j].identifier << "\"" << endl;
 
384
                    if (outputs[j].description != "") {
 
385
                        cout << "             - " 
 
386
                             << outputs[j].description << endl;
 
387
                    }
 
388
                }
 
389
            }
 
390
 
 
391
            ++index;
 
392
 
 
393
            delete plugin;
 
394
        }
 
395
    }
 
396
 
 
397
    cout << endl;
 
398
}
 
399
 
 
400
void
 
401
printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet features)
 
402
{
 
403
    for (unsigned int i = 0; i < features[output].size(); ++i) {
 
404
        Vamp::RealTime rt = Vamp::RealTime::frame2RealTime(frame, sr);
 
405
        if (features[output][i].hasTimestamp) {
 
406
            rt = features[output][i].timestamp;
 
407
        }
 
408
        cout << rt.toString() << ":";
 
409
        for (unsigned int j = 0; j < features[output][i].values.size(); ++j) {
 
410
            cout << " " << features[output][i].values[j];
 
411
        }
 
412
        cout << endl;
 
413
    }
 
414
}
 
415
 
 
416
 
 
417