~ubuntu-branches/debian/lenny/libofa/lenny

« back to all changes in this revision

Viewing changes to lib/signal_op.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Lukáš Lalinský
  • Date: 2006-08-21 23:06:01 UTC
  • Revision ID: james.westby@ubuntu.com-20060821230601-ik253yugpxbbo9xt
Tags: upstream-0.9.3
Import upstream version 0.9.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ------------------------------------------------------------------
 
2
 
 
3
   libofa -- the Open Fingerprint Architecture library
 
4
 
 
5
   Copyright (C) 2006 MusicIP Corporation
 
6
   All rights reserved.
 
7
 
 
8
-------------------------------------------------------------------*/
 
9
// FILE: "signal_op.cpp"
 
10
// MODULE: Implementation for class Signal_op
 
11
// AUTHOR: Frode Holm
 
12
// DATE CREATED: 1/12/06
 
13
 
 
14
 
 
15
#include <math.h>
 
16
#include "signal_op.h"
 
17
#include "AFLIB/aflibConverter.h"
 
18
#include "error_op.h"
 
19
 
 
20
 
 
21
Signal_op::Signal_op()
 
22
{
 
23
        Data = 0;
 
24
        iOwnData = false;
 
25
        NumChannels = 0;
 
26
        BufSize = 0;
 
27
        NumBlocks = 0;
 
28
        Rate = 0;
 
29
}
 
30
 
 
31
Signal_op::~Signal_op()
 
32
{
 
33
        if (iOwnData)
 
34
                delete[] Data;
 
35
}
 
36
 
 
37
 
 
38
void
 
39
Signal_op::Load(short* samples, long size, int sRate, bool stereo)
 
40
{
 
41
        Data = samples;
 
42
        iOwnData = false;
 
43
        NumChannels = stereo ? 2 : 1;
 
44
        BufSize = size;
 
45
        NumBlocks = BufSize / NumChannels;
 
46
        Rate = sRate;
 
47
}
 
48
 
 
49
 
 
50
// CutSignal deletes samples from the sample buffer
 
51
void
 
52
Signal_op::CutSignal(double start, double dur)
 
53
{
 
54
        int i, n;
 
55
        short* samples = Data;
 
56
 
 
57
        long startS = (long)(start * Rate / 1000.0);
 
58
        long stopS = (long)(startS + dur * Rate / 1000.0);
 
59
 
 
60
        NumBlocks = (stopS-startS);
 
61
        if (NumBlocks <= 0)
 
62
                throw OnePrintError("Programming error: CutSignal");
 
63
 
 
64
        BufSize = NumBlocks * NumChannels;
 
65
        short* tmpBuf = new short[BufSize];
 
66
 
 
67
        startS *= NumChannels;
 
68
        stopS *= NumChannels;
 
69
 
 
70
        // Copy to new buffer
 
71
        for (i=startS, n=0; i<stopS; i++, n++)
 
72
                tmpBuf[n] = samples[i];
 
73
        if (iOwnData)
 
74
                delete[] Data;
 
75
        Data = tmpBuf;
 
76
        iOwnData = true;
 
77
}
 
78
 
 
79
 
 
80
void
 
81
Signal_op::PrepareStereo(long newRate, double silTh)
 
82
{
 
83
        // Convert to mono
 
84
        if (GetCrossCorrelation() < -0.98)
 
85
                LMinusR();
 
86
        else
 
87
                LPlusR();
 
88
 
 
89
        PrepareMono(newRate, silTh);
 
90
}
 
91
 
 
92
 
 
93
void
 
94
Signal_op::PrepareMono(long newRate, double silTh)
 
95
{
 
96
        RemoveSilence(silTh, silTh);
 
97
 
 
98
        RemoveDCOffset();
 
99
 
 
100
        // Check for rate conversion
 
101
        if (newRate != Rate)
 
102
                ConvertSampleRate(newRate);
 
103
 
 
104
        Normalize();
 
105
 
 
106
}
 
107
 
 
108
// Add left and right channels
 
109
 
 
110
void Signal_op::LPlusR() 
 
111
{
 
112
        if (NumChannels != 2) 
 
113
                return;
 
114
        short* tmpBuf = new short[NumBlocks];
 
115
        short* samples = Data;
 
116
        for (long i=0, n=0; i<NumBlocks*2; i+=2, n++) 
 
117
        {
 
118
                int sum = samples[i] + samples[i+1];
 
119
                tmpBuf[n] = sum / 2;
 
120
        }
 
121
        if (iOwnData)
 
122
                delete[] Data;
 
123
        Data = tmpBuf;
 
124
        iOwnData = true;
 
125
        NumChannels = 1;
 
126
        BufSize = NumBlocks;
 
127
}
 
