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

« back to all changes in this revision

Viewing changes to lib-src/soundtouch/source/SoundTouch/FIRFilter.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
 
////////////////////////////////////////////////////////////////////////////////
2
 
///
3
 
/// General FIR digital filter routines with MMX optimization.
4
 
///
5
 
/// Note : MMX optimized functions reside in a separate, platform-specific file,
6
 
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
7
 
///
8
 
/// Author        : Copyright (c) Olli Parviainen
9
 
/// Author e-mail : oparviai 'at' iki.fi
10
 
/// SoundTouch WWW: http://www.surina.net/soundtouch
11
 
///
12
 
////////////////////////////////////////////////////////////////////////////////
13
 
//
14
 
// Last changed  : $Date: 2006/09/18 22:29:22 $
15
 
// File revision : $Revision: 1.4 $
16
 
//
17
 
// $Id: FIRFilter.cpp,v 1.4 2006/09/18 22:29:22 martynshaw Exp $
18
 
//
19
 
////////////////////////////////////////////////////////////////////////////////
20
 
//
21
 
// License :
22
 
//
23
 
//  SoundTouch audio processing library
24
 
//  Copyright (c) Olli Parviainen
25
 
//
26
 
//  This library is free software; you can redistribute it and/or
27
 
//  modify it under the terms of the GNU Lesser General Public
28
 
//  License as published by the Free Software Foundation; either
29
 
//  version 2.1 of the License, or (at your option) any later version.
30
 
//
31
 
//  This library is distributed in the hope that it will be useful,
32
 
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
33
 
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
34
 
//  Lesser General Public License for more details.
35
 
//
36
 
//  You should have received a copy of the GNU Lesser General Public
37
 
//  License along with this library; if not, write to the Free Software
38
 
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
39
 
//
40
 
////////////////////////////////////////////////////////////////////////////////
41
 
 
42
 
#include <memory.h>
43
 
#include <assert.h>
44
 
#include <math.h>
45
 
#include <stdlib.h>
46
 
#include <stdexcept>
47
 
#include "FIRFilter.h"
48
 
#include "cpu_detect.h"
49
 
 
50
 
using namespace soundtouch;
51
 
 
52
 
/*****************************************************************************
53
 
 *
54
 
 * Implementation of the class 'FIRFilter'
55
 
 *
56
 
 *****************************************************************************/
57
 
 
58
 
FIRFilter::FIRFilter()
59
 
{
60
 
    resultDivFactor = 0;
61
 
    length = 0;
62
 
    lengthDiv8 = 0;
63
 
    filterCoeffs = NULL;
64
 
}
65
 
 
66
 
 
67
 
FIRFilter::~FIRFilter()
68
 
{
69
 
    delete[] filterCoeffs;
70
 
}
71
 
 
72
 
// Usual C-version of the filter routine for stereo sound
73
 
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
74
 
{
75
 
    uint i, j, end;
76
 
    LONG_SAMPLETYPE suml, sumr;
77
 
#ifdef FLOAT_SAMPLES
78
 
    // when using floating point samples, use a scaler instead of a divider
79
 
    // because division is much slower operation than multiplying.
80
 
    double dScaler = 1.0 / (double)resultDivider;
81
 
#endif
82
 
 
83
 
    assert(length != 0);
84
 
 
85
 
    end = 2 * (numSamples - length);
86
 
 
87
 
    for (j = 0; j < end; j += 2)
88
 
    {
89
 
        const SAMPLETYPE *ptr;
90
 
 
91
 
        suml = sumr = 0;
92
 
        ptr = src + j;
93
 
 
94
 
        for (i = 0; i < length; i += 4)
95
 
        {
96
 
            // loop is unrolled by factor of 4 here for efficiency
97
 
            suml += ptr[2 * i + 0] * filterCoeffs[i + 0] +
98
 
                    ptr[2 * i + 2] * filterCoeffs[i + 1] +
99
 
                    ptr[2 * i + 4] * filterCoeffs[i + 2] +
100
 
                    ptr[2 * i + 6] * filterCoeffs[i + 3];
101
 
            sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] +
102
 
                    ptr[2 * i + 3] * filterCoeffs[i + 1] +
103
 
                    ptr[2 * i + 5] * filterCoeffs[i + 2] +
104
 
                    ptr[2 * i + 7] * filterCoeffs[i + 3];
105
 
        }
106
 
 
107
 
#ifdef INTEGER_SAMPLES
108
 
        suml >>= resultDivFactor;
109
 
        sumr >>= resultDivFactor;
110
 
        // saturate to 16 bit integer limits
111
 
        suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml;
112
 
        // saturate to 16 bit integer limits
113
 
        sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr;
114
 
#else
115
 
        suml *= dScaler;
116
 
        sumr *= dScaler;
117
 
#endif // INTEGER_SAMPLES
118
 
        dest[j] = (SAMPLETYPE)suml;
119
 
        dest[j + 1] = (SAMPLETYPE)sumr;
120
 
    }
121
 
    return numSamples - length;
