Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tsio_aiff.h"
Toshihiro Shimizu 890ddd
#include "tmachine.h"
Toshihiro Shimizu 890ddd
#include "tsound_t.h"
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
#include "tfilepath_io.h"
Toshihiro Shimizu 890ddd
#include "tfilepath_io.h"
Toshihiro Shimizu 890ddd
#include <math.h></math.h>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define DEFAULT_OFFSET 0
Toshihiro Shimizu 890ddd
#define DEFAULT_BLOCKSIZE 0
Toshihiro Shimizu 890ddd
#define AIFF_NBYTE 4
Toshihiro Shimizu 890ddd
#define COMM_NBYTE 24
Toshihiro Shimizu 890ddd
#define OFFSETBLOCSIZE_NBYTE 8
Toshihiro Shimizu 890ddd
#define SSND_PREDATA_NBYTE 16
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#if !defined(TNZ_LITTLE_ENDIAN)
Toshihiro Shimizu 890ddd
TNZ_LITTLE_ENDIAN undefined !!
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	using namespace std;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void swapAndCopySamples(short *srcBuffer, short *dstBuffer, TINT32 sampleCount);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TUINT32 convertToLong(UCHAR *buffer);
Toshihiro Shimizu 890ddd
void storeFloat(unsigned char *buffer, TUINT32 value);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TAIFFChunk: classe base per i vari chunk
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class TAIFFChunk
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	string m_name;
Toshihiro Shimizu 890ddd
	TINT32 m_length; // lunghezza del chunk in byte
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TAIFFChunk(string name, TINT32 length)
Toshihiro Shimizu 890ddd
		: m_name(name), m_length(length) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	virtual ~TAIFFChunk() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	virtual bool read(ifstream &is)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		skip(is);
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void skip(ifstream &is)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		is.seekg((TINT32)is.tellg() + (TINT32)m_length);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static bool readHeader(ifstream &is, string &name, TINT32 &length)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		char cName[5];
Toshihiro Shimizu 890ddd
		TINT32 len;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		is.read((char *)&cName, 4);
Toshihiro Shimizu 890ddd
		if (is.fail())
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
		cName[4] = '\0';
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		is.read((char *)&len, sizeof(len));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (TNZ_LITTLE_ENDIAN)
Toshihiro Shimizu 890ddd
			len = swapTINT32(len);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (is.fail())
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		name = string(cName);
Toshihiro Shimizu 890ddd
		length = len;
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  COMM Chunk: Chunk contenente le informazioni sulla traccia
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class TCOMMChunk : public TAIFFChunk
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	USHORT m_chans;   // numero di canali
Toshihiro Shimizu 890ddd
	TUINT32 m_frames; // numero di campioni
Toshihiro Shimizu 890ddd
	USHORT m_bitPerSample;
Toshihiro Shimizu 890ddd
	TUINT32 m_sampleRate;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TCOMMChunk(string name, TINT32 length)
Toshihiro Shimizu 890ddd
		: TAIFFChunk(name, length) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	virtual bool read(ifstream &is)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		is.read((char *)&m_chans, sizeof(m_chans));
Toshihiro Shimizu 890ddd
		is.read((char *)&m_frames, sizeof(m_frames));
