/**
 * audio_decoder_mp3.h: The mp3 decoder
 * 
 * Copyright: See COPYING file that comes with this distribution
 *
 * Author: Matthias Feistel <hitman_47@users.sourceforge.net>, (C) 2007
 */

#ifndef AUDIO_DECODER_MP3_H_
#define AUDIO_DECODER_MP3_H_

#include <stdint.h>
#include <mad.h>
#include "config.h"
#include "audio_buffer.h"
#include "audio_madresampler.h"

/**
 * 
 * cMP3Decoder opens an iStream (filestream or netstream) and
 * puts the data pieces on the mad_stream_decoder.
 * The mad_decoder will fill the output with PCM data.
 * PCM data must be resampled.
 * That PCM data will be placed on the audio_buffer (SimpleRingBuffer),
 * which can be read by the audio_player.
 * 
 * ISTREAM ---> MAD_DECODER ---> MAD_RESAMPLER ---> PCMBuffer
 */
class cMp3Decoder
{
public:
	cMp3Decoder( void );
	virtual ~cMp3Decoder( );
	unsigned long GetMp3Data( uint8_t *data, const unsigned long count );
	/**
	 * IsMp3DataAvailable
	 * @return: boolean value, whether the decoder is in  " decodeResult == -1 "  or not
	 */
	bool IsMp3DataAvailable( void );
	/**
	 * GetIndex
	 * @param: reference to the current position of the current track
	 * @return: errorcode
	 */
	int GetIndex( int &Current, int &Total, bool SnapToIFrame = false );
private:
	void Resample( mad_pcm& pcm );
	signed int ScaleTo16Bit( mad_fixed_t sample );
	int FillReadBuffer( );
	/**
	 * DecodeNextChunk loads data from mp3-source and
	 * decodes that data.
	 * After that, it calls MadResample and in the latter function,
	 * the pointers according to the decoded data will be set.
	 */
	void DecodeNextChunk( );
	virtual unsigned long GetDataFromSource( uint8_t *data,
												const unsigned long count ) = 0;
private:
	static const int readBufferSize = READBUFFSIZE;
	MadResampler resampler;
	unsigned int sampleRate;
	unsigned char readBuffer[readBufferSize];
	struct mad_stream madStream;
	struct mad_frame madFrame;
	struct mad_synth madSynth;
	mad_fixed_t* leftBuffer;
	mad_fixed_t* rightBuffer;
	mad_fixed_t* leftBufferReadPtr;
	mad_fixed_t* rightBufferReadPtr;
	int samplesInBuffer;
	mad_timer_t timeIndex;
	cSimpleRingBuffer *mo_PCMBuffer;
	bool mp_mp3dataavailable;
};

#endif /*AUDIO_DECODER_H_*/
