~ubuntu-branches/ubuntu/wily/ecasound/wily-proposed

« back to all changes in this revision

Viewing changes to libecasound/audiofx_analysis.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghedini
  • Date: 2011-05-12 17:58:03 UTC
  • Revision ID: james.westby@ubuntu.com-20110512175803-zy3lodjecabt9r3v
Tags: upstream-2.8.0
ImportĀ upstreamĀ versionĀ 2.8.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// ------------------------------------------------------------------------
 
2
// audiofx_analysis.cpp: Classes for signal analysis
 
3
// Copyright (C) 1999-2002,2008 Kai Vehmanen
 
4
//
 
5
// Attributes:
 
6
//     eca-style-version: 3 (see Ecasound Programmer's Guide)
 
7
//
 
8
// This program is free software; you can redistribute it and/or modify
 
9
// it under the terms of the GNU General Public License as published by
 
10
// the Free Software Foundation; either version 2 of the License, or
 
11
// (at your option) any later version.
 
12
// 
 
13
// This program is distributed in the hope that it will be useful,
 
14
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
// GNU General Public License for more details.
 
17
// 
 
18
// You should have received a copy of the GNU General Public License
 
19
// along with this program; if not, write to the Free Software
 
20
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 
21
// ------------------------------------------------------------------------
 
22
 
 
23
#include <string>
 
24
#include <cmath>
 
25
 
 
26
#include <kvu_dbc.h>
 
27
#include <kvu_message_item.h>
 
28
#include <kvu_numtostr.h>
 
29
 
 
30
#include "samplebuffer_iterators.h"
 
31
#include "audiofx_analysis.h"
 
32
#include "audiofx_amplitude.h"
 
33
 
 
34
#include "eca-logger.h"
 
35
#include "eca-error.h"
 
36
 
 
37
using namespace std;
 
38
 
 
39
static string priv_align_right(const string txt, int width, char padchar)
 
40
{
 
41
  string res;
 
42
  int pad = width - static_cast<int>(txt.size());
 
43
  if (pad > 0) {
 
44
    res.resize(pad, padchar);
 
45
  }
 
46
  return res + txt;
 
47
}
 
48
 
 
49
struct bucket {
 
50
  const char *name;
 
51
  SAMPLE_SPECS::sample_t threshold;
 
52
};
 
53
 
 
54
#define BUCKET_ENTRY_DB(x) \
 
