[Scummvm-cvs-logs] CVS: scummvm/sound flac.cpp,NONE,1.1 flac.h,NONE,1.1 module.mk,1.16,1.17 audiocd.cpp,1.10,1.11 audiostream.cpp,1.55,1.56 mixer.cpp,1.157,1.158 mp3.cpp,1.8,1.9 vorbis.cpp,1.11,1.12 audiostream.h,1.31,1.32 mixer.h,1.75,1.76 mp3.h,1.7,1.8 vorbis.h,1.7,1.8

Max Horn fingolfin at users.sourceforge.net
Sun Feb 22 06:25:05 CET 2004


Update of /cvsroot/scummvm/scummvm/sound
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv387/sound

Modified Files:
	module.mk audiocd.cpp audiostream.cpp mixer.cpp mp3.cpp 
	vorbis.cpp audiostream.h mixer.h mp3.h vorbis.h 
Added Files:
	flac.cpp flac.h 
Log Message:
Patch #885904 (Flac Support) with some tweaks by me

--- NEW FILE: flac.cpp ---
/* ScummVM - Scumm Interpreter

 * Copyright (C) 2003-2004 The ScummVM project

 *

 * This program is free software; you can redistribute it and/or

 * modify it under the terms of the GNU General Public License

 * as published by the Free Software Foundation; either version 2

 * of the License, or (at your option) any later version.



 * This program 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 General Public License for more details.



 * You should have received a copy of the GNU General Public License

 * along with this program; if not, write to the Free Software

 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 *

 * $Header: /cvsroot/scummvm/scummvm/sound/flac.cpp,v 1.1 2004/02/22 14:11:10 fingolfin Exp $

 *

 */



#include "sound/flac.h"



#ifdef USE_FLAC



#include "common/file.h"

#include "common/util.h"



#include "sound/audiostream.h"

#include "sound/audiocd.h"



#define FLAC__NO_DLL // that MS-magic gave me headaches - just link the library you like

#include <FLAC/seekable_stream_decoder.h>



#pragma mark -

#pragma mark --- Flac stream ---

#pragma mark -



static const uint MAX_OUTPUT_CHANNELS = 2;





class FlacInputStream : public AudioStream {



public:

	FlacInputStream(File *sourceFile, const uint32 fileStart, const uint32 fileStop);

	FlacInputStream(File *sourceFile, const uint32 fileStart = 0);

	virtual ~FlacInputStream();



	int readBuffer(int16 *buffer, const int numSamples);



	bool isStereo() const { return _streaminfo.channels >= 2; }

	int getRate() const { return _streaminfo.sample_rate; }

	bool endOfStream() const { return _streaminfo.channels == 0 || (_lastSampleWritten && getBufferedSamples() == 0); }

	/** the mixer aint supporting it right now.. */

	//bool endOfData() const { return getBufferedSamples() == 0; }

	bool endOfData() const { return endOfStream(); }



	uint getChannels() const { return MIN(_streaminfo.channels, MAX_OUTPUT_CHANNELS); }

	uint getBufferedSamples() const { return _preBuffer.bufFill; };



	const FLAC__StreamMetadata_StreamInfo& getStreamInfo() const {return _streaminfo;}



	inline FLAC__SeekableStreamDecoderState getState() const;

	inline FLAC__StreamDecoderState getStreamDecoderState() const;





	bool isStreamDecoderReady() const { return getStreamDecoderState() == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC ; }

	bool init();

	bool finish();

	bool flush();

	inline bool processSingleBlock();

	inline bool processUntilEndOfMetadata();

	bool seekAbsolute(FLAC__uint64 sample);

	inline void setLastSample(FLAC__uint64 absoluteSample);



protected:

	inline ::FLAC__SeekableStreamDecoderReadStatus callbackRead(FLAC__byte buffer[], uint *bytes);

	inline ::FLAC__SeekableStreamDecoderSeekStatus callbackSeek(FLAC__uint64 absoluteByteOffset);

	inline ::FLAC__SeekableStreamDecoderTellStatus callbackTell(FLAC__uint64 *absoluteByteOffset);

	inline ::FLAC__SeekableStreamDecoderLengthStatus callbackLength(FLAC__uint64 *streamLength);

	inline bool callbackEOF();

	inline ::FLAC__StreamDecoderWriteStatus callbackWrite(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);

	inline void callbackMetadata(const ::FLAC__StreamMetadata *metadata);

	inline void callbackError(::FLAC__StreamDecoderErrorStatus status);

	

	::FLAC__SeekableStreamDecoder *_decoder;



private:

	static ::FLAC__SeekableStreamDecoderReadStatus callWrapRead(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], uint *bytes, void *clientData);

	static ::FLAC__SeekableStreamDecoderSeekStatus callWrapSeek(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absoluteByteOffset, void *clientData);

	static ::FLAC__SeekableStreamDecoderTellStatus callWrapTell(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absoluteByteOffset, void *clientData);

	static ::FLAC__SeekableStreamDecoderLengthStatus callWrapLength(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *streamLength, void *clientData);

	static FLAC__bool callWrapEOF(const ::FLAC__SeekableStreamDecoder *decoder, void *clientData);

	static ::FLAC__StreamDecoderWriteStatus callWrapWrite(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData);

	static void callWrapMetadata(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *clientData);

	static void callWrapError(const ::FLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *clientData);

	// Private and undefined so you can't use them:

	FlacInputStream(const FlacInputStream &);

	void operator=(const FlacInputStream &);



	bool isValid() const { return _decoder != NULL; }

	

	bool allocateBuffer(uint minSamples);

	inline void flushBuffer();

	inline void deleteBuffer();

	

	/** Header of the Stream */

	FLAC__StreamMetadata_StreamInfo _streaminfo;

	

	struct {

		/** Handle to the File */

		File *fileHandle;

		/** Index of next Byte to read */

		uint32 filePos;

		/** start of stream - not necessary start of file */

		uint32 fileStartPos;

		/** last index of Stream + 1(!) - not necessary end of file */

		uint32 fileEndPos;

	} _fileInfo;

	

	/** index of the first Sample to be played */

	FLAC__uint64 _firstSample;

	/** index + 1(!) of the last Sample to be played - 0 is end of Stream*/

	FLAC__uint64 _lastSample;

	

	/** true if the last Sample was decoded from the FLAC-API - there might still be data in the buffer */

	bool _lastSampleWritten;

	

	typedef int16 bufType;

	enum { BUFTYPE_BITS = 16 };

	

	struct {

		bufType *bufData;

		bufType *bufReadPos;

		uint bufSize;

		uint bufFill;

	} _preBuffer;

	

	bufType *_outBuffer;

	uint _requestedSamples;



	void setBestConvertBufferMethod();

	typedef void (*PFCONVERTBUFFERS)(bufType*,const FLAC__int32*[], uint, const uint, const uint8);

	PFCONVERTBUFFERS _methodConvertBuffers;

	static void convertBuffersGeneric(bufType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);

	static void convertBuffersStereoNS(bufType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);

	static void convertBuffersStereo8Bit(bufType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);

	static void convertBuffersMonoNS(bufType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);

	static void convertBuffersMono8Bit(bufType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);

};



