//	VorbisfileLoader.cpp - Sound file loaders for .ogg files, using vorbisfile.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//	
//	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 3 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, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#include "VorbisfileLoader.h"
#include "DebugHeaders.h"
#include "UTF8File.h"

#include <cassert>

using std::string;

//------------------------------------------------------------------------------
VorbisfileLoader::Creator VorbisfileLoader::creator;

//------------------------------------------------------------------------------
VorbisfileLoader::VorbisfileLoader(const FilePath& path):
SoundFileLoader(path),
filePath(path),
fileLength(0),
fileSamplerate(44100.0f),
fileNumChannels(2),
valid(false)
{
	if(path.exists())
	{
		string tempstr;

		UTF8File::wstringToChar(path.getPath(), tempstr);

		//Open the file.
		if(!ov_fopen(tempstr.c_str(), &vorbisFile))
		{
			//Make sure there's at least one bitstream in it.
			if(ov_streams(&vorbisFile) > 0)
			{
				vorbis_info *vorbisInfo;

				//Get the samplerate and number of channels.
				vorbisInfo = ov_info(&vorbisFile, 0);
				fileSamplerate = (float)vorbisInfo->rate;
				fileNumChannels = vorbisInfo->channels;

				//Get the length of the file.
				fileLength = ov_pcm_total(&vorbisFile, 0);

				valid = true;
			}
			else
				DebugStatement(L"VorbisfileLoader: No streams in file? " << path.getPath().c_str());
		}
		else
			DebugStatement(L"VorbisfileLoader: Could not open file: " << path.getPath().c_str());
	}
	else
		DebugStatement(L"VorbisfileLoader: There was no file at: " << path.getPath().c_str());
}

//------------------------------------------------------------------------------
VorbisfileLoader::~VorbisfileLoader()
{
	ov_clear(&vorbisFile);
}

//------------------------------------------------------------------------------
int VorbisfileLoader::loadChunk(float *buffer,
								int64_t& position,
								int bufferSize,
								int bufferOffset)
{
	int i, j;
	int result;
	int retval = bufferOffset;
	float **tempBuf;
	int currentBitstream = 0;

	assert(fileNumChannels > 0);
	int numSamples = bufferSize/fileNumChannels;

	if(valid)
	{
		//Make sure we're at the correct point to read from.
		ov_pcm_seek(&vorbisFile, position);

		//Read audio from disk into the buffer.
		while(retval < numSamples)
		{
			result = ov_read_float(&vorbisFile,
								   &tempBuf,
								   (numSamples-retval),
								   &currentBitstream);

			if((currentBitstream > 0)||(result <= 0))
			{
				//We've either gone past the end of our bitstream, or there are
				//no other bitstreams in the file, and we've reached the end of
				//the file. (or there was an error (result < 0)).
				position = 0;
				break;
			}
			else if(result <= (numSamples-retval))
			{
				//Copy the audio data to the output buffer.
				for(i=0,j=(retval*fileNumChannels);
					i<result;
					++i,j+=fileNumChannels)
				{
					if(retval >= numSamples)
						break;

					buffer[j] = tempBuf[0][i];
					if(fileNumChannels > 1)
						buffer[j+1] = tempBuf[1][i];

					++retval;
					++position;
				}
			}
		}
	}

	return (retval-bufferOffset);
}
