To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at https://github.com/cannam/constant-q-cpp/ .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Revision:

root / test / processfile.cpp

History | View | Annotate | Download (7.76 KB)

1

    
2
#include "ConstantQ.h"
3
#include "CQInverse.h"
4

    
5
#include <sndfile.h>
6

    
7
#include <iostream>
8

    
9
using std::vector;
10
using std::cerr;
11
using std::endl;
12

    
13
#include <cstring>
14

    
15
#include <getopt.h>
16
#include <unistd.h>
17
#include <sys/time.h>
18
#include <cstdlib>
19

    
20
int main(int argc, char **argv)
21
{
22
    double maxFreq = 0;
23
    double minFreq = 0;
24
    int bpo = 0;
25
    bool help = false;
26
    
27
    int c;
28

    
29
    while (1) {
30
        int optionIndex = 0;
31
        
32
        static struct option longOpts[] = {
33
            { "help", 0, 0, 'h', },
34
            { "maxfreq", 1, 0, 'x', },
35
            { "minfreq", 1, 0, 'n', },
36
            { "bpo", 1, 0, 'b' },
37
            { 0, 0, 0, 0 },
38
        };
39

    
40
        c = getopt_long(argc, argv,
41
                        "hx:n:b:",
42
                        longOpts, &optionIndex);
43
        if (c == -1) break;
44

    
45
        switch (c) {
46
        case 'h': help = true; break;
47
        case 'x': maxFreq = atof(optarg); break;
48
        case 'n': minFreq = atof(optarg); break;
49
        case 'b': bpo = atoi(optarg); break;
50
        default: help = true; break;
51
        }
52
    }
53

    
54
    if (help || (optind + 2 != argc && optind + 3 != argc)) {
55
        cerr << endl;
56
        cerr << "Usage: " << argv[0] << " [options] infile.wav outfile.wav [differencefile.wav]" << endl;
57
        cerr << endl;
58
        cerr << "Options:" << endl;
59
        cerr << "  -x<X>, --maxfreq <X>  Maximum frequency (default = sample rate / 3)" << endl;
60
        cerr << "  -n<X>, --minfreq <X>  Minimum frequency (default = 100, actual min may vary)" << endl;
61
        cerr << "  -b<X>, --bpo <X>      Bins per octave   (default = 60)" << endl;
62
        cerr << "  -h, --help            Print this help" << endl;
63
        cerr << endl;
64
        cerr << "This rather useless program simply performs a forward Constant-Q transform with" << endl;
65
        cerr << "the requested parameters, followed by its inverse, and writes the result to the" << endl;
66
        cerr << "output file. If a diff file name is provided, the difference between input and" << endl;
67
        cerr << "output signals is also written to that. All this accomplishes is to produce a" << endl;
68
        cerr << "signal that approximates the input: it's intended for test purposes only." << endl;
69
        cerr << endl;
70
        cerr << "(Want to calculate and obtain a Constant-Q spectrogram? Use the CQVamp plugin" << endl;
71
        cerr << "in a Vamp plugin host.)" << endl;
72
        cerr << endl;
73
        return 2;
74
    }
75

    
76
    char *fileName = strdup(argv[optind++]);
77
    char *fileNameOut = strdup(argv[optind++]);
78
    char *diffFileName = (optind < argc ? strdup(argv[optind++]) : 0);
79
    bool doDiff = (diffFileName != 0);
80

    
81
    SNDFILE *sndfile;
82
    SNDFILE *sndfileOut;
83
    SNDFILE *sndDiffFile = 0;
84
    SF_INFO sfinfo;
85
    SF_INFO sfinfoOut;
86
    SF_INFO sfinfoDiff;
87
    memset(&sfinfo, 0, sizeof(SF_INFO));
88

    
89
    sndfile = sf_open(fileName, SFM_READ, &sfinfo);
90
    if (!sndfile) {
91
        cerr << "ERROR: Failed to open input file \"" << fileName << "\": "
92
             << sf_strerror(sndfile) << endl;
93
        return 1;
94
    }
95

    
96
    sfinfoOut.channels = 1;
97
    sfinfoOut.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
98
    sfinfoOut.frames = sfinfo.frames;
99
    sfinfoOut.samplerate = sfinfo.samplerate;
100
    sfinfoOut.sections = sfinfo.sections;
101
    sfinfoOut.seekable = sfinfo.seekable;
102

    
103
    sndfileOut = sf_open(fileNameOut, SFM_WRITE, &sfinfoOut) ;
104
    if (!sndfileOut) {
105
        cerr << "ERROR: Failed to open output file \"" << fileNameOut << "\" for writing: "
106
             << sf_strerror(sndfileOut) << endl;
107
        return 1;
108
    }
109

    
110
    if (doDiff) {
111
        sfinfoDiff = sfinfoOut;
112
        sndDiffFile = sf_open(diffFileName, SFM_WRITE, &sfinfoDiff);
113
        if (!sndDiffFile) {
114
            cerr << "ERROR: Failed to open diff output file \"" << diffFileName << "\" for writing: "
115
                 << sf_strerror(sndDiffFile) << endl;
116
            return 1;
117
        }
118
    }
119

    
120
    int ibs = 1024;
121
    int channels = sfinfo.channels;
122
    float *fbuf = new float[channels * ibs];
123

    
124
    if (maxFreq == 0.0) maxFreq = sfinfo.samplerate / 3;
125
    if (minFreq == 0.0) minFreq = 100;
126
    if (bpo == 0) bpo = 60;
127

    
128
    CQParameters params(sfinfo.samplerate, minFreq, maxFreq, bpo);
129
    ConstantQ cq(params);
130
    CQInverse cqi(params);
131

    
132
    cerr << "max freq = " << cq.getMaxFrequency() << ", min freq = "
133
         << cq.getMinFrequency() << ", octaves = " << cq.getOctaves() << endl;
134

    
135
    cerr << "octave boundaries: ";
136
    for (int i = 0; i < cq.getOctaves(); ++i) {
137
        cerr << cq.getMaxFrequency() / pow(2, i) << " ";
138
    }
139
    cerr << endl;
140

    
141
    int inframe = 0;
142
    int outframe = 0;
143
    int latency = cq.getLatency() + cqi.getLatency();
144

    
145
    vector<double> buffer;
146

    
147
    double maxdiff = 0.0;
148
    int maxdiffidx = 0;
149

    
150
    cerr << "forward latency = " << cq.getLatency() << ", inverse latency = " 
151
         << cqi.getLatency() << ", total = " << latency << endl;
152

    
153
    timeval tv;
154
    (void)gettimeofday(&tv, 0);
155

    
156
    while (inframe < sfinfo.frames) {
157

    
158
        int count = -1;
159
        
160
        if ((count = sf_readf_float(sndfile, fbuf, ibs)) < 0) {
161
            break;
162
        }
163

    
164
        vector<double> cqin;
165
        for (int i = 0; i < count; ++i) {
166
            double v = fbuf[i * channels];
167
            if (channels > 1) {
168
                for (int c = 1; c < channels; ++c) {
169
                    v += fbuf[i * channels + c];
170
                }
171
                v /= channels;
172
            }
173
            cqin.push_back(v);
174
        }
175

    
176
        if (doDiff) {
177
            buffer.insert(buffer.end(), cqin.begin(), cqin.end());
178
        }
179
        
180
        vector<double> cqout = cqi.process(cq.process(cqin));
181

    
182
        for (int i = 0; i < int(cqout.size()); ++i) {
183
            if (cqout[i] > 1.0) cqout[i] = 1.0;
184
            if (cqout[i] < -1.0) cqout[i] = -1.0;
185
        }
186

    
187
        if (outframe >= latency) {
188

    
189
            sf_writef_double(sndfileOut, 
190
                             cqout.data(), 
191
                             cqout.size());
192

    
193
        } else if (outframe + (int)cqout.size() >= latency) {
194

    
195
            int offset = latency - outframe;
196
            sf_writef_double(sndfileOut, 
197
                             cqout.data() + offset,
198
                             cqout.size() - offset);
199
        }
200

    
201
        if (doDiff) {
202
            for (int i = 0; i < (int)cqout.size(); ++i) {
203
                if (outframe + i >= latency) {
204
                    int dframe = outframe + i - latency;
205
                    if (dframe >= (int)buffer.size()) cqout[i] = 0;
206
                    else cqout[i] -= buffer[dframe];
207
                    if (fabs(cqout[i]) > maxdiff &&
208
                        dframe > sfinfo.samplerate && // ignore first/last sec
209
                        dframe + sfinfo.samplerate < sfinfo.frames) {
210
                        maxdiff = fabs(cqout[i]);
211
                        maxdiffidx = dframe;
212
                    }
213
                }
214
            }
215
            
216
            if (outframe >= latency) {
217

    
218
                sf_writef_double(sndDiffFile, 
219
                                 cqout.data(), 
220
                                 cqout.size());
221

    
222
            } else if (outframe + (int)cqout.size() >= latency) {
223

    
224
                int offset = latency - outframe;
225
                sf_writef_double(sndDiffFile, 
226
                                 cqout.data() + offset,
227
                                 cqout.size() - offset);
228
            }
229
        }
230

    
231
        inframe += count;
232
        outframe += cqout.size();
233
    }
234

    
235
    vector<double> r = cqi.process(cq.getRemainingOutput());
236
    vector<double> r2 = cqi.getRemainingOutput();
237

    
238
    r.insert(r.end(), r2.begin(), r2.end());
239

    
240
    for (int i = 0; i < int(r.size()); ++i) {
241
        if (r[i] > 1.0) r[i] = 1.0;
242
        if (r[i] < -1.0) r[i] = -1.0;
243
    }
244

    
245
    sf_writef_double(sndfileOut, r.data(), r.size());
246
    if (doDiff) {
247
        for (int i = 0; i < (int)r.size(); ++i) {
248
            if (outframe + i >= latency) {
249
                int dframe = outframe + i - latency;
250
                if (dframe >= (int)buffer.size()) r[i] = 0;
251
                else r[i] -= buffer[dframe];
252
                if (fabs(r[i]) > maxdiff &&
253
                    dframe > sfinfo.samplerate && // ignore first/last sec
254
                    dframe + sfinfo.samplerate < sfinfo.frames) {
255
                    maxdiff = fabs(r[i]);
256
                    maxdiffidx = dframe;
257
                }
258
            }
259
        }
260
        sf_writef_double(sndDiffFile, r.data(), r.size());
261
    }
262
    outframe += r.size();
263

    
264
    sf_close(sndfile);
265
    sf_close(sndfileOut);
266

    
267
    if (doDiff) {
268
        sf_close(sndDiffFile);
269
    }
270

    
271
    cerr << "in: " << inframe << ", out: " << outframe - latency << endl;
272

    
273
    if (doDiff) {
274
        double db = 10 * log10(maxdiff);
275
        cerr << "max diff [excluding first and last second of audio] is "
276
             << maxdiff << " (" << db << " dBFS)"
277
             << " at sample index " << maxdiffidx << endl;
278
    }
279
    
280
    timeval etv;
281
    (void)gettimeofday(&etv, 0);
282
        
283
    etv.tv_sec -= tv.tv_sec;
284
    if (etv.tv_usec < tv.tv_usec) {
285
        etv.tv_usec += 1000000;
286
        etv.tv_sec -= 1;
287
    }
288
    etv.tv_usec -= tv.tv_usec;
289
        
290
    double sec = double(etv.tv_sec) + (double(etv.tv_usec) / 1000000.0);
291
    cerr << "elapsed time (not counting init): " << sec << " sec, frames/sec at input: " << inframe/sec << endl;
292

    
293
    return 0;
294
}
295