FlacInputStream::FlacInputStream(File *sourceFile, const uint32 fileStart)

			:	_decoder(::FLAC__seekable_stream_decoder_new()), _firstSample(0), _lastSample(0), 

				_outBuffer(NULL), _requestedSamples(0), _lastSampleWritten(true),

				_methodConvertBuffers(&FlacInputStream::convertBuffersGeneric)

{

	assert(sourceFile != NULL && sourceFile->isOpen());



	memset(&_streaminfo, 0, sizeof(_streaminfo));



	_preBuffer.bufData = NULL;

	_preBuffer.bufFill = 0;

	_preBuffer.bufSize = 0;



	_fileInfo.fileHandle = sourceFile;

	_fileInfo.fileStartPos = fileStart;

	_fileInfo.filePos = fileStart;

	_fileInfo.fileEndPos = sourceFile->size();

}



FlacInputStream::FlacInputStream(File *sourceFile, const uint32 fileStart, const uint32 fileStop)	

			:	_decoder(::FLAC__seekable_stream_decoder_new()), _firstSample(0), _lastSample(0), 

				_outBuffer(NULL), _requestedSamples(0), _lastSampleWritten(true),

				_methodConvertBuffers(&FlacInputStream::convertBuffersGeneric)

{ 

	assert(sourceFile != NULL && sourceFile->isOpen());

	assert(fileStop <= 0 || (fileStart < fileStop && fileStop <= sourceFile->size()));



	memset(&_streaminfo, 0, sizeof(_streaminfo));



	_preBuffer.bufData = NULL;

	_preBuffer.bufFill = 0;

	_preBuffer.bufSize = 0;



	_fileInfo.fileHandle = sourceFile;

	_fileInfo.fileStartPos = fileStart;

	_fileInfo.filePos = fileStart;

	_fileInfo.fileEndPos = fileStop;

}



FlacInputStream::~FlacInputStream() {

	if (_decoder != NULL) {

		(void) ::FLAC__seekable_stream_decoder_finish(_decoder);

		::FLAC__seekable_stream_decoder_delete(_decoder);

	}

	if (_preBuffer.bufData != NULL)

		delete[] _preBuffer.bufData;

}



inline FLAC__SeekableStreamDecoderState FlacInputStream::getState() const {

	assert(isValid());

	return ::FLAC__seekable_stream_decoder_get_state(_decoder);

}



inline FLAC__StreamDecoderState FlacInputStream::getStreamDecoderState() const {

	assert(isValid());

	return ::FLAC__seekable_stream_decoder_get_stream_decoder_state(_decoder);

}



bool FlacInputStream::init() {

	assert(isValid());



	memset(&_streaminfo, 0, sizeof (_streaminfo));

	deleteBuffer();

	_fileInfo.filePos = _fileInfo.fileStartPos;

	_lastSampleWritten = false;

	_methodConvertBuffers = &FlacInputStream::convertBuffersGeneric;



	::FLAC__seekable_stream_decoder_set_read_callback(_decoder, &FlacInputStream::callWrapRead);

	::FLAC__seekable_stream_decoder_set_seek_callback(_decoder, &FlacInputStream::callWrapSeek);

	::FLAC__seekable_stream_decoder_set_tell_callback(_decoder, &FlacInputStream::callWrapTell);

	::FLAC__seekable_stream_decoder_set_length_callback(_decoder, &FlacInputStream::callWrapLength);

	::FLAC__seekable_stream_decoder_set_eof_callback(_decoder, &FlacInputStream::callWrapEOF);

	::FLAC__seekable_stream_decoder_set_write_callback(_decoder, &FlacInputStream::callWrapWrite);

	::FLAC__seekable_stream_decoder_set_metadata_callback(_decoder, &FlacInputStream::callWrapMetadata);

	::FLAC__seekable_stream_decoder_set_error_callback(_decoder, &FlacInputStream::callWrapError);

	::FLAC__seekable_stream_decoder_set_client_data(_decoder, (void*)this);



	if (::FLAC__seekable_stream_decoder_init(_decoder) == FLAC__SEEKABLE_STREAM_DECODER_OK) {

		if (processUntilEndOfMetadata() && _streaminfo.channels > 0) {

			if (_firstSample == 0 || 0 != ::FLAC__seekable_stream_decoder_seek_absolute(_decoder, _firstSample)) {

				// FLAC__StreamDecoderState state = getStreamDecoderState();

				return true; // no error occured

			}

		}

	}



	warning("FlacInputStream: could not create an Audiostream from File %s", _fileInfo.fileHandle->name());

	return false; 

}



bool FlacInputStream::finish() {

	assert(isValid());

	deleteBuffer();

	return 0 != ::FLAC__seekable_stream_decoder_finish(_decoder);

}



bool FlacInputStream::flush() {

	assert(isValid());

	flushBuffer();

	return 0 != ::FLAC__seekable_stream_decoder_flush(_decoder);

}



inline bool FlacInputStream::processSingleBlock() {

	assert(isValid());

	return 0 != ::FLAC__seekable_stream_decoder_process_single(_decoder);

}



