CLAM-Development  1.4.0
EnvelopeExtractor.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 #include "EnvelopeExtractor.hxx"
23 
24 
25 namespace CLAM {
26 
27  void IntervalAmplitudeAverages::Reconfigure(int points_per_frame,int memory_points)
28  {
29  int new_size = points_per_frame + memory_points;
30 
31  if (mArray.Size() < new_size)
32  mArray.Resize(new_size);
33 
34  if (mArray.Size() != new_size)
35  mArray.SetSize(new_size);
36 
37  mCurrentPos = memory_points-1;
38  mNMemoryPoints = memory_points;
39  mPointsPerFrame = points_per_frame;
40  }
41 
43  {
44  return mArray.Size() != 0;
45  }
46 
47  TData &IntervalAmplitudeAverages::Current(int index)
48  {
49  return mArray[mCurrentPos+index];
50  }
51 
53  {
54  int i, npoints = mArray.Size();
55  for (i=0; i<npoints; i++)
56  mArray[i]=0.0;
57  }
58 
60  {
61  for (int i = -mCurrentPos; i<=0; i++)
62  Current(i) = Current(i+mPointsPerFrame);
63  }
64 
66  Array<TData> &audio,
67  int interval_start,
68  int interval_end)
69  {
70  TData interval_mean = 0.0;
71  for (int i=interval_start; i<interval_end; i++)
72  interval_mean += fabs(audio[i]);
73  interval_mean /= interval_end - interval_start;
74  Current(interval) = interval_mean;
75  }
76 
77  TData IntervalAmplitudeAverages::AcumulationShape(int i)
78  {
79  return TData(mNMemoryPoints-i)/TData(mNMemoryPoints);
80  }
81 
83  {
84  TData res =0.0;
85  for (unsigned i=0; i< mNMemoryPoints; i++)
86  res += AcumulationShape(i) * Current(ipoint-i);
87  return res;
88  }
89 
90 
92  {
93  AddAll();
94  UpdateData();
95  SetSampleRate(44100);
96  SetFrameSize(512);
97 
98  GetInterpolationPeriod().SetInitValue(5.0);
99  GetInterpolationPeriod().SetMinValue(2.0);
100  GetInterpolationPeriod().SetMaxValue(10.0);
101 
102  GetIntegrationLength().SetInitValue(50.0);
103  GetIntegrationLength().SetMinValue(10.0);
104  GetIntegrationLength().SetMaxValue(2000.0);
105 
106  GetNormalLevel().SetInitValue(0.25);
107  GetNormalLevel().SetMinValue(0.01);
108  GetNormalLevel().SetMaxValue(10.0);
109 
110  GetSilenceLevel().SetInitValue(0.0);
111  GetSilenceLevel().SetMinValue(0.0);
112  GetSilenceLevel().SetMaxValue(0.2);
113 
114  SetNInterpPointsPerFrame(0);
115  SetNMemoryPoints(0);
116  SetInterpolationType(EInterpolation::eLinear);
117  }
118 
119 #define CONTROL(name) c##name(#name,this,&EnvelopeExtractor::name##Change)
120 
122  : CONTROL(InterpolationPeriod)
123  , CONTROL(IntegrationLength)
124  , CONTROL(NormalLevel)
125  , CONTROL(SilenceLevel)
126  , Input("Input",this)
127  , Output("Output",this)
128  , mPointsPerFrame(0)
129  , mNMemoryPoints(0)
130  , mNormalLevel(0.0)
131  , mSilenceLevel(0.0)
132  , mDeltaX(0.0)
133  , mFrameTime(0.0)
134  , mFrameSize(0)
135  , mInterpolationPeriod(0.0)
136  , mIntegrationLength(0.0)
137  , mIsSpline(false)
138  {
139  Configure(c);
140  }
141 
142 #undef CONTROL
143 
144  bool EnvelopeExtractor::ConcreteStart()
145  {
146  if (!mAmplitudeAverages.Configured())
147  return false;
148 
149  mAmplitudeAverages.Clear();
150 
151  int i,n_interp_points;
152 
153  if (mIsSpline) n_interp_points = mPointsPerFrame + 3;
154  else n_interp_points = mPointsPerFrame + 1;
155  for (i=0; i<n_interp_points; i++)
156  mInterpolationPoints[i]=0.0;
157 
158  return true;
159  }
160 
161  void EnvelopeExtractor::ConfigureEnvelope(BPFTmpl<TTime,TData> & bpf)
162  {
163  if (bpf.Size() != mPointsPerFrame+1) {
164  bpf.Resize (mPointsPerFrame+1);
165  bpf.SetSize (mPointsPerFrame+1);
166  }
167 
168  if (bpf.GetInterpolation() != mConfig.GetInterpolationType())
169  bpf.SetIntpType(mConfig.GetInterpolationType());
170 
171  double pos=0.0;
172  int i;
173  for (i=0; i<=mPointsPerFrame; i++) {
174  bpf.SetXValue(i,pos);
175  pos+=mDeltaX;
176  }
177  }
178 
179  bool EnvelopeExtractor::SetPointsPerFrame(int npoints)
180  {
181  if ( ( npoints < 1 ) ||
182  ( npoints < 2 && mIsSpline ) )
183  {
184  return false;
185  }
186 
187  mPointsPerFrame = npoints;
188 
189  int n_interp_points = mPointsPerFrame + 1;
190 
191  if (mIsSpline)
192  n_interp_points +=2; // Needed for boundary derivatives
193 
194  if (mInterpolationPoints.AllocatedSize() < n_interp_points)
195  mInterpolationPoints.Resize(n_interp_points);
196 
197  mInterpolationPoints.SetSize(n_interp_points);
198 
199  mAmplitudeAverages.Reconfigure(mPointsPerFrame,mNMemoryPoints);
200 
201  mDeltaX = (mSampleDelta * TTime(mFrameSize)) / TTime(mPointsPerFrame);
202 
203  return true;
204  }
205 
206  bool EnvelopeExtractor::SetInterpolationPeriod(TTime period)
207  {
208  int points_per_frame = int(mFrameTime / period);
209 
210  if (!SetPointsPerFrame(points_per_frame))
211  return false;
212 
213  mInterpolationPeriod = period;
214 
215  return true;
216  }
217 
218  void EnvelopeExtractor::SetNMemoryPoints(int mpoints)
219  {
220  mNMemoryPoints = mpoints;
221 
222  mAmplitudeAverages.Reconfigure(mPointsPerFrame,mNMemoryPoints);
223  }
224 
225  bool EnvelopeExtractor::SetIntegrationLength(TTime length)
226  {
227  int memory_points = int(length / mInterpolationPeriod);
228 
229  if (memory_points <= 0)
230  return false;
231 
232  mIntegrationLength = length;
233 
234  SetNMemoryPoints(memory_points);
235 
236  return true;
237  }
238 
239  void EnvelopeExtractor::SetNormalLevel(TData nlevel)
240  {
241  mNormalLevel = nlevel;
242  }
243 
244  void EnvelopeExtractor::SetSilenceLevel(TData slevel)
245  {
246  mSilenceLevel = slevel;
247  }
248 
249  bool EnvelopeExtractor::ConcreteConfigure(const ProcessingConfig& c)
250  {
251  CopyAsConcreteConfig(mConfig, c);
252 
253  mIsSpline = (mConfig.GetInterpolationType() == EInterpolation::eSpline);
254 
255  mFrameSize = mConfig.GetFrameSize();
256 
257  if (!mFrameSize)
258  {
259  AddConfigErrorMessage("FrameSize must be non-zero");
260  return false;
261  }
262 
263  mFrameTime = 1000.0 * double(mFrameSize) / double(mConfig.GetSampleRate());
264 
265  if (mConfig.GetNInterpPointsPerFrame() > 0)
266  {
267  SetPointsPerFrame(mConfig.GetNInterpPointsPerFrame());
268  }
269  else if (mConfig.GetInterpolationPeriod().GetInitValue() > 0.0)
270  {
271  if (!SetInterpolationPeriod(mConfig.GetInterpolationPeriod().GetInitValue()))
272  {
273  AddConfigErrorMessage("The interpolation period requested in config would require\n"
274  "less than one interpolation point per frame");
275  return false;
276  }
277  }
278  else {
279  AddConfigErrorMessage("Neither the number of interpolation points per frame nor the \n"
280  "interpolation period requested in configuration are valid.");
281  return false;
282  }
283 
284  if (mConfig.GetNMemoryPoints() > 0 )
285  {
286  SetNMemoryPoints(mConfig.GetNMemoryPoints());
287  }
288  else if ( mConfig.GetIntegrationLength().GetInitValue() > 0.0 )
289  {
290  if (!SetIntegrationLength(mConfig.GetIntegrationLength().GetInitValue()))
291  {
292  AddConfigErrorMessage("The integration length requested leads"
293  "to a non-positive number of memory points.");
294  return false;
295  }
296  }
297  else
298  {
299  AddConfigErrorMessage("Neither the integration length nor the number of memory points"
300  "requested in configuration are valid.");
301  return false;
302  }
303 
304  SetNormalLevel(mConfig.GetNormalLevel().GetInitValue());
305 
306  SetSilenceLevel(mConfig.GetSilenceLevel().GetInitValue());
307 
308  mSampleDelta = 1000.0 / (TTime)mConfig.GetSampleRate();
309 
310  mDeltaX = (mSampleDelta * TTime(mFrameSize)) / TTime(mPointsPerFrame);
311 
312  InitializeControls();
313 
314  Input.SetSize(mFrameSize);
315  return true;
316  }
317 
318  void EnvelopeExtractor::CleanSilence()
319  {
320  int i,first,end;
321 
322  if (mIsSpline) {
323  first = 3;
324  end = mPointsPerFrame+2;
325  }
326  else {
327  first = 1;
328  end = mPointsPerFrame;
329  }
330 
331  for (i=first; i<=end; i++)
332  if (mInterpolationPoints[i] < mSilenceLevel)
333  mInterpolationPoints[i] = 0.0;
334  else
335  mInterpolationPoints[i] -= mSilenceLevel;
336  }
337 
338  void EnvelopeExtractor::WriteEnvelope(BPFTmpl<TTime,TData> &bpf)
339  {
340  int i,ipos;
341 
342  if (mIsSpline) ipos=1;
343  else ipos=0;
344 
345  for (i=0; i<=mPointsPerFrame; i++)
346  bpf.SetValue(i,mInterpolationPoints[ipos++]);
347 
348  if (mIsSpline) {
349  bpf.SetLeftDerivative(
350  (mInterpolationPoints[2]-mInterpolationPoints[0]) / mDeltaX);
351  bpf.SetRightDerivative(
352  (mInterpolationPoints[mPointsPerFrame+2] -
353  mInterpolationPoints[mPointsPerFrame] ) / mDeltaX);
354  bpf.UpdateSplineTable();
355  }
356  }
357 
358  void EnvelopeExtractor::StoreInterpolationPoints()
359  {
360  mInterpolationPoints[0] = mInterpolationPoints[mPointsPerFrame];
361  if (mIsSpline) {
362  mInterpolationPoints[1] = mInterpolationPoints[mPointsPerFrame+1];
363  mInterpolationPoints[2] = mInterpolationPoints[mPointsPerFrame+2];
364  }
365  }
366 
367 
368 
369 
370  void EnvelopeExtractor::InterpolationPeriodChange(TControlData val)
371  {
372  SetInterpolationPeriod(mIpMin + val * mIpFactor);
373  mInterpolationPeriodControl = val;
374  }
375 
376  void EnvelopeExtractor::IntegrationLengthChange(TControlData val)
377  {
378  SetIntegrationLength(mIlMin + val * mIlFactor);
379  mIntegrationLengthControl = val;
380  }
381 
382  void EnvelopeExtractor::NormalLevelChange(TControlData val)
383  {
384  SetNormalLevel(mNlMin + val * mNlFactor);
385  mNormalLevelControl = val;
386  }
387 
388  void EnvelopeExtractor::SilenceLevelChange(TControlData val)
389  {
390  SetSilenceLevel(mSlMin + val * mSlFactor);
391  mSilenceLevelControl = val;
392  }
393 
394  void EnvelopeExtractor::InitializeControls(void)
395  {
396  mIpMin = mConfig.GetInterpolationPeriod().GetMinValue();
397  mIpFactor = mConfig.GetInterpolationPeriod().GetMaxValue() - mIpMin;
398  mInterpolationPeriodControl =
399  (mConfig.GetInterpolationPeriod().GetInitValue() -mIpMin) / mIpFactor;
400 
401  mIlMin = mConfig.GetIntegrationLength().GetMinValue();
402  mIlFactor = mConfig.GetIntegrationLength().GetMaxValue() - mIlMin;
403  mIntegrationLengthControl =
404  (mConfig.GetIntegrationLength().GetInitValue() - mIlMin) / mIlFactor;
405 
406  mNlMin = mConfig.GetNormalLevel().GetMinValue();
407  mNlFactor = mConfig.GetNormalLevel().GetMaxValue() - mNlMin;
408  mNormalLevelControl =
409  (mConfig.GetNormalLevel().GetInitValue() - mNlMin) / mNlFactor;
410 
411  mSlMin = mConfig.GetSilenceLevel().GetMinValue();
412  mSlFactor = mConfig.GetSilenceLevel().GetMaxValue() - mSlMin;
413  mSilenceLevelControl =
414  (mConfig.GetSilenceLevel().GetInitValue() - mSlMin) / mSlFactor;
415 
416  }
417 
419  {
420  bool res = Do(Input.GetData(),Output.GetData());
421  Input.Consume();
422  Output.Produce();
423  return res;
424  }
425 
426  bool EnvelopeExtractor::Do(const Audio& inp, Envelope& env)
427  {
428  CLAM_ASSERT(inp.GetSize() == mFrameSize,
429  "EnvelopeExtractor::Do(): Wrong audio size.");
430 
431  Array<TData> &audio = inp.GetBuffer();
432  BPFTmpl<TTime,TData> &bpf = env.GetAmplitudeBPF();
433  int i,ipos,interval_start=0, interval_end;
434 
435  ConfigureEnvelope(bpf);
436 
437  if (mIsSpline) ipos=3;
438  else ipos=1;
439 
440  for (i=1; i<=mPointsPerFrame; i++) {
441  interval_end = (mFrameSize*i)/mPointsPerFrame;
442  mAmplitudeAverages.Compute(i,audio,interval_start,interval_end);
443  interval_start = interval_end;
444  mInterpolationPoints[ipos++] = mAmplitudeAverages.Acumulated(i) /
445  (mNMemoryPoints*mNormalLevel);
446  }
447  if (mSilenceLevel > 0.0)
448  CleanSilence();
449  WriteEnvelope(bpf);
450  StoreInterpolationPoints();
451  mAmplitudeAverages.AdvanceFrame();
452  return true;
453  }
454 }
455