player-mp3.c
branchtrunk
changeset 0 474a1293c3c0
child 6 111ef8181229
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/player-mp3.c	Sat Dec 29 14:47:40 2007 +0100
     1.3 @@ -0,0 +1,1979 @@
     1.4 +/*
     1.5 + * MP3/MPlayer plugin to VDR (C++)
     1.6 + *
     1.7 + * (C) 2001-2007 Stefan Huelswitt <s.huelswitt@gmx.de>
     1.8 + *
     1.9 + * This code is free software; you can redistribute it and/or
    1.10 + * modify it under the terms of the GNU General Public License
    1.11 + * as published by the Free Software Foundation; either version 2
    1.12 + * of the License, or (at your option) any later version.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful,
    1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.17 + * GNU General Public License for more details.
    1.18 + *
    1.19 + * You should have received a copy of the GNU General Public License
    1.20 + * along with this program; if not, write to the Free Software
    1.21 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    1.22 + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
    1.23 + */
    1.24 +
    1.25 +#include <stdlib.h>
    1.26 +#include <stdio.h>
    1.27 +#include <sys/ioctl.h>
    1.28 +#include <math.h>
    1.29 +#ifdef WITH_OSS
    1.30 +#include <sys/soundcard.h>
    1.31 +#endif
    1.32 +
    1.33 +#include <mad.h>
    1.34 +#include <id3tag.h>
    1.35 +
    1.36 +#include <vdr/player.h>
    1.37 +#include <vdr/ringbuffer.h>
    1.38 +#include <vdr/thread.h>
    1.39 +#include <vdr/tools.h>
    1.40 +
    1.41 +#include "common.h"
    1.42 +#include "setup-mp3.h"
    1.43 +#include "player-mp3.h"
    1.44 +#include "data-mp3.h"
    1.45 +#include "decoder.h"
    1.46 +#include "decoder-core.h"
    1.47 +
    1.48 +#ifndef NO_DEBUG
    1.49 +//#define DEBUG_MODE      // debug playmode changes
    1.50 +#define DEBUG_BGR       // debug backround scan thread
    1.51 +#define DEBUG_DELAY 300 // debug write/decode delays
    1.52 +//#define ACC_DUMP        // dump limiter lookup table to /tmp/limiter
    1.53 +#endif
    1.54 +
    1.55 +#if !defined(NO_DEBUG) && defined(DEBUG_MODE)
    1.56 +#define dm(x) { (x); }
    1.57 +#else
    1.58 +#define dm(x) ; 
    1.59 +#endif
    1.60 +
    1.61 +#if !defined(NO_DEBUG) && defined(DEBUG_BGR)
    1.62 +#define db(x) { (x); }
    1.63 +#else
    1.64 +#define db(x) ; 
    1.65 +#endif
    1.66 +
    1.67 +// ----------------------------------------------------------------
    1.68 +
    1.69 +#define MP3BUFSIZE (1024*1024)                               // output ringbuffer size
    1.70 +#define OUT_BITS 16                                          // output 16 bit samples to DVB driver
    1.71 +#define OUT_FACT (OUT_BITS/8*2)                              // output factor is 16 bit & 2 channels -> 4 bytes
    1.72 +// cResample
    1.73 +#define MAX_NSAMPLES (1152*7)                                // max. buffer for resampled frame
    1.74 +// cNormalize
    1.75 +#define MIN_GAIN   0.03                                      // min. gain required to launch the normalizer
    1.76 +#define MAX_GAIN   3.0                                       // max. allowed gain
    1.77 +#define USE_FAST_LIMITER
    1.78 +#define LIM_ACC    12                                        // bit, accuracy for lookup table
    1.79 +#define F_LIM_MAX  (mad_fixed_t)((1<<(MAD_F_FRACBITS+2))-1)  // max. value covered by lookup table
    1.80 +#define LIM_SHIFT  (MAD_F_FRACBITS-LIM_ACC)                  // shift value for table lookup
    1.81 +#define F_LIM_JMP  (mad_fixed_t)(1<<LIM_SHIFT)               // lookup table jump between values
    1.82 +// cLevel
    1.83 +#define POW_WIN 100                                          // window width for smoothing power values
    1.84 +#define EPSILON 0.00000000001                                // anything less than EPSILON is considered zero
    1.85 +
    1.86 +// --- cResample ------------------------------------------------------------
    1.87 +
    1.88 +// The resample code has been adapted from the madplay project
    1.89 +// (resample.c) found in the libmad distribution
    1.90 +   
    1.91 +class cResample {
    1.92 +private:
    1.93 +  mad_fixed_t ratio;
    1.94 +  mad_fixed_t step;
    1.95 +  mad_fixed_t last;
    1.96 +  mad_fixed_t resampled[MAX_NSAMPLES];
    1.97 +public:
    1.98 +  bool SetInputRate(unsigned int oldrate, unsigned int newrate);
    1.99 +  unsigned int ResampleBlock(unsigned int nsamples, const mad_fixed_t *old);
   1.100 +  const mad_fixed_t *Resampled(void) { return resampled; }
   1.101 +  };
   1.102 +
   1.103 +bool cResample::SetInputRate(unsigned int oldrate, unsigned int newrate)
   1.104 +{
   1.105 +  if(oldrate<8000 || oldrate>newrate*6) { // out of range
   1.106 +    esyslog("WARNING: samplerate %d out of range 8000-%d\n",oldrate,newrate*6);
   1.107 +    return 0;
   1.108 +    }
   1.109 +  ratio=mad_f_tofixed((double)oldrate/(double)newrate);
   1.110 +  step=0; last=0;
   1.111 +#ifdef DEBUG
   1.112 +  static mad_fixed_t oldratio=0;
   1.113 +  if(oldratio!=ratio) {
   1.114 +    printf("mad: new resample ratio %f (from %d kHz to %d kHz)\n",mad_f_todouble(ratio),oldrate,newrate);
   1.115 +    oldratio=ratio;
   1.116 +    }
   1.117 +#endif
   1.118 +  return ratio!=MAD_F_ONE;
   1.119 +}
   1.120 +
   1.121 +unsigned int cResample::ResampleBlock(unsigned int nsamples, const mad_fixed_t *old)
   1.122 +{
   1.123 +  // This resampling algorithm is based on a linear interpolation, which is
   1.124 +  // not at all the best sounding but is relatively fast and efficient.
   1.125 +  //
   1.126 +  // A better algorithm would be one that implements a bandlimited
   1.127 +  // interpolation.
   1.128 +
   1.129 +  mad_fixed_t *nsam=resampled;
   1.130 +  const mad_fixed_t *end=old+nsamples;
   1.131 +  const mad_fixed_t *begin=nsam;
   1.132 +
   1.133 +  if(step < 0) {
   1.134 +    step = mad_f_fracpart(-step);
   1.135 +
   1.136 +    while (step < MAD_F_ONE) {
   1.137 +      *nsam++ = step ? last+mad_f_mul(*old-last,step) : last;
   1.138 +      step += ratio;
   1.139 +      if(((step + 0x00000080L) & 0x0fffff00L) == 0)
   1.140 +	step = (step + 0x00000080L) & ~0x0fffffffL;
   1.141 +      }
   1.142 +    step -= MAD_F_ONE;
   1.143 +    }
   1.144 +
   1.145 +  while (end - old > 1 + mad_f_intpart(step)) {
   1.146 +    old += mad_f_intpart(step);
   1.147 +    step = mad_f_fracpart(step);
   1.148 +    *nsam++ = step ? *old + mad_f_mul(old[1] - old[0], step) : *old;
   1.149 +    step += ratio;
   1.150 +    if (((step + 0x00000080L) & 0x0fffff00L) == 0)
   1.151 +      step = (step + 0x00000080L) & ~0x0fffffffL;
   1.152 +    }
   1.153 +
   1.154 +  if (end - old == 1 + mad_f_intpart(step)) {
   1.155 +    last = end[-1];
   1.156 +    step = -step;
   1.157 +    }
   1.158 +  else step -= mad_f_fromint(end - old);
   1.159 +
   1.160 +  return nsam-begin;
   1.161 +}
   1.162 +
   1.163 +// --- cLevel ----------------------------------------------------------------
   1.164 +
   1.165 +// The normalize algorithm and parts of the code has been adapted from the
   1.166 +// Normalize 0.7 project. (C) 1999-2002, Chris Vaill <cvaill@cs.columbia.edu>
   1.167 +
   1.168 +// A little background on how normalize computes the volume
   1.169 +// of a wav file, in case you want to know just how your
   1.170 +// files are being munged:
   1.171 +//
   1.172 +// The volumes calculated are RMS amplitudes, which corre­
   1.173 +// spond (roughly) to perceived volume. Taking the RMS ampli­
   1.174 +// tude of an entire file would not give us quite the measure
   1.175 +// we want, though, because a quiet song punctuated by short
   1.176 +// loud parts would average out to a quiet song, and the
   1.177 +// adjustment we would compute would make the loud parts
   1.178 +// excessively loud.
   1.179 +//
   1.180 +// What we want is to consider the maximum volume of the
   1.181 +// file, and normalize according to that. We break up the
   1.182 +// signal into 100 chunks per second, and get the signal
   1.183 +// power of each chunk, in order to get an estimation of
   1.184 +// "instantaneous power" over time. This "instantaneous
   1.185 +// power" signal varies too much to get a good measure of the
   1.186 +// original signal's maximum sustained power, so we run a
   1.187 +// smoothing algorithm over the power signal (specifically, a
   1.188 +// mean filter with a window width of 100 elements). The max­
   1.189 +// imum point of the smoothed power signal turns out to be a
   1.190 +// good measure of the maximum sustained power of the file.
   1.191 +// We can then take the square root of the power to get maxi­
   1.192 +// mum sustained RMS amplitude.
   1.193 +
   1.194 +class cLevel {
   1.195 +private:
   1.196 +  double maxpow;
   1.197 +  mad_fixed_t peak;
   1.198 +  struct Power {
   1.199 +    // smooth
   1.200 +    int npow, wpow;
   1.201 +    double powsum, pows[POW_WIN];
   1.202 +    // sum
   1.203 +    unsigned int nsum;
   1.204 +    double sum;
   1.205 +    } power[2];
   1.206 +  //
   1.207 +  inline void AddPower(struct Power *p, double pow);
   1.208 +public:
   1.209 +  void Init(void);
   1.210 +  void GetPower(struct mad_pcm *pcm);
   1.211 +  double GetLevel(void);
   1.212 +  double GetPeak(void);
   1.213 +  };
   1.214 +
   1.215 +void cLevel::Init(void)
   1.216 +{
   1.217 +  for(int l=0 ; l<2 ; l++) {
   1.218 +    struct Power *p=&power[l];
   1.219 +    p->sum=p->powsum=0.0; p->wpow=p->npow=p->nsum=0;
   1.220 +    for(int i=POW_WIN-1 ; i>=0 ; i--) p->pows[i]=0.0;
   1.221 +    }
   1.222 +  maxpow=0.0; peak=0;
   1.223 +}
   1.224 +
   1.225 +void cLevel::GetPower(struct mad_pcm *pcm)
   1.226 +{
   1.227 +  for(int i=0 ; i<pcm->channels ; i++) {
   1.228 +    struct Power *p=&power[i];
   1.229 +    mad_fixed_t *data=pcm->samples[i];
   1.230 +    for(int n=pcm->length ; n>0 ; n--) {
   1.231 +      if(*data < -peak) peak = -*data;
   1.232 +      if(*data >  peak) peak =  *data;
   1.233 +      double s=mad_f_todouble(*data++);
   1.234 +      p->sum+=(s*s);
   1.235 +      if(++(p->nsum)>=pcm->samplerate/100) {
   1.236 +        AddPower(p,p->sum/(double)p->nsum);
   1.237 +        p->sum=0.0; p->nsum=0;
   1.238 +        }
   1.239 +      }
   1.240 +    }
   1.241 +}
   1.242 +
   1.243 +void cLevel::AddPower(struct Power *p, double pow)
   1.244 +{
   1.245 +  p->powsum+=pow;
   1.246 +  if(p->npow>=POW_WIN) {
   1.247 +    if(p->powsum>maxpow) maxpow=p->powsum;
   1.248 +    p->powsum-=p->pows[p->wpow];
   1.249 +    }
   1.250 +  else p->npow++;
   1.251 +  p->pows[p->wpow]=pow;
   1.252 +  p->wpow=(p->wpow+1) % POW_WIN;
   1.253 +}
   1.254 +
   1.255 +double cLevel::GetLevel(void)
   1.256 +{
   1.257 +  if(maxpow<EPSILON) {
   1.258 +    // Either this whole file has zero power, or was too short to ever
   1.259 +    // fill the smoothing buffer.  In the latter case, we need to just
   1.260 +    // get maxpow from whatever data we did collect.
   1.261 +
   1.262 +    if(power[0].powsum>maxpow) maxpow=power[0].powsum;
   1.263 +    if(power[1].powsum>maxpow) maxpow=power[1].powsum;
   1.264 +    }
   1.265 +  double level=sqrt(maxpow/(double)POW_WIN);     // adjust for the smoothing window size and root
   1.266 +  d(printf("norm: new volumen level=%f peak=%f\n",level,mad_f_todouble(peak)))
   1.267 +  return level;
   1.268 +}
   1.269 +
   1.270 +double cLevel::GetPeak(void)
   1.271 +{
   1.272 +  return mad_f_todouble(peak);
   1.273 +}
   1.274 +
   1.275 +// --- cNormalize ------------------------------------------------------------
   1.276 +
   1.277 +class cNormalize {
   1.278 +private:
   1.279 +  mad_fixed_t gain;
   1.280 +  double d_limlvl, one_limlvl;
   1.281 +  mad_fixed_t limlvl;
   1.282 +  bool dogain, dolimit;
   1.283 +#ifdef DEBUG
   1.284 +  // stats
   1.285 +  unsigned long limited, clipped, total;
   1.286 +  mad_fixed_t peak;
   1.287 +#endif
   1.288 +  // limiter
   1.289 +#ifdef USE_FAST_LIMITER
   1.290 +  mad_fixed_t *table, tablestart;
   1.291 +  int tablesize;
   1.292 +  inline mad_fixed_t FastLimiter(mad_fixed_t x);
   1.293 +#endif
   1.294 +  inline mad_fixed_t Limiter(mad_fixed_t x);
   1.295 +public:
   1.296 +  cNormalize(void);
   1.297 +  ~cNormalize();
   1.298 +  void Init(double Level, double Peak);
   1.299 +  void Stats(void);
   1.300 +  void AddGain(struct mad_pcm *pcm);
   1.301 +  };
   1.302 +
   1.303 +cNormalize::cNormalize(void)
   1.304 +{
   1.305 +  d_limlvl=(double)MP3Setup.LimiterLevel/100.0;
   1.306 +  one_limlvl=1-d_limlvl;
   1.307 +  limlvl=mad_f_tofixed(d_limlvl);
   1.308 +  d(printf("norm: lim_lev=%f lim_acc=%d\n",d_limlvl,LIM_ACC))
   1.309 +
   1.310 +#ifdef USE_FAST_LIMITER
   1.311 +  mad_fixed_t start=limlvl & ~(F_LIM_JMP-1);
   1.312 +  tablestart=start;
   1.313 +  tablesize=(unsigned int)(F_LIM_MAX-start)/F_LIM_JMP + 2;
   1.314 +  table=new mad_fixed_t[tablesize];
   1.315 +  if(table) {
   1.316 +    d(printf("norm: table size=%d start=%08x jump=%08x\n",tablesize,start,F_LIM_JMP))
   1.317 +    for(int i=0 ; i<tablesize ; i++) {
   1.318 +      table[i]=Limiter(start);
   1.319 +      start+=F_LIM_JMP;
   1.320 +      }
   1.321 +    tablesize--; // avoid a -1 in FastLimiter()
   1.322 +
   1.323 +    // do a quick accuracy check, just to be sure that FastLimiter() is working
   1.324 +    // as expected :-)
   1.325 +#ifdef ACC_DUMP
   1.326 +    FILE *out=fopen("/tmp/limiter","w");
   1.327 +#endif
   1.328 +    mad_fixed_t maxdiff=0;
   1.329 +    for(mad_fixed_t x=F_LIM_MAX ; x>=limlvl ; x-=mad_f_tofixed(1e-4)) {
   1.330 +      mad_fixed_t diff=mad_f_abs(Limiter(x)-FastLimiter(x));
   1.331 +      if(diff>maxdiff) maxdiff=diff;
   1.332 +#ifdef ACC_DUMP
   1.333 +      fprintf(out,"%0.10f\t%0.10f\t%0.10f\t%0.10f\t%0.10f\n",
   1.334 +        mad_f_todouble(x),mad_f_todouble(Limiter(x)),mad_f_todouble(FastLimiter(x)),mad_f_todouble(diff),mad_f_todouble(maxdiff));
   1.335 +      if(ferror(out)) break;
   1.336 +#endif
   1.337 +      }
   1.338 +#ifdef ACC_DUMP
   1.339 +    fclose(out);
   1.340 +#endif
   1.341 +    d(printf("norm: accuracy %.12f\n",mad_f_todouble(maxdiff)))
   1.342 +    if(mad_f_todouble(maxdiff)>1e-6) {
   1.343 +      esyslog("ERROR: accuracy check failed, normalizer disabled");
   1.344 +      delete table; table=0;
   1.345 +      }
   1.346 +    }
   1.347 +  else esyslog("ERROR: no memory for lookup table, normalizer disabled");
   1.348 +#endif // USE_FAST_LIMITER
   1.349 +}
   1.350 +
   1.351 +cNormalize::~cNormalize()
   1.352 +{
   1.353 +#ifdef USE_FAST_LIMITER
   1.354 +  delete[] table;
   1.355 +#endif
   1.356 +}
   1.357 +
   1.358 +void cNormalize::Init(double Level, double Peak)
   1.359 +{
   1.360 +  double Target=(double)MP3Setup.TargetLevel/100.0;
   1.361 +  double dgain=Target/Level;
   1.362 +  if(dgain>MAX_GAIN) dgain=MAX_GAIN;
   1.363 +  gain=mad_f_tofixed(dgain);
   1.364 +  // Check if we actually need to apply a gain
   1.365 +  dogain=(Target>0.0 && fabs(1-dgain)>MIN_GAIN);
   1.366 +#ifdef USE_FAST_LIMITER
   1.367 +  if(!table) dogain=false;
   1.368 +#endif
   1.369 +  // Check if we actually need to do limiting:
   1.370 +  // we have to if limiter is enabled, if gain>1 and if the peaks will clip.
   1.371 +  dolimit=(d_limlvl<1.0 && dgain>1.0 && Peak*dgain>1.0);
   1.372 +#ifdef DEBUG
   1.373 +  printf("norm: gain=%f dogain=%d dolimit=%d (target=%f level=%f peak=%f)\n",dgain,dogain,dolimit,Target,Level,Peak);
   1.374 +  limited=clipped=total=0; peak=0;
   1.375 +#endif
   1.376 +}
   1.377 +
   1.378 +void cNormalize::Stats(void)
   1.379 +{
   1.380 +#ifdef DEBUG
   1.381 +  if(total)
   1.382 +    printf("norm: stats tot=%ld lim=%ld/%.3f%% clip=%ld/%.3f%% peak=%.3f\n",
   1.383 +           total,limited,(double)limited/total*100.0,clipped,(double)clipped/total*100.0,mad_f_todouble(peak));
   1.384 +#endif
   1.385 +}
   1.386 +
   1.387 +mad_fixed_t cNormalize::Limiter(mad_fixed_t x)
   1.388 +{
   1.389 +// Limiter function:
   1.390 +//
   1.391 +//        / x                                                (for x <= lev)
   1.392 +//   x' = |
   1.393 +//        \ tanh((x - lev) / (1-lev)) * (1-lev) + lev        (for x > lev)
   1.394 +//
   1.395 +// call only with x>=0. For negative samples, preserve sign outside this function
   1.396 +//
   1.397 +// With limiter level = 0, this is equivalent to a tanh() function;
   1.398 +// with limiter level = 1, this is equivalent to clipping.
   1.399 +
   1.400 +  if(x>limlvl) {
   1.401 +#ifdef DEBUG
   1.402 +    if(x>MAD_F_ONE) clipped++;
   1.403 +    limited++;
   1.404 +#endif
   1.405 +    x=mad_f_tofixed(tanh((mad_f_todouble(x)-d_limlvl) / one_limlvl) * one_limlvl + d_limlvl);
   1.406 +    }
   1.407 +  return x;
   1.408 +}
   1.409 +
   1.410 +#ifdef USE_FAST_LIMITER
   1.411 +mad_fixed_t cNormalize::FastLimiter(mad_fixed_t x)
   1.412 +{
   1.413 +// The fast algorithm is based on a linear interpolation between the
   1.414 +// the values in the lookup table. Relays heavly on libmads fixed point format.
   1.415 +
   1.416 +  if(x>limlvl) {
   1.417 +    int i=(unsigned int)(x-tablestart)/F_LIM_JMP;
   1.418 +#ifdef DEBUG
   1.419 +    if(x>MAD_F_ONE) clipped++;
   1.420 +    limited++;
   1.421 +    if(i>=tablesize) printf("norm: overflow x=%f x-ts=%f i=%d tsize=%d\n",
   1.422 +                            mad_f_todouble(x),mad_f_todouble(x-tablestart),i,tablesize);
   1.423 +#endif
   1.424 +    mad_fixed_t r=x & (F_LIM_JMP-1);
   1.425 +    x=MAD_F_ONE;
   1.426 +    if(i<tablesize) {
   1.427 +      mad_fixed_t *ptr=&table[i];
   1.428 +      x=*ptr;
   1.429 +      mad_fixed_t d=*(ptr+1)-x;
   1.430 +      //x+=mad_f_mul(d,r)<<LIM_ACC;                // this is not accurate as mad_f_mul() does >>MAD_F_FRACBITS
   1.431 +                                                   // which is senseless in the case of following <<LIM_ACC.
   1.432 +      x+=((long long)d*(long long)r)>>LIM_SHIFT;   // better, don't know if works on all machines
   1.433 +      }
   1.434 +    }
   1.435 +  return x;
   1.436 +}
   1.437 +#endif
   1.438 +
   1.439 +#ifdef USE_FAST_LIMITER
   1.440 +#define LIMITER_FUNC FastLimiter
   1.441 +#else
   1.442 +#define LIMITER_FUNC Limiter
   1.443 +#endif
   1.444 +
   1.445 +void cNormalize::AddGain(struct mad_pcm *pcm)
   1.446 +{
   1.447 +  if(dogain) {
   1.448 +    for(int i=0 ; i<pcm->channels ; i++) {
   1.449 +      mad_fixed_t *data=pcm->samples[i];
   1.450 +#ifdef DEBUG
   1.451 +      total+=pcm->length;
   1.452 +#endif
   1.453 +      if(dolimit) {
   1.454 +        for(int n=pcm->length ; n>0 ; n--) {
   1.455 +          mad_fixed_t s=mad_f_mul(*data,gain);
   1.456 +          if(s<0) {
   1.457 +            s=-s;
   1.458 +#ifdef DEBUG
   1.459 +            if(s>peak) peak=s;
   1.460 +#endif
   1.461 +            s=LIMITER_FUNC(s);
   1.462 +            s=-s;
   1.463 +            }
   1.464 +          else {
   1.465 +#ifdef DEBUG
   1.466 +            if(s>peak) peak=s;
   1.467 +#endif
   1.468 +            s=LIMITER_FUNC(s);
   1.469 +            }
   1.470 +          *data++=s;
   1.471 +          }
   1.472 +        }
   1.473 +      else {
   1.474 +        for(int n=pcm->length ; n>0 ; n--) {
   1.475 +          mad_fixed_t s=mad_f_mul(*data,gain);
   1.476 +#ifdef DEBUG
   1.477 +          if(s>peak) peak=s;
   1.478 +          else if(-s>peak) peak=-s;
   1.479 +#endif
   1.480 +          if(s>MAD_F_ONE) s=MAD_F_ONE;   // do clipping
   1.481 +          if(s<-MAD_F_ONE) s=-MAD_F_ONE;
   1.482 +          *data++=s;
   1.483 +          }
   1.484 +        }
   1.485 +      }
   1.486 +    }
   1.487 +}
   1.488 +
   1.489 +// --- cScale ----------------------------------------------------------------
   1.490 +
   1.491 +// The dither code has been adapted from the madplay project
   1.492 +// (audio.c) found in the libmad distribution
   1.493 +
   1.494 +enum eAudioMode { amRoundBE, amDitherBE, amRoundLE, amDitherLE };
   1.495 +
   1.496 +class cScale {
   1.497 +private:
   1.498 +  enum { MIN=-MAD_F_ONE, MAX=MAD_F_ONE - 1 };
   1.499 +#ifdef DEBUG
   1.500 +  // audio stats
   1.501 +  unsigned long clipped_samples;
   1.502 +  mad_fixed_t peak_clipping;
   1.503 +  mad_fixed_t peak_sample;
   1.504 +#endif
   1.505 +  // dither
   1.506 +  struct dither {
   1.507 +    mad_fixed_t error[3];
   1.508 +    mad_fixed_t random;
   1.509 +    } leftD, rightD;
   1.510 +  //
   1.511 +  inline mad_fixed_t Clip(mad_fixed_t sample, bool stats=true);
   1.512 +  inline unsigned long Prng(unsigned long state);
   1.513 +  signed long LinearRound(mad_fixed_t sample);
   1.514 +  signed long LinearDither(mad_fixed_t sample, struct dither *dither);
   1.515 +public:
   1.516 +  void Init(void);
   1.517 +  void Stats(void);
   1.518 +  unsigned int ScaleBlock(unsigned char *data, unsigned int size, unsigned int &nsamples, const mad_fixed_t * &left, const mad_fixed_t * &right, eAudioMode mode);
   1.519 +  };
   1.520 +
   1.521 +void cScale::Init(void)
   1.522 +{
   1.523 +#ifdef DEBUG
   1.524 +  clipped_samples=0; peak_clipping=peak_sample=0;
   1.525 +#endif
   1.526 +  memset(&leftD,0,sizeof(leftD));
   1.527 +  memset(&rightD,0,sizeof(rightD));
   1.528 +}
   1.529 +
   1.530 +void cScale::Stats(void)
   1.531 +{
   1.532 +#ifdef DEBUG
   1.533 +  printf("mp3: scale stats clipped=%ld peak_clip=%f peak=%f\n",
   1.534 +         clipped_samples,mad_f_todouble(peak_clipping),mad_f_todouble(peak_sample));
   1.535 +#endif
   1.536 +}
   1.537 +
   1.538 +// gather signal statistics while clipping
   1.539 +mad_fixed_t cScale::Clip(mad_fixed_t sample, bool stats)
   1.540 +{
   1.541 +#ifndef DEBUG
   1.542 +  if (sample > MAX) sample = MAX;
   1.543 +  if (sample < MIN) sample = MIN;
   1.544 +#else
   1.545 +  if(!stats) {
   1.546 +    if (sample > MAX) sample = MAX;
   1.547 +    if (sample < MIN) sample = MIN;
   1.548 +    }
   1.549 +  else {
   1.550 +    if (sample >= peak_sample) {
   1.551 +      if (sample > MAX) {
   1.552 +        ++clipped_samples;
   1.553 +        if (sample - MAX > peak_clipping)
   1.554 +	  peak_clipping = sample - MAX;
   1.555 +        sample = MAX;
   1.556 +        }
   1.557 +      peak_sample = sample;
   1.558 +      }
   1.559 +    else if (sample < -peak_sample) {
   1.560 +      if (sample < MIN) {
   1.561 +        ++clipped_samples;
   1.562 +        if (MIN - sample > peak_clipping)
   1.563 +	  peak_clipping = MIN - sample;
   1.564 +        sample = MIN;
   1.565 +        }
   1.566 +      peak_sample = -sample;
   1.567 +      }
   1.568 +    }
   1.569 +#endif
   1.570 +  return sample;
   1.571 +}
   1.572 +
   1.573 +// generic linear sample quantize routine
   1.574 +signed long cScale::LinearRound(mad_fixed_t sample)
   1.575 +{
   1.576 +  // round
   1.577 +  sample += (1L << (MAD_F_FRACBITS - OUT_BITS));
   1.578 +  // clip
   1.579 +  sample=Clip(sample);
   1.580 +  // quantize and scale
   1.581 +  return sample >> (MAD_F_FRACBITS + 1 - OUT_BITS);
   1.582 +}
   1.583 +
   1.584 +// 32-bit pseudo-random number generator
   1.585 +unsigned long cScale::Prng(unsigned long state)
   1.586 +{
   1.587 +  return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
   1.588 +}
   1.589 +
   1.590 +// generic linear sample quantize and dither routine
   1.591 +signed long cScale::LinearDither(mad_fixed_t sample, struct dither *dither)
   1.592 +{
   1.593 +  // noise shape
   1.594 +  sample += dither->error[0] - dither->error[1] + dither->error[2];
   1.595 +  dither->error[2] = dither->error[1];
   1.596 +  dither->error[1] = dither->error[0] / 2;
   1.597 +  // bias
   1.598 +  mad_fixed_t output = sample + (1L << (MAD_F_FRACBITS + 1 - OUT_BITS - 1));
   1.599 +  const int scalebits = MAD_F_FRACBITS + 1 - OUT_BITS;
   1.600 +  const mad_fixed_t mask = (1L << scalebits) - 1;
   1.601 +  // dither
   1.602 +  const mad_fixed_t random = Prng(dither->random);
   1.603 +  output += (random & mask) - (dither->random & mask);
   1.604 +  dither->random = random;
   1.605 +  // clip
   1.606 +  output=Clip(output);
   1.607 +  sample=Clip(sample,false);
   1.608 +  // quantize
   1.609 +  output &= ~mask;
   1.610 +  // error feedback
   1.611 +  dither->error[0] = sample - output;
   1.612 +  // scale
   1.613 +  return output >> scalebits;
   1.614 +}
   1.615 +
   1.616 +#define PUT_BE(data,sample) { *data++=(sample)>>8; *data++=(sample)>>0; }
   1.617 +#define PUT_LE(data,sample) { *data++=(sample)>>0; *data++=(sample)>>8; }
   1.618 +
   1.619 +// write a block of signed 16-bit PCM samples
   1.620 +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)
   1.621 +{
   1.622 +  unsigned int len=size/OUT_FACT;
   1.623 +  if(len>nsamples) { len=nsamples; size=len*OUT_FACT; }
   1.624 +  nsamples-=len;
   1.625 +  switch(mode) {
   1.626 +    case amRoundBE:
   1.627 +      while(len--) {
   1.628 +        signed int sample=LinearRound(*left++);
   1.629 +        PUT_BE(data,sample);
   1.630 +        if(right) sample=LinearRound(*right++);
   1.631 +        PUT_BE(data,sample);
   1.632 +        }
   1.633 +      break;
   1.634 +    case amDitherBE:
   1.635 +      while(len--) {
   1.636 +	signed int sample=LinearDither(*left++,&leftD);
   1.637 +        PUT_BE(data,sample);
   1.638 +	if(right) sample=LinearDither(*right++,&rightD);
   1.639 +        PUT_BE(data,sample);
   1.640 +        }
   1.641 +      break;
   1.642 +    case amRoundLE:
   1.643 +      while(len--) {
   1.644 +        signed int sample=LinearRound(*left++);
   1.645 +        PUT_LE(data,sample);
   1.646 +        if(right) sample=LinearRound(*right++);
   1.647 +        PUT_LE(data,sample);
   1.648 +        }
   1.649 +      break;
   1.650 +    case amDitherLE:
   1.651 +      while(len--) {
   1.652 +	signed int sample=LinearDither(*left++,&leftD);
   1.653 +        PUT_LE(data,sample);
   1.654 +	if(right) sample=LinearDither(*right++,&rightD);
   1.655 +        PUT_LE(data,sample);
   1.656 +        }
   1.657 +      break;
   1.658 +    }
   1.659 + return size;
   1.660 +}
   1.661 +
   1.662 +// --- cShuffle ----------------------------------------------------------------
   1.663 +
   1.664 +class cShuffle {
   1.665 +private:
   1.666 +  int *shuffle, max;
   1.667 +  unsigned int seed;
   1.668 +  //
   1.669 +  int Index(int pos);
   1.670 +public:
   1.671 +  cShuffle(void);
   1.672 +  ~cShuffle();
   1.673 +  void Shuffle(int num, int curr);
   1.674 +  void Del(int pos);
   1.675 +  void Flush(void);
   1.676 +  int First(void);
   1.677 +  int Next(int curr);
   1.678 +  int Prev(int curr);
   1.679 +  int Goto(int pos, int curr);
   1.680 +  };
   1.681 +
   1.682 +cShuffle::cShuffle(void)
   1.683 +{
   1.684 +  shuffle=0; max=0;
   1.685 +  seed=time(0);
   1.686 +}
   1.687 +
   1.688 +cShuffle::~cShuffle(void)
   1.689 +{
   1.690 +  Flush();
   1.691 +}
   1.692 +
   1.693 +void cShuffle::Flush(void)
   1.694 +{
   1.695 +  delete shuffle; shuffle=0;
   1.696 +  max=0;
   1.697 +}
   1.698 +
   1.699 +int cShuffle::Index(int pos)
   1.700 +{
   1.701 +  if(pos>=0)
   1.702 +    for(int i=0; i<max; i++) if(shuffle[i]==pos) return i;
   1.703 +  return -1;
   1.704 +}
   1.705 +
   1.706 +void cShuffle::Shuffle(int num, int curr)
   1.707 +{
   1.708 +  int oldmax=0;
   1.709 +  if(num!=max) {
   1.710 +    int *ns=new int[num];
   1.711 +    if(shuffle) {
   1.712 +      if(num>max) {
   1.713 +        memcpy(ns,shuffle,max*sizeof(int));
   1.714 +        oldmax=max;
   1.715 +        }
   1.716 +      delete shuffle;
   1.717 +      }
   1.718 +    shuffle=ns; max=num;
   1.719 +    }
   1.720 +  if(!oldmax) curr=-1;
   1.721 +  for(int i=oldmax ; i<max ; i++) shuffle[i]=i;
   1.722 +
   1.723 +  int in=Index(curr)+1; if(in<0) in=0;
   1.724 +  if((max-in)>=2) {
   1.725 +    for(int i=in ; i<max ; i++) {
   1.726 +      int ran=(rand_r(&seed) % ((max-in)*4-4))/4; ran+=((ran+in) >= i);
   1.727 +      int t=shuffle[i];
   1.728 +      shuffle[i]=shuffle[ran+in];
   1.729 +      shuffle[ran+in]=t;
   1.730 +      }
   1.731 +    }
   1.732 +#ifdef DEBUG
   1.733 +  printf("shuffle: order (%d , %d -> %d) ",num,curr,in);
   1.734 +  for(int i=0 ; i<max ; i++) printf("%d ",shuffle[i]);
   1.735 +  printf("\n");
   1.736 +#endif
   1.737 +}
   1.738 +
   1.739 +void cShuffle::Del(int pos)
   1.740 +{
   1.741 +  int i=Index(pos);
   1.742 +  if(i>=0) {
   1.743 +    if(i+1<max) memmove(&shuffle[i],&shuffle[i+1],(max-i-1)*sizeof(int));
   1.744 +    max--;
   1.745 +    }
   1.746 +}
   1.747 +
   1.748 +int cShuffle::First(void)
   1.749 +{
   1.750 +  return shuffle[0];
   1.751 +}
   1.752 +
   1.753 +int cShuffle::Next(int curr)
   1.754 +{
   1.755 +  int i=Index(curr);
   1.756 +  return (i>=0 && i+1<max) ? shuffle[i+1] : -1;
   1.757 +}
   1.758 +
   1.759 +int cShuffle::Prev(int curr)
   1.760 +{
   1.761 +  int i=Index(curr);
   1.762 +  return (i>0) ? shuffle[i-1] : -1;
   1.763 +}
   1.764 +
   1.765 +int cShuffle::Goto(int pos, int curr)
   1.766 +{
   1.767 +  int i=Index(curr);
   1.768 +  int g=Index(pos);
   1.769 +  if(g>=0) {
   1.770 +    if(g<i) {
   1.771 +      for(int l=g; l<i; l++) shuffle[l]=shuffle[l+1];
   1.772 +      shuffle[i]=pos;
   1.773 +      }
   1.774 +    else if(g>i) {
   1.775 +      for(int l=g; l>i+1; l--) shuffle[l]=shuffle[l-1];
   1.776 +      shuffle[i+1]=pos;
   1.777 +      }
   1.778 +#ifdef DEBUG
   1.779 +    printf("shuffle: goto order (%d -> %d , %d -> %d) ",pos,g,curr,i);
   1.780 +    for(int i=0 ; i<max ; i++) printf("%d ",shuffle[i]);
   1.781 +    printf("\n");
   1.782 +#endif
   1.783 +    return pos;
   1.784 +    }
   1.785 +  return -1;
   1.786 +}
   1.787 +
   1.788 +// --- cPlayManager ------------------------------------------------------------
   1.789 +
   1.790 +#define SCANNED_ID3 1
   1.791 +#define SCANNED_LVL 2
   1.792 +
   1.793 +cPlayManager *mgr=0;
   1.794 +
   1.795 +cPlayManager::cPlayManager(void)
   1.796 +{
   1.797 +  curr=0; currIndex=-1;
   1.798 +  scan=0; stopscan=throttle=pass2=release=false;
   1.799 +  play=0; playNew=eol=false;
   1.800 +  shuffle=new cShuffle;
   1.801 +  loopMode=(MP3Setup.InitLoopMode>0);
   1.802 +  shuffleMode=(MP3Setup.InitShuffleMode>0);
   1.803 +}
   1.804 +
   1.805 +cPlayManager::~cPlayManager()
   1.806 +{
   1.807 +  Flush();
   1.808 +  Release();
   1.809 +  listMutex.Lock();
   1.810 +  stopscan=true; bgCond.Broadcast();
   1.811 +  listMutex.Unlock();
   1.812 +  Cancel(2);
   1.813 +  delete shuffle;
   1.814 +}
   1.815 +
   1.816 +void cPlayManager::ThrottleWait(void)
   1.817 +{
   1.818 +  while(!stopscan && !release && throttle) {
   1.819 +    db(printf("mgr: background scan throttled\n"))
   1.820 +    bgCond.Wait(listMutex);
   1.821 +    db(printf("mgr: background scan throttle wakeup\n"))
   1.822 +    }
   1.823 +}
   1.824 +
   1.825 +void cPlayManager::Action(void)
   1.826 +{
   1.827 +  db(printf("mgr: background scan thread started (pid=%d)\n", getpid()))
   1.828 +  nice(5);
   1.829 +  listMutex.Lock();
   1.830 +  while(!stopscan) {
   1.831 +    for(scan=list.First(); !stopscan && !release && scan; scan=list.Next(scan)) {
   1.832 +      ThrottleWait();
   1.833 +      listMutex.Unlock();
   1.834 +      if(!(scan->user & SCANNED_ID3)) {
   1.835 +        db(printf("mgr: scanning (id3) %s\n",scan->Name()))
   1.836 +        cSongInfo *si=scan->Info(true);
   1.837 +        if(si && si->Level>0.0) scan->user|=SCANNED_LVL;
   1.838 +        scan->user|=SCANNED_ID3;
   1.839 +        }
   1.840 +      listMutex.Lock();
   1.841 +      }
   1.842 +    if(MP3Setup.BgrScan>1) {
   1.843 +      pass2=true;
   1.844 +      for(scan=list.First(); !stopscan && !release && scan; scan=list.Next(scan)) {
   1.845 +        if(scan==curr) continue;
   1.846 +        ThrottleWait();
   1.847 +        listMutex.Unlock();
   1.848 +        if(!(scan->user & SCANNED_LVL)) {
   1.849 +          cDecoder *dec=scan->Decoder();
   1.850 +          if(dec) {
   1.851 +            cSongInfo *si=scan->Info(false);
   1.852 +            if(!dec->IsStream() && (!si || si->Level<=0.0) && dec->Start()) {
   1.853 +              db(printf("mgr: scanning (lvl) %s\n",scan->Name()))
   1.854 +              cLevel level;
   1.855 +              level.Init();
   1.856 +              bool go=true;
   1.857 +              while(go && !release) {
   1.858 +                if(throttle) {
   1.859 +                  listMutex.Lock(); ThrottleWait(); listMutex.Unlock();
   1.860 +                  continue;
   1.861 +                  }
   1.862 +                struct Decode *ds=dec->Decode();
   1.863 +                switch(ds->status) {
   1.864 +                  case dsPlay:
   1.865 +                    level.GetPower(ds->pcm);
   1.866 +                    break;
   1.867 +                  case dsSkip:
   1.868 +                  case dsSoftError:
   1.869 +                    break;
   1.870 +                  case dsEof:
   1.871 +                    {
   1.872 +                    double l=level.GetLevel();
   1.873 +                    if(l>0.0) {
   1.874 +                      cSongInfo *si=dec->SongInfo(false);
   1.875 +                      cFileInfo *fi=dec->FileInfo();
   1.876 +                      if(si && fi) {
   1.877 +                        si->Level=l;
   1.878 +                        si->Peak=level.GetPeak();
   1.879 +                        InfoCache.Cache(si,fi);
   1.880 +                        }
   1.881 +                      }
   1.882 +                    }
   1.883 +                    //fall through
   1.884 +                  case dsOK:
   1.885 +                  case dsError:
   1.886 +                    scan->user|=SCANNED_LVL;
   1.887 +                    go=false;
   1.888 +                    break;
   1.889 +                  }
   1.890 +                }
   1.891 +              }
   1.892 +            else scan->user|=SCANNED_LVL;
   1.893 +            dec->Stop();
   1.894 +            }
   1.895 +          }
   1.896 +        listMutex.Lock();
   1.897 +        }
   1.898 +      pass2=false;
   1.899 +      }
   1.900 +    do {
   1.901 +      scan=0; release=false; fgCond.Broadcast();
   1.902 +      db(printf("mgr: background scan idle\n"))
   1.903 +      bgCond.Wait(listMutex);
   1.904 +      db(printf("mgr: background scan idle wakeup\n"))
   1.905 +      } while(!stopscan && (release || throttle));
   1.906 +    }
   1.907 +  listMutex.Unlock();
   1.908 +  db(printf("mgr: background scan thread ended (pid=%d)\n", getpid()))
   1.909 +}
   1.910 +
   1.911 +void cPlayManager::Throttle(bool thr)
   1.912 +{
   1.913 +  if(MP3Setup.BgrScan) {
   1.914 +    if(!thr && throttle) {
   1.915 +      db(printf("mgr: bgr-scan -> run (%d)\n",time_ms()))
   1.916 +      listMutex.Lock();
   1.917 +      throttle=false; bgCond.Broadcast();
   1.918 +      listMutex.Unlock();
   1.919 +      }
   1.920 +    if(thr && !throttle) {
   1.921 +      db(printf("mgr: bgr-scan -> throttle (%d)\n",time_ms()))
   1.922 +      throttle=true;
   1.923 +      }
   1.924 +    }
   1.925 +}
   1.926 +
   1.927 +void cPlayManager::ToggleShuffle(void)
   1.928 +{
   1.929 +  shuffleMode=!shuffleMode;
   1.930 +  d(printf("mgr: shuffle mode toggled : %d\n",shuffleMode))
   1.931 +  if(shuffleMode && !eol) {
   1.932 +    curr=0; currIndex=-1;
   1.933 +    shuffle->Shuffle(maxIndex+1,-1);
   1.934 +    Next();
   1.935 +    }
   1.936 +}
   1.937 +
   1.938 +void cPlayManager::ToggleLoop(void)
   1.939 +{
   1.940 +  loopMode=!loopMode;
   1.941 +  d(printf("mgr: loop mode toggled : %d\n",loopMode))
   1.942 +}
   1.943 +
   1.944 +bool cPlayManager::Info(int num, cMP3PlayInfo *pi)
   1.945 +{
   1.946 +  cSong *s;
   1.947 +  int idx=num-1;
   1.948 +  if(idx<0) { idx=currIndex; s=curr; }
   1.949 +  else      { s=list.Get(idx); }
   1.950 +  memset(pi,0,sizeof(*pi));
   1.951 +  pi->Num=idx+1;
   1.952 +  pi->MaxNum=maxIndex+1;
   1.953 +  pi->Loop=loopMode;
   1.954 +  pi->Shuffle=shuffleMode;
   1.955 +  bool res=false;
   1.956 +  if(s) {
   1.957 +    strn0cpy(pi->Title,s->Name(),sizeof(pi->Title));
   1.958 +    strn0cpy(pi->Filename,s->FullPath(),sizeof(pi->Filename));
   1.959 +    cSongInfo *si=s->Info(false);
   1.960 +    if(si && si->HasInfo()) {
   1.961 +      static char *modestr[] = { "Mono","Dual","Joint-Stereo","Stereo" };
   1.962 +
   1.963 +      if(si->Title)  strn0cpy(pi->Title,si->Title,sizeof(pi->Title));
   1.964 +      if(si->Artist) strn0cpy(pi->Artist,si->Artist,sizeof(pi->Artist));
   1.965 +      if(si->Album)  strn0cpy(pi->Album,si->Album,sizeof(pi->Album));
   1.966 +      strn0cpy(pi->SMode,modestr[si->ChMode],sizeof(pi->SMode));
   1.967 +      pi->Year=si->Year;
   1.968 +      pi->SampleFreq=si->SampleFreq;
   1.969 +      pi->Bitrate=si->Bitrate;
   1.970 +      pi->MaxBitrate=si->MaxBitrate;
   1.971 +      res=true;
   1.972 +      }
   1.973 +    }
   1.974 +  pi->Hash=MakeHashBuff((char *)pi,(char *)&pi->Loop-(char *)pi);
   1.975 +  return res;
   1.976 +}
   1.977 +
   1.978 +void cPlayManager::Add(cPlayList *pl)
   1.979 +{
   1.980 +  cMutexLock lock(&listMutex);
   1.981 +  bool real=false;
   1.982 +  for(cSong *song=pl->First(); song; song=pl->cList<cSong>::Next(song)) {
   1.983 +    cSong *ns=new cSong(song);
   1.984 +    list.Add(ns);
   1.985 +    real=true;
   1.986 +    }
   1.987 +  if(real) {
   1.988 +    if(MP3Setup.BgrScan) { stopscan=false; if(!Active()) Start(); }
   1.989 +    else stopscan=true;
   1.990 +    bgCond.Broadcast();
   1.991 +    maxIndex=list.Count()-1;
   1.992 +    if(shuffleMode) shuffle->Shuffle(maxIndex+1,currIndex);
   1.993 +    if(!curr) Next();
   1.994 +    }
   1.995 +}
   1.996 +
   1.997 +void cPlayManager::Flush(void)
   1.998 +{
   1.999 +  cMutexLock lock(&listMutex);
  1.1000 +  Halt();
  1.1001 +  list.Clear();
  1.1002 +  shuffle->Flush();
  1.1003 +}
  1.1004 +
  1.1005 +void cPlayManager::Halt(void)
  1.1006 +{
  1.1007 +  cMutexLock lock(&listMutex);
  1.1008 +  curr=0; currIndex=-1;
  1.1009 +  playNew=true;
  1.1010 +  stopscan=true; bgCond.Broadcast();
  1.1011 +  NoScan(0);
  1.1012 +  NoPlay(0);
  1.1013 +}
  1.1014 +
  1.1015 +void cPlayManager::NoScan(cSong *nono)
  1.1016 +{
  1.1017 +  // call with listMutex locked!!
  1.1018 +  while((nono && pass2 && scan==nono) || (!nono && scan)) {
  1.1019 +    release=true; bgCond.Broadcast();
  1.1020 +    d(printf("mgr: waiting for bgr release ... (pass2=%d nono=%p scan=%p)\n",pass2,nono,scan))
  1.1021 +    fgCond.Wait(listMutex);
  1.1022 +    }
  1.1023 +}
  1.1024 +
  1.1025 +void cPlayManager::NoPlay(cSong *nono)
  1.1026 +{
  1.1027 +  // call with listMutex locked!!
  1.1028 +  while((nono && play==nono) || (!nono && play)) {
  1.1029 +    playNew=true;
  1.1030 +    fgCond.Wait(listMutex);
  1.1031 +    }
  1.1032 +}
  1.1033 +
  1.1034 +bool cPlayManager::Next(void)
  1.1035 +{
  1.1036 +  cMutexLock lock(&listMutex);
  1.1037 +  int ni;
  1.1038 +  cSong *n;
  1.1039 +  if(shuffleMode) {
  1.1040 +    if(curr) {
  1.1041 +      ni=shuffle->Next(currIndex);
  1.1042 +      if(ni<0) {
  1.1043 +        if(loopMode || eol) {
  1.1044 +          shuffle->Shuffle(maxIndex+1,-1);
  1.1045 +          ni=shuffle->First();
  1.1046 +          }
  1.1047 +        else eol=true;
  1.1048 +        }
  1.1049 +      }
  1.1050 +    else
  1.1051 +      ni=shuffle->First();
  1.1052 +    n=(ni>=0) ? list.Get(ni) : 0;
  1.1053 +    }
  1.1054 +  else {
  1.1055 +    if(curr) {
  1.1056 +      n=list.cList<cSong>::Next(curr);
  1.1057 +      if(!n) {
  1.1058 +        if(loopMode || eol) n=list.First();
  1.1059 +        else eol=true;
  1.1060 +        }
  1.1061 +      }
  1.1062 +    else
  1.1063 +      n=list.First();
  1.1064 +    ni=n ? n->Index() : -1;
  1.1065 +    }
  1.1066 +  if(n) {
  1.1067 +    curr=n; currIndex=ni;
  1.1068 +    playNew=true; eol=false;
  1.1069 +    d(printf("mgr: next -> %d\n",currIndex))
  1.1070 +    return true;
  1.1071 +    }
  1.1072 +  return false;
  1.1073 +}
  1.1074 +
  1.1075 +bool cPlayManager::Prev(void)
  1.1076 +{
  1.1077 +  cMutexLock lock(&listMutex);
  1.1078 +  int ni;
  1.1079 +  cSong *n;
  1.1080 +  if(shuffleMode) {
  1.1081 +    ni=shuffle->Prev(currIndex);
  1.1082 +    n=(ni>=0) ? list.Get(ni) : 0;
  1.1083 +    }
  1.1084 +  else {
  1.1085 +    n=list.cList<cSong>::Prev(curr);
  1.1086 +    ni=n ? n->Index() : -1;
  1.1087 +    }
  1.1088 +  if(n) {
  1.1089 +    curr=n; currIndex=ni;
  1.1090 +    playNew=true; eol=false;
  1.1091 +    d(printf("mgr: prev -> %d\n",currIndex))
  1.1092 +    return true;
  1.1093 +    }
  1.1094 +  return false;
  1.1095 +}
  1.1096 +
  1.1097 +void cPlayManager::Goto(int num)
  1.1098 +{
  1.1099 +  cMutexLock lock(&listMutex);
  1.1100 +  if(num>0 && num<=maxIndex+1) {
  1.1101 +    int idx=num-1;
  1.1102 +    if(shuffleMode) {
  1.1103 +      if(eol) {
  1.1104 +        shuffle->Shuffle(maxIndex+1,-1);
  1.1105 +        currIndex=shuffle->Goto(idx,-1);
  1.1106 +        }
  1.1107 +      else
  1.1108 +        currIndex=shuffle->Goto(idx,currIndex);
  1.1109 +      }
  1.1110 +    else
  1.1111 +      currIndex=idx;
  1.1112 +    curr=(currIndex>=0) ? list.Get(currIndex) : 0;
  1.1113 +    playNew=true; eol=false;
  1.1114 +    d(printf("mgr: goto -> %d\n",currIndex))
  1.1115 +    }
  1.1116 +}
  1.1117 +
  1.1118 +cSong *cPlayManager::Current(void)
  1.1119 +{
  1.1120 +  cMutexLock lock(&listMutex);
  1.1121 +  if(!play) {
  1.1122 +    NoScan(curr);
  1.1123 +    play=curr;
  1.1124 +    playNew=false;
  1.1125 +    if(play) d(printf("mgr: playing %s\n",play->Name()))
  1.1126 +    else d(printf("mgr: nothing to play\n"))
  1.1127 +    fgCond.Broadcast();
  1.1128 +    }
  1.1129 +  return play;
  1.1130 +}
  1.1131 +
  1.1132 +bool cPlayManager::NextCurrent(void)
  1.1133 +{
  1.1134 +  cMutexLock lock(&listMutex);
  1.1135 +  return (!eol && (playNew || Next()));
  1.1136 +}
  1.1137 +
  1.1138 +bool cPlayManager::NewCurrent(void)
  1.1139 +{
  1.1140 +  return playNew;
  1.1141 +}
  1.1142 +
  1.1143 +void cPlayManager::Release(void)
  1.1144 +{
  1.1145 +  cMutexLock lock(&listMutex);
  1.1146 +  play=0;
  1.1147 +  fgCond.Broadcast();
  1.1148 +}
  1.1149 +
  1.1150 +// --- cOutput -----------------------------------------------------------------
  1.1151 +
  1.1152 +struct FrameHeader {
  1.1153 +  unsigned int samplerate;
  1.1154 +  };
  1.1155 +#define FHS sizeof(struct FrameHeader)
  1.1156 +
  1.1157 +class cOutput {
  1.1158 +protected:
  1.1159 +  cMP3Player *player;
  1.1160 +  cScale scale;
  1.1161 +public:
  1.1162 +  cOutput(cMP3Player *Player);
  1.1163 +  virtual ~cOutput() {}
  1.1164 +  virtual void Init(void);
  1.1165 +  virtual unsigned int SampleRate(unsigned int PcmSampleRate)=0;
  1.1166 +  virtual cFrame *MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr)=0;
  1.1167 +  virtual int Output(const unsigned char *Data, int Len, bool SOF)=0;
  1.1168 +  virtual bool Poll(void)=0;
  1.1169 +  virtual void Play(void)=0;
  1.1170 +  virtual void Pause(void)=0;
  1.1171 +#ifdef DEBUG
  1.1172 +  virtual void Stats(void);
  1.1173 +#endif
  1.1174 +  };
  1.1175 +
  1.1176 +cOutput::cOutput(cMP3Player *Player)
  1.1177 +{
  1.1178 +  player=Player;
  1.1179 +}
  1.1180 +
  1.1181 +void cOutput::Init(void)
  1.1182 +{
  1.1183 +  scale.Init();
  1.1184 +}
  1.1185 +
  1.1186 +#ifdef DEBUG
  1.1187 +void cOutput::Stats(void)
  1.1188 +{
  1.1189 +  scale.Stats();
  1.1190 +}
  1.1191 +#endif
  1.1192 +
  1.1193 +// --- cOutputDvb --------------------------------------------------------------
  1.1194 +
  1.1195 +/*
  1.1196 +struct LPCMHeader { int id:8;              // id
  1.1197 +                    int frame_count:8;     // number of frames
  1.1198 +                    int access_ptr:16;     // first acces unit pointer, i.e. start of audio frame
  1.1199 +                    bool emphasis:1;       // audio emphasis on-off
  1.1200 +                    bool mute:1;           // audio mute on-off
  1.1201 +                    bool reserved:1;       // reserved
  1.1202 +                    int frame_number:5;    // audio frame number
  1.1203 +                    int quant_wlen:2;      // quantization word length
  1.1204 +                    int sample_freq:2;     // audio sampling frequency (48khz=0, 96khz=1, 44,1khz=2, 32khz=3)
  1.1205 +                    bool reserved2:1;      // reserved
  1.1206 +                    int chan_count:3;      // number of audio channels - 1 (e.g. stereo = 1)
  1.1207 +                    int dyn_range_ctrl:8;  // dynamic range control (0x80 if off)
  1.1208 +                    };
  1.1209 +*/
  1.1210 +
  1.1211 +#define FRAMESIZE 2048 // max. frame size allowed for DVB driver
  1.1212 +
  1.1213 +class cOutputDvb : public cOutput {
  1.1214 +private:
  1.1215 +  cPoller poll;
  1.1216 +  unsigned int outSr;
  1.1217 +  bool only48khz;
  1.1218 +public:
  1.1219 +  cOutputDvb(cMP3Player *Player);
  1.1220 +  virtual unsigned int SampleRate(unsigned int PcmSampleRate);
  1.1221 +  virtual cFrame *MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr);
  1.1222 +  virtual int Output(const unsigned char *Data, int Len, bool SOF);
  1.1223 +  virtual bool Poll(void);
  1.1224 +  virtual void Play(void);
  1.1225 +  virtual void Pause(void);
  1.1226 +  };
  1.1227 +
  1.1228 +cOutputDvb::cOutputDvb(cMP3Player *Player)
  1.1229 +:cOutput(Player)
  1.1230 +{
  1.1231 +  only48khz=MP3Setup.Only48kHz;
  1.1232 +  outSr=0;
  1.1233 +#if APIVERSNUM == 10318
  1.1234 +  cDevice::PrimaryDevice()->SetCurrentAudioTrack(ttDolbyFirst);
  1.1235 +#elif APIVERSNUM >= 10319
  1.1236 +  cDevice::PrimaryDevice()->SetCurrentAudioTrack(ttAudio);
  1.1237 +#endif
  1.1238 +  d(printf("mp3-dvb: using DVB output\n"))
  1.1239 +}
  1.1240 +
  1.1241 +unsigned int cOutputDvb::SampleRate(unsigned int PcmSampleRate)
  1.1242 +{
  1.1243 +  unsigned int samplerate=48000;
  1.1244 +  if(!only48khz) {
  1.1245 +    switch(PcmSampleRate) { // If one of the supported frequencies, do it without resampling.
  1.1246 +      case 96000:           // Select a "even" upsampling frequency if possible, too.
  1.1247 +        samplerate=96000;
  1.1248 +        break;
  1.1249 +      //case 48000: // this is already the default ...
  1.1250 +      //  samplerate=48000;
  1.1251 +      //  break;
  1.1252 +      case 11025:
  1.1253 +      case 22050:
  1.1254 +      case 44100:
  1.1255 +        samplerate=44100;
  1.1256 +        break;
  1.1257 +      case 8000:
  1.1258 +      case 16000:
  1.1259 +      case 32000:
  1.1260 +        samplerate=32000;
  1.1261 +        break;
  1.1262 +      }
  1.1263 +    }
  1.1264 +  return samplerate;
  1.1265 +}
  1.1266 +
  1.1267 +cFrame *cOutputDvb::MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr)
  1.1268 +{
  1.1269 +  static const unsigned char header[] = {
  1.1270 +    0x00, // PES header
  1.1271 +    0x00,
  1.1272 +    0x01,
  1.1273 +    0xBD, // private stream
  1.1274 +    0x00,
  1.1275 +    0x00,
  1.1276 +    0x87, // mpeg2, aligned, copyright, original
  1.1277 +    0x00, // no pts/dts
  1.1278 +    0x00, // PES header data len
  1.1279 +    0xA0, // aLPCM header
  1.1280 +    0xFF,
  1.1281 +    0x00,
  1.1282 +    0x04,
  1.1283 +    0x00,
  1.1284 +    0x01, // 2-channel stereo (n-1)
  1.1285 +    0x80  // neutral dynamic range
  1.1286 +    };
  1.1287 +  cFrame *f=0;
  1.1288 +  unsigned char *buff=MALLOC(uchar,FRAMESIZE);
  1.1289 +  if(buff) {
  1.1290 +    struct FrameHeader *fh=(struct FrameHeader *)buff;
  1.1291 +    fh->samplerate=sr;
  1.1292 +    memcpy(buff+FHS,header,sizeof(header));
  1.1293 +    int srMode;
  1.1294 +    switch(sr) {
  1.1295 +      default:
  1.1296 +      case 48000: srMode=0<<4; break;
  1.1297 +      case 96000: srMode=1<<4; break;
  1.1298 +      case 44100: srMode=2<<4; break;
  1.1299 +      case 32000: srMode=3<<4; break;
  1.1300 +      }
  1.1301 +    buff[14+FHS]|=srMode;
  1.1302 +    unsigned int outlen=scale.ScaleBlock(buff+sizeof(header)+FHS,FRAMESIZE-sizeof(header)-FHS,Samples,Data[0],Data[1],MP3Setup.AudioMode?amDitherBE:amRoundBE);
  1.1303 +    if(outlen) { 
  1.1304 +      // lPCM has 600 fps which is 80 samples at 48kHz per channel
  1.1305 +      // Frame size = (sample_rate * quantization * channels)/4800
  1.1306 +      buff[10+FHS]=outlen*(4800/16/2)/sr;
  1.1307 +      outlen+=(sizeof(header)-6);
  1.1308 +      buff[4+FHS]=outlen>>8;
  1.1309 +      buff[5+FHS]=outlen;
  1.1310 +      f=new cFrame(buff,-(outlen+6+FHS),ftUnknown,index);
  1.1311 +      }
  1.1312 +    if(!f) free(buff);
  1.1313 +    }
  1.1314 +  return f;
  1.1315 +}
  1.1316 +
  1.1317 +#ifdef BROKEN_PCM
  1.1318 +#include "player-mp3-sample.c"
  1.1319 +#endif
  1.1320 +
  1.1321 +int cOutputDvb::Output(const unsigned char *Data, int Len, bool SOF)
  1.1322 +{
  1.1323 +  int n=0;
  1.1324 +  if(SOF) {
  1.1325 +#ifdef BROKEN_PCM
  1.1326 +    struct FrameHeader *fh=(struct FrameHeader *)Data;
  1.1327 +    if(fh->samplerate!=outSr) {
  1.1328 +      if(outSr) {
  1.1329 +        // at this point we would need access to AUDIO_STOP/AUDIO_PLAY
  1.1330 +        // ioctl, but unfortunaly VDR's API doesn't provides this.
  1.1331 +        // So we have to do magic to make the driver switch samplerate.
  1.1332 +        const unsigned char *p=testAudio;
  1.1333 +        int pc=sizeof(testAudio);
  1.1334 +        int r;
  1.1335 +        do {
  1.1336 +#if APIVERSNUM < 10318
  1.1337 +          r=player->PlayVideo(p,pc);
  1.1338 +#else
  1.1339 +          r=player->PlayPes(p,pc);
  1.1340 +#endif
  1.1341 +          if(r>0) { p+=r; pc-=r; }
  1.1342 +          if(r==0) Poll();
  1.1343 +          } while(r>=0 && pc>0);
  1.1344 +        }
  1.1345 +      outSr=fh->samplerate;
  1.1346 +      d(printf("mp3-dvb: output samplerate now %d\n",outSr))
  1.1347 +      }
  1.1348 +#endif
  1.1349 +    n=FHS;
  1.1350 +    Data+=n; Len-=n;
  1.1351 +    }
  1.1352 +#if APIVERSNUM < 10318
  1.1353 +  int r=player->PlayVideo(Data,Len);
  1.1354 +#else
  1.1355 +  int r=player->PlayPes(Data,Len);
  1.1356 +#endif
  1.1357 +  return (r>=0 ? r+n : -1);
  1.1358 +}
  1.1359 +
  1.1360 +bool cOutputDvb::Poll(void)
  1.1361 +{
  1.1362 +  return player->DevicePoll(poll,500);
  1.1363 +}
  1.1364 +
  1.1365 +void cOutputDvb::Play(void)
  1.1366 +{
  1.1367 +#ifndef BROKEN_PCM
  1.1368 +  player->DevicePlay();
  1.1369 +#endif
  1.1370 +}
  1.1371 +
  1.1372 +void cOutputDvb::Pause(void)
  1.1373 +{
  1.1374 +#ifndef BROKEN_PCM
  1.1375 +  player->DeviceFreeze();
  1.1376 +#endif
  1.1377 +}
  1.1378 +
  1.1379 +// --- cOutputOss --------------------------------------------------------------
  1.1380 +
  1.1381 +#ifdef WITH_OSS
  1.1382 +
  1.1383 +const char *dspdevice="/dev/dsp";
  1.1384 +
  1.1385 +class cOutputOss : public cOutput {
  1.1386 +private:
  1.1387 +  int fd;
  1.1388 +  cPoller poll;
  1.1389 +  unsigned int outSr;
  1.1390 +  unsigned char buff[8192];
  1.1391 +  //
  1.1392 +  bool Reset(unsigned int sr);
  1.1393 +public:
  1.1394 +  cOutputOss(cMP3Player *Player);
  1.1395 +  virtual ~cOutputOss();
  1.1396 +  virtual void Init(void);
  1.1397 +  virtual unsigned int SampleRate(unsigned int PcmSampleRate);
  1.1398 +  virtual cFrame *MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr);
  1.1399 +  virtual int Output(const unsigned char *Data, int Len, bool SOF);
  1.1400 +  virtual bool Poll(void);
  1.1401 +  virtual void Play(void);
  1.1402 +  virtual void Pause(void);
  1.1403 +  };
  1.1404 +
  1.1405 +cOutputOss::cOutputOss(cMP3Player *Player)
  1.1406 +:cOutput(Player)
  1.1407 +{
  1.1408 +  fd=-1; outSr=0;
  1.1409 +  d(printf("mp3-oss: using OSS output\n"))
  1.1410 +}
  1.1411 +
  1.1412 +cOutputOss::~cOutputOss()
  1.1413 +{
  1.1414 +  close(fd);
  1.1415 +}
  1.1416 +
  1.1417 +void cOutputOss::Init(void)
  1.1418 +{
  1.1419 +  if(fd<0) {
  1.1420 +    fd=open(dspdevice,O_WRONLY|O_NONBLOCK);
  1.1421 +    if(fd>=0) poll.Add(fd,true);
  1.1422 +    else esyslog("ERROR: Cannot open dsp device '%s': %s!",dspdevice,strerror(errno));
  1.1423 +    }
  1.1424 +  cOutput::Init();
  1.1425 +}
  1.1426 +
  1.1427 +bool cOutputOss::Reset(unsigned int sr)
  1.1428 +{
  1.1429 +  if(fd>=0) {
  1.1430 +    CHECK(ioctl(fd,SNDCTL_DSP_SYNC,0));
  1.1431 +    int format=AFMT_S16_LE;
  1.1432 +    CHECK(ioctl(fd,SNDCTL_DSP_SETFMT,&format));
  1.1433 +    if(format==AFMT_S16_LE) {
  1.1434 +      int channels=2;
  1.1435 +      CHECK(ioctl(fd,SNDCTL_DSP_CHANNELS,&channels));
  1.1436 +      if(channels==2) {
  1.1437 +        int real=sr;
  1.1438 +        CHECK(ioctl(fd,SNDCTL_DSP_SPEED,&real));
  1.1439 +        d(printf("oss: DSP samplerate now %d\n",real))
  1.1440 +        if(abs(real-sr)<sr/50) {
  1.1441 +          outSr=sr;
  1.1442 +          d(printf("mp3-oss: DSP reset done\n"))
  1.1443 +          return true;
  1.1444 +          }
  1.1445 +        else {
  1.1446 +          d(printf("mp3-oss: driver can't handle samplerate %d, got %d\n",sr,real))
  1.1447 +          esyslog("ERROR: OSS driver can't handle samplerate %d, got %d\n",sr,real);
  1.1448 +          }
  1.1449 +        }
  1.1450 +      else {
  1.1451 +        d(printf("mp3-oss: 2-channel stereo not supported\n"))
  1.1452 +        esyslog("ERROR: OSS driver doesn't support 2-channel stereo.");
  1.1453 +        }
  1.1454 +      }
  1.1455 +    else {
  1.1456 +      d(printf("mp3-oss: little-endian samples not supported\n"))
  1.1457 +      esyslog("ERROR: OSS driver doesn't support 16-bit little-endian samples.");
  1.1458 +      }
  1.1459 +    close(fd); fd=-1;
  1.1460 +    }
  1.1461 +  return false;
  1.1462 +}
  1.1463 +
  1.1464 +unsigned int cOutputOss::SampleRate(unsigned int PcmSampleRate)
  1.1465 +{
  1.1466 +  return PcmSampleRate;
  1.1467 +}
  1.1468 +
  1.1469 +cFrame *cOutputOss::MakeFrame(unsigned int & Samples, const mad_fixed_t **Data, int index, int sr)
  1.1470 +{
  1.1471 +  struct FrameHeader *fh=(struct FrameHeader *)buff;
  1.1472 +  fh->samplerate=sr;
  1.1473 +  cFrame *f=0;
  1.1474 +  unsigned int outlen=scale.ScaleBlock(buff+FHS,sizeof(buff)-FHS,Samples,Data[0],Data[1],MP3Setup.AudioMode?amDitherLE:amRoundLE);
  1.1475 +  if(outlen) 
  1.1476 +    f=new cFrame(buff,outlen+FHS,ftUnknown,index);
  1.1477 +  return f;
  1.1478 +}
  1.1479 +
  1.1480 +int cOutputOss::Output(const unsigned char *Data, int Len, bool SOF)
  1.1481 +{
  1.1482 +  if(fd>=0) {
  1.1483 +    int n=0;
  1.1484 +    if(SOF) {
  1.1485 +      struct FrameHeader *fh=(struct FrameHeader *)Data;
  1.1486 +      if(fh->samplerate!=outSr) Reset(fh->samplerate);
  1.1487 +      n=FHS;
  1.1488 +      Data+=n; Len-=n;
  1.1489 +      }
  1.1490 +    int r=write(fd,Data,Len);
  1.1491 +    if(r<0 && !FATALERRNO) r=0;
  1.1492 +    if(r>=0) return n+r;
  1.1493 +    }
  1.1494 +  return -1;
  1.1495 +}
  1.1496 +
  1.1497 +bool cOutputOss::Poll(void)
  1.1498 +{
  1.1499 +  return fd>=0 ? poll.Poll(500) : false;
  1.1500 +}
  1.1501 +
  1.1502 +void cOutputOss::Play(void)
  1.1503 +{
  1.1504 +}
  1.1505 +
  1.1506 +void cOutputOss::Pause(void)
  1.1507 +{
  1.1508 +  CHECK(ioctl(fd,SNDCTL_DSP_POST,0));
  1.1509 +}
  1.1510 +
  1.1511 +#endif
  1.1512 +
  1.1513 +// --- cMP3Player --------------------------------------------------------------
  1.1514 +
  1.1515 +cMP3Player::cMP3Player()
  1.1516 +:cPlayer(MP3Setup.BackgrMode==1 ? pmAudioOnly : pmAudioOnlyBlack)
  1.1517 +{
  1.1518 +  active=true; started=false; isStream=false;
  1.1519 +  ringBuffer=new cRingBufferFrame(MP3BUFSIZE);
  1.1520 +  rframe=0; pframe=0; decoder=0; output=0;
  1.1521 +  playMode=pmStartup; state=msStop;
  1.1522 +  playindex=total=0;
  1.1523 +}
  1.1524 +
  1.1525 +cMP3Player::~cMP3Player()
  1.1526 +{
  1.1527 +  Detach();
  1.1528 +  delete ringBuffer;
  1.1529 +}
  1.1530 +
  1.1531 +void cMP3Player::Activate(bool On)
  1.1532 +{
  1.1533 +  if(On) {
  1.1534 +    d(printf("mp3: player active true requested...\n"))
  1.1535 +    if(!started) {
  1.1536 +      playMode=pmStartup; Start(); started=true;
  1.1537 +      playModeMutex.Lock();
  1.1538 +      WaitPlayMode(pmStartup,true); // wait for the decoder to become ready
  1.1539 +      playModeMutex.Unlock();
  1.1540 +      Lock();
  1.1541 +      Play();
  1.1542 +      Unlock();
  1.1543 +      }
  1.1544 +    d(printf("mp3: player active true done\n"))
  1.1545 +    }
  1.1546 +  else if(started && active) {
  1.1547 +    d(printf("mp3: player active false requested...\n"))
  1.1548 +    Lock(); StopPlay(); Unlock();
  1.1549 +    active=false;
  1.1550 +    SetPlayMode(pmStartup);
  1.1551 +    Cancel(2);
  1.1552 +    d(printf("mp3: player active false done\n"))
  1.1553 +    }
  1.1554 +}
  1.1555 +
  1.1556 +void cMP3Player::SetPlayMode(ePlayMode mode)
  1.1557 +{
  1.1558 +  playModeMutex.Lock();
  1.1559 +  if(mode!=playMode) {
  1.1560 +    playMode=mode;
  1.1561 +    dm(printf("mp3: setting mode=%d (pid=%d)\n",mode,getpid()))
  1.1562 +    playModeCond.Broadcast();
  1.1563 +    }
  1.1564 +  playModeMutex.Unlock();
  1.1565 +}
  1.1566 +
  1.1567 +void cMP3Player::WaitPlayMode(ePlayMode mode, bool inv)
  1.1568 +{
  1.1569 +  // must be called with playModeMutex LOCKED !!!
  1.1570 +
  1.1571 +  while(active && ((!inv && mode!=playMode) || (inv && mode==playMode))) {
  1.1572 +    dm(printf("mp3: entering wait for mode%s%d with mode=%d (pid=%d)\n",inv?"!=":"==",mode,playMode,getpid()))
  1.1573 +    playModeCond.Wait(playModeMutex);
  1.1574 +    dm(printf("mp3: returning from wait with mode=%d (pid=%d)\n",playMode,getpid()))
  1.1575 +    }
  1.1576 +}
  1.1577 +
  1.1578 +void cMP3Player::Action(void)
  1.1579 +{
  1.1580 +  cSong *playing=0;
  1.1581 +  struct mad_pcm *pcm=0;
  1.1582 +  cResample resample[2];
  1.1583 +  unsigned int nsamples[2];
  1.1584 +  const mad_fixed_t *data[2];
  1.1585 +  cLevel level;
  1.1586 +  cNormalize norm;
  1.1587 +  bool haslevel=false;
  1.1588 +  const unsigned char *p=0;
  1.1589 +  int pc=0, readindex=0;
  1.1590 +  bool imageValid=true;
  1.1591 +  int imageCheck=0;
  1.1592 +#ifdef DEBUG
  1.1593 +  int beat=0;
  1.1594 +#endif
  1.1595 +#ifdef DEBUG_DELAY
  1.1596 +  int lastwrite=0;
  1.1597 +#endif
  1.1598 +
  1.1599 +  dsyslog("mp3: player thread started (pid=%d)", getpid());
  1.1600 +  state=msStop;
  1.1601 +  SetPlayMode(pmStopped);
  1.1602 +
  1.1603 +  delete output; output=0;
  1.1604 +#ifdef WITH_OSS
  1.1605 +  if(MP3Setup.AudioOutMode==AUDIOOUTMODE_OSS) output=new cOutputOss(this);
  1.1606 +#endif
  1.1607 +  if(MP3Setup.AudioOutMode==AUDIOOUTMODE_DVB) output=new cOutputDvb(this);
  1.1608 +  if(!output) {
  1.1609 +    d(printf("mp3: audiooutmode mismatch or no output driver\n"))
  1.1610 +    esyslog("ERROR: no audio output driver. balling out");
  1.1611 +    goto abort;
  1.1612 +    }
  1.1613 +
  1.1614 +  while(active) {
  1.1615 +#ifdef DEBUG
  1.1616 +    {
  1.1617 +    int now=time(0);
  1.1618 +    if(now>=beat) {
  1.1619 +      int avail=ringBuffer->Available();
  1.1620 +      printf("mp3: heartbeat buffer=%d now=%d\n",avail,now&4095);
  1.1621 +      //output->Stats(); if(haslevel) norm.Stats();
  1.1622 +      beat=now+(avail>(MP3BUFSIZE*10/100) ? (avail<(MP3BUFSIZE*50/100) ? 2 : 20) : 1);
  1.1623 +      }
  1.1624 +    }
  1.1625 +#endif
  1.1626 +
  1.1627 +    Lock();
  1.1628 +
  1.1629 +next:
  1.1630 +    if(!pframe && playing && !imageValid && imageCheck<time_ms()) {
  1.1631 +      unsigned char *mem;
  1.1632 +      int len;
  1.1633 +      imageCheck=time_ms()+250;
  1.1634 +      imageValid=playing->Image(mem,len);
  1.1635 +      if(mem) {
  1.1636 +        if(playindex) SLEEP(80); // stillpicture ioctl freezes without this
  1.1637 +        DeviceStillPicture(mem,len);
  1.1638 +        free(mem);
  1.1639 +        }
  1.1640 +      }
  1.1641 +
  1.1642 +    bool SOF=false;
  1.1643 +    if(!pframe && playMode==pmPlay) {
  1.1644 +      pframe=ringBuffer->Get();
  1.1645 +      if(pframe) {
  1.1646 +        playindex=pframe->Index();
  1.1647 +        p=pframe->Data();
  1.1648 +        pc=pframe->Count();
  1.1649 +        SOF=true;
  1.1650 +        }
  1.1651 +      }
  1.1652 +
  1.1653 +    if(pframe) {
  1.1654 +#ifdef DEBUG_DELAY
  1.1655 +      {
  1.1656 +      int now=time_ms();
  1.1657 +      if(lastwrite && lastwrite<now-(DEBUG_DELAY+50))
  1.1658 +        printf("mp3: write delayed %d ms\n",now-lastwrite);
  1.1659 +      lastwrite=now;
  1.1660 +      }
  1.1661 +#endif
  1.1662 +      int w=output->Output(p,pc,SOF);
  1.1663 +      if(w>0) {
  1.1664 +        p+=w; pc-=w;
  1.1665 +        if(pc<=0) {
  1.1666 +          ringBuffer->Drop(pframe);
  1.1667 +          pframe=0;
  1.1668 +          goto next;
  1.1669 +          }
  1.1670 +        }
  1.1671 +      else if(w<0 && FATALERRNO) {
  1.1672 +        LOG_ERROR;
  1.1673 +        d(printf("mp3: output failed: %s\n",strerror(errno)))
  1.1674 +        Unlock();
  1.1675 +        goto abort;
  1.1676 +        }
  1.1677 +      }
  1.1678 +
  1.1679 +    if(mgr->NewCurrent() && playMode==pmPlay && state!=msStart) {
  1.1680 +      Empty();
  1.1681 +      state=msRestart;
  1.1682 +      d(printf("mp3: stale song change, restart.\n"))
  1.1683 +      }
  1.1684 +
  1.1685 +    if(!rframe && playMode==pmPlay) {
  1.1686 +      switch(state) {
  1.1687 +        case msStart:
  1.1688 +          d(printf("mp3: starting play\n"))
  1.1689 +          mgr->Throttle(true);
  1.1690 +          playindex=readindex=total=0;
  1.1691 +          playing=mgr->Current();
  1.1692 +          if(playing) {
  1.1693 +            if((decoder=playing->Decoder()) && decoder->Start()) {
  1.1694 +              isStream=decoder->IsStream(); levelgood=!isStream; haslevel=false;
  1.1695 +              cSongInfo *si=playing->Info(true);
  1.1696 +              if(si) {
  1.1697 +                if(si->Level>0.0) {
  1.1698 +                  d(printf("mp3: found song level=%f peak=%f\n",si->Level,si->Peak))
  1.1699 +                  haslevel=true;
  1.1700 +                  norm.Init(si->Level,si->Peak);
  1.1701 +                  }
  1.1702 +                if(si->HasInfo())
  1.1703 +                  total=SecondsToFrames(si->Total);
  1.1704 +                }
  1.1705 +              d(printf("mp3: isStream=%d levelgood=%d haslevel=%d\n",isStream,levelgood,haslevel))
  1.1706 +              output->Init();
  1.1707 +              level.Init();
  1.1708 +              if(MP3Setup.BackgrMode==2) imageValid=false;
  1.1709 +              state=msDecode;
  1.1710 +              break;
  1.1711 +              }
  1.1712 +            else
  1.1713 +              esyslog("ERROR: playlist entry %s is not a valid file",playing->Name());
  1.1714 +            }
  1.1715 +          else
  1.1716 +            d(printf("mp3: no current on start play\n"))
  1.1717 +          state=msEof;
  1.1718 +          break;
  1.1719 +        case msDecode:
  1.1720 +          {
  1.1721 +#ifdef DEBUG_DELAY
  1.1722 +          int now=time_ms();
  1.1723 +#endif
  1.1724 +          struct Decode *ds=decoder->Decode();
  1.1725 +#ifdef DEBUG_DELAY
  1.1726 +          now=time_ms()-now;
  1.1727 +          if(now>DEBUG_DELAY) printf("mp3: decode delayed %d ms\n",now);
  1.1728 +#endif
  1.1729 +          switch(ds->status) {
  1.1730 +            case dsPlay:
  1.1731 +              pcm=ds->pcm;
  1.1732 +              readindex=ds->index;
  1.1733 +              state=msNormalize;
  1.1734 +              break;
  1.1735 +            case dsSkip:
  1.1736 +            case dsSoftError:
  1.1737 +              // skipping, state unchanged, next decode
  1.1738 +              break;
  1.1739 +            case dsEof:
  1.1740 +              if(!haslevel && levelgood) { // save level & peak to infocache on eof
  1.1741 +                double l=level.GetLevel();
  1.1742 +                if(l>0.0) {
  1.1743 +                  cSongInfo *si=decoder->SongInfo(false);
  1.1744 +                  cFileInfo *fi=decoder->FileInfo();
  1.1745 +                  if(si && fi) {
  1.1746 +                    si->Level=l;
  1.1747 +                    si->Peak=level.GetPeak();
  1.1748 +                    InfoCache.Cache(si,fi);
  1.1749 +                    }
  1.1750 +                  }
  1.1751 +                }
  1.1752 +              state=msEof;
  1.1753 +              break;
  1.1754 +            case dsOK:
  1.1755 +            case dsError:
  1.1756 +              state=msError;
  1.1757 +              break;
  1.1758 +            }
  1.1759 +          break;
  1.1760 +          }
  1.1761 +        case msNormalize:
  1.1762 +          if(!haslevel) { if(levelgood) level.GetPower(pcm); }
  1.1763 +          else norm.AddGain(pcm);
  1.1764 +          state=msResample;
  1.1765 +          break;
  1.1766 +        case msResample:
  1.1767 +#ifdef DEBUG
  1.1768 +          {
  1.1769 +          static unsigned int oldrate=0;
  1.1770 +          if(oldrate!=pcm->samplerate) {
  1.1771 +            printf("mp3: new input sample rate %d\n",pcm->samplerate);
  1.1772 +            oldrate=pcm->samplerate;
  1.1773 +            }
  1.1774 +          }
  1.1775 +#endif
  1.1776 +          nsamples[0]=nsamples[1]=pcm->length;
  1.1777 +          data[0]=pcm->samples[0];
  1.1778 +          data[1]=pcm->channels>1 ? pcm->samples[1]:0;
  1.1779 +
  1.1780 +          dvbSampleRate=output->SampleRate(pcm->samplerate);
  1.1781 +          if(dvbSampleRate!=pcm->samplerate) {
  1.1782 +            if(resample[0].SetInputRate(pcm->samplerate,dvbSampleRate)) {
  1.1783 +              nsamples[0]=resample[0].ResampleBlock(nsamples[0],data[0]);
  1.1784 +              data[0]    =resample[0].Resampled();
  1.1785 +              }
  1.1786 +            if(data[1] && resample[1].SetInputRate(pcm->samplerate,dvbSampleRate)) {
  1.1787 +              nsamples[1]=resample[1].ResampleBlock(nsamples[1],data[1]);
  1.1788 +              data[1]    =resample[1].Resampled();
  1.1789 +              }
  1.1790 +            }
  1.1791 +          state=msOutput;
  1.1792 +          break;
  1.1793 +        case msOutput:
  1.1794 +          if(nsamples[0]>0) rframe=output->MakeFrame(nsamples[0],data,readindex,dvbSampleRate);
  1.1795 +          else state=msDecode;
  1.1796 +          break;
  1.1797 +        case msError:
  1.1798 +        case msEof:
  1.1799 +          d(printf("mp3: eof or error\n"))
  1.1800 +          state=msWait;
  1.1801 +          // fall through
  1.1802 +        case msRestart:
  1.1803 +        case msStop:
  1.1804 +          d(printf("mp3: stopping play\n"))
  1.1805 +          if(decoder) { decoder->Stop(); decoder=0; }
  1.1806 +          mgr->Release(); playing=0; imageValid=true;
  1.1807 +          levelgood=false;
  1.1808 +#ifdef DEBUG
  1.1809 +          output->Stats(); if(haslevel) norm.Stats();
  1.1810 +#endif
  1.1811 +          if(state==msStop) SetPlayMode(pmStopped);
  1.1812 +          if(state==msRestart) state=msStart;
  1.1813 +          break;
  1.1814 +        case msWait:
  1.1815 +          if(ringBuffer->Available()==0) {
  1.1816 +            if(mgr->NextCurrent()) {
  1.1817 +              d(printf("mp3: playing next\n"))
  1.1818 +              state=msStart;
  1.1819 +              }
  1.1820 +            else {
  1.1821 +              d(printf("mp3: end of playlist\n"))
  1.1822 +              if(MP3Setup.AbortAtEOL) {
  1.1823 +                active=false;
  1.1824 +                d(printf("mp3: aborting player...\n"))
  1.1825 +                }
  1.1826 +              else d(printf("mp3: player idle...\n"))
  1.1827 +              SetPlayMode(pmStopped);
  1.1828 +              }
  1.1829 +            }
  1.1830 +          break;
  1.1831 +        }
  1.1832 +      }
  1.1833 +
  1.1834 +    if(rframe && ringBuffer->Put(rframe)) rframe=0;
  1.1835 +
  1.1836 +    Unlock();
  1.1837 +
  1.1838 +    if((rframe || state==msWait) && pframe) {
  1.1839 +      mgr->Throttle(false);
  1.1840 +      output->Poll();
  1.1841 +      }
  1.1842 +    else if(playMode!=pmPlay) {
  1.1843 +      mgr->Throttle(false);
  1.1844 +      if(!imageValid)
  1.1845 +        SLEEP(100);
  1.1846 +      else {
  1.1847 +        playModeMutex.Lock();
  1.1848 +        if(playMode!=pmPlay) WaitPlayMode(playMode,true);
  1.1849 +        playModeMutex.Unlock();
  1.1850 +        }
  1.1851 +#ifdef DEBUG_DELAY
  1.1852 +      lastwrite=0;
  1.1853 +#endif
  1.1854 +      }
  1.1855 +    else if(state!=msWait && ringBuffer->Available()<(MP3BUFSIZE*50/100)) {
  1.1856 +      mgr->Throttle(true);
  1.1857 +      }
  1.1858 +    }
  1.1859 +
  1.1860 +abort:
  1.1861 +  Lock();
  1.1862 +  delete rframe;
  1.1863 +  delete output; output=0;
  1.1864 +  if(decoder) { decoder->Stop(); decoder=0; }
  1.1865 +  mgr->Release(); playing=0;
  1.1866 +  SetPlayMode(pmStopped);
  1.1867 +  Unlock();
  1.1868 +  active=false;
  1.1869 +
  1.1870 +  dsyslog("mp3: player thread ended (pid=%d)", getpid());
  1.1871 +}
  1.1872 +
  1.1873 +void cMP3Player::Empty(void)
  1.1874 +{
  1.1875 +  Lock();
  1.1876 +  delete rframe; rframe=0; pframe=0;
  1.1877 +  ringBuffer->Clear();
  1.1878 +  DeviceClear();
  1.1879 +  Unlock();
  1.1880 +}
  1.1881 +
  1.1882 +void cMP3Player::StopPlay(void) // StopPlay() must be called in locked state!!!
  1.1883 +{
  1.1884 +  if(playMode!=pmStopped) {
  1.1885 +    Empty();
  1.1886 +    state=msStop;
  1.1887 +    SetPlayMode(pmPlay);
  1.1888 +    Unlock();                 // let the decode thread process the stop signal
  1.1889 +    playModeMutex.Lock();
  1.1890 +    WaitPlayMode(pmStopped,false);
  1.1891 +    playModeMutex.Unlock();
  1.1892 +    Lock();
  1.1893 +    }
  1.1894 +}
  1.1895 +
  1.1896 +void cMP3Player::Pause(void)
  1.1897 +{
  1.1898 +  Lock();
  1.1899 +  if(playMode==pmPaused) Play();
  1.1900 +  else if(playMode==pmPlay && !isStream) {
  1.1901 +    d(printf("mp3: pause\n"))
  1.1902 +    if(output) output->Pause();
  1.1903 +    SetPlayMode(pmPaused);
  1.1904 +    }
  1.1905 +  Unlock();
  1.1906 +}
  1.1907 +
  1.1908 +void cMP3Player::Play(void)
  1.1909 +{
  1.1910 +  Lock();
  1.1911 +  if(playMode!=pmPlay) {
  1.1912 +    d(printf("mp3: play\n"))
  1.1913 +    if(playMode==pmStopped) state=msStart;
  1.1914 +    if(output) output->Play();
  1.1915 +    SetPlayMode(pmPlay);
  1.1916 +    }
  1.1917 +  Unlock();
  1.1918 +}
  1.1919 +
  1.1920 +bool cMP3Player::PrevCheck(void)
  1.1921 +{
  1.1922 +  bool res=false;
  1.1923 +  Lock();
  1.1924 +  if(playindex>=2000 && !isStream) {
  1.1925 +    state=msRestart; res=true;
  1.1926 +    Empty();
  1.1927 +    d(printf("mp3: skip to start of song\n"))
  1.1928 +    }
  1.1929 +  Unlock();
  1.1930 +  return res;
  1.1931 +}
  1.1932 +
  1.1933 +void cMP3Player::SkipSeconds(int secs)
  1.1934 +{
  1.1935 +  if(playMode!=pmStopped && !isStream) {
  1.1936 +    Lock();
  1.1937 +    d(printf("mp3: skip secs %d\n",secs))
  1.1938 +    if(playMode==pmPaused) SetPlayMode(pmPlay);
  1.1939 +    float bufsecs=(float)ringBuffer->Available() / (float)(dvbSampleRate*OUT_FACT);
  1.1940 +    d(printf("mp3: ringbuffer available %f secs\n",bufsecs))
  1.1941 +    if(secs>0 && bufsecs>=(float)secs) {
  1.1942 +      // clear intermediate queue
  1.1943 +      if(pframe) {
  1.1944 +        ringBuffer->Drop(pframe);
  1.1945 +        pframe=0;
  1.1946 +        }
  1.1947 +      DeviceClear();
  1.1948 +      // skip inside ringbuffer
  1.1949 +      int skipindex=playindex+secs*1000;
  1.1950 +      d(printf("mp3: skipping play=%d skip=%d ...",playindex,skipindex))
  1.1951 +      cFrame *f;
  1.1952 +      do {
  1.1953 +        f=ringBuffer->Get();
  1.1954 +        if(f) {
  1.1955 +          playindex=f->Index();
  1.1956 +          ringBuffer->Drop(f);
  1.1957 +          d(printf("*"))
  1.1958 +          }
  1.1959 +        } while(f && playindex<skipindex);
  1.1960 +      d(printf("\nmp3: skipped play=%d skip=%d\n",playindex,skipindex))
  1.1961 +      }
  1.1962 +    else {
  1.1963 +      if(decoder && decoder->Skip(secs,bufsecs)) levelgood=false;
  1.1964 +      Empty();
  1.1965 +      }
  1.1966 +    Unlock();
  1.1967 +    }
  1.1968 +}
  1.1969 +
  1.1970 +bool cMP3Player::GetIndex(int &Current, int &Total, bool SnapToIFrame)
  1.1971 +{
  1.1972 +  Current=SecondsToFrames(playindex/1000); Total=total;
  1.1973 +  return total>=0;
  1.1974 +}
  1.1975 +
  1.1976 +bool cMP3Player::GetReplayMode(bool &Play, bool &Forward, int &Speed)
  1.1977 +{
  1.1978 +  Play=(playMode==pmPlay);
  1.1979 +  Forward=true;
  1.1980 +  Speed=-1;
  1.1981 +  return true;
  1.1982 +}