inline bool FlacInputStream::processUntilEndOfMetadata() {

	assert(isValid());

	return 0 != ::FLAC__seekable_stream_decoder_process_until_end_of_metadata(_decoder);

}



bool FlacInputStream::seekAbsolute(FLAC__uint64 sample) {

	assert(isValid());

	const bool result = (0 != ::FLAC__seekable_stream_decoder_seek_absolute(_decoder, sample));

	if (result) {

		flushBuffer();

		_lastSampleWritten = (_lastSample != 0 && sample >= _lastSample); // only set if we are SURE

	}

	return result;

}



int FlacInputStream::readBuffer(int16 *buffer, const int numSamples) {

	const uint kNumChannels = getChannels();



	if (kNumChannels == 0) {

		warning("FlacInputStream: Stream not sucessfully initialised, cant playback");

		return -1; // streaminfo wasnt read!

	}



	assert(numSamples % kNumChannels == 0); // must be multiple of channels!

	assert(buffer != NULL);

	assert(_outBuffer == NULL);

	assert(_requestedSamples == 0);



	_outBuffer = buffer;

	_requestedSamples = numSamples;



	if (_preBuffer.bufFill > 0) {

		assert(_preBuffer.bufData != NULL && _preBuffer.bufReadPos != NULL && _preBuffer.bufSize > 0);

		assert(_preBuffer.bufReadPos >= _preBuffer.bufData);

		assert(_preBuffer.bufFill % kNumChannels == 0);



		const uint copySamples = MIN((uint)numSamples, _preBuffer.bufFill);

		memcpy(buffer, _preBuffer.bufReadPos, copySamples*sizeof(buffer[0]));

		

		_outBuffer = buffer + copySamples;

		_requestedSamples = numSamples - copySamples;

		_preBuffer.bufReadPos += copySamples;

		_preBuffer.bufFill -= copySamples;

	}



	bool decoderOk = true;



	if (!_lastSampleWritten) {

		FLAC__StreamDecoderState state = getStreamDecoderState();



		for (; _requestedSamples > 0 && state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; state = getStreamDecoderState()) {

			assert(_preBuffer.bufFill == 0);

			assert(_requestedSamples % kNumChannels == 0);

			processSingleBlock();

		}



		if (state != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) {

			switch (state) {

			case FLAC__STREAM_DECODER_END_OF_STREAM :

				_lastSampleWritten = true;

				decoderOk = true; // no REAL error

				break;



			default:

				decoderOk = false;

				warning("FlacInputStream: An error occured while decoding. DecoderState is: %s",

					FLAC__StreamDecoderStateString[getStreamDecoderState()]);

			}

		}

	}



	const int samples = (int)(_outBuffer - buffer);

	assert(samples % kNumChannels == 0);



	_outBuffer = NULL; // basically unnessecary, only for the purpose of the asserts

	_requestedSamples = 0; // basically unnessecary, only for the purpose of the asserts



	return decoderOk ? samples : -1;

}



inline ::FLAC__SeekableStreamDecoderReadStatus FlacInputStream::callbackRead(FLAC__byte buffer[], uint *bytes) {

	assert(_fileInfo.fileHandle != NULL);



	if (*bytes == 0)

		return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; /* abort to avoid a deadlock */

	

	const uint32 length = MIN(_fileInfo.fileEndPos - _fileInfo.filePos, static_cast<uint32>(*bytes));

	

	_fileInfo.fileHandle->seek(_fileInfo.filePos);

	const uint32 bytesRead = _fileInfo.fileHandle->read(buffer, length);



	if (bytesRead == 0 && _fileInfo.fileHandle->ioFailed())

		return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;



	_fileInfo.filePos += bytesRead;

	*bytes = static_cast<uint>(bytesRead);

	return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;

}



inline void FlacInputStream::setLastSample(FLAC__uint64 absoluteSample) { 

	if (_lastSampleWritten && absoluteSample > _lastSample)

		_lastSampleWritten = false;

	_lastSample = absoluteSample;

}



inline void FlacInputStream::flushBuffer() {

	_lastSampleWritten = _lastSampleWritten && _preBuffer.bufFill == 0;

	_preBuffer.bufFill = 0;

}



inline void FlacInputStream::deleteBuffer() {

	flushBuffer();

	_preBuffer.bufSize = 0;

	if (_preBuffer.bufData != NULL) {

		delete[] _preBuffer.bufData;

		_preBuffer.bufData = NULL;

	}

}



bool FlacInputStream::allocateBuffer(uint minSamples) {

	uint allocateSize = minSamples / getChannels();

	/** insert funky algorythm for optimum buffersize here */

	allocateSize = MIN(_streaminfo.max_blocksize, MAX(_streaminfo.min_blocksize, allocateSize));

	allocateSize += 8 - (allocateSize % 8); // make sure its an nice even amount

	allocateSize *= getChannels();



	deleteBuffer();



	_preBuffer.bufData = new bufType[allocateSize];

	if (_preBuffer.bufData != NULL) {

		_preBuffer.bufSize = allocateSize;

		return true;

	}

	return false;

}



void FlacInputStream::setBestConvertBufferMethod()

{

	PFCONVERTBUFFERS tempMethod = &FlacInputStream::convertBuffersGeneric;



	const uint kNumChannels = getChannels();

	const uint8 kNumBits = (uint8)_streaminfo.bits_per_sample;



	assert(kNumChannels >= 1);

	assert(kNumBits >= 4 && kNumBits <=32);



	if (kNumChannels == 1) {

		if (kNumBits == 8)

			tempMethod = &FlacInputStream::convertBuffersMono8Bit;

		if (kNumBits == BUFTYPE_BITS)

			tempMethod = &FlacInputStream::convertBuffersMonoNS;

	} else if (kNumChannels == 2) {

		if (kNumBits == 8)

			tempMethod = &FlacInputStream::convertBuffersStereo8Bit;

		if (kNumBits == BUFTYPE_BITS)

			tempMethod = &FlacInputStream::convertBuffersStereoNS;

	} /* else ... */



	_methodConvertBuffers = tempMethod;

}



// 1 channel, no scaling

