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 +}