122
 
}
123
 
 
124
 
 
125
 
 
126
 
 
127
 
// Usual C-version of the filter routine for mono sound
128
 
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
129
 
{
130
 
    uint i, j, end;
131
 
    LONG_SAMPLETYPE sum;
132
 
#ifdef FLOAT_SAMPLES
133
 
    // when using floating point samples, use a scaler instead of a divider
134
 
    // because division is much slower operation than multiplying.
135
 
    double dScaler = 1.0 / (double)resultDivider;
136
 
#endif
137
 
 
138
 
 
139
 
    assert(length != 0);
140
 
 
141
 
    end = numSamples - length;
142
 
    for (j = 0; j < end; j ++)
143
 
    {
144
 
        sum = 0;
145
 
        for (i = 0; i < length; i += 4)
146
 
        {
147
 
            // loop is unrolled by factor of 4 here for efficiency
148
 
            sum += src[i + 0] * filterCoeffs[i + 0] +
149
 
                   src[i + 1] * filterCoeffs[i + 1] +
150
 
                   src[i + 2] * filterCoeffs[i + 2] +
151
 
                   src[i + 3] * filterCoeffs[i + 3];
152
 
        }
153
 
#ifdef INTEGER_SAMPLES
154
 
        sum >>= resultDivFactor;
155
 
        // saturate to 16 bit integer limits
156
 
        sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum;
157
 
#else
158
 
        sum *= dScaler;
159
 
#endif // INTEGER_SAMPLES
160
 
        dest[j] = (SAMPLETYPE)sum;
161
 
        src ++;
162
 
    }
163
 
    return end;
164
 
}
165
 
 
166
 
 
167
 
// Set filter coeffiecients and length.
168
 
//
169
 
// Throws an exception if filter length isn't divisible by 8
170
 
void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor)
171
 
{
172
 
    assert(newLength > 0);
173
 
    if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8");
174
 
 
175
 
    lengthDiv8 = newLength / 8;
176
 
    length = lengthDiv8 * 8;
177
 
    assert(length == newLength);
178
 
 
179
 
    resultDivFactor = uResultDivFactor;
180
 
    resultDivider = (SAMPLETYPE)pow(2., (double)resultDivFactor);
181
 
 
182
 
    delete[] filterCoeffs;
183
 
    filterCoeffs = new SAMPLETYPE[length];
184
 
    memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE));
185
 
}
186
 
 
187
 
 
188
 
uint FIRFilter::getLength() const
189
 
{
190
 
    return length;
191
 
}
192
 
 
193
 
 
194
 
 
195
 
// Applies the filter to the given sequence of samples.
196
 
//
197
 
// Note : The amount of outputted samples is by value of 'filter_length'
198
 
// smaller than the amount of input samples.
199
 
uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
200
 
{
201
 
    assert(numChannels == 1 || numChannels == 2);
202
 
 
203
 
    assert(length > 0);
204
 
    assert(lengthDiv8 * 8 == length);
205
 
    if (numSamples < length) return 0;
206
 
    assert(resultDivFactor >= 0);
207
 
    if (numChannels == 2)
208
 
    {
209
 
        return evaluateFilterStereo(dest, src, numSamples);
210
 
    } else {
211
 
        return evaluateFilterMono(dest, src, numSamples);
212
 
    }
213
 
}
214
 
 
215
 
 
216
 
 
217
 
// Operator 'new' is overloaded so that it automatically creates a suitable instance
218
 
// depending on if we've a MMX-capable CPU available or not.
219
 
void * FIRFilter::operator new(size_t s)
220
 
{
221
 
    // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead!
222
 
    throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!");
223
 
    return NULL;
224
 
}
225
 
 
226
 
 
227
 
FIRFilter * FIRFilter::newInstance()
228
 
{
229
 
    uint uExtensions;
230
 
 
231
 
    uExtensions = detectCPUextensions();
232
 
 
233
 
    // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU
234
 
 
235
 
#ifdef ALLOW_MMX
236
 
    // MMX routines available only with integer sample types
237
 
    if (uExtensions & SUPPORT_MMX)
238
 
    {
239
 
        return ::new FIRFilterMMX;
240
 
    }
241
 
    else
242
 
#endif // ALLOW_MMX
243
 
 
244
 
#ifdef ALLOW_SSE
245
 
    if (uExtensions & SUPPORT_SSE)
246
 
    {
247
 
        // SSE support
248
 
        return ::new FIRFilterSSE;
249
 
    }
250
 
    else
251
 
#endif // ALLOW_SSE
252
 
 
253
 
#ifdef ALLOW_3DNOW
254
 
    if (uExtensions & SUPPORT_3DNOW)
255
 
    {
256
 
        // 3DNow! support
257
 
        return ::new FIRFilter3DNow;
258
 
    }
259
 
    else
260
 
#endif // ALLOW_3DNOW
261
 
 
262
 
    {
263
 
        // ISA optimizations not supported, use plain C version
264
 
        return ::new FIRFilter;
265
 
    }
266
 
}