void FlacInputStream::convertBuffersMonoNS(bufType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits)

{

	assert(numChannels == 1);

	assert(numBits == BUFTYPE_BITS);



	FLAC__int32 const* inChannel1 = inChannels[0];



	while (numSamples >= 4) {

		bufDestination[0] = static_cast<bufType>(inChannel1[0]);

		bufDestination[1] = static_cast<bufType>(inChannel1[1]);

		bufDestination[2] = static_cast<bufType>(inChannel1[2]);

		bufDestination[3] = static_cast<bufType>(inChannel1[3]);

		bufDestination += 4;

		inChannel1 += 4;

		numSamples -= 4;

	}



	for (; numSamples > 0; --numSamples) {

		*bufDestination++ = static_cast<bufType>(*inChannel1++);

	}



	inChannels[0] = inChannel1;

	assert(numSamples == 0); // dint copy too many samples

}



// 1 channel, scaling from 8Bit

void FlacInputStream::convertBuffersMono8Bit(bufType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits)

{

	assert(numChannels == 1);

	assert(numBits == 8);

	assert(8 < BUFTYPE_BITS);



	FLAC__int32 const* inChannel1 = inChannels[0];



	while (numSamples >= 4) {

		bufDestination[0] = static_cast<bufType>(inChannel1[0]) << (BUFTYPE_BITS - 8);

		bufDestination[1] = static_cast<bufType>(inChannel1[1]) << (BUFTYPE_BITS - 8);

		bufDestination[2] = static_cast<bufType>(inChannel1[2]) << (BUFTYPE_BITS - 8);

		bufDestination[3] = static_cast<bufType>(inChannel1[3]) << (BUFTYPE_BITS - 8);

		bufDestination += 4;

		inChannel1 += 4;

		numSamples -= 4;

	}



	for (; numSamples > 0; --numSamples) {

		*bufDestination++ = static_cast<bufType>(*inChannel1++) << (BUFTYPE_BITS - 8);

	}



	inChannels[0] = inChannel1;

	assert(numSamples == 0); // dint copy too many samples

}



// 2 channels, no scaling

void FlacInputStream::convertBuffersStereoNS(bufType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits)

{

	assert(numChannels == 2);

	assert(numBits == BUFTYPE_BITS);

	assert(numSamples % 2 == 0); // must be integral multiply of channels





	FLAC__int32 const* inChannel1 = inChannels[0];	// Left Channel

	FLAC__int32 const* inChannel2 = inChannels[1];	// Right Channel



	while (numSamples >= 2*2) {

		bufDestination[0] = static_cast<bufType>(inChannel1[0]);

		bufDestination[1] = static_cast<bufType>(inChannel2[0]);

		bufDestination[2] = static_cast<bufType>(inChannel1[1]);

		bufDestination[3] = static_cast<bufType>(inChannel2[1]);

		bufDestination += 2 * 2;

		inChannel1 += 2;

		inChannel2 += 2;

		numSamples -= 2 * 2;

	}



	while (numSamples > 0) {

		bufDestination[0] = static_cast<bufType>(*inChannel1++);

		bufDestination[1] = static_cast<bufType>(*inChannel2++);

		bufDestination += 2;

		numSamples -= 2;

	}



	inChannels[0] = inChannel1;

	inChannels[1] = inChannel2;

	assert(numSamples == 0); // dint copy too many samples

}



// 2 channels, scaling from 8Bit

void FlacInputStream::convertBuffersStereo8Bit(bufType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits)

{

	assert(numChannels == 2);

	assert(numBits == 8);

	assert(numSamples % 2 == 0); // must be integral multiply of channels

	assert(8 < BUFTYPE_BITS);



	FLAC__int32 const* inChannel1 = inChannels[0];	// Left Channel

	FLAC__int32 const* inChannel2 = inChannels[1];	// Right Channel



	while (numSamples >= 2*2) {

		bufDestination[0] = static_cast<bufType>(inChannel1[0]) << (BUFTYPE_BITS - 8);

		bufDestination[1] = static_cast<bufType>(inChannel2[0]) << (BUFTYPE_BITS - 8);

		bufDestination[2] = static_cast<bufType>(inChannel1[1]) << (BUFTYPE_BITS - 8);

		bufDestination[3] = static_cast<bufType>(inChannel2[1]) << (BUFTYPE_BITS - 8);

		bufDestination += 2 * 2;

		inChannel1 += 2;

		inChannel2 += 2;

		numSamples -= 2 * 2;

	}



	while (numSamples > 0) {

		bufDestination[0] = static_cast<bufType>(*inChannel1++) << (BUFTYPE_BITS - 8);

		bufDestination[1] = static_cast<bufType>(*inChannel2++) << (BUFTYPE_BITS - 8);

		bufDestination += 2;

		numSamples -= 2;

	}



	inChannels[0] = inChannel1;

	inChannels[1] = inChannel2;

	assert(numSamples == 0); // dint copy too many samples

}



// all Purpose-conversion - slowest of em all

void FlacInputStream::convertBuffersGeneric(bufType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits)

{

	assert(numSamples % numChannels == 0); // must be integral multiply of channels



	if (numBits < BUFTYPE_BITS) {

		const uint8 kPower = (uint8)(BUFTYPE_BITS - numBits);

		

		for (; numSamples > 0; numSamples -= numChannels) {

			for (uint i = 0; i < numChannels; ++i)

				*bufDestination++ = static_cast<bufType>(*(inChannels[i]++)) << kPower;

		}

	} else if (numBits > BUFTYPE_BITS) {

		const uint8 kPower = (uint8)(numBits - BUFTYPE_BITS);

		

		for (; numSamples > 0; numSamples -= numChannels) {

			for (uint i = 0; i < numChannels; ++i)

				*bufDestination++ = static_cast<bufType>(*(inChannels[i]++) >> kPower) ;

		}

	} else {

		for (; numSamples > 0; numSamples -= numChannels) {

			for (uint i = 0; i < numChannels; ++i)

				*bufDestination++ = static_cast<bufType>(*(inChannels[i]++));

		}

	}



	assert(numSamples == 0); // dint copy too many samples

}



