MythTV  0.28pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
FIRFilter.cpp
Go to the documentation of this file.
1 //
14 // Last changed : $Date$
15 // File revision : $Revision$
16 //
17 // $Id$
18 //
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
39 //
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 
59 {
60  resultDivFactor = 0;
61  resultDivider = 0;
62  length = 0;
63  lengthDiv8 = 0;
64  filterCoeffs = NULL;
65 }
66 
67 
69 {
70  delete[] filterCoeffs;
71 }
72 
73 // Usual C-version of the filter routine for stereo sound
75 {
76  uint i, j, end;
77  LONG_SAMPLETYPE suml, sumr;
78 #ifdef FLOAT_SAMPLES
79  // when using floating point samples, use a scaler instead of a divider
80  // because division is much slower operation than multiplying.
81  double dScaler = 1.0 / (double)resultDivider;
82 #endif
83 
84  assert(length != 0);
85 
86  end = 2 * (numSamples - length);
87 
88  for (j = 0; j < end; j += 2)
89  {
90  const SAMPLETYPE *ptr;
91 
92  suml = sumr = 0;
93  ptr = src + j;
94 
95  for (i = 0; i < length; i += 4)
96  {
97  // loop is unrolled by factor of 4 here for efficiency
98  suml += ptr[2 * i + 0] * filterCoeffs[i + 0] +
99  ptr[2 * i + 2] * filterCoeffs[i + 1] +
100  ptr[2 * i + 4] * filterCoeffs[i + 2] +
101  ptr[2 * i + 6] * filterCoeffs[i + 3];
102  sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] +
103  ptr[2 * i + 3] * filterCoeffs[i + 1] +
104  ptr[2 * i + 5] * filterCoeffs[i + 2] +
105  ptr[2 * i + 7] * filterCoeffs[i + 3];
106  }
107 
108 #ifdef INTEGER_SAMPLES
109  suml >>= resultDivFactor;
110  sumr >>= resultDivFactor;
111  // saturate to 16 bit integer limits
112  suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml;
113  // saturate to 16 bit integer limits
114  sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr;
115 #else
116  suml *= dScaler;
117  sumr *= dScaler;
118 #endif // INTEGER_SAMPLES
119  dest[j] = (SAMPLETYPE)suml;
120  dest[j + 1] = (SAMPLETYPE)sumr;
121  }
122  return numSamples - length;
123 }
124 
125 
126 
127 
128 // Usual C-version of the filter routine for mono sound
130 {
131  uint i, j, end;
132  LONG_SAMPLETYPE sum;
133 #ifdef FLOAT_SAMPLES
134  // when using floating point samples, use a scaler instead of a divider
135  // because division is much slower operation than multiplying.
136  double dScaler = 1.0 / (double)resultDivider;
137 #endif
138 
139 
140  assert(length != 0);
141 
142  end = numSamples - length;
143  for (j = 0; j < end; j ++)
144  {
145  sum = 0;
146  for (i = 0; i < length; i += 4)
147  {
148  // loop is unrolled by factor of 4 here for efficiency
149  sum += src[i + 0] * filterCoeffs[i + 0] +
150  src[i + 1] * filterCoeffs[i + 1] +
151  src[i + 2] * filterCoeffs[i + 2] +
152  src[i + 3] * filterCoeffs[i + 3];
153  }
154 #ifdef INTEGER_SAMPLES
155  sum >>= resultDivFactor;
156  // saturate to 16 bit integer limits
157  sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum;
158 #else
159  sum *= dScaler;
160 #endif // INTEGER_SAMPLES
161  dest[j] = (SAMPLETYPE)sum;
162  src ++;
163  }
164  return end;
165 }
166 
167 
168 // Set filter coeffiecients and length.
169 //
170 // Throws an exception if filter length isn't divisible by 8
171 void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor)
172 {
173  assert(newLength > 0);
174  if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8");
175 
176  lengthDiv8 = newLength / 8;
177  length = lengthDiv8 * 8;
178  assert(length == newLength);
179 
180  resultDivFactor = uResultDivFactor;
181  resultDivider = (SAMPLETYPE)pow( (SAMPLETYPE)2, (int)resultDivFactor);
182 
183  delete[] filterCoeffs;
184  filterCoeffs = new SAMPLETYPE[length];
185  memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE));
186 }
187 
188 
190 {
191  return length;
192 }
193 
194 
195 
196 // Applies the filter to the given sequence of samples.
197 //
198 // Note : The amount of outputted samples is by value of 'filter_length'
199 // smaller than the amount of input samples.
200 uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
201 {
202  assert(numChannels == 1 || numChannels == 2);
203 
204  assert(length > 0);
205  assert(lengthDiv8 * 8 == length);
206  if (numSamples < length) return 0;
207  //assert(resultDivFactor >= 0); // Commented out in MythTV : see #4846
208  if (numChannels == 2)
209  {
210  return evaluateFilterStereo(dest, src, numSamples);
211  } else {
212  return evaluateFilterMono(dest, src, numSamples);
213  }
214 }
215 
216 
217 
218 // Operator 'new' is overloaded so that it automatically creates a suitable instance
219 // depending on if we've a MMX-capable CPU available or not.
220 void * FIRFilter::operator new(size_t s)
221 {
222  // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead!
223  throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!");
224  return NULL;
225 }
226 
227 
229 {
230  uint uExtensions;
231 
232  uExtensions = detectCPUextensions();
233 
234  // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU
235 #ifdef ALLOW_SSE2
236  if (uExtensions & MM_SSE2)
237  {
238  // SSE support
239  return ::new FIRFilterSSE2;
240  }
241  else
242 #endif // ALLOW_SSE2
243  {
244  // ISA optimizations not supported, use plain C version
245  return ::new FIRFilter;
246  }
247 }
long LONG_SAMPLETYPE
Definition: STTypes.h:108
lzo_voidp ptr
Definition: lzoconf.h:275
assert(size > 0)
return memcpy(dest, src, len)
unsigned int uint
Definition: compat.h:135
static FIRFilter * newInstance()
Definition: FIRFilter.cpp:228
Class that implements SSE optimized functions exclusive for floating point samples type...
Definition: FIRFilter.h:103
virtual ~FIRFilter()
Definition: FIRFilter.cpp:68
dest
Definition: minilzo.cpp:2074
short SAMPLETYPE
Definition: STTypes.h:106
return s
Definition: minilzo.cpp:2409
virtual void setCoefficients(const soundtouch::SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor)
Definition: FIRFilter.cpp:171
uint getLength() const
Definition: FIRFilter.cpp:189
uint detectCPUextensions(void)
Checks which instruction set extensions are supported by the CPU.
typedef int
Definition: lzoconf.h:279
uint evaluate(soundtouch::SAMPLETYPE *dest, const soundtouch::SAMPLETYPE *src, uint numSamples, uint numChannels) const
Applies the filter to the given sequence of samples.
Definition: FIRFilter.cpp:200
src
Definition: minilzo.cpp:2074
virtual uint evaluateFilterStereo(soundtouch::SAMPLETYPE *dest, const soundtouch::SAMPLETYPE *src, uint numSamples) const
Definition: FIRFilter.cpp:74
virtual uint evaluateFilterMono(soundtouch::SAMPLETYPE *dest, const soundtouch::SAMPLETYPE *src, uint numSamples) const
Definition: FIRFilter.cpp:129