diff options
| author | Max Horn | 2003-07-31 01:21:38 +0000 | 
|---|---|---|
| committer | Max Horn | 2003-07-31 01:21:38 +0000 | 
| commit | 9b2d4f92aab4ecf52afd49865a3b7efa879391b8 (patch) | |
| tree | c7ccfc9ddf1c880c9cdf4764a824a17390ee852a | |
| parent | 5225597d85089935eb25ed57c0e8d7d94681ad68 (diff) | |
| download | scummvm-rg350-9b2d4f92aab4ecf52afd49865a3b7efa879391b8.tar.gz scummvm-rg350-9b2d4f92aab4ecf52afd49865a3b7efa879391b8.tar.bz2 scummvm-rg350-9b2d4f92aab4ecf52afd49865a3b7efa879391b8.zip  | |
removed the AudioInputStream::size method -> only eof() is really needed, and this can be implemented more efficiently stand-alone; implemented MP3InputStream (work in progress)
svn-id: r9313
| -rw-r--r-- | sound/audiostream.cpp | 188 | ||||
| -rw-r--r-- | sound/audiostream.h | 53 | ||||
| -rw-r--r-- | sound/rate.cpp | 3 | 
3 files changed, 197 insertions, 47 deletions
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp index ea4c0534f9..0d769e3df7 100644 --- a/sound/audiostream.cpp +++ b/sound/audiostream.cpp @@ -23,6 +23,7 @@  #include "audiostream.h"  #include "mixer.h"  #include "common/engine.h" +#include "common/file.h"  #include "common/util.h" @@ -57,8 +58,8 @@ public:  		_ptr += (is16Bit ? 2 : 1);  		return val;  	} -	int size() const { -		return (_end - _ptr) / (is16Bit ? 2 : 1); +	bool eof() const { +		return _end <= _ptr;  	}  	bool isStereo() const {  		return stereo; @@ -84,7 +85,7 @@ public:  	WrappedMemoryStream(uint bufferSize);  	~WrappedMemoryStream() { free(_bufferStart); }  	int16 read(); -	int size() const; +	bool eof() const;  	bool isStereo() const {  		return stereo;  	} @@ -116,11 +117,8 @@ int16 WrappedMemoryStream<stereo, is16Bit, isUnsigned>::read() {  }  template<bool stereo, bool is16Bit, bool isUnsigned> -int WrappedMemoryStream<stereo, is16Bit, isUnsigned>::size() const { -	int len = _end - _pos; -	if (len < 0) -		len += (_bufferEnd - _bufferStart); -	return len / (is16Bit ? 2 : 1); +bool WrappedMemoryStream<stereo, is16Bit, isUnsigned>::eof() const { +	return _end == _pos;  }  template<bool stereo, bool is16Bit, bool isUnsigned> @@ -152,27 +150,144 @@ void WrappedMemoryStream<stereo, is16Bit, isUnsigned>::append(const byte *data,  #pragma mark - -/*  #ifdef USE_MAD -class MP3InputStream : public AudioInputStream { -	struct mad_stream _stream; -	struct mad_frame _frame; -	struct mad_synth _synth; -	uint32 _posInFrame; -	int _chan; - -	void refill(); -public: + +#define MP3_BUFFER_SIZE 131072 + +/** + * Playback the MP3 data in the given file for the specified duration. + * + * @param file		file containing the MP3 data + * @param duration	playback duration in frames (1/75th of a second), 0 means playback until EOF + */ +MP3InputStream::MP3InputStream(File *file, mad_timer_t duration) { +	// duration == 0 means: play everything till end of file +	 +	_isStereo = false; +	_curChannel = 0; +	_file = file; +	_rate = 0; +	_posInFrame = 0; +	 +	_duration = duration; + +	mad_stream_init(&_stream); +	mad_frame_init(&_frame); +	mad_synth_init(&_synth); +	 +	_ptr = (byte *)malloc(MP3_BUFFER_SIZE + MAD_BUFFER_GUARD); +	 +	_initialized = init(); +} + +MP3InputStream::~MP3InputStream() { +	mad_synth_finish(&_synth); +	mad_frame_finish(&_frame); +	mad_stream_finish(&_stream); +	 +	free(_ptr); +} + +bool MP3InputStream::init() {  	// TODO -	MP3InputStream(); -}; +	 +	// Read in the first chunk of the MP3 file +	_size = _file->read(_ptr, MP3_BUFFER_SIZE); +	if (_size <= 0) { +		warning("MP3InputStream: Failed to read MP3 data"); +		return false; +	} +	 +	// Feed the data we just read into the stream decoder +	mad_stream_buffer(&_stream, _ptr, _size); + +	// Read in initial data +	refill(); + +	// Check the header, determine if this is a stereo stream +	int num; +	switch(_frame.header.mode) +	{ +		case MAD_MODE_SINGLE_CHANNEL: +		case MAD_MODE_DUAL_CHANNEL: +		case MAD_MODE_JOINT_STEREO: +		case MAD_MODE_STEREO: +			num = MAD_NCHANNELS(&_frame.header); +			assert(num == 1 || num == 2); +			_isStereo = (num == 2); +			break; +		default: +			warning("MP3InputStream: Cannot determine number of channels"); +			return false; +	} +	 +	// Determine the sample rate +	_rate = _frame.header.samplerate; -MP3InputStream::MP3InputStream() { -	_chan = 0; +	return true;  }  void MP3InputStream::refill() { -	// TODO + +	// Read the next frame (may have to retry several times, e.g. +	// to skip over ID3 information). +	while (mad_frame_decode(&_frame, &_stream)) { +		if (_stream.error == MAD_ERROR_BUFLEN) { +			int offset; + +			// Give up immediately if we are at the EOF already +			if (_size <= 0) +				return; + +			if (!_stream.next_frame) { +				offset = 0; +				memset(_ptr, 0, MP3_BUFFER_SIZE + MAD_BUFFER_GUARD); +			} else { +				offset = _stream.bufend - _stream.next_frame; +				memcpy(_ptr, _stream.next_frame, offset); +			} +			// Read in more data from the input file +			_size = _file->read(_ptr + offset, MP3_BUFFER_SIZE - offset); +			 +			// Nothing read -> EOF -> bail out +			if (_size <= 0) { +				return; +			} +			_stream.error = (enum mad_error)0; + +			// Feed the data we just read into the stream decoder +			mad_stream_buffer(&_stream, _ptr, _size + offset); + +		} else if (MAD_RECOVERABLE(_stream.error)) { +			// FIXME: should we do anything here? +			warning("MP3InputStream: Recoverable error..."); +		} else { +			error("MP3InputStream: Unrecoverable error"); +		} +	} +	 +	// Subtract the duration of this frame from the time left to play +	mad_timer_t frame_duration = _frame.header.duration; +	mad_timer_negate(&frame_duration); +	mad_timer_add(&_duration, _frame.header.duration); +	 +	// Synthesise the frame into PCM samples and reset the buffer position +	mad_synth_frame(&_synth, &_frame); +	_posInFrame = 0; +} + +bool MP3InputStream::eof() const { +	// Time over -> input steam ends +	if (mad_timer_compare(_duration, mad_timer_zero) <= 0) +		return true; +	// Data left in the PCM buffer -> we are not yet done!  +	if (_posInFrame < _synth.pcm.length) +		return false; +	// EOF of the input file, we are done +	if (_size < 0) +		return true; +	// Otherwise, we are still good to go +	return false;  }  static inline int scale_sample(mad_fixed_t sample) { @@ -192,19 +307,22 @@ static inline int scale_sample(mad_fixed_t sample) {  int16 MP3InputStream::read() {  	if (_posInFrame >= _synth.pcm.length) {  		refill(); +		if (_size < 0)	// EOF +			return 0;  	} +  	int16 sample; -	if (stereo) { -		sample = (int16)scale_sample(_synth.pcm.samples[_chan][_posInFrame]; -		if (_chan == 0) { -			_chan = 1; +	if (_isStereo) { +		sample = (int16)scale_sample(_synth.pcm.samples[_curChannel][_posInFrame]); +		if (_curChannel == 0) { +			_curChannel = 1;  		} else {  			_posInFrame++; -			_chan = 0; +			_curChannel = 0;  		}  	} else { -		sample = (int16)scale_sample(_synth.pcm.samples[0][_posInFrame]; +		sample = (int16)scale_sample(_synth.pcm.samples[0][_posInFrame]);  		_posInFrame++;  	} @@ -212,7 +330,7 @@ int16 MP3InputStream::read() {  }  #endif -*/ +  #pragma mark -  #pragma mark --- Ogg Vorbis stream --- @@ -229,7 +347,7 @@ int16 MP3InputStream::read() {  VorbisInputStream::VorbisInputStream(OggVorbis_File *file, int duration)   	: _ov_file(file) {  	_pos = _buffer + ARRAYSIZE(_buffer); -	_channels = ov_info(_ov_file, -1)->channels; +	_numChannels = ov_info(_ov_file, -1)->channels;  	if (duration)  		_end_pos = ov_pcm_tell(_ov_file) + duration; @@ -246,10 +364,12 @@ int16 VorbisInputStream::read() {  	return *_pos++;  } -int VorbisInputStream::size() const { +bool VorbisInputStream::eof() const {  	if (_eof_flag) -		return 0; -	return (_end_pos - ov_pcm_tell(_ov_file)) + (_buffer + ARRAYSIZE(_buffer) - _pos); +		return true; +	if (_pos < _buffer + ARRAYSIZE(_buffer)) +		return false; +	return (_end_pos <= ov_pcm_tell(_ov_file));  }  void VorbisInputStream::refill() { diff --git a/sound/audiostream.h b/sound/audiostream.h index c7c2614230..a40e27aaef 100644 --- a/sound/audiostream.h +++ b/sound/audiostream.h @@ -24,10 +24,16 @@  #include "scummsys.h"  #include <assert.h> +#ifdef USE_MAD +#include <mad.h> +#endif  #ifdef USE_VORBIS  #include <vorbis/vorbisfile.h>  #endif +class File; + +  // TODO:  // * maybe make readIntern return 16.16 or 24.8 fixed point values  //   since MAD (and maybe OggVorbis?) gives us those -> higher quality. @@ -42,10 +48,9 @@ public:  	virtual ~AudioInputStream() {}  	virtual int16 read() = 0; -	virtual int size() const = 0; +	//virtual int size() const = 0;  	virtual bool isStereo() const = 0; - -	bool eof() const { return size() <= 0; } +	virtual bool eof() const = 0;  };  class WrappedAudioInputStream : public AudioInputStream { @@ -61,11 +66,36 @@ public:  	int16 read() { assert(_len > 0); _len--; return 0; }  	int size() const { return _len; }  	bool isStereo() const { return false; } +	bool eof() const { return _len <= 0; }  }; -AudioInputStream *makeLinearInputStream(byte _flags, const byte *ptr, uint32 len); -WrappedAudioInputStream *makeWrappedInputStream(byte _flags, uint32 len); - +#ifdef USE_MAD +class MP3InputStream : public AudioInputStream { +	struct mad_stream _stream; +	struct mad_frame _frame; +	struct mad_synth _synth; +	uint32 _posInFrame; +	int _size; +	bool _isStereo; +	int _curChannel; +	File *_file; +	byte *_ptr; +	int _rate; +	bool _initialized; +	mad_timer_t _duration; + +	bool init(); +	void refill(); +public: +	MP3InputStream(File *file, mad_timer_t duration); +	~MP3InputStream(); +	int16 read(); +	bool eof() const; +	bool isStereo() const { return _isStereo; } +	 +	int getRate() const { return _rate; } +}; +#endif  #ifdef USE_VORBIS @@ -73,20 +103,23 @@ class VorbisInputStream : public AudioInputStream {  	OggVorbis_File *_ov_file;  	int _end_pos;  	bool _eof_flag; -	int _channels; +	int _numChannels;  	int16 _buffer[4096];  	int16 *_pos;  	void refill();  public: -	// TODO  	VorbisInputStream(OggVorbis_File *file, int duration);  	int16 read(); -	int size() const; -	bool isStereo() const { return _channels >= 2; } +	bool eof() const; +	bool isStereo() const { return _numChannels >= 2; }  };  #endif +AudioInputStream *makeLinearInputStream(byte _flags, const byte *ptr, uint32 len); +WrappedAudioInputStream *makeWrappedInputStream(byte _flags, uint32 len); + +  #endif diff --git a/sound/rate.cpp b/sound/rate.cpp index 89751029f7..9b79e824ba 100644 --- a/sound/rate.cpp +++ b/sound/rate.cpp @@ -108,9 +108,6 @@ int st_rate_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_size  	ostart = obuf;  	oend = obuf + *osamp * 2; -	if (stereo) -		assert(input.size() % 2 == 0);	// Stereo code assumes even number of input samples -	  	// If the input position exceeds the output position, then we aborted the  	// previous conversion run because the output buffer was full. Resume!  	if (rate->ipos > rate->opos)  | 