inline ::FLAC__StreamDecoderWriteStatus FlacInputStream::callbackWrite(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) {

    assert(frame->header.channels == _streaminfo.channels);

	assert(frame->header.sample_rate == _streaminfo.sample_rate);

	assert(frame->header.bits_per_sample == _streaminfo.bits_per_sample);

	assert(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER || _streaminfo.min_blocksize == _streaminfo.max_blocksize);

	

	assert(_preBuffer.bufFill == 0); // we dont append data



	uint nSamples = frame->header.blocksize;

	const uint kNumChannels = getChannels();

	const uint8 kNumBits = (uint8)_streaminfo.bits_per_sample;



	assert(_requestedSamples % kNumChannels == 0); // must be integral multiply of channels



	const FLAC__uint64 firstSampleNumber = (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER) ?

		frame->header.number.sample_number : (static_cast<FLAC__uint64>(frame->header.number.frame_number)) * _streaminfo.max_blocksize;



	if (_lastSample != 0 && firstSampleNumber + nSamples >= _lastSample) {

		nSamples = (uint)(firstSampleNumber >= _lastSample ? 0 : _lastSample - firstSampleNumber);

		_requestedSamples = MIN(_requestedSamples, nSamples * kNumChannels);

		_lastSampleWritten = true;

	}



	nSamples *= kNumChannels;



	const FLAC__int32 *inChannels[MAX_OUTPUT_CHANNELS] = { buffer[0] }; // one channel is a given...

	for (uint i = 1; i < kNumChannels; ++i)

		inChannels[i] = buffer[i];





	// writing DIRECTLY to the Buffer ScummVM provided

	if (_requestedSamples > 0) {

		assert(_requestedSamples % kNumChannels == 0); // must be integral multiply of channels

		assert(_outBuffer != NULL);

			

		const uint copySamples = MIN(_requestedSamples,nSamples);

		(*_methodConvertBuffers)(_outBuffer, inChannels, copySamples, kNumChannels, kNumBits);



		_requestedSamples -= copySamples;

		nSamples -= copySamples;

		_outBuffer += copySamples;

	}



	// checking if Buffer fits

	if (_preBuffer.bufSize < nSamples) {

		if (!allocateBuffer(nSamples))

			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;

	} // optional check if buffer is wasting too much memory ?



	(*_methodConvertBuffers)(_preBuffer.bufData, inChannels, nSamples, kNumChannels, kNumBits);



	_preBuffer.bufFill = nSamples;

	_preBuffer.bufReadPos = _preBuffer.bufData;



	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;

}



inline ::FLAC__SeekableStreamDecoderSeekStatus FlacInputStream::callbackSeek(FLAC__uint64 absoluteByteOffset) {

    FLAC__uint64 newPos = absoluteByteOffset + _fileInfo.fileStartPos;

	const bool result = (newPos < _fileInfo.fileEndPos);



	if (result)

		_fileInfo.filePos = static_cast<uint32>(newPos);



	return result ? FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK : FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;



}



inline ::FLAC__SeekableStreamDecoderTellStatus FlacInputStream::callbackTell(FLAC__uint64 *absoluteByteOffset) {

	/*if ()

		return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;*/

	*absoluteByteOffset = static_cast<FLAC__uint64>(_fileInfo.filePos-_fileInfo.fileStartPos);

	return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;

}



inline ::FLAC__SeekableStreamDecoderLengthStatus FlacInputStream::callbackLength(FLAC__uint64 *streamLength) {

	if (_fileInfo.fileStartPos > _fileInfo.fileEndPos)

		return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR;



	*streamLength = static_cast<FLAC__uint64>(_fileInfo.fileEndPos - _fileInfo.fileStartPos);

	return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;

}



inline bool FlacInputStream::callbackEOF() {

	return _fileInfo.filePos >= _fileInfo.fileEndPos;

}





inline void FlacInputStream::callbackMetadata(const ::FLAC__StreamMetadata *metadata) {

	assert(isValid());

	assert(metadata->type == FLAC__METADATA_TYPE_STREAMINFO); // others arent really interesting



	_streaminfo = metadata->data.stream_info;

	setBestConvertBufferMethod(); // should be set after getting stream-information. FLAC always parses the info first

}

inline void FlacInputStream::callbackError(::FLAC__StreamDecoderErrorStatus status) {

	// some of these are non-critical-Errors

	debug(1, "FlacInputStream: An error occured while decoding. DecoderState is: %s", 

			FLAC__StreamDecoderErrorStatusString[status]);

}



/* Static Callback Wrappers */

::FLAC__SeekableStreamDecoderReadStatus FlacInputStream::callWrapRead(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], uint *bytes, void *clientData) {

	assert(0 != clientData);

	FlacInputStream *instance = reinterpret_cast<FlacInputStream *>(clientData);

	assert(0 != instance);

	return instance->callbackRead(buffer, bytes);

}



::FLAC__SeekableStreamDecoderSeekStatus FlacInputStream::callWrapSeek(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absoluteByteOffset, void *clientData) {

	assert(0 != clientData);

	FlacInputStream *instance = reinterpret_cast<FlacInputStream *>(clientData);

	assert(0 != instance);

	return instance->callbackSeek(absoluteByteOffset);

}



::FLAC__SeekableStreamDecoderTellStatus FlacInputStream::callWrapTell(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absoluteByteOffset, void *clientData) {

	assert(0 != clientData);

	FlacInputStream *instance = reinterpret_cast<FlacInputStream *>(clientData);

	assert(0 != instance);

	return instance->callbackTell(absoluteByteOffset);

}



::FLAC__SeekableStreamDecoderLengthStatus FlacInputStream::callWrapLength(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *streamLength, void *clientData) {

	assert(0 != clientData);

	FlacInputStream *instance = reinterpret_cast<FlacInputStream *>(clientData);

	assert(0 != instance);

	return instance->callbackLength(streamLength);

}



FLAC__bool FlacInputStream::callWrapEOF(const ::FLAC__SeekableStreamDecoder *decoder, void *clientData) {

	assert(0 != clientData);

	FlacInputStream *instance = reinterpret_cast<FlacInputStream *>(clientData);

	assert(0 != instance);

	return instance->callbackEOF();

}



