summaryrefslogtreecommitdiff
path: root/vdr_sound.c
diff options
context:
space:
mode:
Diffstat (limited to 'vdr_sound.c')
-rw-r--r--vdr_sound.c935
1 files changed, 540 insertions, 395 deletions
diff --git a/vdr_sound.c b/vdr_sound.c
index b06061c..7fc8361 100644
--- a/vdr_sound.c
+++ b/vdr_sound.c
@@ -3,13 +3,13 @@
* \brief Sound manipulation classes for a VDR media plugin (muggle)
*
* \version $Revision: 1.2 $
- * \date $Date: 2004/05/28 15:29:19 $
+ * \date $Date$
* \author Ralf Klueber, Lars von Wedel, Andreas Kellner
- * \author Responsible author: $Author: lvw $
+ * \author Responsible author: $Author$
*
- * $Id: vdr_sound.c,v 1.2 2004/05/28 15:29:19 lvw Exp $
+ * $Id$
*
- * Adapted from
+ * Adapted from
* MP3/MPlayer plugin to VDR (C++)
* (C) 2001,2002 Stefan Huelswitt <huels@iname.com>
*/
@@ -18,80 +18,97 @@
// The resample code has been adapted from the madplay project
// (resample.c) found in the libmad distribution
-
+
class cResample
{
-private:
- mad_fixed_t ratio;
- mad_fixed_t step;
- mad_fixed_t last;
- mad_fixed_t resampled[MAX_NSAMPLES];
-public:
- bool SetInputRate(unsigned int oldrate, unsigned int newrate);
- unsigned int ResampleBlock(unsigned int nsamples, const mad_fixed_t *old);
- const mad_fixed_t *Resampled(void) { return resampled; }
- };
-
-bool cResample::SetInputRate(unsigned int oldrate, unsigned int newrate)
+ private:
+ mad_fixed_t ratio;
+ mad_fixed_t step;
+ mad_fixed_t last;
+ mad_fixed_t resampled[MAX_NSAMPLES];
+ public:
+ bool SetInputRate (unsigned int oldrate, unsigned int newrate);
+ unsigned int ResampleBlock (unsigned int nsamples, const mad_fixed_t * old);
+ const mad_fixed_t *Resampled (void)
+ {
+ return resampled;
+ }
+};
+
+bool cResample::SetInputRate (unsigned int oldrate, unsigned int newrate)
{
- if(oldrate<8000 || oldrate>newrate*6) { // out of range
- esyslog("WARNING: samplerate %d out of range 8000-%d\n",oldrate,newrate*6);
- return 0;
+ if (oldrate < 8000 || oldrate > newrate * 6)
+ { // out of range
+ esyslog ("WARNING: samplerate %d out of range 8000-%d\n", oldrate,
+ newrate * 6);
+ return 0;
}
- ratio=mad_f_tofixed((double)oldrate/(double)newrate);
- step=0; last=0;
+ ratio = mad_f_tofixed ((double) oldrate / (double) newrate);
+ step = 0;
+ last = 0;
#ifdef DEBUG
- static mad_fixed_t oldratio=0;
- if(oldratio!=ratio) {
- printf("mad: new resample ratio %f (from %d kHz to %d kHz)\n",mad_f_todouble(ratio),oldrate,newrate);
- oldratio=ratio;
+ static mad_fixed_t
+ oldratio = 0;
+ if (oldratio != ratio)
+ {
+ printf ("mad: new resample ratio %f (from %d kHz to %d kHz)\n",
+ mad_f_todouble (ratio), oldrate, newrate);
+ oldratio = ratio;
}
#endif
- return ratio!=MAD_F_ONE;
+ return ratio != MAD_F_ONE;
}
-unsigned int cResample::ResampleBlock(unsigned int nsamples, const mad_fixed_t *old)
+
+unsigned int
+cResample::ResampleBlock (unsigned int nsamples, const mad_fixed_t * old)
{
- // This resampling algorithm is based on a linear interpolation, which is
- // not at all the best sounding but is relatively fast and efficient.
- //
- // A better algorithm would be one that implements a bandlimited
- // interpolation.
-
- mad_fixed_t *nsam=resampled;
- const mad_fixed_t *end=old+nsamples;
- const mad_fixed_t *begin=nsam;
-
- if(step < 0) {
- step = mad_f_fracpart(-step);
-
- while (step < MAD_F_ONE) {
- *nsam++ = step ? last+mad_f_mul(*old-last,step) : last;
- step += ratio;
- if(((step + 0x00000080L) & 0x0fffff00L) == 0)
- step = (step + 0x00000080L) & ~0x0fffffffL;
- }
- step -= MAD_F_ONE;
+// This resampling algorithm is based on a linear interpolation, which is
+// not at all the best sounding but is relatively fast and efficient.
+//
+// A better algorithm would be one that implements a bandlimited
+// interpolation.
+
+ mad_fixed_t *nsam = resampled;
+ const mad_fixed_t *end = old + nsamples;
+ const mad_fixed_t *begin = nsam;
+
+ if (step < 0)
+ {
+ step = mad_f_fracpart (-step);
+
+ while (step < MAD_F_ONE)
+ {
+ *nsam++ = step ? last + mad_f_mul (*old - last, step) : last;
+ step += ratio;
+ if (((step + 0x00000080L) & 0x0fffff00L) == 0)
+ step = (step + 0x00000080L) & ~0x0fffffffL;
+ }
+ step -= MAD_F_ONE;
}
- while (end - old > 1 + mad_f_intpart(step)) {
- old += mad_f_intpart(step);
- step = mad_f_fracpart(step);
- *nsam++ = step ? *old + mad_f_mul(old[1] - old[0], step) : *old;
- step += ratio;
- if (((step + 0x00000080L) & 0x0fffff00L) == 0)
- step = (step + 0x00000080L) & ~0x0fffffffL;
+ while (end - old > 1 + mad_f_intpart (step))
+ {
+ old += mad_f_intpart (step);
+ step = mad_f_fracpart (step);
+ *nsam++ = step ? *old + mad_f_mul (old[1] - old[0], step) : *old;
+ step += ratio;
+ if (((step + 0x00000080L) & 0x0fffff00L) == 0)
+ step = (step + 0x00000080L) & ~0x0fffffffL;
}
- if (end - old == 1 + mad_f_intpart(step)) {
- last = end[-1];
- step = -step;
+ if (end - old == 1 + mad_f_intpart (step))
+ {
+ last = end[-1];
+ step = -step;
}
- else step -= mad_f_fromint(end - old);
+ else
+ step -= mad_f_fromint (end - old);
- return nsam-begin;
+ return nsam - begin;
}
+
// --- cLevel ----------------------------------------------------------------
// The normalize algorithm and parts of the code has been adapted from the
@@ -123,201 +140,253 @@ unsigned int cResample::ResampleBlock(unsigned int nsamples, const mad_fixed_t *
// We can then take the square root of the power to get maxi­
// mum sustained RMS amplitude.
-class cLevel {
-private:
- double maxpow;
- mad_fixed_t peak;
- struct Power {
- // smooth
- int npow, wpow;
- double powsum, pows[POW_WIN];
- // sum
- unsigned int nsum;
- double sum;
- } power[2];
- //
- inline void AddPower(struct Power *p, double pow);
-public:
- void Init(void);
- void GetPower(struct mad_pcm *pcm);
- double GetLevel(void);
- double GetPeak(void);
- };
-
-void cLevel::Init(void)
+class cLevel
+{
+ private:
+ double maxpow;
+ mad_fixed_t peak;
+ struct Power
+ {
+// smooth
+ int npow, wpow;
+ double powsum, pows[POW_WIN];
+// sum
+ unsigned int nsum;
+ double sum;
+ } power[2];
+//
+ inline void AddPower (struct Power *p, double pow);
+ public:
+ void Init (void);
+ void GetPower (struct mad_pcm *pcm);
+ double GetLevel (void);
+ double GetPeak (void);
+};
+
+void
+cLevel::Init (void)
{
- for(int l=0 ; l<2 ; l++) {
- struct Power *p=&power[l];
- p->sum=p->powsum=0.0; p->wpow=p->npow=p->nsum=0;
- for(int i=POW_WIN-1 ; i>=0 ; i--) p->pows[i]=0.0;
+ for (int l = 0; l < 2; l++)
+ {
+ struct Power *p = &power[l];
+ p->sum = p->powsum = 0.0;
+ p->wpow = p->npow = p->nsum = 0;
+ for (int i = POW_WIN - 1; i >= 0; i--)
+ p->pows[i] = 0.0;
}
- maxpow=0.0; peak=0;
+ maxpow = 0.0;
+ peak = 0;
}
-void cLevel::GetPower(struct mad_pcm *pcm)
+
+void
+cLevel::GetPower (struct mad_pcm *pcm)
{
- for(int i=0 ; i<pcm->channels ; i++) {
- struct Power *p=&power[i];
- mad_fixed_t *data=pcm->samples[i];
- for(int n=pcm->length ; n>0 ; n--) {
- if(*data < -peak) peak = -*data;
- if(*data > peak) peak = *data;
- double s=mad_f_todouble(*data++);
- p->sum+=(s*s);
- if(++(p->nsum)>=pcm->samplerate/100) {
- AddPower(p,p->sum/(double)p->nsum);
- p->sum=0.0; p->nsum=0;
+ for (int i = 0; i < pcm->channels; i++)
+ {
+ struct Power *p = &power[i];
+ mad_fixed_t *data = pcm->samples[i];
+ for (int n = pcm->length; n > 0; n--)
+ {
+ if (*data < -peak)
+ peak = -*data;
+ if (*data > peak)
+ peak = *data;
+ double s = mad_f_todouble (*data++);
+ p->sum += (s * s);
+ if (++(p->nsum) >= pcm->samplerate / 100)
+ {
+ AddPower (p, p->sum / (double) p->nsum);
+ p->sum = 0.0;
+ p->nsum = 0;
+ }
}
- }
}
}
-void cLevel::AddPower(struct Power *p, double pow)
+
+void
+cLevel::AddPower (struct Power *p, double pow)
{
- p->powsum+=pow;
- if(p->npow>=POW_WIN) {
- if(p->powsum>maxpow) maxpow=p->powsum;
- p->powsum-=p->pows[p->wpow];
+ p->powsum += pow;
+ if (p->npow >= POW_WIN)
+ {
+ if (p->powsum > maxpow)
+ maxpow = p->powsum;
+ p->powsum -= p->pows[p->wpow];
}
- else p->npow++;
- p->pows[p->wpow]=pow;
- p->wpow=(p->wpow+1) % POW_WIN;
+ else
+ p->npow++;
+ p->pows[p->wpow] = pow;
+ p->wpow = (p->wpow + 1) % POW_WIN;
}
-double cLevel::GetLevel(void)
-{
- if(maxpow<EPSILON) {
- // Either this whole file has zero power, or was too short to ever
- // fill the smoothing buffer. In the latter case, we need to just
- // get maxpow from whatever data we did collect.
- if(power[0].powsum>maxpow) maxpow=power[0].powsum;
- if(power[1].powsum>maxpow) maxpow=power[1].powsum;
+double
+cLevel::GetLevel (void)
+{
+ if (maxpow < EPSILON)
+ {
+// Either this whole file has zero power, or was too short to ever
+// fill the smoothing buffer. In the latter case, we need to just
+// get maxpow from whatever data we did collect.
+
+ if (power[0].powsum > maxpow)
+ maxpow = power[0].powsum;
+ if (power[1].powsum > maxpow)
+ maxpow = power[1].powsum;
}
- double level=sqrt(maxpow/(double)POW_WIN); // adjust for the smoothing window size and root
- printf("norm: new volumen level=%f peak=%f\n",level,mad_f_todouble(peak));
- return level;
+ // adjust for the smoothing window size and root
+ double level = sqrt (maxpow / (double) POW_WIN);
+ printf ("norm: new volumen level=%f peak=%f\n", level,
+ mad_f_todouble (peak));
+ return level;
}
-double cLevel::GetPeak(void)
+
+double
+cLevel::GetPeak (void)
{
- return mad_f_todouble(peak);
+ return mad_f_todouble (peak);
}
+
// --- cNormalize ------------------------------------------------------------
-class cNormalize {
-private:
- mad_fixed_t gain;
- double d_limlvl, one_limlvl;
- mad_fixed_t limlvl;
- bool dogain, dolimit;
+class cNormalize
+{
+ private:
+ mad_fixed_t gain;
+ double d_limlvl, one_limlvl;
+ mad_fixed_t limlvl;
+ bool dogain, dolimit;
#ifdef DEBUG
- // stats
- unsigned long limited, clipped, total;
- mad_fixed_t peak;
+// stats
+ unsigned long limited, clipped, total;
+ mad_fixed_t peak;
#endif
- // limiter
+// limiter
#ifdef USE_FAST_LIMITER
- mad_fixed_t *table, tablestart;
- int tablesize;
- inline mad_fixed_t FastLimiter(mad_fixed_t x);
+ mad_fixed_t *table, tablestart;
+ int tablesize;
+ inline mad_fixed_t FastLimiter (mad_fixed_t x);
#endif
- inline mad_fixed_t Limiter(mad_fixed_t x);
-public:
- cNormalize(void);
- ~cNormalize();
- void Init(double Level, double Peak);
- void Stats(void);
- void AddGain(struct mad_pcm *pcm);
- };
-
-cNormalize::cNormalize(void)
+ inline mad_fixed_t Limiter (mad_fixed_t x);
+ public:
+ cNormalize (void);
+ ~cNormalize ();
+ void Init (double Level, double Peak);
+ void Stats (void);
+ void AddGain (struct mad_pcm *pcm);
+};
+
+cNormalize::cNormalize (void)
{
- d_limlvl = (double)the_setup.LimiterLevel / 100.0;
- one_limlvl = 1 - d_limlvl;
- limlvl = mad_f_tofixed(d_limlvl);
- printf( "norm: lim_lev=%f lim_acc=%d\n", d_limlvl, LIM_ACC );
+ d_limlvl = (double) the_setup.LimiterLevel / 100.0;
+ one_limlvl = 1 - d_limlvl;
+ limlvl = mad_f_tofixed (d_limlvl);
+ printf ("norm: lim_lev=%f lim_acc=%d\n", d_limlvl, LIM_ACC);
#ifdef USE_FAST_LIMITER
- mad_fixed_t start=limlvl & ~(F_LIM_JMP-1);
- tablestart=start;
- tablesize=(unsigned int)(F_LIM_MAX-start)/F_LIM_JMP + 2;
- table=new mad_fixed_t[tablesize];
- if(table) {
- printf("norm: table size=%d start=%08x jump=%08x\n",tablesize,start,F_LIM_JMP);
- for(int i=0 ; i<tablesize ; i++) {
- table[i]=Limiter(start);
- start+=F_LIM_JMP;
- }
- tablesize--; // avoid a -1 in FastLimiter()
-
- // do a quick accuracy check, just to be sure that FastLimiter() is working
- // as expected :-)
+ mad_fixed_t start = limlvl & ~(F_LIM_JMP - 1);
+ tablestart = start;
+ tablesize = (unsigned int) (F_LIM_MAX - start) / F_LIM_JMP + 2;
+ table = new mad_fixed_t[tablesize];
+ if (table)
+ {
+ printf ("norm: table size=%d start=%08x jump=%08x\n", tablesize, start,
+ F_LIM_JMP);
+ for (int i = 0; i < tablesize; i++)
+ {
+ table[i] = Limiter (start);
+ start += F_LIM_JMP;
+ }
+ tablesize--; // avoid a -1 in FastLimiter()
+
+// do a quick accuracy check, just to be sure that FastLimiter() is working
+// as expected :-)
#ifdef ACC_DUMP
- FILE *out=fopen("/tmp/limiter","w");
+ FILE *out = fopen ("/tmp/limiter", "w");
#endif
- mad_fixed_t maxdiff=0;
- for(mad_fixed_t x=F_LIM_MAX ; x>=limlvl ; x-=mad_f_tofixed(1e-4)) {
- mad_fixed_t diff=mad_f_abs(Limiter(x)-FastLimiter(x));
- if(diff>maxdiff) maxdiff=diff;
+ mad_fixed_t maxdiff = 0;
+ for (mad_fixed_t x = F_LIM_MAX; x >= limlvl; x -= mad_f_tofixed (1e-4))
+ {
+ mad_fixed_t diff = mad_f_abs (Limiter (x) - FastLimiter (x));
+ if (diff > maxdiff)
+ maxdiff = diff;
#ifdef ACC_DUMP
- fprintf(out,"%0.10f\t%0.10f\t%0.10f\t%0.10f\t%0.10f\n",
- mad_f_todouble(x),mad_f_todouble(Limiter(x)),mad_f_todouble(FastLimiter(x)),mad_f_todouble(diff),mad_f_todouble(maxdiff));
- if(ferror(out)) break;
+ fprintf (out, "%0.10f\t%0.10f\t%0.10f\t%0.10f\t%0.10f\n",
+ mad_f_todouble (x), mad_f_todouble (Limiter (x)),
+ mad_f_todouble (FastLimiter (x)), mad_f_todouble (diff),
+ mad_f_todouble (maxdiff));
+ if (ferror (out))
+ break;
#endif
- }
+ }
#ifdef ACC_DUMP
- fclose(out);
+ fclose (out);
#endif
- printf("norm: accuracy %.12f\n",mad_f_todouble(maxdiff));
- if(mad_f_todouble(maxdiff)>1e-6)
- {
- esyslog("ERROR: accuracy check failed, normalizer disabled");
- delete table; table=0;
- }
+ printf ("norm: accuracy %.12f\n", mad_f_todouble (maxdiff));
+ if (mad_f_todouble (maxdiff) > 1e-6)
+ {
+ esyslog ("ERROR: accuracy check failed, normalizer disabled");
+ delete table;
+ table = 0;
+ }
}
- else esyslog("ERROR: no memory for lookup table, normalizer disabled");
-#endif // USE_FAST_LIMITER
+ else
+ esyslog ("ERROR: no memory for lookup table, normalizer disabled");
+#endif // USE_FAST_LIMITER
}
-cNormalize::~cNormalize()
+
+cNormalize::~cNormalize ()
{
#ifdef USE_FAST_LIMITER
- delete table;
+ delete table;
#endif
}
-void cNormalize::Init(double Level, double Peak)
+
+void
+cNormalize::Init (double Level, double Peak)
{
- double Target=(double)the_setup.TargetLevel/100.0;
- double dgain=Target/Level;
- if(dgain>MAX_GAIN) dgain=MAX_GAIN;
- gain=mad_f_tofixed(dgain);
- // Check if we actually need to apply a gain
- dogain=(Target>0.0 && fabs(1-dgain)>MIN_GAIN);
+ double Target = (double) the_setup.TargetLevel / 100.0;
+ double dgain = Target / Level;
+ if (dgain > MAX_GAIN)
+ dgain = MAX_GAIN;
+ gain = mad_f_tofixed (dgain);
+// Check if we actually need to apply a gain
+ dogain = (Target > 0.0 && fabs (1 - dgain) > MIN_GAIN);
#ifdef USE_FAST_LIMITER
- if(!table) dogain=false;
+ if (!table)
+ dogain = false;
#endif
- // Check if we actually need to do limiting:
- // we have to if limiter is enabled, if gain>1 and if the peaks will clip.
- dolimit=(d_limlvl<1.0 && dgain>1.0 && Peak*dgain>1.0);
+// Check if we actually need to do limiting:
+// we have to if limiter is enabled, if gain>1 and if the peaks will clip.
+ dolimit = (d_limlvl < 1.0 && dgain > 1.0 && Peak * dgain > 1.0);
#ifdef DEBUG
- printf("norm: gain=%f dogain=%d dolimit=%d (target=%f level=%f peak=%f)\n",dgain,dogain,dolimit,Target,Level,Peak);
- limited=clipped=total=0; peak=0;
+ printf ("norm: gain=%f dogain=%d dolimit=%d (target=%f level=%f peak=%f)\n",
+ dgain, dogain, dolimit, Target, Level, Peak);
+ limited = clipped = total = 0;
+ peak = 0;
#endif
}
-void cNormalize::Stats(void)
+
+void
+cNormalize::Stats (void)
{
#ifdef DEBUG
- if(total)
- printf("norm: stats tot=%ld lim=%ld/%.3f%% clip=%ld/%.3f%% peak=%.3f\n",
- total,limited,(double)limited/total*100.0,clipped,(double)clipped/total*100.0,mad_f_todouble(peak));
+ if (total)
+ printf ("norm: stats tot=%ld lim=%ld/%.3f%% clip=%ld/%.3f%% peak=%.3f\n",
+ total, limited, (double) limited / total * 100.0, clipped,
+ (double) clipped / total * 100.0, mad_f_todouble (peak));
#endif
}
-mad_fixed_t cNormalize::Limiter(mad_fixed_t x)
+
+mad_fixed_t cNormalize::Limiter (mad_fixed_t x)
{
// Limiter function:
//
@@ -330,42 +399,57 @@ mad_fixed_t cNormalize::Limiter(mad_fixed_t x)
// With limiter level = 0, this is equivalent to a tanh() function;
// with limiter level = 1, this is equivalent to clipping.
- if(x>limlvl) {
+ if (x > limlvl)
+ {
#ifdef DEBUG
- if(x>MAD_F_ONE) clipped++;
- limited++;
+ if (x > MAD_F_ONE)
+ clipped++;
+ limited++;
#endif
- x=mad_f_tofixed(tanh((mad_f_todouble(x)-d_limlvl) / one_limlvl) * one_limlvl + d_limlvl);
+ x =
+ mad_f_tofixed (tanh ((mad_f_todouble (x) - d_limlvl) / one_limlvl) *
+ one_limlvl + d_limlvl);
}
- return x;
+ return x;
}
+
#ifdef USE_FAST_LIMITER
-mad_fixed_t cNormalize::FastLimiter(mad_fixed_t x)
+mad_fixed_t cNormalize::FastLimiter (mad_fixed_t x)
{
// The fast algorithm is based on a linear interpolation between the
// the values in the lookup table. Relays heavly on libmads fixed point format.
- if(x>limlvl) {
- int i=(unsigned int)(x-tablestart)/F_LIM_JMP;
+ if (x > limlvl)
+ {
+ int
+ i = (unsigned int) (x - tablestart) / F_LIM_JMP;
#ifdef DEBUG
- if(x>MAD_F_ONE) clipped++;
- limited++;
- if(i>=tablesize) printf("norm: overflow x=%f x-ts=%f i=%d tsize=%d\n",
- mad_f_todouble(x),mad_f_todouble(x-tablestart),i,tablesize);
+ if (x > MAD_F_ONE)
+ clipped++;
+ limited++;
+ if (i >= tablesize)
+ printf ("norm: overflow x=%f x-ts=%f i=%d tsize=%d\n",
+ mad_f_todouble (x), mad_f_todouble (x - tablestart), i,
+ tablesize);
#endif
- mad_fixed_t r=x & (F_LIM_JMP-1);
- x=MAD_F_ONE;
- if(i<tablesize) {
- mad_fixed_t *ptr=&table[i];
- x=*ptr;
- mad_fixed_t d=*(ptr+1)-x;
- //x+=mad_f_mul(d,r)<<LIM_ACC; // this is not accurate as mad_f_mul() does >>MAD_F_FRACBITS
- // which is senseless in the case of following <<LIM_ACC.
- x+=((long long)d*(long long)r)>>LIM_SHIFT; // better, don't know if works on all machines
- }
+ mad_fixed_t
+ r = x & (F_LIM_JMP - 1);
+ x = MAD_F_ONE;
+ if (i < tablesize)
+ {
+ mad_fixed_t *
+ ptr = &table[i];
+ x = *ptr;
+ mad_fixed_t
+ d = *(ptr + 1) - x;
+//x+=mad_f_mul(d,r)<<LIM_ACC; // this is not accurate as mad_f_mul() does >>MAD_F_FRACBITS
+// which is senseless in the case of following <<LIM_ACC.
+ // better, don't know if works on all machines
+ x += ((long long) d * (long long) r) >> LIM_SHIFT;
+ }
}
- return x;
+ return x;
}
#endif
@@ -375,235 +459,296 @@ mad_fixed_t cNormalize::FastLimiter(mad_fixed_t x)
#define LIMITER_FUNC Limiter
#endif
-void cNormalize::AddGain(struct mad_pcm *pcm)
+void
+cNormalize::AddGain (struct mad_pcm *pcm)
{
- if(dogain) {
- for(int i=0 ; i<pcm->channels ; i++) {
- mad_fixed_t *data=pcm->samples[i];
+ if (dogain)
+ {
+ for (int i = 0; i < pcm->channels; i++)
+ {
+ mad_fixed_t *data = pcm->samples[i];
#ifdef DEBUG
- total+=pcm->length;
+ total += pcm->length;
#endif
- if(dolimit) {
- for(int n=pcm->length ; n>0 ; n--) {
- mad_fixed_t s=mad_f_mul(*data,gain);
- if(s<0) {
- s=-s;
+ if (dolimit)
+ {
+ for (int n = pcm->length; n > 0; n--)
+ {
+ mad_fixed_t s = mad_f_mul (*data, gain);
+ if (s < 0)
+ {
+ s = -s;
#ifdef DEBUG
- if(s>peak) peak=s;
+ if (s > peak)
+ peak = s;
#endif
- s=LIMITER_FUNC(s);
- s=-s;
- }
- else {
+ s = LIMITER_FUNC (s);
+ s = -s;
+ }
+ else
+ {
#ifdef DEBUG
- if(s>peak) peak=s;
+ if (s > peak)
+ peak = s;
#endif
- s=LIMITER_FUNC(s);
+ s = LIMITER_FUNC (s);
+ }
+ *data++ = s;
+ }
}
- *data++=s;
- }
- }
- else {
- for(int n=pcm->length ; n>0 ; n--) {
- mad_fixed_t s=mad_f_mul(*data,gain);
+ else
+ {
+ for (int n = pcm->length; n > 0; n--)
+ {
+ mad_fixed_t s = mad_f_mul (*data, gain);
#ifdef DEBUG
- if(s>peak) peak=s;
- else if(-s>peak) peak=-s;
+ if (s > peak)
+ peak = s;
+ else if (-s > peak)
+ peak = -s;
#endif
- if(s>MAD_F_ONE) s=MAD_F_ONE; // do clipping
- if(s<-MAD_F_ONE) s=-MAD_F_ONE;
- *data++=s;
- }
+ if (s > MAD_F_ONE)
+ s = MAD_F_ONE; // do clipping
+ if (s < -MAD_F_ONE)
+ s = -MAD_F_ONE;
+ *data++ = s;
+ }
+ }
}
- }
}
}
+
// --- cScale ----------------------------------------------------------------
// The dither code has been adapted from the madplay project
// (audio.c) found in the libmad distribution
-enum eAudioMode { amRound, amDither };
+enum eAudioMode
+{ amRound, amDither };
-class cScale {
-private:
- enum { MIN=-MAD_F_ONE, MAX=MAD_F_ONE - 1 };
+class cScale
+{
+ private:
+ enum
+ { MIN = -MAD_F_ONE, MAX = MAD_F_ONE - 1 };
#ifdef DEBUG
- // audio stats
- unsigned long clipped_samples;
- mad_fixed_t peak_clipping;
- mad_fixed_t peak_sample;
+// audio stats
+ unsigned long clipped_samples;
+ mad_fixed_t peak_clipping;
+ mad_fixed_t peak_sample;
#endif
- // dither
- struct dither {
- mad_fixed_t error[3];
- mad_fixed_t random;
- } leftD, rightD;
- //
- inline mad_fixed_t Clip(mad_fixed_t sample, bool stats=true);
- inline signed long LinearRound(mad_fixed_t sample);
- inline unsigned long Prng(unsigned long state);
- inline signed long LinearDither(mad_fixed_t sample, struct dither *dither);
-public:
- void Init(void);
- void Stats(void);
- unsigned int ScaleBlock(unsigned char *data, unsigned int size, unsigned int &nsamples, const mad_fixed_t * &left, const mad_fixed_t * &right, eAudioMode mode);
- };
-
-void cScale::Init(void)
+// dither
+ struct dither
+ {
+ mad_fixed_t error[3];
+ mad_fixed_t random;
+ } leftD, rightD;
+//
+ inline mad_fixed_t Clip (mad_fixed_t sample, bool stats = true);
+ inline signed long LinearRound (mad_fixed_t sample);
+ inline unsigned long Prng (unsigned long state);
+ inline signed long LinearDither (mad_fixed_t sample, struct dither *dither);
+ public:
+ void Init (void);
+ void Stats (void);
+ unsigned int ScaleBlock (unsigned char *data, unsigned int size,
+ unsigned int &nsamples, const mad_fixed_t * &left,
+ const mad_fixed_t * &right, eAudioMode mode);
+};
+
+void
+cScale::Init (void)
{
#ifdef DEBUG
- clipped_samples=0; peak_clipping=peak_sample=0;
+ clipped_samples = 0;
+ peak_clipping = peak_sample = 0;
#endif
- memset(&leftD,0,sizeof(leftD));
- memset(&rightD,0,sizeof(rightD));
+ memset (&leftD, 0, sizeof (leftD));
+ memset (&rightD, 0, sizeof (rightD));
}
-void cScale::Stats(void)
+
+void
+cScale::Stats (void)
{
#ifdef DEBUG
- printf("mp3: scale stats clipped=%ld peak_clip=%f peak=%f\n",
- clipped_samples,mad_f_todouble(peak_clipping),mad_f_todouble(peak_sample));
+ printf ("mp3: scale stats clipped=%ld peak_clip=%f peak=%f\n",
+ clipped_samples, mad_f_todouble (peak_clipping),
+ mad_f_todouble (peak_sample));
#endif
}
+
// gather signal statistics while clipping
-mad_fixed_t cScale::Clip(mad_fixed_t sample, bool stats)
+mad_fixed_t cScale::Clip (mad_fixed_t sample, bool stats)
{
#ifndef DEBUG
- if (sample > MAX) sample = MAX;
- if (sample < MIN) sample = MIN;
+ if (sample > MAX)
+ sample = MAX;
+ if (sample < MIN)
+ sample = MIN;
#else
- if(!stats) {
- if (sample > MAX) sample = MAX;
- if (sample < MIN) sample = MIN;
+ if (!stats)
+ {
+ if (sample > MAX)
+ sample = MAX;
+ if (sample < MIN)
+ sample = MIN;
}
- else {
- if (sample >= peak_sample) {
- if (sample > MAX) {
- ++clipped_samples;
- if (sample - MAX > peak_clipping)
- peak_clipping = sample - MAX;
- sample = MAX;
+ else
+ {
+ if (sample >= peak_sample)
+ {
+ if (sample > MAX)
+ {
+ ++clipped_samples;
+ if (sample - MAX > peak_clipping)
+ peak_clipping = sample - MAX;
+ sample = MAX;
+ }
+ peak_sample = sample;
}
- peak_sample = sample;
- }
- else if (sample < -peak_sample) {
- if (sample < MIN) {
- ++clipped_samples;
- if (MIN - sample > peak_clipping)
- peak_clipping = MIN - sample;
- sample = MIN;
+ else if (sample < -peak_sample)
+ {
+ if (sample < MIN)
+ {
+ ++clipped_samples;
+ if (MIN - sample > peak_clipping)
+ peak_clipping = MIN - sample;
+ sample = MIN;
+ }
+ peak_sample = -sample;
}
- peak_sample = -sample;
- }
}
#endif
- return sample;
+ return sample;
}
+
// generic linear sample quantize routine
-signed long cScale::LinearRound(mad_fixed_t sample)
+signed long
+cScale::LinearRound (mad_fixed_t sample)
{
- // round
- sample += (1L << (MAD_F_FRACBITS - OUT_BITS));
- // clip
- sample=Clip(sample);
- // quantize and scale
- return sample >> (MAD_F_FRACBITS + 1 - OUT_BITS);
+// round
+ sample += (1L << (MAD_F_FRACBITS - OUT_BITS));
+// clip
+ sample = Clip (sample);
+// quantize and scale
+ return sample >> (MAD_F_FRACBITS + 1 - OUT_BITS);
}
+
// 32-bit pseudo-random number generator
-unsigned long cScale::Prng(unsigned long state)
+unsigned long
+cScale::Prng (unsigned long state)
{
- return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
+ return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
}
+
// generic linear sample quantize and dither routine
-signed long cScale::LinearDither(mad_fixed_t sample, struct dither *dither)
+signed long
+cScale::LinearDither (mad_fixed_t sample, struct dither *dither)
{
- unsigned int scalebits;
- mad_fixed_t output, mask, random;
-
- // noise shape
- sample += dither->error[0] - dither->error[1] + dither->error[2];
- dither->error[2] = dither->error[1];
- dither->error[1] = dither->error[0] / 2;
- // bias
- output = sample + (1L << (MAD_F_FRACBITS + 1 - OUT_BITS - 1));
- scalebits = MAD_F_FRACBITS + 1 - OUT_BITS;
- mask = (1L << scalebits) - 1;
- // dither
- random = Prng(dither->random);
- output += (random & mask) - (dither->random & mask);
- dither->random = random;
- // clip
- output=Clip(output);
- sample=Clip(sample,false);
- // quantize
- output &= ~mask;
- // error feedback
- dither->error[0] = sample - output;
- // scale
- return output >> scalebits;
+ unsigned int scalebits;
+ mad_fixed_t output, mask, random;
+
+// noise shape
+ sample += dither->error[0] - dither->error[1] + dither->error[2];
+ dither->error[2] = dither->error[1];
+ dither->error[1] = dither->error[0] / 2;
+// bias
+ output = sample + (1L << (MAD_F_FRACBITS + 1 - OUT_BITS - 1));
+ scalebits = MAD_F_FRACBITS + 1 - OUT_BITS;
+ mask = (1L << scalebits) - 1;
+// dither
+ random = Prng (dither->random);
+ output += (random & mask) - (dither->random & mask);
+ dither->random = random;
+// clip
+ output = Clip (output);
+ sample = Clip (sample, false);
+// quantize
+ output &= ~mask;
+// error feedback
+ dither->error[0] = sample - output;
+// scale
+ return output >> scalebits;
}
+
// write a block of signed 16-bit big-endian PCM samples
-unsigned int cScale::ScaleBlock(unsigned char *data, unsigned int size, unsigned int &nsamples, const mad_fixed_t * &left, const mad_fixed_t * &right, eAudioMode mode)
+unsigned int
+cScale::ScaleBlock (unsigned char *data, unsigned int size,
+unsigned int &nsamples, const mad_fixed_t * &left,
+const mad_fixed_t * &right, eAudioMode mode)
{
- signed int sample;
- unsigned int len, res;
-
- len=size/OUT_FACT; res=size;
- if(len>nsamples) { len=nsamples; res=len*OUT_FACT; }
- nsamples-=len;
-
- if(right) { // stereo
- switch (mode) {
- case amRound:
- while (len--) {
- sample = LinearRound(*left++);
- *data++ = sample >> 8;
- *data++ = sample >> 0;
- sample = LinearRound(*right++);
- *data++ = sample >> 8;
- *data++ = sample >> 0;
- }
- break;
- case amDither:
- while (len--) {
- sample = LinearDither(*left++,&leftD);
- *data++ = sample >> 8;
- *data++ = sample >> 0;
- sample = LinearDither(*right++,&rightD);
- *data++ = sample >> 8;
- *data++ = sample >> 0;
- }
- break;
- }
+ signed int sample;
+ unsigned int len, res;
+
+ len = size / OUT_FACT;
+ res = size;
+ if (len > nsamples)
+ {
+ len = nsamples;
+ res = len * OUT_FACT;
}
- else { // mono, duplicate left channel
- switch (mode) {
- case amRound:
- while (len--) {
- sample = LinearRound(*left++);
- *data++ = sample >> 8;
- *data++ = sample >> 0;
- *data++ = sample >> 8;
- *data++ = sample >> 0;
- }
- break;
- case amDither:
- while (len--) {
- sample = LinearDither(*left++,&leftD);
- *data++ = sample >> 8;
- *data++ = sample >> 0;
- *data++ = sample >> 8;
- *data++ = sample >> 0;
- }
- break;
- }
+ nsamples -= len;
+
+ if (right)
+ { // stereo
+ switch (mode)
+ {
+ case amRound:
+ while (len--)
+ {
+ sample = LinearRound (*left++);
+ *data++ = sample >> 8;
+ *data++ = sample >> 0;
+ sample = LinearRound (*right++);
+ *data++ = sample >> 8;
+ *data++ = sample >> 0;
+ }
+ break;
+ case amDither:
+ while (len--)
+ {
+ sample = LinearDither (*left++, &leftD);
+ *data++ = sample >> 8;
+ *data++ = sample >> 0;
+ sample = LinearDither (*right++, &rightD);
+ *data++ = sample >> 8;
+ *data++ = sample >> 0;
+ }
+ break;
+ }
+ }
+ else
+ { // mono, duplicate left channel
+ switch (mode)
+ {
+ case amRound:
+ while (len--)
+ {
+ sample = LinearRound (*left++);
+ *data++ = sample >> 8;
+ *data++ = sample >> 0;
+ *data++ = sample >> 8;
+ *data++ = sample >> 0;
+ }
+ break;
+ case amDither:
+ while (len--)
+ {
+ sample = LinearDither (*left++, &leftD);
+ *data++ = sample >> 8;
+ *data++ = sample >> 0;
+ *data++ = sample >> 8;
+ *data++ = sample >> 0;
+ }
+ break;
+ }
}
- return res;
+ return res;
}