/*  SpiralSynth
 *  Copyleft (C) 2000 David Griffiths <dave@pawfal.org>
 *
 *  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.
*/ 

#include <iostream.h>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include "RiffWav.h"
#include "SpiralInfo.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

const int HEADERLEN = (4+24+8);

#if __BYTE_ORDER == BIG_ENDIAN
#define SWAPINT(a) (a)=(((a)&0x000000ff)<<24)|(((a)&0x0000ff00)<<8)|\
						    (((a)&0x00ff0000)>>8)|(((a)&0xff000000)>>24)
#endif

WavFile::HeaderInfo::HeaderInfo() : RiffStr1("RIFF"),RiffStr2("WAVE"),FrmtStr("fmt "),DataStr("data")
{
	RiffSize = HEADERLEN; // needs size of data too?

	Length          = 0x10;  // length of format, always this
	Unknown         = 0x01;  // ?
	Channels        = 0x01;  // Mono, stereo=0x02
	SampleRate      = SpiralInfo::SAMPLERATE; 
	BytesPerSec     = SpiralInfo::SAMPLERATE*2; // 2 bytes = 16 bits
	BytesPerSample  = 0x02;
	BitsPerSample 	= 0x10;

	DataLength		= 2055;	
	Zero			= 0x00;
#if __BYTE_ORDER == BIG_ENDIAN
	SWAPINT(RiffSize);
	SWAPINT(SampleRate);
	SWAPINT(BytesPerSec);
	SWAPINT(DataLength);
#endif
}
int WavFile::Open(string FileName, Mode mode)
{
	if (m_Stream!=NULL) 
	{
		cerr<<"WavFile: File already open"<<endl;
		return 0;
	}
	
	if (mode==WRITE)
	{
		m_Stream = fopen (FileName.c_str(), "wb"); 
	}
	else
	{
		m_Stream = fopen (FileName.c_str(), "rb"); 
	}
	
	if (m_Stream == (FILE*)0)
	{
		cerr<<"WavFile: File open error"<<endl;
		return 0;
	}

	//Write the header

	if (mode==WRITE)
	{
		HeaderInfo w;
	
		// todo: sort this mess out!
	
		fwrite(w.RiffStr1.c_str(),4,1,m_Stream);
		fwrite(&w.RiffSize,sizeof(w.RiffSize),1,m_Stream);
		fwrite(w.RiffStr2.c_str(),4,1,m_Stream);
		
		fwrite(w.FrmtStr.c_str(),4,1,m_Stream);

		fwrite(&w.Length,sizeof(w.Length),1,m_Stream);
		
		fwrite(&w.Zero,sizeof(w.Zero),1,m_Stream);
		fwrite(&w.Zero,sizeof(w.Zero),1,m_Stream);
		fwrite(&w.Zero,sizeof(w.Zero),1,m_Stream);
		fwrite(&w.Unknown,sizeof(w.Unknown),1,m_Stream);
	
		fwrite(&w.Zero,sizeof(w.Zero),1,m_Stream);
		fwrite(&w.Channels,sizeof(w.Channels),1,m_Stream);
	
		fwrite(&w.Zero,sizeof(w.Zero),1,m_Stream);
		fwrite(&w.SampleRate,sizeof(w.SampleRate),1,m_Stream);

		fwrite(&w.BytesPerSec,sizeof(w.BytesPerSec),1,m_Stream);
	
		fwrite(&w.BytesPerSample,sizeof(w.BytesPerSample),1,m_Stream);
	
		fwrite(&w.Zero,sizeof(w.Zero),1,m_Stream);
		fwrite(&w.BitsPerSample,sizeof(w.BitsPerSample),1,m_Stream);
			
		fwrite(&w.Zero,sizeof(w.Zero),1,m_Stream);

		fwrite(w.DataStr.c_str(),4,1,m_Stream);		
		fwrite(&w.DataLength,sizeof(w.DataLength),1,m_Stream);		
	
		return 1;
	}
	else
	if (mode==READ)
	{
		// check we have a wav file here
		char Check[4];
		fread(Check,4,1,m_Stream);		
		if (Check[0]=='R' && Check[1]=='I' && Check[2]=='F' && Check[3]=='F')
		{
			// todo: check, and implement other formats
			
			// see if it's saved in stereo
			char temp=0;
			fseek(m_Stream, 19, SEEK_SET);
			fread(&temp,4,1,m_Stream);		
			if (temp==0x02) 
			{
				m_Stereo=true;
			}
			
			// get the total size
			fseek(m_Stream, 40, SEEK_SET);
			fread(&m_TotalLength,4,1,m_Stream);		
			m_TotalLength/=2;
			
			// leave the filepointer on the first sample
		}
		else
		{
			fclose(m_Stream);
			cerr<<"WavFile: File open error, wrong format"<<endl;
			return 0;
		}
		
	}
}

int WavFile::Close()
{
	if (m_Stream==NULL) 
	{
		//cerr<<"WavFile: File already closed"<<endl;
		return 0;
	}

	// write the total length in	
	fseek(m_Stream, 40, SEEK_SET);
	m_TotalLength*=2;
	fwrite(&m_TotalLength,sizeof(m_TotalLength),1,m_Stream);		
	
	fclose(m_Stream); 

	m_Stream=NULL;
	m_TotalLength=0;

	return 1;	
}

int WavFile::Save(int Length, short *data)
{
	if (m_Stream==NULL)
	{
		cerr<<"WavFile: No stream open"<<endl;
		return 0;
	}
	
	if (!data) return 0;
	
	m_TotalLength+=Length;
	
	fwrite(data,sizeof(data),Length/2,m_Stream);
	
	return 1;
}

int WavFile::GetSize()
{
	return m_TotalLength;
}

int WavFile::Load(short *data)
{
        if (m_TotalLength==(int)fread(data,2,m_TotalLength,m_Stream))
        {
                return 1;
        }

        cerr<<"WavFile: Read error"<<endl;
        return 0;
}