::FLAC__StreamDecoderWriteStatus FlacInputStream::callWrapWrite(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData) {

	assert(0 != clientData);

	FlacInputStream *instance = reinterpret_cast<FlacInputStream *>(clientData);

	assert(0 != instance);

	return instance->callbackWrite(frame, buffer);

}



void FlacInputStream::callWrapMetadata(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *clientData) {

	assert(0 != clientData);

	FlacInputStream *instance = reinterpret_cast<FlacInputStream *>(clientData);

	assert(0 != instance);

	instance->callbackMetadata(metadata);

}



void FlacInputStream::callWrapError(const ::FLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *clientData) {

	assert(0 != clientData);

	FlacInputStream *instance = reinterpret_cast<FlacInputStream *>(clientData);

	assert(0 != instance);

	instance->callbackError(status);

}





#pragma mark -

#pragma mark --- Flac Audio CD emulation ---

#pragma mark -





class FlacTrackInfo : public DigitalTrackInfo {

private:

	File *_file;

	FlacInputStream *_firstStream; // avoid having to open the Stream twice the first time



public:

	FlacTrackInfo(File *file);

	~FlacTrackInfo();

	bool error() { return _file == NULL; }

	void play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration);

};



FlacTrackInfo::FlacTrackInfo(File *file) : _file(NULL), _firstStream(NULL)

{

	FlacInputStream *tempStream = new FlacInputStream(file);

	/* first time the file will be tested, but not used */

	if (tempStream->init()) {

		_firstStream = tempStream;

		_file = file;

	} else

		delete tempStream;

}



void FlacTrackInfo::play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration) {

	if (error()) {

		debug(1, "FlacTrackInfo::play:  invalid state, method should not been called");

	}



	FlacInputStream *flac;



	if (_firstStream != NULL) {

		flac = _firstStream;

		_firstStream = NULL;

	} else {

		flac = new FlacInputStream(_file);

		flac->init();

	}



	if (flac->isStreamDecoderReady()) {

		const FLAC__StreamMetadata_StreamInfo &info = flac->getStreamInfo();

		flac->setLastSample(static_cast<FLAC__uint64>(startFrame + duration) * (info.sample_rate / 75));



		if (flac->seekAbsolute(static_cast<FLAC__uint64>(startFrame) * (info.sample_rate / 75))) {

			mixer->playInputStream(handle, flac, true);

			return;

		}

		// startSample is beyond the existing Samples

		debug(1, "FlacTrackInfo: Audiostream %s coud not seek to frame %d (ca %d secs)", _file->name(), startFrame, startFrame/75);

		flac->finish();

	}

	delete flac; 

}



FlacTrackInfo::~FlacTrackInfo()

{

	if (_firstStream)

		delete _firstStream;

	if (_file)

		delete _file;

}



DigitalTrackInfo* getFlacTrack(int track)

{

	assert(track >=1);

	char track_name[32];

	File *file = new File();



	sprintf(track_name, "track%d.flac", track);

	file->open(track_name);



	if (file->isOpen()) {

		FlacTrackInfo *trackInfo = new FlacTrackInfo(file);

		if (!trackInfo->error())

			return trackInfo;

		delete trackInfo;

	}



	sprintf(track_name, "track%d.fla", track);

	file->open(track_name);



	if (file->isOpen()) {

		FlacTrackInfo *trackInfo = new FlacTrackInfo(file);

		if (!trackInfo->error())

			return trackInfo;

		delete trackInfo;

	}





	delete file;

	return NULL;

}



AudioStream *makeFlacStream(File *file, uint32 length)

{

	assert(file != NULL);

	uint32 start = file->pos();



	FlacInputStream *flac = new FlacInputStream(file, start, start + length);

	if (flac->init())

		return flac;



	delete flac;

	return NULL;

}





#endif // #ifdef USE_FLAC


--- NEW FILE: flac.h ---
/* ScummVM - Scumm Interpreter

 * Copyright (C) 2003-2004 The ScummVM project

 *

 * This program is free software; you can redistribute it and/or

 * modify it under the terms of the GNU General Public License

 * as published by the Free Software Foundation; either version 2

 * of the License, or (at your option) any later version.



 * This program 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 General Public License for more details.



 * You should have received a copy of the GNU General Public License

 * along with this program; if not, write to the Free Software

 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 *

 * $Header: /cvsroot/scummvm/scummvm/sound/flac.h,v 1.1 2004/02/22 14:11:11 fingolfin Exp $

 *

 */



#ifndef SOUND_FLAC_H

#define SOUND_FLAC_H



#include "stdafx.h"

#include "common/scummsys.h"



#ifdef USE_FLAC



class AudioStream;

class DigitalTrackInfo;

class File;



DigitalTrackInfo *getFlacTrack(int track);



AudioStream *makeFlacStream(File *file, uint32 size);



#endif // #ifdef USE_FLAC

#endif // #ifndef SOUND_FLAC_H


Index: module.mk
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/module.mk,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- module.mk	30 Jan 2004 21:54:28 -0000	1.16
+++ module.mk	22 Feb 2004 14:11:10 -0000	1.17
@@ -13,7 +13,8 @@
 	sound/mpu401.o \
 	sound/rate.o \
 	sound/voc.o \
-	sound/vorbis.o
+	sound/vorbis.o \
+	sound/flac.o
 #	sound/resample.o \
 
 MODULE_DIRS += \

Index: audiocd.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/audiocd.cpp,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- audiocd.cpp	6 Jan 2004 12:45:33 -0000	1.10
+++ audiocd.cpp	22 Feb 2004 14:11:10 -0000	1.11
@@ -24,10 +24,38 @@
 #include "sound/audiocd.h"
 #include "sound/mp3.h"
 #include "sound/vorbis.h"
+#include "sound/flac.h"
 #include "base/engine.h"
 #include "common/file.h"
 #include "common/util.h"
 
