annotate chordextract.cpp @ 162:c585c95f2d86

Fix memory leaks
author Chris Cannam
date Tue, 27 Jan 2015 09:47:37 +0000
parents 9d706d314e08
children
rev   line source
Chris@158 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@158 2
Chris@158 3 /*
Chris@158 4 NNLS-Chroma / Chordino
Chris@158 5
Chris@158 6 Audio feature extraction plugins for chromagram and chord
Chris@158 7 estimation.
Chris@158 8
Chris@158 9 Centre for Digital Music, Queen Mary University of London.
Chris@158 10 This file copyright 2014 QMUL.
Chris@158 11
Chris@158 12 This program is free software; you can redistribute it and/or
Chris@158 13 modify it under the terms of the GNU General Public License as
Chris@158 14 published by the Free Software Foundation; either version 2 of the
Chris@158 15 License, or (at your option) any later version. See the file
Chris@158 16 COPYING included with this distribution for more information.
Chris@158 17 */
Chris@158 18
Chris@158 19 /*
Chris@158 20 Extract chords from an audio file, read using libsndfile. Works by
Chris@158 21 constructing the plugin as a C++ class directly, and using plugin
Chris@158 22 adapters from the Vamp Host SDK to provide input.
Chris@158 23
Chris@158 24 You can compile this with e.g. the following (Linux example):
Chris@158 25
Chris@158 26 $ g++ -D_VAMP_PLUGIN_IN_HOST_NAMESPACE -O2 -ffast-math chordextract.cpp Chordino.cpp NNLSBase.cpp chromamethods.cpp viterbi.cpp nnls.c -o chordextract -lsndfile -lvamp-hostsdk -ldl
Chris@158 27
Chris@158 28 But the same idea should work on any platform, so long as the Boost
Chris@158 29 Tokenizer headers and the Vamp Host SDK library are available and
Chris@158 30 the _VAMP_PLUGIN_IN_HOST_NAMESPACE preprocessor symbol is defined
Chris@158 31 throughout.
Chris@158 32 */
Chris@158 33
Chris@158 34 #define _VAMP_PLUGIN_IN_HOST_NAMESPACE 1
Chris@158 35
Chris@158 36 #include <vamp-hostsdk/PluginInputDomainAdapter.h>
Chris@158 37 #include <vamp-hostsdk/PluginBufferingAdapter.h>
Chris@158 38
Chris@158 39 #include "Chordino.h"
Chris@158 40
Chris@158 41 #include <sndfile.h>
Chris@158 42
Chris@158 43 #include <iostream>
Chris@158 44 #include <string>
Chris@158 45
Chris@158 46 using namespace std;
Chris@158 47 using namespace Vamp;
Chris@158 48 using namespace Vamp::HostExt;
Chris@158 49
Chris@158 50 int main(int argc, char **argv)
Chris@158 51 {
Chris@158 52 const char *myname = argv[0];
Chris@158 53
Chris@158 54 if (argc != 2) {
Chris@158 55 cerr << "usage: " << myname << " file.wav" << endl;
Chris@158 56 return 2;
Chris@158 57 }
Chris@158 58
Chris@158 59 const char *infile = argv[1];
Chris@158 60
Chris@158 61 SF_INFO sfinfo;
Chris@158 62 SNDFILE *sndfile = sf_open(infile, SFM_READ, &sfinfo);
Chris@158 63
Chris@158 64 if (!sndfile) {
Chris@158 65 cerr << myname << ": Failed to open input file " << infile
Chris@158 66 << ": " << sf_strerror(sndfile) << endl;
Chris@158 67 return 1;
Chris@158 68 }
Chris@158 69
Chris@158 70 Chordino *chordino = new Chordino(sfinfo.samplerate);
Chris@158 71 PluginInputDomainAdapter *ia = new PluginInputDomainAdapter(chordino);
Chris@158 72 ia->setProcessTimestampMethod(PluginInputDomainAdapter::ShiftData);
Chris@158 73 PluginBufferingAdapter *adapter = new PluginBufferingAdapter(ia);
Chris@158 74
Chris@158 75 int blocksize = adapter->getPreferredBlockSize();
Chris@158 76
Chris@158 77 // Plugin requires 1 channel (we will mix down)
Chris@158 78 if (!adapter->initialise(1, blocksize, blocksize)) {
Chris@158 79 cerr << myname << ": Failed to initialise Chordino adapter!" << endl;
Chris@158 80 return 1;
Chris@158 81 }
Chris@158 82
Chris@158 83 float *filebuf = new float[sfinfo.channels * blocksize];
Chris@158 84 float *mixbuf = new float[blocksize];
Chris@158 85
Chris@158 86 Plugin::FeatureList chordFeatures;
Chris@158 87 Plugin::FeatureSet fs;
Chris@158 88
Chris@158 89 int chordFeatureNo = -1;
Chris@158 90 Plugin::OutputList outputs = adapter->getOutputDescriptors();
Chris@158 91 for (int i = 0; i < int(outputs.size()); ++i) {
Chris@158 92 if (outputs[i].identifier == "simplechord") {
Chris@158 93 chordFeatureNo = i;
Chris@158 94 }
Chris@158 95 }
Chris@158 96 if (chordFeatureNo < 0) {
Chris@158 97 cerr << myname << ": Failed to identify chords output!" << endl;
Chris@158 98 return 1;
Chris@158 99 }
Chris@158 100
Chris@158 101 int frame = 0;
Chris@158 102 while (frame < sfinfo.frames) {
Chris@158 103
Chris@158 104 int count = -1;
Chris@158 105 if ((count = sf_readf_float(sndfile, filebuf, blocksize)) <= 0) break;
Chris@158 106
Chris@158 107 // mix down
Chris@158 108 for (int i = 0; i < blocksize; ++i) {
Chris@158 109 mixbuf[i] = 0.f;
Chris@158 110 if (i < count) {
Chris@158 111 for (int c = 0; c < sfinfo.channels; ++c) {
Chris@158 112 mixbuf[i] += filebuf[i * sfinfo.channels + c] / sfinfo.channels;
Chris@158 113 }
Chris@158 114 }
Chris@158 115 }
Chris@158 116
Chris@158 117 RealTime timestamp = RealTime::frame2RealTime(frame, sfinfo.samplerate);
Chris@158 118
Chris@158 119 // feed to plugin: can just take address of buffer, as only one channel
Chris@158 120 fs = adapter->process(&mixbuf, timestamp);
Chris@158 121
Chris@158 122 chordFeatures.insert(chordFeatures.end(),
Chris@158 123 fs[chordFeatureNo].begin(),
Chris@158 124 fs[chordFeatureNo].end());
Chris@158 125
Chris@158 126 frame += count;
Chris@158 127 }
Chris@158 128
Chris@158 129 sf_close(sndfile);
Chris@158 130
Chris@158 131 // features at end of processing (actually Chordino does all its work here)
Chris@158 132 fs = adapter->getRemainingFeatures();
Chris@158 133
Chris@158 134 // chord output is output index 0
Chris@158 135 chordFeatures.insert(chordFeatures.end(),
Chris@158 136 fs[chordFeatureNo].begin(),
Chris@158 137 fs[chordFeatureNo].end());
Chris@158 138
Chris@158 139 for (int i = 0; i < (int)chordFeatures.size(); ++i) {
Chris@160 140 cout << chordFeatures[i].timestamp.toString() << ": "
Chris@158 141 << chordFeatures[i].label << endl;
Chris@158 142 }
Chris@158 143
Chris@162 144 delete[] filebuf;
Chris@162 145 delete[] mixbuf;
Chris@162 146
Chris@158 147 delete adapter;
Chris@158 148 }
Chris@158 149