128
 
 
129
 
 
130
// Subtract left and right channels.
 
131
 
 
132
void Signal_op::LMinusR() 
 
133
{
 
134
        if (NumChannels != 2) 
 
135
                return;
 
136
        short * tmpBuf = new short[NumBlocks];
 
137
        short * samples = Data;
 
138
        for (long i=0, n=0; i<NumBlocks*2; i+=2, n++) 
 
139
        {
 
140
                int sum = samples[i] - samples[i+1];
 
141
                tmpBuf[n] = sum / 2;
 
142
        }
 
143
        if (iOwnData)
 
144
                delete[] Data;
 
145
        Data = tmpBuf;
 
146
        iOwnData = true;
 
147
        NumChannels = 1;
 
148
        BufSize = NumBlocks;
 
149
}
 
150
 
 
151
 
 
152
void 
 
153
Signal_op::RemoveSilence(double startTh, double endTh)
 
154
{
 
155
        long i, n;
 
156
 
 
157
        short* samples = Data;
 
158
 
 
159
        // Truncate leading and trailing silence
 
160
        long stop = NumBlocks;
 
161
        int silBlock = (int) (Rate*2.2/400);
 
162
        int count = 0;
 
163
        long sum = 0;
 
164
        long start = 0;
 
165
 
 
166
        // Front silence removal
 
167
        while (start < stop) 
 
168
        {
 
169
                sum += abs(samples[start]);
 
170
                count++;
 
171
                if (count >= silBlock)
 
172
                {
 
173
                        double av = (double)sum/silBlock;
 
174
                        if (av > startTh)
 
175
                        {
 
176
                                start -= count-1;
 
177
                                break;
 
178
                        }
 
179
                        count = 0;
 
180
                        sum = 0;
 
181
                }
 
182
 
 
183
                start++;
 
184
        }
 
185
    if (start < 0) start = 0;
 
186
 
 
187
        // Back silence removal
 
188
        count = 0;
 
189
        sum = 0;
 
190
        while (stop > start) 
 
191
        {
 
192
                sum += abs(samples[stop-1]);
 
193
                count++;
 
194
                if (count >= silBlock)
 
195
                {
 
196
                        double av = (double)sum/silBlock;
 
197
                        if (av > endTh)
 
198
                        {
 
199
                                stop += count;
 
200
                                break;
 
201
                        }
 
202
                        count = 0;
 
203
                        sum = 0;
 
204
                }
 
205
 
 
206
            stop--;
 
207
        }
 
208
        if (stop > NumBlocks) stop = NumBlocks;
 
209
        
 
210
        if (stop-start <= 0)
 
211
                throw OnePrintError("Signal has silence only", SILENCEONLY);
 
212
 
 
213
    NumBlocks = (stop-start);
 
214
        if (NumBlocks <= 0)
 
215
                throw OnePrintError("Signal is corrupt");
 
216
 
 
217
        BufSize = NumBlocks;
 
218
        short* tmpBuf = new short[BufSize];
 
219
 
 
220
        // Copy to new buffer
 
221
        for (i=start, n=0; i<stop; i++, n++)
 
222
                tmpBuf[n] = samples[i];
 
223
        if (iOwnData)
 
224
                delete[] Data;
 
225
        Data = tmpBuf;
 
226
        iOwnData = true;
 
227
}
 
228
 
 
229
 
 
230
void
 
231
Signal_op::RemoveDCOffset()
 