55
 { #x, EFFECT_AMPLITUDE::db_to_linear(x) }
 
56
 
 
57
static struct bucket bucket_table[] = 
 
58
  { BUCKET_ENTRY_DB(3),
 
59
    BUCKET_ENTRY_DB(0),
 
60
    BUCKET_ENTRY_DB(-0.1),
 
61
    BUCKET_ENTRY_DB(-3),
 
62
    BUCKET_ENTRY_DB(-6),
 
63
    BUCKET_ENTRY_DB(-10),
 
64
    BUCKET_ENTRY_DB(-20),
 
65
    BUCKET_ENTRY_DB(-30),
 
66
    BUCKET_ENTRY_DB(-60),
 
67
    { "-inf", -1 }
 
68
  };
 
69
 
 
70
EFFECT_ANALYSIS::~EFFECT_ANALYSIS(void)
 
71
{
 
72
}
 
73
 
 
74
 
 
75
EFFECT_VOLUME_BUCKETS::EFFECT_VOLUME_BUCKETS (void)
 
76
{
 
77
  reset_all_stats();
 
78
  int res = pthread_mutex_init(&lock_rep, NULL);
 
79
  DBC_CHECK(res == 0);
 
80
}
 
81
 
 
82
EFFECT_VOLUME_BUCKETS::~EFFECT_VOLUME_BUCKETS (void)
 
83
{
 
84
}
 
85
 
 
86
void EFFECT_VOLUME_BUCKETS::status_entry(const std::vector<unsigned long int>& buckets, std::string& otemp) const
 
87
{
 
88
  /* note: is called with 'lock_rep' taken */
 
89
 
 
90
  for(unsigned int n = 0; n < buckets.size(); n++) {
 
91
    string samples = kvu_numtostr(buckets[n]);
 
92
 
 
93
    otemp += priv_align_right(samples, 8, '_');
 
94
 
 
95
#if NEVER_USED_PRINT_PERCENTAGE
 
96
    otemp += " (";
 
97
    otemp += priv_align_right(kvu_numtostr(100.0f *  
 
98
                                           buckets[n] / 
 
99
                                           num_of_samples[n], 2),
 
100
                              6, '_');
 
101
    otemp += "%)";
 
102
#endif
 
103
    if (n != buckets.size())
 
104
      otemp += " ";
 
105
  }
 
106
 
107
 
 
108
 
 
109
void EFFECT_VOLUME_BUCKETS::reset_all_stats(void)
 
110
{
 
111
  reset_period_stats();
 
112
  max_pos = max_neg = 0.0f;
 
113
}
 
114
 
 
115
void EFFECT_VOLUME_BUCKETS::reset_period_stats(void)
 
116
{
 
117
  for(unsigned int nm = 0; nm < pos_samples_db.size(); nm++)
 
118
    for(unsigned int ch = 0; ch < pos_samples_db[nm].size(); ch++)
 
119
      pos_samples_db[nm][ch] = 0;
 
120
 
 
121
  for(unsigned int nm = 0; nm < neg_samples_db.size(); nm++)
 
122
    for(unsigned int ch = 0; ch < neg_samples_db[nm].size(); ch++)
 
123
      neg_samples_db[nm][ch] = 0;
 
124
 
 
125
  for(unsigned int nm = 0; nm < num_of_samples.size(); nm++)
 
126
    num_of_samples[nm] = 0;
 
127
}
 
128
 
 
129
string EFFECT_VOLUME_BUCKETS::status(void) const
 
130
{
 
131
  int res = pthread_mutex_lock(&lock_rep);
 
132
  DBC_CHECK(res == 0);
 
133
 
 
134
  std::string status_str;
 
135
 
 
136
  status_str = "-- Amplitude statistics --\n";
 
137
  status_str += "Pos/neg, count,(%), ch1...n";
 
138
 
 
139
  for(unsigned j = 0; j < pos_samples_db.size(); j++) {
 
140
    status_str += std::string("\nPos ")
 
141
      + priv_align_right(bucket_table[j].name, 4, ' ')
 
142
      + "dB: ";
 
143
    status_entry(pos_samples_db[j], status_str);
 
144
  }
 
145
 
 
146
  for(unsigned int j = neg_samples_db.size(); j > 0; j--) {
 
147
    DBC_CHECK(j >= 0);
 
148
    status_str += std::string("\nNeg ")
 
149
      + priv_align_right(bucket_table[j-1].name, 4, ' ')
 
150
      + "dB: ";
 
151
    status_entry(neg_samples_db[j-1], status_str);
 
152
  }
 
153
 
 
154
  status_str += std::string("\nTotal.....: ");
 
155
  status_entry(num_of_samples, status_str);
 
156
  status_str += "\n";
 
157
 
 
158
  status_str += "(audiofx) Peak amplitude: pos=" + kvu_numtostr(max_pos,5) + " neg=" + kvu_numtostr(max_neg,5) + ".\n";
 
159
  status_str += "(audiofx) Max gain without clipping: " + kvu_numtostr(max_multiplier(),5) + ".\n";
 
160
 
 
161
  status_str += "(audiofx) -- End of statistics --\n";
 
162
 
 
163
  res = pthread_mutex_unlock(&lock_rep);
 
164
  DBC_CHECK(res == 0);
 
165
 
 
166
  return status_str;
 
167
}
 
168
 
 
169
void EFFECT_VOLUME_BUCKETS::parameter_description(int param, 
 
170
                                                  struct PARAM_DESCRIPTION *pd) const
 
171
{
 
172
  switch(param) {
 
173
  case 1: 
 
174
    pd->default_value = 0;
 
175
    pd->description = get_parameter_name(param);
 
176
    pd->bounded_above = true;
 
177
    pd->upper_bound = 1.0;
 
178
    pd->bounded_below = true;
 
179
    pd->lower_bound = 0.0f;
 
180
    pd->toggled = true;
 
181
    pd->integer = true;
 
182
    pd->logarithmic = false;
 
183
    pd->output = false;
 
184
    break;
 
185
 
 
186
  case 2: 
 
187
    pd->default_value = 1.0f;
 
188
    pd->description = get_parameter_name(param);
 
189
    pd->bounded_above = false;
 
190
    pd->upper_bound = 0.0f;
 
191
    pd->bounded_below = false;
 
192
    pd->lower_bound = 0.0f;
 
193
    pd->toggled = false;
 
194
    pd->integer = false;
 
195
    pd->logarithmic = false;
 
196
    pd->output = true;
 
197
    break;
 
198
  }
 
199
}
 
200
 
 
201
void EFFECT_VOLUME_BUCKETS::set_parameter(int param, CHAIN_OPERATOR::parameter_t value)
 
202
{
 
203
  return;
 
204
}
 
205
 
 
206
CHAIN_OPERATOR::parameter_t EFFECT_VOLUME_BUCKETS::get_parameter(int param) const
 
207
{
 
208
  switch (param) {
 
209
  case 1: 
 
210
    /* note: always enabled since 2.7.0, but keeping the parameter 
 
211
     *       still for backwards compatibility */
 
212
    return 1.0f;
 
213
    
 
214
  case 2:
 
215
    return max_multiplier();
 
216
  }
 
217
  return 0.0;
 
218
}
 
219
 
 
220
CHAIN_OPERATOR::parameter_t EFFECT_VOLUME_BUCKETS::max_multiplier(void) const
 
221
{
 
222
  parameter_t k;
 
223
  SAMPLE_SPECS::sample_t max_peak = max_pos;
 
224
 
 
225
  if (max_neg > max_pos) 
 
226
    max_peak = max_neg;
 
227
  if (max_peak != 0.0f) 
 
228
    k = SAMPLE_SPECS::max_amplitude / max_peak;
 
229
  else 
 
230
    k = 0.0f;
 
231
 
 
232
  return k;
 
233
}
 
234
 
 
235
void EFFECT_VOLUME_BUCKETS::init(SAMPLE_BUFFER* insample)
 
236
{
 
237
  int res = pthread_mutex_lock(&lock_rep);
 
238
  DBC_CHECK(res == 0);
 
239
  
 
240
  i.init(insample);
 
241
  set_channels(insample->number_of_channels());
 
242
  DBC_CHECK(channels() == insample->number_of_channels());
 
243
  num_of_samples.resize(insample->number_of_channels(), 0);
 
244
 
 
245
  int entries = sizeof(bucket_table) / sizeof(struct bucket);
 
246
 
 
247
  pos_samples_db.resize(entries, std::vector<unsigned long int> (channels()));
 
248
  neg_samples_db.resize(entries, std::vector<unsigned long int> (channels()));
 
249
 
 
250
  reset_all_stats();
 
251
  
 
252
  res = pthread_mutex_unlock(&lock_rep);
 
253
  DBC_CHECK(res == 0);
 
254
 
 
255
  EFFECT_ANALYSIS::init(insample);
 
256
}
 
257
 
 
258
void EFFECT_VOLUME_BUCKETS::process(void)
 
259
{
 
260
  DBC_CHECK(static_cast<int>(num_of_samples.size()) == channels());
 
261
 
 
262
  int res = pthread_mutex_trylock(&lock_rep);
 
263
  if (res == 0) {
 
264
    i.begin();
 
265
    while(!i.end()) {
 
266
 
 
267
      DBC_CHECK(num_of_samples.size() > static_cast<unsigned>(i.channel()));
 
268
      num_of_samples[i.channel()]++;
 
269
 
 
270
      if (*i.current() >= 0) {
 
271
        if (*i.current() > max_pos) max_pos = *i.current();
 
272
 
 
273
        for(unsigned j = 0; j < pos_samples_db.size(); j++) {
 
274
          if (*i.current() > bucket_table[j].threshold) {
 
275
            pos_samples_db[j][i.channel()]++;
 
276
            break;
 
277
          }
 
278
        }
 
279
      }
 
280
      else {
 
281
        if (-(*i.current()) > max_neg) max_neg = -(*i.current());
 
282
 
 
283
        for(unsigned j = 0; j < neg_samples_db.size(); j++) {
 
284
          if (*i.current() < -bucket_table[j].threshold) {
 
285
            neg_samples_db[j][i.channel()]++;
 
286
            break;
 
287
          }
 
288
        }
 
289
      }
 
290
      i.next();
 
291
    }
 
292
 
 
293
    res = pthread_mutex_unlock(&lock_rep);
 
294
    DBC_CHECK(res == 0);
 
295
  }
 
296
  // else { std::cerr << "(audiofx_analysis) lock taken, skipping process().\n"; }
 
297
}
 
298
 
 
299
EFFECT_VOLUME_PEAK::EFFECT_VOLUME_PEAK (void)
 
300
{
 
301
  max_amplitude_repp = 0;
 
302
}
 
303
 
 
304
EFFECT_VOLUME_PEAK::~EFFECT_VOLUME_PEAK (void)
 
305
{
 
306
  if (max_amplitude_repp != 0) {
 
307
    delete[] max_amplitude_repp;
 
308
    max_amplitude_repp = 0;
 
309
  }
 
310
}
 
311
 
 
312
void EFFECT_VOLUME_PEAK::parameter_description(int param, 
 
313
                                               struct PARAM_DESCRIPTION *pd) const
 
314
{
 
315
  if (param > 0 && param <= channels()) {
 
316
    pd->default_value = 0;
 
317
    pd->description = get_parameter_name(param);
 
318
    pd->bounded_above = false;
 
319
    pd->bounded_below = true;
 
320
    pd->lower_bound = 0.0f;
 
321
    pd->toggled = false;
 
322
    pd->integer = false;
 
323
    pd->logarithmic = false;
 
324
    pd->output = true;
 
325
  }
 
326
}
 
327
 
 
328
std::string EFFECT_VOLUME_PEAK::parameter_names(void) const
 
329
{
 
330
  string params;
 
331
  for(int n = 0; n < channels(); n++) {
 
332
    params += "peak-amplitude-ch" + kvu_numtostr(n + 1);
 
333
    if (n != channels()) params += ",";
 
334
  }
 
335
  return params;
 
336
}
 
337
 
 
338
void EFFECT_VOLUME_PEAK::set_parameter(int param, CHAIN_OPERATOR::parameter_t value)
 
339
{
 
340
}
 
341
 
 
342
CHAIN_OPERATOR::parameter_t EFFECT_VOLUME_PEAK::get_parameter(int param) const
 
343
{
 
344
  if (param > 0 && param <= channels()) {
 
345
    parameter_t temp = max_amplitude_repp[param - 1];
 
346
    max_amplitude_repp[param - 1] = 0.0f;
 
347
    return temp;
 
348
  }
 
349
  return 0.0f;
 
350
}
 
351
 
 
352
void EFFECT_VOLUME_PEAK::init(SAMPLE_BUFFER* insample)
 
353
{
 
354
  i.init(insample);
 
355
  if (max_amplitude_repp != 0) {
 
356
    delete[] max_amplitude_repp;
 
357
    max_amplitude_repp = 0;
 
358
  }
 
359
  max_amplitude_repp = new parameter_t [insample->number_of_channels()];
 
360
  set_channels(insample->number_of_channels());
 
361
}
 
362
 
 
363
void EFFECT_VOLUME_PEAK::process(void)
 
364
{
 
365
  i.begin();
 
366
  while(!i.end()) {
 
367
    SAMPLE_SPECS::sample_t abscurrent = std::fabs(*i.current());
 
368
    DBC_CHECK(i.channel() >= 0);
 
369
    DBC_CHECK(i.channel() < channels());
 
370
    if (abscurrent > max_amplitude_repp[i.channel()]) {
 
371
      max_amplitude_repp[i.channel()] = std::fabs(*i.current());
 
372
    }
 
373
    i.next();
 
374
  }
 
375
}
 
376
 
 
377
EFFECT_DCFIND::EFFECT_DCFIND (void)
 
378
{
 
379
}
 
380
 
 
381
string EFFECT_DCFIND::status(void) const
 
382
{
 
383
  MESSAGE_ITEM mitem;
 
384
  mitem.setprecision(5);
 
385
  mitem << "(audiofx) Optimal value for DC-adjust: ";
 
386
  mitem << get_deltafix(SAMPLE_SPECS::ch_left) << " (left), ";
 
387
  mitem << get_deltafix(SAMPLE_SPECS::ch_right) << " (right).";
 
388
  return mitem.to_string();
 
389
}
 
390
 
 
391
string EFFECT_DCFIND::parameter_names(void) const
 
392
{
 
393
  std::vector<std::string> t;
 
394
  for(int n = 0; n < channels(); n++) {
 
395
    t.push_back("result-offset-ch" + kvu_numtostr(n + 1));
 
396
  }
 
397
  return kvu_vector_to_string(t, ",");
 
398
}
 
399
 
 
400
CHAIN_OPERATOR::parameter_t EFFECT_DCFIND::get_deltafix(int channel) const
 
401
{
 
402
  SAMPLE_SPECS::sample_t deltafix;
 
403
 
 
404
  if (channel < 0 || 
 
405
      channel >= static_cast<int>(pos_sum.size()) ||
 
406
      channel >= static_cast<int>(neg_sum.size())) return 0.0;
 
407
 
 
408
  if (pos_sum[channel] > neg_sum[channel]) deltafix = -(pos_sum[channel] - neg_sum[channel]) / num_of_samples[channel];
 
409
  else deltafix = (neg_sum[channel] - pos_sum[channel]) / num_of_samples[channel];
 
410
 
 
411
  return (CHAIN_OPERATOR::parameter_t)deltafix; 
 
412
}
 
413
 
 
414
void EFFECT_DCFIND::parameter_description(int param, 
 
415
                                          struct PARAM_DESCRIPTION *pd) const
 
416
{
 
417
  pd->default_value = 0.0f;
 
418
  pd->description = get_parameter_name(param);
 
419
  pd->bounded_above = false;
 
420
  pd->upper_bound = 0.0f;
 
421
  pd->bounded_below = false;
 
422
  pd->lower_bound = 0.0f;
 
423
  pd->toggled = false;
 
424
  pd->integer = false;
 
425
  pd->logarithmic = false;
 
426
  pd->output = true;
 
427
}
 
428
 
 
429
void EFFECT_DCFIND::set_parameter(int param,
 
430
                                  CHAIN_OPERATOR::parameter_t value)
 
431
{
 
432
}
 
433
 
 
434
CHAIN_OPERATOR::parameter_t EFFECT_DCFIND::get_parameter(int param) const
 
435
{
 
436
  return get_deltafix(param-1);
 
437
}
 
438
 
 
439
void EFFECT_DCFIND::init(SAMPLE_BUFFER *insample)
 
440
{
 
441
  i.init(insample);
 
442
  set_channels(insample->number_of_channels());
 
443
  pos_sum.resize(channels());
 
444
  neg_sum.resize(channels());
 
445
  num_of_samples.resize(channels());
 
446
}
 
447
 
 
448
void EFFECT_DCFIND::process(void)
 
449
{
 
450
  i.begin();
 
451
  while(!i.end()) {
 
452
    tempval = *i.current();
 
453
    if (tempval > SAMPLE_SPECS::silent_value)
 
454
      pos_sum[i.channel()] += tempval;
 
455
    else
 
456
      neg_sum[i.channel()] += fabs(tempval);
 
457
    num_of_samples[i.channel()]++;
 
458
    i.next();
 
459
  }
 
460
}