Toshihiro Shimizu 890ddd
		is.read((char *)&m_bitPerSample, sizeof(m_bitPerSample));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (TNZ_LITTLE_ENDIAN) {
Toshihiro Shimizu 890ddd
			m_chans = swapUshort(m_chans);
Toshihiro Shimizu 890ddd
			m_frames = swapTINT32(m_frames);
Toshihiro Shimizu 890ddd
			m_bitPerSample = swapUshort(m_bitPerSample);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		UCHAR sampleRateBuffer[10]; // sample rate come letto dallo stream
Toshihiro Shimizu 890ddd
		memset(sampleRateBuffer, 0, 10);
Toshihiro Shimizu 890ddd
		is.read((char *)&sampleRateBuffer, sizeof(sampleRateBuffer));
Toshihiro Shimizu 890ddd
		m_sampleRate = convertToLong(sampleRateBuffer);
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool write(ofstream &os)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TINT32 length = m_length;
Toshihiro Shimizu 890ddd
		USHORT chans = m_chans;
Toshihiro Shimizu 890ddd
		TUINT32 frames = m_frames;
Toshihiro Shimizu 890ddd
		USHORT bitPerSample = m_bitPerSample;
Toshihiro Shimizu 890ddd
		TUINT32 sampleRate = m_sampleRate;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (TNZ_LITTLE_ENDIAN) {
Toshihiro Shimizu 890ddd
			length = swapTINT32(length);
Toshihiro Shimizu 890ddd
			chans = swapUshort(chans);
Toshihiro Shimizu 890ddd
			frames = swapTINT32(frames);
Toshihiro Shimizu 890ddd
			bitPerSample = swapUshort(bitPerSample);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		UCHAR sampleRateBuffer[10];
Toshihiro Shimizu 890ddd
		storeFloat(sampleRateBuffer, sampleRate);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//assert(convertToLong(sampleRateBuffer) == sampleRate);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		os.write((char *)"COMM", 4);
Toshihiro Shimizu 890ddd
		os.write((char *)&length, sizeof(TINT32));
Toshihiro Shimizu 890ddd
		os.write((char *)&chans, sizeof(short));
Toshihiro Shimizu 890ddd
		os.write((char *)&frames, sizeof(TINT32));
Toshihiro Shimizu 890ddd
		os.write((char *)&bitPerSample, sizeof(short));
Toshihiro Shimizu 890ddd
		os.write((char *)&sampleRateBuffer, sizeof(sampleRateBuffer));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	virtual void print(ostream &os) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		os << "canali   = '" << m_chans << endl;
Toshihiro Shimizu 890ddd
		os << "frames   = '" << (unsigned int)m_frames << endl;
Toshihiro Shimizu 890ddd
		os << "bitxsam  = '" << m_bitPerSample << endl;
Toshihiro Shimizu 890ddd
		os << "rate	    = '" << (unsigned int)m_sampleRate << endl;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ostream &operator<<(ostream &os, const TCOMMChunk &commChunk)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	commChunk.print(os);
Toshihiro Shimizu 890ddd
	return os;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  SSND Chunk: Chunk contenente i campioni della traccia
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class TSSNDChunk : public TAIFFChunk
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TUINT32 m_offset; //dall'inizio dei sample frames tra i wavedata
Toshihiro Shimizu 890ddd
	TUINT32 m_blockSize;
Shinya Kitaoka 6a4e01
	std::unique_ptr<uchar[]> m_waveData;</uchar[]>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TSSNDChunk(string name, TINT32 length)
Toshihiro Shimizu 890ddd
		: TAIFFChunk(name, length) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool read(ifstream &is)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		is.read((char *)&m_offset, sizeof(m_offset));
Toshihiro Shimizu 890ddd
		is.read((char *)&m_blockSize, sizeof(m_blockSize));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (TNZ_LITTLE_ENDIAN) {
Toshihiro Shimizu 890ddd
			m_offset = swapTINT32(m_offset);
Toshihiro Shimizu 890ddd
			m_blockSize = swapTINT32(m_blockSize);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// alloca il buffer dei campioni
Shinya Kitaoka 6a4e01
		m_waveData.reset(new UCHAR[m_length - OFFSETBLOCSIZE_NBYTE]);
Toshihiro Shimizu 890ddd
		if (!m_waveData)
Toshihiro Shimizu 890ddd
			cout << " ERRORE " << endl;
Shinya Kitaoka 6a4e01
		is.read((char *)m_waveData.get(), m_length - OFFSETBLOCSIZE_NBYTE);
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool write(ofstream &os)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TINT32 length = m_length;
Toshihiro Shimizu 890ddd
		TUINT32 offset = m_offset;
Toshihiro Shimizu 890ddd
		TUINT32 blockSize = m_blockSize;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (TNZ_LITTLE_ENDIAN) {
Toshihiro Shimizu 890ddd
			length = swapTINT32(length);
Toshihiro Shimizu 890ddd
			offset = swapTINT32(offset);
Toshihiro Shimizu 890ddd
			blockSize = swapTINT32(blockSize);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		os.write((char *)"SSND", 4);
Toshihiro Shimizu 890ddd
		os.write((char *)&length, sizeof(TINT32));
Toshihiro Shimizu 890ddd
		os.write((char *)&offset, sizeof(TINT32));
Toshihiro Shimizu 890ddd
		os.write((char *)&blockSize, sizeof(TINT32));
Shinya Kitaoka 6a4e01
		os.write((char *)m_waveData.get(), m_length - OFFSETBLOCSIZE_NBYTE);
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ostream &operator<<(ostream &os, const TSSNDChunk &ssndChunk)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	os << "name      = '" << ssndChunk.m_name << endl;
Toshihiro Shimizu 890ddd
	os << "length    = '" << ssndChunk.m_length << endl;
Toshihiro Shimizu 890ddd
	os << "offset    = '" << (unsigned int)ssndChunk.m_offset << endl;
Toshihiro Shimizu 890ddd
	os << "blocksize = '" << (unsigned int)ssndChunk.m_blockSize << endl;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef PRINT_SAMPLES
Toshihiro Shimizu 890ddd
	os << " samples" << endl;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < ((ssndChunk.m_length - 8) / 2); ++i)
Toshihiro Shimizu 890ddd
		os << i << ((short *)*(ssndChunk.m_waveData + i)) << dec << endl;
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return os;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void flipLong(unsigned char *ptrc)
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 4c5bd5
	unsigned char val;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	val = *(ptrc);
Toshihiro Shimizu 890ddd
	*(ptrc) = *(ptrc + 3);
Toshihiro Shimizu 890ddd
	*(ptrc + 3) = val;
Toshihiro Shimizu 890ddd
	ptrc += 1;
Toshihiro Shimizu 890ddd
	val = *(ptrc);
Toshihiro Shimizu 890ddd
	*(ptrc) = *(ptrc + 1);
Toshihiro Shimizu 890ddd
	*(ptrc + 1) = val;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TUINT32 fetchLong(TUINT32 *ptrl)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return (*ptrl);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TUINT32 convertToLong(UCHAR *buffer)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TUINT32 mantissa;
Toshihiro Shimizu 890ddd
	TUINT32 last = 0;
Toshihiro Shimizu 890ddd
	UCHAR exp;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (TNZ_LITTLE_ENDIAN) {
Toshihiro Shimizu 890ddd
		//flipLong((TUINT32 *) (buffer+2));
Toshihiro Shimizu 890ddd
		flipLong(buffer + 2);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	mantissa = *((TUINT32 *)(buffer + 2));
Toshihiro Shimizu 890ddd
	exp = 30 - *(buffer + 1);
Toshihiro Shimizu 890ddd
	while (exp--) {
Toshihiro Shimizu 890ddd
		last = mantissa;
Toshihiro Shimizu 890ddd
		mantissa >>= 1;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (last & 0x00000001)
Toshihiro Shimizu 890ddd
		mantissa++;
Toshihiro Shimizu 890ddd
	return (mantissa);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void storeLong(TUINT32 val, TUINT32 *ptr)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	*ptr = val;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void storeFloat(unsigned char *buffer, TUINT32 value)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TUINT32 exp;
Toshihiro Shimizu 890ddd
	unsigned char i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	memset(buffer, 0, 10);
Toshihiro Shimizu 890ddd
	exp = value;
Toshihiro Shimizu 890ddd
	exp >>= 1;
Toshihiro Shimizu 890ddd
	for (i = 0; i < 32; i++) {
Toshihiro Shimizu 890ddd
		exp >>= 1;
Toshihiro Shimizu 890ddd
		if (!exp)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	*(buffer + 1) = i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 32; i; i--) {
Toshihiro Shimizu 890ddd
		if (value & 0x80000000)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		value <<= 1;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	*((TUINT32 *)(buffer + 2)) = value;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	buffer[0] = 0x40;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (TNZ_LITTLE_ENDIAN) {
Toshihiro Shimizu 890ddd
		//flipLong((TUINT32*) (buffer+2));
Toshihiro Shimizu 890ddd
		flipLong(buffer + 2);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TSoundTrackReaderAiff::TSoundTrackReaderAiff(const TFilePath &fp)
Toshihiro Shimizu 890ddd
	: TSoundTrackReader(fp)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TSoundTrackP TSoundTrackReaderAiff::load()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	char ckID[5];
Toshihiro Shimizu 890ddd
	char formType[5];
Toshihiro Shimizu 890ddd
	TINT32 ckSize;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Tifstream is(m_path);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!is)
Toshihiro Shimizu 890ddd
		throw TException(L"Unable to load the AIFF file " +
Toshihiro Shimizu 890ddd
						 m_path.getWideString() + L" : doesn't exist");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// legge il chunk ID
Toshihiro Shimizu 890ddd
	is.read((char *)&ckID, sizeof(ckID) - 1);
Toshihiro Shimizu 890ddd
	ckID[4] = '\0';
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// legge il chunk Size
Toshihiro Shimizu 890ddd
	is.read((char *)&ckSize, sizeof(ckSize));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (TNZ_LITTLE_ENDIAN)
Toshihiro Shimizu 890ddd
		ckSize = swapTINT32(ckSize);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// legge il formType
Toshihiro Shimizu 890ddd
	is.read((char *)&formType, sizeof(formType) - 1);
Toshihiro Shimizu 890ddd
	formType[4] = '\0';
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// il formType DEVE essere uguale a "AIFF"
Toshihiro Shimizu 890ddd
	if ((string(formType, 4) != "AIFF"))
Toshihiro Shimizu 890ddd
		throw TException("The AIFF file doesn't contain the AIFF form");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TCOMMChunk *commChunk = 0;
Toshihiro Shimizu 890ddd
	TSSNDChunk *ssndChunk = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	while (!is.eof()) {
Toshihiro Shimizu 890ddd
		string name;
Toshihiro Shimizu 890ddd
		TINT32 length;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool ret = TAIFFChunk::readHeader(is, name, length);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!ret)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// legge solo i chunk che ci interessano, ossia COMM e SSND
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (name == "COMM") {
Toshihiro Shimizu 890ddd
			// legge i dati del chunk COMM
Toshihiro Shimizu 890ddd
			commChunk = new TCOMMChunk("COMM", length);
Toshihiro Shimizu 890ddd
			commChunk->read(is);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// considera il byte di pad alla fine del chunk nel caso
Toshihiro Shimizu 890ddd
			// in cui la lunghezza di questi e' dispari
Toshihiro Shimizu 890ddd
			if (length % 2)
Toshihiro Shimizu 890ddd
				is.seekg((TINT32)is.tellg() + 1);
Toshihiro Shimizu 890ddd
		} else if (name == "SSND") {
Toshihiro Shimizu 890ddd
			// legge i dati del chunk SSND
Toshihiro Shimizu 890ddd
			ssndChunk = new TSSNDChunk("SSND", length);
Toshihiro Shimizu 890ddd
			ssndChunk->read(is);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// considera il byte di pad alla fine del chunk nel caso
Toshihiro Shimizu 890ddd
			// in cui la lunghezza di questi e' dispari
Toshihiro Shimizu 890ddd
			if (length % 2)
Toshihiro Shimizu 890ddd
				is.seekg((TINT32)is.tellg() + 1);
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			// spostati nello stream di un numero di byte pari a length
Toshihiro Shimizu 890ddd
			if (!(length % 2))
Toshihiro Shimizu 890ddd
				is.seekg((TINT32)is.tellg() + length);
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				is.seekg((TINT32)is.tellg() + (TINT32)length + 1);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TSoundTrack *track = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (commChunk && ssndChunk) {
Toshihiro Shimizu 890ddd
		if (commChunk->m_chans < 1)
Toshihiro Shimizu 890ddd
			throw TException("Invalid channels number in sound file");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (commChunk->m_chans > 2)
Toshihiro Shimizu 890ddd
			throw TException("Unsupported channels number in sound file");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		switch (commChunk->m_bitPerSample) {
Toshihiro Shimizu 890ddd
		case 8:
Toshihiro Shimizu 890ddd
			if (commChunk->m_chans == 1)
Toshihiro Shimizu 890ddd
				track = new TSoundTrackMono8Signed(
Toshihiro Shimizu 890ddd
					commChunk->m_sampleRate,
Toshihiro Shimizu 890ddd
					1, (TINT32)commChunk->m_frames);
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				track = new TSoundTrackStereo8Signed(
Toshihiro Shimizu 890ddd
					commChunk->m_sampleRate,
Toshihiro Shimizu 890ddd
					2, (TINT32)commChunk->m_frames);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			memcpy(
Toshihiro Shimizu 890ddd
				(void *)track->getRawData(),
Shinya Kitaoka 6a4e01
				(void *)(ssndChunk->m_waveData.get() + ssndChunk->m_offset),
Toshihiro Shimizu 890ddd
				commChunk->m_frames * commChunk->m_chans);
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		case 16:
Toshihiro Shimizu 890ddd
			if (commChunk->m_chans == 1)
Toshihiro Shimizu 890ddd
				track = new TSoundTrackMono16(
Toshihiro Shimizu 890ddd
					commChunk->m_sampleRate,
Toshihiro Shimizu 890ddd
					1, (TINT32)commChunk->m_frames);
Toshihiro Shimizu 890ddd
			else // due canali
Toshihiro Shimizu 890ddd
				track = new TSoundTrackStereo16(
Toshihiro Shimizu 890ddd
					commChunk->m_sampleRate,
Toshihiro Shimizu 890ddd
					2, (TINT32)commChunk->m_frames);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (!TNZ_LITTLE_ENDIAN)
Toshihiro Shimizu 890ddd
				memcpy(
Toshihiro Shimizu 890ddd
					(void *)track->getRawData(),
Shinya Kitaoka 6a4e01
					(void *)(ssndChunk->m_waveData.get() + ssndChunk->m_offset),
Toshihiro Shimizu 890ddd
					commChunk->m_frames * track->getSampleSize());
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				swapAndCopySamples(
Shinya Kitaoka 6a4e01
					(short *)(ssndChunk->m_waveData.get() + ssndChunk->m_offset),
Toshihiro Shimizu 890ddd
					(short *)track->getRawData(),
Toshihiro Shimizu 890ddd
					(TINT32)(commChunk->m_frames * commChunk->m_chans));
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		case 24:
Toshihiro Shimizu 890ddd
			if (commChunk->m_chans == 1)
Toshihiro Shimizu 890ddd
				track = new TSoundTrackMono24(
Toshihiro Shimizu 890ddd
					commChunk->m_sampleRate,
Toshihiro Shimizu 890ddd
					1, (TINT32)commChunk->m_frames);
Toshihiro Shimizu 890ddd
			else // due canali
Toshihiro Shimizu 890ddd
				track = new TSoundTrackStereo24(
Toshihiro Shimizu 890ddd
					commChunk->m_sampleRate,
Toshihiro Shimizu 890ddd
					2, (TINT32)commChunk->m_frames);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (!TNZ_LITTLE_ENDIAN) {
Toshihiro Shimizu 890ddd
				UCHAR *begin = (UCHAR *)track->getRawData();
Toshihiro Shimizu 890ddd
				for (int i = 0; i < (int)(commChunk->m_frames * commChunk->m_chans); ++i) { //dovrebbe andare bene anche adesso
Toshihiro Shimizu 890ddd
					*(begin + 4 * i) = 0;
Toshihiro Shimizu 890ddd
					*(begin + 4 * i + 1) =
Shinya Kitaoka 6a4e01
						*(ssndChunk->m_waveData.get() + ssndChunk->m_offset + 3 * i);
Toshihiro Shimizu 890ddd
					*(begin + 4 * i + 2) =
Shinya Kitaoka 6a4e01
						*(ssndChunk->m_waveData.get() + ssndChunk->m_offset + 3 * i + 1);
Toshihiro Shimizu 890ddd
					*(begin + 4 * i + 3) =
Shinya Kitaoka 6a4e01
						*(ssndChunk->m_waveData.get() + ssndChunk->m_offset + 3 * i + 2);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				UCHAR *begin = (UCHAR *)track->getRawData();
Toshihiro Shimizu 890ddd
				for (int i = 0; i < (int)(commChunk->m_frames * commChunk->m_chans); ++i) {
Toshihiro Shimizu 890ddd
					*(begin + 4 * i) =
Shinya Kitaoka 6a4e01
						*(ssndChunk->m_waveData.get() + ssndChunk->m_offset + 3 * i + 2);
Toshihiro Shimizu 890ddd
					*(begin + 4 * i + 1) =
Shinya Kitaoka 6a4e01
						*(ssndChunk->m_waveData.get() + ssndChunk->m_offset + 3 * i + 1);
Toshihiro Shimizu 890ddd
					*(begin + 4 * i + 2) =
Shinya Kitaoka 6a4e01
						*(ssndChunk->m_waveData.get() + ssndChunk->m_offset + 3 * i);
Toshihiro Shimizu 890ddd
					*(begin + 4 * i + 3) = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					/*
Toshihiro Shimizu 890ddd
            *(begin + 4*i) = 0;
Toshihiro Shimizu 890ddd
            *(begin + 4*i + 3) =
Toshihiro Shimizu 890ddd
              *(ssndChunk->m_waveData+ssndChunk->m_offset + 3*i + 2);
Toshihiro Shimizu 890ddd
            
Toshihiro Shimizu 890ddd
            // sono i due byte che vengono invertiti
Toshihiro Shimizu 890ddd
            *(begin + 4*i + 1) = 
Toshihiro Shimizu 890ddd
              *(ssndChunk->m_waveData+ssndChunk->m_offset + 3*i + 1);
Toshihiro Shimizu 890ddd
            *(begin + 4*i + 2) = 
Toshihiro Shimizu 890ddd
              *(ssndChunk->m_waveData+ssndChunk->m_offset + 3*i);
Toshihiro Shimizu 890ddd
            */
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (commChunk)
Toshihiro Shimizu 890ddd
			delete commChunk;
Toshihiro Shimizu 890ddd
		if (ssndChunk)
Toshihiro Shimizu 890ddd
			delete ssndChunk;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return track;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TSoundTrackWriterAiff::TSoundTrackWriterAiff(const TFilePath &fp)
Toshihiro Shimizu 890ddd
	: TSoundTrackWriter(fp)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool TSoundTrackWriterAiff::save(const TSoundTrackP &st)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(st);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TSoundTrackP sndtrack;
Toshihiro Shimizu 890ddd
	if (st->getBitPerSample() == 8 && !st->isSampleSigned())
Toshihiro Shimizu 890ddd
		throw TException("The format (8 bit unsigned) is incompatible with AIFF file");
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		sndtrack = st;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TINT32 soundDataCount = (TINT32)(sndtrack->getSampleCount() * sndtrack->getChannelCount() *
Toshihiro Shimizu 890ddd
									 tceil(sndtrack->getBitPerSample() / 8));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TINT32 postHeadData = AIFF_NBYTE + COMM_NBYTE + SSND_PREDATA_NBYTE + soundDataCount;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TFileStatus fs(m_path);
Toshihiro Shimizu 890ddd
	if (fs.doesExist() && !fs.isWritable())
Toshihiro Shimizu 890ddd
		throw TException(L"Unable to save the soundtrack: " +
Toshihiro Shimizu 890ddd
						 m_path.getWideString() + L" is read-only");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Tofstream os(m_path);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TCOMMChunk commChunk("COMM", 18);
Toshihiro Shimizu 890ddd
	commChunk.m_chans = sndtrack->getChannelCount();
Toshihiro Shimizu 890ddd
	commChunk.m_frames = sndtrack->getSampleCount();
Toshihiro Shimizu 890ddd
	commChunk.m_bitPerSample = sndtrack->getBitPerSample(); //assumendo che non ci siano 12 bit
Toshihiro Shimizu 890ddd
	commChunk.m_sampleRate = sndtrack->getSampleRate();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TSSNDChunk ssndChunk("SSND", soundDataCount + OFFSETBLOCSIZE_NBYTE);
Toshihiro Shimizu 890ddd
	ssndChunk.m_offset = DEFAULT_OFFSET;
Toshihiro Shimizu 890ddd
	ssndChunk.m_blockSize = DEFAULT_BLOCKSIZE;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 6a4e01
	std::unique_ptr<uchar[]> waveData(new UCHAR[soundDataCount]);</uchar[]>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (TNZ_LITTLE_ENDIAN) {
Toshihiro Shimizu 890ddd
		postHeadData = swapTINT32(postHeadData);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (commChunk.m_bitPerSample == 16) {
Toshihiro Shimizu 890ddd
			swapAndCopySamples(
Toshihiro Shimizu 890ddd
				(short *)sndtrack->getRawData(),
Shinya Kitaoka 6a4e01
				(short *)waveData.get(),
Toshihiro Shimizu 890ddd
				(TINT32)(commChunk.m_frames * commChunk.m_chans));
Toshihiro Shimizu 890ddd
		} else if (commChunk.m_bitPerSample == 24) {
Toshihiro Shimizu 890ddd
			UCHAR *begin = (UCHAR *)sndtrack->getRawData();
Toshihiro Shimizu 890ddd
			for (int i = 0; i < (int)commChunk.m_frames * commChunk.m_chans; ++i) {
Shinya Kitaoka 6a4e01
				*(waveData.get() + 3 * i) = *(begin + 4 * i + 2);
Shinya Kitaoka 6a4e01
				*(waveData.get() + 3 * i + 1) = *(begin + 4 * i + 1);
Shinya Kitaoka 6a4e01
				*(waveData.get() + 3 * i + 2) = *(begin + 4 * i);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				/*
Toshihiro Shimizu 890ddd
        *(waveData + 3*i + 2) = *(begin + 4*i + 3);
Toshihiro Shimizu 890ddd
        
Toshihiro Shimizu 890ddd
        // posiziona in modo corretto i due byte prima invertiti
Toshihiro Shimizu 890ddd
        *(waveData + 3*i) = *(begin + 4*i + 2);
Toshihiro Shimizu 890ddd
        *(waveData + 3*i + 1) = *(begin + 4*i + 1);
Toshihiro Shimizu 890ddd
        */
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			memcpy(
Shinya Kitaoka 6a4e01
				(void *)waveData.get(),
Toshihiro Shimizu 890ddd
				(void *)sndtrack->getRawData(),
Toshihiro Shimizu 890ddd
				soundDataCount);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		if (commChunk.m_bitPerSample != 24)
Toshihiro Shimizu 890ddd
			memcpy(
Shinya Kitaoka 6a4e01
				(void *)waveData.get(),
Toshihiro Shimizu 890ddd
				(void *)sndtrack->getRawData(),
Toshihiro Shimizu 890ddd
				soundDataCount);
Toshihiro Shimizu 890ddd
		else {
Toshihiro Shimizu 890ddd
			UCHAR *begin = (UCHAR *)sndtrack->getRawData();
Toshihiro Shimizu 890ddd
			for (int i = 0; i < (int)commChunk.m_frames * commChunk.m_chans; ++i) {
Shinya Kitaoka 6a4e01
				*(waveData.get() + 3 * i) = *(begin + 4 * i + 1);
Shinya Kitaoka 6a4e01
				*(waveData.get() + 3 * i + 1) = *(begin + 4 * i + 2);
Shinya Kitaoka 6a4e01
				*(waveData.get() + 3 * i + 2) = *(begin + 4 * i + 3);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 6a4e01
	ssndChunk.m_waveData = std::move(waveData);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	os.write("FORM", 4);
Toshihiro Shimizu 890ddd
	os.write((char *)&postHeadData, sizeof(TINT32));
Toshihiro Shimizu 890ddd
	os.write("AIFF", 4);
Toshihiro Shimizu 890ddd
	commChunk.write(os);
Toshihiro Shimizu 890ddd
	ssndChunk.write(os);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}