232
{
 
233
        long len = GetLength();
 
234
        short* x = Data;
 
235
        double yn=0, yn1=0;
 
236
        double sum = 0;
 
237
        long cnt = 0;
 
238
        double ramp = 1000.0;                                   // Ramp-up time (ms)
 
239
        long lim = (long) ((ramp/1000)*GetRate());
 
240
        double k = 1000.0/(GetRate()*ramp);
 
241
        double maxP = 0, maxN = 0;
 
242
        for (long n=1; n<=len; n++)
 
243
        {
 
244
                yn = yn1 + k*((double)x[n-1] - yn1);
 
245
                yn1 = yn;
 
246
                if (n > lim*3)
 
247
                {
 
248
                        sum += yn;
 
249
                        cnt++;
 
250
                }
 
251
                if (x[n-1] > maxP)
 
252
                        maxP = x[n-1];
 
253
                if (x[n-1] < maxN)
 
254
                        maxN = x[n-1];
 
255
        }
 
256
 
 
257
        double dcOffset = sum/(double)cnt;
 
258
 
 
259
        // Remove if greater than this
 
260
        if (fabs(dcOffset) > 15)        // otherwise don't bother
 
261
        {
 
262
                // Check to se if we have to "denormalize" to make sure there's headroom for the DC removal
 
263
                double factorP=0, factorN=0, factor=0;
 
264
                if (maxP - dcOffset > MaxSample)
 
265
                        factorP = ((double)MaxSample - dcOffset) / maxP;
 
266
                if (maxN - dcOffset < MinSample)
 
267
                        factorN = ((double)MinSample + dcOffset) / maxN;
 
268
                // only one can apply
 
269
                if (factorP > 0)
 
270
                        factor = factorP;
 
271
                else if (factorN > 0)
 
272
                        factor = factorN;
 
273
 
 
274
                for (long i=0; i<len; i++)
 
275
                {
 
276
                        double sample = (double)x[i];
 
277
                        if (factor > 0)
 
278
                                sample *= factor;
 
279
                        sample -= dcOffset;
 
280
                        // round sample
 
281
                        if (sample > 0)
 
282
                                x[i] = (short) floor(sample + 0.5);
 
283
                        else
 
284
                                x[i] = (short) ceil(sample - 0.5);
 
285
                }
 
286
        }
 
287
}
 
288
 
 
289
 
 
290
void
 
291
Signal_op::Normalize()
 
292
{
 
293
        short* samples = Data;
 
294
 
 
295
        long i;
 
296
        int max = 0;
 
297
        double factor;
 
298
        
 
299
        for (i=0; i<NumBlocks; i++)
 
300
        {
 
301
                if (abs(samples[i]) > max)
 
302
                        max = abs(samples[i]);
 
303
        }
 
304
 
 
305
        if (max >= MaxSample) {
 
306
                factor = 1;
 
307
        } else {
 
308
                factor = MaxSample / (double) max;
 
309
                for (i=0; i<NumBlocks; i++)
 
310
                {
 
311
                        double tmp = (double)samples[i] * factor;
 
312
                        // round sample
 
313
                        if (tmp > 0)
 
314
                                samples[i] = (short) floor(tmp + 0.5);
 
315
                        else
 
316
                                samples[i] = (short) ceil(tmp - 0.5);
 
317
                }
 
318
        }
 
319
}
 
320
 
 
321
 
 
322
 
 
323
// Mono signals only
 
324
void 
 
325
Signal_op::ConvertSampleRate(long targetSR)
 
326
{
 
327
        if (NumChannels > 1) return;
 
328
 
 
329
        aflibConverter srConv(true, false, true);       // Large filter with coefficients interpolation
 
330
 
 
331
        double factor = (double)targetSR/(double)Rate;
 
332
 
 
333
        long tmpSize = (long) (BufSize * factor + 2);
 
334
        short* tmpBuf = new short[tmpSize];
 
335
 
 
336
        srConv.initialize(factor, 1);
 
337
 
 
338
        int inCount = BufSize;
 
339
        int outCount = (int) (BufSize * factor);
 
340
        int outRet;
 
341
        outRet = srConv.resample(inCount, outCount, GetBuffer(), tmpBuf);
 
342
 
 
343
        if (iOwnData)
 
344
                delete[] Data;
 
345
        Data = tmpBuf;
 
346
        iOwnData = true;
 
347
        Rate = targetSR;
 
348
        NumBlocks = BufSize = outRet;
 
349
}
 
350
 
 
351
 
 
352
double
 
353
Signal_op::GetCrossCorrelation()
 
354
{
 
355
        // Cross Channel Correlation - stereo signals only
 
356
        long k;
 
357
        double C12 = 0, C11 = 0, C22 = 0;
 
358
        short* samples = Data;
 
359
 
 
360
        for (k=0; k<NumBlocks*2; k+=2) 
 
361
        {
 
362
                C12 += samples[k]*samples[k+1];
 
363
                C11 += samples[k]*samples[k];
 
364
                C22 += samples[k+1]*samples[k+1];
 
365
        }
 
366
 
 
367
        return C12/sqrt(C11*C22);
 
368
}