+struct TrackFormat {
+	/** Decodername */
+	const char* decoderName;
+	/** 
+	 * Pointer to a function which tries to open the specified track - the only argument
+	 * is the number of the track to be played.
+	 * Returns either the DigitalTrackInfo object representing the requested track or null
+	 * in case of an error
+	 */
+	DigitalTrackInfo* (*openTrackFunction)(int);
+};
+
+static const TrackFormat TRACK_FORMATS[] = {
+	/* decoderName,		openTrackFunction */ 
+#ifdef USE_FLAC
+	{ "Flac",			getFlacTrack },
+#endif // #ifdef USE_FLAC
+#ifdef USE_VORBIS
+	{ "Ogg Vorbis",		getVorbisTrack },
+#endif // #ifdef USE_VORBIS
+#ifdef USE_MAD
+	{ "Mpeg Layer 3",	getMP3Track },
+#endif // #ifdef USE_MAD
+
+	{ NULL, NULL } // Terminator
+};
+
 
 AudioCDManager::AudioCDManager() {
 	memset(&_cd, 0, sizeof(_cd));
@@ -101,15 +129,10 @@
 }
 
 int AudioCDManager::getCachedTrack(int track) {
-	int i;
-#if defined(USE_MAD) || defined(USE_VORBIS)
-	char track_name[1024];
-	File *file = new File();
-#endif
 	int current_index;
 
 	// See if we find the track in the cache
-	for (i = 0; i < CACHE_TRACKS; i++)
+	for (int i = 0; i < CACHE_TRACKS; i++)
 		if (_cached_tracks[i] == track) {
 			if (_track_info[i])
 				return i;
@@ -127,35 +150,11 @@
 
 	_cached_tracks[current_index] = track;
 
-#ifdef USE_MAD
-	sprintf(track_name, "track%d.mp3", track);
-	file->open(track_name);
-
-	if (file->isOpen()) {
-		_track_info[current_index] = makeMP3TrackInfo(file);
-		if (_track_info[current_index]->error()) {
-			delete _track_info[current_index];
-			_track_info[current_index] = NULL;
-			return -1;
-		}
-		return current_index;
-	}
-#endif
-
-#ifdef USE_VORBIS
-	sprintf(track_name, "track%d.ogg", track);
-	file->open(track_name);
+	for (int i = 0; i < ARRAYSIZE(TRACK_FORMATS)-1 && _track_info[current_index] == NULL; ++i)
+		_track_info[current_index] = TRACK_FORMATS[i].openTrackFunction(track);
 
-	if (file->isOpen()) {
-		_track_info[current_index] = makeVorbisTrackInfo(file);
-		if (_track_info[current_index]->error()) {
-			delete _track_info[current_index];
-			_track_info[current_index] = NULL;
-			return -1;
-		}
+	if (_track_info[current_index] != NULL)
 		return current_index;
-	}
-#endif
 
 	debug(2, "Track %d not available in compressed format", track);
 	return -1;

Index: audiostream.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/audiostream.cpp,v
retrieving revision 1.55
retrieving revision 1.56
diff -u -d -r1.55 -r1.56
--- audiostream.cpp	8 Feb 2004 17:19:09 -0000	1.55
+++ audiostream.cpp	22 Feb 2004 14:11:10 -0000	1.56
@@ -24,7 +24,9 @@
 #include "common/util.h"
 #include "sound/audiostream.h"
 #include "sound/mixer.h"
-
+#include "sound/mp3.h"
+#include "sound/vorbis.h"
+#include "sound/flac.h"
 
 // This used to be an inline template function, but
 // buggy template function handling in MSVC6 forced
@@ -37,6 +39,61 @@
 #define READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, ptr, isLE) \
 	((is16Bit ? (isLE ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr)) : (*ptr << 8)) ^ (isUnsigned ? 0x8000 : 0))
 
+
+struct StreamFileFormat {
+	/** Decodername */
+	const char* decoderName;
+	const char* fileExtension;
+	/** 
+	 * Pointer to a function which tries to open a file of type StreamFormat.
+	 * Return NULL in case of an error (invalid/nonexisting file). 
+	 */
+	AudioStream* (*openStreamFile)(File *file, uint32 size);
+};
+
+static const StreamFileFormat STREAM_FILEFORMATS[] = {	
+	/* decoderName,		fileExt, openStreamFuntion */ 
+#ifdef USE_FLAC
+	{ "Flac",			"flac", makeFlacStream },
+	{ "Flac",			"fla",  makeFlacStream },
+#endif // #ifdef USE_FLAC
+#ifdef USE_VORBIS
+	{ "Ogg Vorbis",		"ogg",  makeVorbisStream },
+#endif // #ifdef USE_VORBIS
+#ifdef USE_MAD
+	{ "Mpeg Layer 3",	"mp3",  makeMP3Stream },
+#endif // #ifdef USE_MAD
+
+	{ NULL, NULL, NULL } // Terminator
+};
+
+AudioStream* AudioStream::openStreamFile(const char* filename, File *fileHandle)
+{
+	char buffer[1024];
+	const uint len = strlen(filename);
+	assert(len+6 < sizeof(buffer)); // we need a bigger buffer if wrong
+	
+	memcpy(buffer, filename, len);
+	buffer[len] = '.';
+	char *ext = &buffer[len+1];
+
+	AudioStream* stream = NULL;
+
+	for (int i = 0; i < ARRAYSIZE(STREAM_FILEFORMATS)-1 && stream == NULL; ++i) {
+		strcpy(ext, STREAM_FILEFORMATS[i].fileExtension);
+		fileHandle->open(buffer);
+		if (fileHandle->isOpen())
+			stream = STREAM_FILEFORMATS[i].openStreamFile(fileHandle, fileHandle->size());
+	}
+
+	if (stream == NULL) {
+		fileHandle->close();
+		debug(1, "AudioStream: Could not open compressed AudioFile %s", filename);
+	}
+
+	return stream;
+}
+
 #pragma mark -
 #pragma mark --- LinearMemoryStream ---
 #pragma mark -

Index: mixer.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/mixer.cpp,v
retrieving revision 1.157
retrieving revision 1.158
diff -u -d -r1.157 -r1.158
--- mixer.cpp	12 Feb 2004 16:25:28 -0000	1.157
+++ mixer.cpp	22 Feb 2004 14:11:10 -0000	1.158
@@ -29,6 +29,7 @@
 #include "sound/audiostream.h"
 #include "sound/mp3.h"
 #include "sound/vorbis.h"
+#include "sound/flac.h"
 
 
 #pragma mark -
@@ -269,6 +270,14 @@
 }
 #endif
 
