/*
SMPEG - SDL MPEG Player Library
Copyright (C) 1999 Loki Entertainment Software
- Modified by Michel Darricau from eProcess <mdarricau@eprocess.fr> for popcorn -
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* A class based on the MPEG stream class, used to parse and play audio */
#ifndef _MPEGAUDIO_H_
#define _MPEGAUDIO_H_
#include "SDL.h"
#include "MPEGerror.h"
#include "MPEGaction.h"
#ifdef THREADED_AUDIO
#include "MPEGring.h"
#endif
void Play_MPEGaudioSDL(void *udata, Uint8 *stream, int len);
#ifdef THREADED_AUDIO
int Decode_MPEGaudio(void *udata);
#endif
class MPEGstream;
/* MPEG/WAVE Sound library
(C) 1997 by Woo-jae Jung */
/**************************/
/* Define values for MPEG */
/**************************/
#define SCALEBLOCK 12
#define CALCBUFFERSIZE 512
#define MAXSUBBAND 32
#define MAXCHANNEL 2
#define MAXTABLE 2
#define SCALE 32768
#define MAXSCALE (SCALE-1)
#define MINSCALE (-SCALE)
#define RAWDATASIZE (2*2*32*SSLIMIT)
#define LS 0
#define RS 1
#define SSLIMIT 18
#define SBLIMIT 32
#define WINDOWSIZE 4096
// Huffmancode
#define HTN 34
/********************/
/* Type definitions */
/********************/
typedef float REAL;
typedef struct
{
bool generalflag;
unsigned int part2_3_length;
unsigned int big_values;
unsigned int global_gain;
unsigned int scalefac_compress;
unsigned int window_switching_flag;
unsigned int block_type;
unsigned int mixed_block_flag;
unsigned int table_select[3];
unsigned int subblock_gain[3];
unsigned int region0_count;
unsigned int region1_count;
unsigned int preflag;
unsigned int scalefac_scale;
unsigned int count1table_select;
}layer3grinfo;
typedef struct
{
unsigned main_data_begin;
unsigned private_bits;
struct
{
unsigned scfsi[4];
layer3grinfo gr[2];
}ch[2];
}layer3sideinfo;
typedef struct
{
int l[23]; /* [cb] */
int s[3][13]; /* [window][cb] */
}layer3scalefactor; /* [ch] */
typedef struct
{
int tablename;
unsigned int xlen,ylen;
unsigned int linbits;
unsigned int treelen;
const unsigned int (*val)[2];
}HUFFMANCODETABLE;
// Class for Mpeg layer3
class Mpegbitwindow
{
public:
Mpegbitwindow(){bitindex=point=0;};
void initialize(void) {bitindex=point=0;};
int gettotalbit(void) const {return bitindex;};
void putbyte(int c) {buffer[point&(WINDOWSIZE-1)]=c;point++;};
void wrap(void);
void rewind(int bits) {bitindex-=bits;};
void forward(int bits) {bitindex+=bits;};
int getbit(void) {
register int r=(buffer[bitindex>>3]>>(7-(bitindex&7)))&1;
bitindex++;
return r;
}
int getbits9(int bits)
{
register unsigned short a;
{ int offset=bitindex>>3;
a=(((unsigned char)buffer[offset])<<8) | ((unsigned char)buffer[offset+1]);
}
a<<=(bitindex&7);
bitindex+=bits;
return (int)((unsigned int)(a>>(16-bits)));
}
int getbits(int bits);
private:
int point,bitindex;
char buffer[2*WINDOWSIZE];
};
/* The actual MPEG audio class */
class MPEGaudio : public MPEGerror, public MPEGaudioaction {
public:
MPEGaudio(MPEGstream *stream, bool initSDL = true);
virtual ~MPEGaudio();
/* MPEG actions */
bool GetAudioInfo(MPEG_AudioInfo *info);
double Time(void);
void Play(void);
void Stop(void);
void Rewind(void);
void ResetSynchro(double time);
void Skip(float seconds);
void Volume(int vol);
/* Michel Darricau from eProcess <mdarricau@eprocess.fr> conflict name in popcorn */
MPEGstatus GetStatus(void);
/* Returns the desired SDL audio spec for this stream */
bool WantedSpec(SDL_AudioSpec *wanted);
/* Inform SMPEG of the actual audio format if configuring SDL
outside of this class */
void ActualSpec(SDL_AudioSpec *actual);
protected:
bool sdl_audio;
MPEGstream *mpeg;
int valid_stream;
bool stereo;
double rate_in_s;
Uint32 frags_playing;
Uint32 frag_time;
#ifdef THREADED_AUDIO
bool decoding;
SDL_Thread *decode_thread;
void StartDecoding(void);
void StopDecoding(void);
#endif
/* Code from splay 1.8.2 */
/*****************************/
/* Constant tables for layer */
/*****************************/
private:
static const int bitrate[2][3][15],frequencies[2][3];
static const REAL scalefactorstable[64];
static const HUFFMANCODETABLE ht[HTN];
static const REAL filter[512];
static REAL hcos_64[16],hcos_32[8],hcos_16[4],hcos_8[2],hcos_4;
/*************************/
/* MPEG header variables */
/*************************/
private:
int last_speed;
int layer,protection,bitrateindex,padding,extendedmode;
enum _mpegversion {mpeg1,mpeg2} version;
enum _mode {fullstereo,joint,dual,single} mode;
enum _frequency {frequency44100,frequency48000,frequency32000} frequency;
/***************************************/
/* Interface for setting music quality */
/***************************************/
private:
bool forcetomonoflag;
bool forcetostereoflag;
bool swapendianflag;
int downfrequency;
public:
void setforcetomono(bool flag);
void setdownfrequency(int value);
/******************************/
/* Frame management variables */
/******************************/
private:
int decodedframe,currentframe,totalframe;
/***************************************/
/* Variables made by MPEG-Audio header */
/***************************************/
private:
int tableindex,channelbitrate;
int stereobound,subbandnumber,inputstereo,outputstereo;
REAL scalefactor;
int framesize;
/*******************/
/* Mpegtoraw class */
/*******************/
public:
void initialize();
bool run(int frames, double *timestamp = NULL);
void clearbuffer(void);
/*****************************/
/* Loading MPEG-Audio stream */
/*****************************/
private:
Uint8 _buffer[4096];
Uint32 _buffer_pos;
int bitindex;
bool fillbuffer(int size);
void sync(void);
bool issync(void);
int getbyte(void);
int getbit(void);
int getbits8(void);
int getbits9(int bits);
int getbits(int bits);
/********************/
/* Global variables */
/********************/
private:
int lastfrequency,laststereo;
// for Layer3
int layer3slots,layer3framestart,layer3part2start;
REAL prevblck[2][2][SBLIMIT][SSLIMIT];
int currentprevblock;
layer3sideinfo sideinfo;
layer3scalefactor scalefactors[2];
Mpegbitwindow bitwindow;
int wgetbit (void) {return bitwindow.getbit (); }
int wgetbits9(int bits){return bitwindow.getbits9(bits);}
int wgetbits (int bits){return bitwindow.getbits (bits);}
/*************************************/
/* Decoding functions for each layer */
/*************************************/
private:
bool loadheader(void);
//
// Subbandsynthesis
//
REAL calcbufferL[2][CALCBUFFERSIZE],calcbufferR[2][CALCBUFFERSIZE];
int currentcalcbuffer,calcbufferoffset;
void computebuffer(REAL *fraction,REAL buffer[2][CALCBUFFERSIZE]);
void generatesingle(void);
void generate(void);
void subbandsynthesis(REAL *fractionL,REAL *fractionR);
void computebuffer_2(REAL *fraction,REAL buffer[2][CALCBUFFERSIZE]);
void generatesingle_2(void);
void generate_2(void);
void subbandsynthesis_2(REAL *fractionL,REAL *fractionR);
// Extarctor
void extractlayer1(void); // MPEG-1
void extractlayer2(void);
void extractlayer3(void);
void extractlayer3_2(void); // MPEG-2
// Functions for layer 3
void layer3initialize(void);
bool layer3getsideinfo(void);
bool layer3getsideinfo_2(void);
void layer3getscalefactors(int ch,int gr);
void layer3getscalefactors_2(int ch);
void layer3huffmandecode(int ch,int gr,int out[SBLIMIT][SSLIMIT]);
REAL layer3twopow2(int scale,int preflag,int pretab_offset,int l);
REAL layer3twopow2_1(int a,int b,int c);
void layer3dequantizesample(int ch,int gr,int in[SBLIMIT][SSLIMIT],
REAL out[SBLIMIT][SSLIMIT]);
void layer3fixtostereo(int gr,REAL in[2][SBLIMIT][SSLIMIT]);
void layer3reorderandantialias(int ch,int gr,REAL in[SBLIMIT][SSLIMIT],
REAL out[SBLIMIT][SSLIMIT]);
void layer3hybrid(int ch,int gr,REAL in[SBLIMIT][SSLIMIT],
REAL out[SSLIMIT][SBLIMIT]);
void huffmandecoder_1(const HUFFMANCODETABLE *h,int *x,int *y);
void huffmandecoder_2(const HUFFMANCODETABLE *h,int *x,int *y,int *v,int *w);
/********************/
/* Playing raw data */
/********************/
private:
int samplesperframe;
int rawdatareadoffset, rawdatawriteoffset;
Sint16 *rawdata;
#ifdef THREADED_AUDIO
MPEG_ring *ring;
#else
Sint16 spillover[ RAWDATASIZE ];
#endif
int volume;
void clearrawdata(void) {
rawdatareadoffset=0;
rawdatawriteoffset=0;
rawdata=NULL;
}
void putraw(short int pcm) {rawdata[rawdatawriteoffset++]=pcm;}
/********************/
/* Timestamp sync */
/********************/
public:
#define N_TIMESTAMPS 5
double timestamp[N_TIMESTAMPS];
/* Functions which access MPEGaudio internals */
friend void Play_MPEGaudioSDL(void *udata, Uint8 *stream, int len);
friend int Play_MPEGaudio(MPEGaudio *audio, Uint8 *stream, int len);
#ifdef THREADED_AUDIO
friend int Decode_MPEGaudio(void *udata);
#endif
};
/* Need to duplicate the prototypes, this is not a typo :) */
void Play_MPEGaudioSDL(void *udata, Uint8 *stream, int len);
int Play_MPEGaudio(MPEGaudio *audio, Uint8 *stream, int len);
#ifdef THREADED_AUDIO
int Decode_MPEGaudio(void *udata);
#endif
#endif /* _MPEGAUDIO_H_ */