#ifndef VALIB_AC3_ENC_H
#define VALIB_AC3_ENC_H

#include "../../filter.h"
#include "../../bitstream.h"
#include "../../data.h"
#include "ac3_defs.h"
#include "ac3_mdct.h"

inline int sym_quant(int m, int levels);
inline int asym_quant(int m, int bits);

class AC3Enc : public NullFilter
{
public:
  
  int sample;
  SampleBuf frame_samples;
  DataBuf   frame_buf;
  SampleBuf window;

  
  int sample_rate;
  int bitrate;
  int frame_size;
  int frames;

  MDCT mdct;
  WriteBS pb;

  
  int  acmod;
  bool dolby;
  bool lfe;
  int  nfchans;

  int bsid;                            
  int fscod;                           
  int halfratecod;                     
  int frmsizecod;                      
  
  int sdcycod;                         
  int fdcycod;                         
  int sgaincod;                        
  int dbpbcod;                         
  int floorcod;                        
  int fgaincod;                        

  int csnroffst;                       
  int fsnroffst;                       

  int16_t  delay[AC3_NCHANNELS][AC3_BLOCK_SAMPLES]; 
  int      delay_exp[AC3_NCHANNELS];                
                                           
  int32_t  mant[AC3_NCHANNELS][AC3_NBLOCKS][AC3_BLOCK_SAMPLES];    
  int8_t   exp[AC3_NCHANNELS][AC3_NBLOCKS][AC3_BLOCK_SAMPLES];     
  int8_t   expcod[AC3_NCHANNELS][AC3_NBLOCKS][AC3_BLOCK_SAMPLES];  
  int8_t   bap[AC3_NCHANNELS][AC3_NBLOCKS][AC3_BLOCK_SAMPLES];     

  int      chbwcod[AC3_NCHANNELS-1];                      
  int      nmant[AC3_NCHANNELS];                          
  int      expstr[AC3_NCHANNELS][AC3_NBLOCKS];            
  int      ngrps[AC3_NCHANNELS][AC3_NBLOCKS];             

  inline void output_mant(WriteBS &pb, int8_t bap[AC3_BLOCK_SAMPLES], int32_t mant[AC3_BLOCK_SAMPLES], int8_t exp[AC3_BLOCK_SAMPLES], int start, int end) const;
  inline void compute_expstr(int expstr[AC3_NBLOCKS], int8_t exp[AC3_NBLOCKS][AC3_BLOCK_SAMPLES], int endmant) const;
  inline void restrict_exp(int8_t expcod[AC3_NBLOCKS][AC3_BLOCK_SAMPLES], int ngrps[AC3_NBLOCKS], int8_t exp[AC3_NBLOCKS][AC3_BLOCK_SAMPLES], int expstr[AC3_NBLOCKS], int endmant) const;
  inline int  encode_exp(int8_t expcod[AC3_BLOCK_SAMPLES], int8_t exp[AC3_BLOCK_SAMPLES], int expstr, int endmant) const;

  bool fill_buffer();
  int  encode_frame();

public:
  AC3Enc();

  int  get_bitrate() const;
  bool set_bitrate(int bitrate);

  
  

  virtual void reset();

  virtual bool query_input(Speakers spk) const;
  virtual bool set_input(Speakers spk);

  virtual Speakers get_output() const;
  virtual bool get_chunk(Chunk *chunk);
};




inline int sym_quant(int c, int levels)
{
  int v = (c + 32768) * levels >> 16;

  return v;
}


inline int asym_quant(int c, int bits)
{
  c >>= 16 - bits;
  c &= (1 << bits) - 1; 
  return c;
}

#endif