+#ifdef USE_FLAC
+void SoundMixer::playFlac(PlayingSoundHandle *handle, File *file, uint32 size, byte volume, int8 balance, int id) {
+	// Create the input stream
+	AudioStream *input = makeFlacStream(file, size);
+	playInputStream(handle, input, false, volume, balance, id);
+}
+#endif
+
 void SoundMixer::playInputStream(PlayingSoundHandle *handle, AudioStream *input, bool isMusic, byte volume, int8 balance, int id, bool autofreeStream) {
 	Common::StackLock lock(_mutex);
 

Index: mp3.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/mp3.cpp,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- mp3.cpp	6 Jan 2004 12:45:33 -0000	1.8
+++ mp3.cpp	22 Feb 2004 14:11:10 -0000	1.9
@@ -261,7 +261,7 @@
 	return samples;
 }
 
-AudioStream *makeMP3Stream(File *file, uint size) {
+AudioStream *makeMP3Stream(File *file, uint32 size) {
 	return new MP3InputStream(file, mad_timer_zero, size);
 }
 
@@ -385,8 +385,21 @@
 		_file->close();
 }
 
-DigitalTrackInfo *makeMP3TrackInfo(File *file) {
-	return new MP3TrackInfo(file);
+DigitalTrackInfo *getMP3Track(int track) {
+	char track_name[32];
+	File *file = new File();
+
+	sprintf(track_name, "track%d.mp3", track);
+	file->open(track_name);
+
+	if (file->isOpen()) {
+		MP3TrackInfo *trackInfo = new MP3TrackInfo(file);
+		if (!trackInfo->error())
+			return trackInfo;
+		delete trackInfo;
+	}
+	delete file;
+	return NULL;
 }
 
 

Index: vorbis.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/vorbis.cpp,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- vorbis.cpp	12 Feb 2004 17:31:33 -0000	1.11
+++ vorbis.cpp	22 Feb 2004 14:11:11 -0000	1.12
@@ -156,8 +156,21 @@
 	}
 }
 
-DigitalTrackInfo *makeVorbisTrackInfo(File *file) {
-	return new VorbisTrackInfo(file);
+DigitalTrackInfo *getVorbisTrack(int track) {
+	char track_name[32];
+	File *file = new File();
+
+	sprintf(track_name, "track%d.ogg", track);
+	file->open(track_name);
+
+	if (file->isOpen()) {
+		VorbisTrackInfo *trackInfo = new VorbisTrackInfo(file);
+		if (!trackInfo->error())
+			return trackInfo;
+		delete trackInfo;
+	}
+	delete file;
+	return NULL;
 }
 
 #pragma mark -

Index: audiostream.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/audiostream.h,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -d -r1.31 -r1.32
--- audiostream.h	12 Feb 2004 17:31:33 -0000	1.31
+++ audiostream.h	22 Feb 2004 14:11:11 -0000	1.32
@@ -26,6 +26,8 @@
 #include "common/scummsys.h"
 #include "common/util.h"
 
+class File;
+
 
 /**
  * Generic input stream for the resampling code.
@@ -74,6 +76,17 @@
 
 	/** Sample rate of the stream. */
 	virtual int getRate() const = 0;
+
+	/**
+	 * Tries to load a file by trying all available formats.
+	 * In case of an error, the file handle will be closed, but deleting
+	 * it is still the responsibilty of the caller.
+	 * @param filename		a filename without an extension
+	 * @param fileHandle	a pointer to an existing File instance
+	 * @return	an Audiostream ready to use in case of success; 
+	 *			NULL in case of an error (e.g. invalid/nonexisting file)
+	 */
+	static AudioStream* openStreamFile(const char* filename, File *fileHandle);
 };
 
 class AppendableAudioStream : public AudioStream {

Index: mixer.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/mixer.h,v
retrieving revision 1.75
retrieving revision 1.76
diff -u -d -r1.75 -r1.76
--- mixer.h	12 Feb 2004 16:25:28 -0000	1.75
+++ mixer.h	22 Feb 2004 14:11:11 -0000	1.76
@@ -112,6 +112,9 @@
 #ifdef USE_VORBIS
 	void playVorbis(PlayingSoundHandle *handle, File *file, uint32 size, byte volume = 255, int8 balance = 0, int id = -1);
 #endif
+#ifdef USE_FLAC
+	void playFlac(PlayingSoundHandle *handle, File *file, uint32 size, byte volume = 255, int8 balance = 0, int id = -1);
+#endif
 
 	void playInputStream(PlayingSoundHandle *handle, AudioStream *input, bool isMusic, byte volume = 255, int8 balance = 0, int id = -1, bool autofreeStream = true);
 

Index: mp3.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/mp3.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- mp3.h	6 Jan 2004 12:45:33 -0000	1.7
+++ mp3.h	22 Feb 2004 14:11:11 -0000	1.8
@@ -31,9 +31,9 @@
 class DigitalTrackInfo;
 class File;
 
-DigitalTrackInfo *makeMP3TrackInfo(File *file);
+DigitalTrackInfo *getMP3Track(int track);
 
-AudioStream *makeMP3Stream(File *file, uint size);
+AudioStream *makeMP3Stream(File *file, uint32 size);
 
 #endif
 

Index: vorbis.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/vorbis.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- vorbis.h	6 Jan 2004 12:45:33 -0000	1.7
+++ vorbis.h	22 Feb 2004 14:11:11 -0000	1.8
@@ -31,7 +31,7 @@
 class DigitalTrackInfo;
 class File;
 
-DigitalTrackInfo *makeVorbisTrackInfo(File *file);
+DigitalTrackInfo *getVorbisTrack(int track);
 
 AudioStream *makeVorbisStream(File *file, uint32 size);
 





More information about the Scummvm-git-logs mailing list