Shinya Kitaoka 6a4e01
#include <memory></memory>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tmachine.h"
Toshihiro Shimizu 890ddd
#include "tsio_wav.h"
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
#include "tfilepath_io.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace std;
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
	//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void
Toshihiro Shimizu 890ddd
	swapAndCopySamples(short *srcBuffer, short *dstBuffer, TINT32 sampleCount);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TWAVChunk: classe base per i vari chunk WAV
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class TWAVChunk
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	static TINT32 HDR_LENGTH;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	string m_name;
Toshihiro Shimizu 890ddd
	TINT32 m_length; // lunghezza del chunk in byte
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TWAVChunk(string name, TINT32 length)
Toshihiro Shimizu 890ddd
		: m_name(name), m_length(length) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	virtual ~TWAVChunk() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	virtual bool read(Tifstream &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(Tifstream &is)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		is.seekg(m_length, ios::cur);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static bool readHeader(Tifstream &is, string &name, TINT32 &length)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		char cName[5];
Toshihiro Shimizu 890ddd
		TINT32 len = 0;
Toshihiro Shimizu 890ddd
		memset(cName, 0, sizeof(cName));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		is.read(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
		if (is.fail())
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// il formato WAV memorizza i dati come little-endian
Toshihiro Shimizu 890ddd
		// se la piattaforma non e' little-endian bisogna scambiare i byte
Toshihiro Shimizu 890ddd
		if (!TNZ_LITTLE_ENDIAN)
Toshihiro Shimizu 890ddd
			len = swapTINT32(len);
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
TINT32 TWAVChunk::HDR_LENGTH = 8;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  FMT Chunk: Chunk contenente le informazioni sulla traccia
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class TFMTChunk : public TWAVChunk
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	static TINT32 LENGTH;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	USHORT m_encodingType; // PCM, ...
Toshihiro Shimizu 890ddd
	USHORT m_chans;		   // numero di canali
Toshihiro Shimizu 890ddd
	TUINT32 m_sampleRate;
Toshihiro Shimizu 890ddd
	TUINT32 m_avgBytesPerSecond;
Toshihiro Shimizu 890ddd
	USHORT m_bytesPerSample;
Toshihiro Shimizu 890ddd
	USHORT m_bitPerSample;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TFMTChunk(TINT32 length)
Toshihiro Shimizu 890ddd
		: TWAVChunk("fmt ", length) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	virtual bool read(Tifstream &is)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		is.read((char *)&m_encodingType, sizeof(m_encodingType));
Toshihiro Shimizu 890ddd
		is.read((char *)&m_chans, sizeof(m_chans));
Toshihiro Shimizu 890ddd
		is.read((char *)&m_sampleRate, sizeof(m_sampleRate));
Toshihiro Shimizu 890ddd
		is.read((char *)&m_avgBytesPerSecond, sizeof(m_avgBytesPerSecond));
Toshihiro Shimizu 890ddd
		is.read((char *)&m_bytesPerSample, sizeof(m_bytesPerSample));
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_encodingType = swapUshort(m_encodingType);
Toshihiro Shimizu 890ddd
			m_chans = swapUshort(m_chans);
Toshihiro Shimizu 890ddd
			m_sampleRate = swapTINT32(m_sampleRate);
Toshihiro Shimizu 890ddd
			m_avgBytesPerSecond = swapTINT32(m_avgBytesPerSecond);
Toshihiro Shimizu 890ddd
			m_bytesPerSample = swapUshort(m_bytesPerSample);
Toshihiro Shimizu 890ddd
			m_bitPerSample = swapUshort(m_bitPerSample);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		assert(m_length >= 16);
Toshihiro Shimizu 890ddd
		if (m_length > 16)
Toshihiro Shimizu 890ddd
			is.seekg((long)is.tellg() + m_length - 16);
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
		TUINT32 length = m_length;
Toshihiro Shimizu 890ddd
		USHORT type = m_encodingType;
Toshihiro Shimizu 890ddd
		USHORT chans = m_chans;
Toshihiro Shimizu 890ddd
		TUINT32 sampleRate = m_sampleRate;
Toshihiro Shimizu 890ddd
		TUINT32 bytesPerSecond = m_avgBytesPerSecond;
Toshihiro Shimizu 890ddd
		USHORT bytesPerSample = m_bytesPerSample;
Toshihiro Shimizu 890ddd
		USHORT bitPerSample = m_bitPerSample;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!TNZ_LITTLE_ENDIAN) {
Toshihiro Shimizu 890ddd
			length = swapTINT32(length);
Toshihiro Shimizu 890ddd
			type = swapUshort(type);
Toshihiro Shimizu 890ddd
			chans = swapUshort(chans);
Toshihiro Shimizu 890ddd
			sampleRate = swapTINT32(sampleRate);
Toshihiro Shimizu 890ddd
			bytesPerSecond = swapTINT32(bytesPerSecond);
Toshihiro Shimizu 890ddd
			bytesPerSample = swapUshort(bytesPerSample);
Toshihiro Shimizu 890ddd
			bitPerSample = swapUshort(bitPerSample);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		os.write((char *)"fmt ", 4);
Toshihiro Shimizu 890ddd
		os.write((char *)&length, sizeof(length));
Toshihiro Shimizu 890ddd
		os.write((char *)&type, sizeof(type));
Toshihiro Shimizu 890ddd
		os.write((char *)&chans, sizeof(chans));
Toshihiro Shimizu 890ddd
		os.write((char *)&sampleRate, sizeof(sampleRate));
Toshihiro Shimizu 890ddd
		os.write((char *)&bytesPerSecond, sizeof(bytesPerSecond));
Toshihiro Shimizu 890ddd
		os.write((char *)&bytesPerSample, sizeof(bytesPerSample));
Toshihiro Shimizu 890ddd
		os.write((char *)&bitPerSample, sizeof(bitPerSample));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TINT32 TFMTChunk::LENGTH = TWAVChunk::HDR_LENGTH + 16;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  DATA Chunk: Chunk contenente i campioni
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class TDATAChunk : public TWAVChunk
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 6a4e01
	std::unique_ptr<uchar[]> m_samples;</uchar[]>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TDATAChunk(TINT32 length)
Toshihiro Shimizu 890ddd
		: TWAVChunk("data", length) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool read(Tifstream &is)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// alloca il buffer dei campioni
Shinya Kitaoka 6a4e01
		m_samples.reset(new UCHAR[m_length]);
Toshihiro Shimizu 890ddd
		if (!m_samples)
Toshihiro Shimizu 890ddd
			return false;
Shinya Kitaoka 6a4e01
		is.read((char *)m_samples.get(), m_length);
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
Toshihiro Shimizu 890ddd
		if (!TNZ_LITTLE_ENDIAN) {
Toshihiro Shimizu 890ddd
			length = swapTINT32(length);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		os.write((char *)"data", 4);
Toshihiro Shimizu 890ddd
		os.write((char *)&length, sizeof(length));
Shinya Kitaoka 6a4e01
		os.write((char *)m_samples.get(), m_length);
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TSoundTrackReaderWav::TSoundTrackReaderWav(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 TSoundTrackReaderWav::load()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	char chunkName[5];
Toshihiro Shimizu 890ddd
	char RIFFType[5];
Toshihiro Shimizu 890ddd
	TINT32 chunkLength;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Tifstream is(m_path);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!is)
Toshihiro Shimizu 890ddd
		throw TException(m_path.getWideString() + L" : File doesn't exist");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// legge il nome del chunk
Toshihiro Shimizu 890ddd
	is.read((char *)&chunkName, sizeof(chunkName) - 1);
Toshihiro Shimizu 890ddd
	chunkName[4] = '\0';
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// legge la lunghezza del chunk
Toshihiro Shimizu 890ddd
	is.read((char *)&chunkLength, sizeof(chunkLength));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!TNZ_LITTLE_ENDIAN)
Toshihiro Shimizu 890ddd
		chunkLength = swapTINT32(chunkLength);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// legge il RIFFType
Toshihiro Shimizu 890ddd
	is.read((char *)&RIFFType, sizeof(RIFFType) - 1);
Toshihiro Shimizu 890ddd
	RIFFType[4] = '\0';
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// per i .wav il RIFFType DEVE essere uguale a "WAVE"
Toshihiro Shimizu 890ddd
	if ((string(RIFFType, 4) != "WAVE"))
Toshihiro Shimizu 890ddd
		throw TException("The WAV file doesn't contain the WAVE form");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TFMTChunk *fmtChunk = 0;
Toshihiro Shimizu 890ddd
	TDATAChunk *dataChunk = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	while (!is.eof()) {
Toshihiro Shimizu 890ddd
		string name = "";
Toshihiro Shimizu 890ddd
		TINT32 length = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool ret = TWAVChunk::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 FMT e DATA
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (name == "fmt ") {
Toshihiro Shimizu 890ddd
			// legge i dati del chunk FMT
Toshihiro Shimizu 890ddd
			fmtChunk = new TFMTChunk(length);
Toshihiro Shimizu 890ddd
			fmtChunk->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 & 1) {
Toshihiro Shimizu 890ddd
				is.seekg((long)is.tellg() + 1);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		} else if (name == "data") {
Toshihiro Shimizu 890ddd
			// legge i dati del chunk DATA
Toshihiro Shimizu 890ddd
			dataChunk = new TDATAChunk(length);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			dataChunk->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 & 1) {
Toshihiro Shimizu 890ddd
				is.seekg((long)is.tellg() + 1);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			// spostati nello stream di un numero di byte pari a length
Toshihiro Shimizu 890ddd
			if (length & 1)
Toshihiro Shimizu 890ddd
				is.seekg((long)is.tellg() + (long)length + 1);
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				is.seekg((long)is.tellg() + (long)length);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TSoundTrackP track = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (fmtChunk && dataChunk) {
Toshihiro Shimizu 890ddd
		TINT32 sampleCount = dataChunk->m_length / fmtChunk->m_bytesPerSample;
Toshihiro Shimizu 890ddd
		bool signedSample = (fmtChunk->m_bitPerSample != 8);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		track = TSoundTrack::create(
Toshihiro Shimizu 890ddd
			(int)fmtChunk->m_sampleRate,
Toshihiro Shimizu 890ddd
			fmtChunk->m_bitPerSample,
Toshihiro Shimizu 890ddd
			fmtChunk->m_chans,
Toshihiro Shimizu 890ddd
			sampleCount, signedSample);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (track) {
Toshihiro Shimizu 890ddd
			switch (fmtChunk->m_bitPerSample) {
Toshihiro Shimizu 890ddd
			case 8:
Toshihiro Shimizu 890ddd
				memcpy(
Toshihiro Shimizu 890ddd
					(void *)track->getRawData(),
Shinya Kitaoka 6a4e01
					(void *)(dataChunk->m_samples.get()),
Toshihiro Shimizu 890ddd
					sampleCount * fmtChunk->m_bytesPerSample);
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			case 16:
Toshihiro Shimizu 890ddd
				if (!TNZ_LITTLE_ENDIAN)
Toshihiro Shimizu 890ddd
					swapAndCopySamples(
Shinya Kitaoka 6a4e01
						(short *)dataChunk->m_samples.get(),
Toshihiro Shimizu 890ddd
						(short *)track->getRawData(),
Toshihiro Shimizu 890ddd
						sampleCount * fmtChunk->m_chans);
Toshihiro Shimizu 890ddd
				else
Toshihiro Shimizu 890ddd
					memcpy(
Toshihiro Shimizu 890ddd
						(void *)track->getRawData(),
Shinya Kitaoka 6a4e01
						(void *)(dataChunk->m_samples.get()),
Toshihiro Shimizu 890ddd
						sampleCount * fmtChunk->m_bytesPerSample);
Toshihiro Shimizu 890ddd
				//#endif
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			case 24:
Toshihiro Shimizu 890ddd
				if (!TNZ_LITTLE_ENDIAN) {
Toshihiro Shimizu 890ddd
					UCHAR *begin = (UCHAR *)track->getRawData();
Toshihiro Shimizu 890ddd
					for (int i = 0; i < (int)(sampleCount * fmtChunk->m_chans); ++i) {
Toshihiro Shimizu 890ddd
						*(begin + 4 * i) = 0;
Toshihiro Shimizu 890ddd
						*(begin + 4 * i + 1) =
Shinya Kitaoka 6a4e01
							*(dataChunk->m_samples.get() + 3 * i + 2);
Toshihiro Shimizu 890ddd
						*(begin + 4 * i + 2) =
Shinya Kitaoka 6a4e01
							*(dataChunk->m_samples.get() + 3 * i + 1);
Toshihiro Shimizu 890ddd
						*(begin + 4 * i + 3) =
Shinya Kitaoka 6a4e01
							*(dataChunk->m_samples.get() + 3 * i);
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				} else {
Toshihiro Shimizu 890ddd
					UCHAR *begin = (UCHAR *)track->getRawData();
Toshihiro Shimizu 890ddd
					for (int i = 0; i < (int)(sampleCount * fmtChunk->m_chans); ++i) {
Toshihiro Shimizu 890ddd
						memcpy(
Toshihiro Shimizu 890ddd
							(void *)(begin + 4 * i),
Shinya Kitaoka 6a4e01
							(void *)(dataChunk->m_samples.get() + 3 * i), 3);
Toshihiro Shimizu 890ddd
						*(begin + 4 * i + 3) = 0;
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				//#endif
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		/*if (!TNZ_LITTLE_ENDIAN)
Toshihiro Shimizu 890ddd
    {
Toshihiro Shimizu 890ddd
      if (fmtChunk->m_bitPerSample > 8)
Toshihiro Shimizu 890ddd
      {
Toshihiro Shimizu 890ddd
        assert(fmtChunk->m_bitPerSample <= 16);
Toshihiro Shimizu 890ddd
        swapAndCopySamples(
Toshihiro Shimizu 890ddd
          (short*)dataChunk->m_samples, 
Toshihiro Shimizu 890ddd
          (short*)track->getRawData(), 
Toshihiro Shimizu 890ddd
          sampleCount*fmtChunk->m_chans);
Toshihiro Shimizu 890ddd
      }
Toshihiro Shimizu 890ddd
      else
Toshihiro Shimizu 890ddd
        memcpy(
Toshihiro Shimizu 890ddd
	        (void*)track->getRawData(), 
Toshihiro Shimizu 890ddd
          (void*)(dataChunk->m_samples), 
Toshihiro Shimizu 890ddd
          sampleCount*fmtChunk->m_bytesPerSample);
Toshihiro Shimizu 890ddd
    }
Toshihiro Shimizu 890ddd
    else
Toshihiro Shimizu 890ddd
      memcpy(
Toshihiro Shimizu 890ddd
        (void*)track->getRawData(), 
Toshihiro Shimizu 890ddd
        (void*)(dataChunk->m_samples), 
Toshihiro Shimizu 890ddd
        sampleCount*fmtChunk->m_bytesPerSample);*/
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (fmtChunk)
Toshihiro Shimizu 890ddd
		delete fmtChunk;
Toshihiro Shimizu 890ddd
	if (dataChunk)
Toshihiro Shimizu 890ddd
		delete dataChunk;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return track;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TSoundTrackWriterWav::TSoundTrackWriterWav(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 TSoundTrackWriterWav::save(const TSoundTrackP &sndtrack)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!sndtrack)
Toshihiro Shimizu 890ddd
		throw TException(L"Unable to save the soundtrack: " + m_path.getWideString());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (sndtrack->getBitPerSample() == 8 && sndtrack->isSampleSigned())
Toshihiro Shimizu 890ddd
		throw TException("The format (8 bit signed) is incompatible with WAV file");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TINT32 soundDataLenght = (TINT32)(sndtrack->getSampleCount() * (sndtrack->getBitPerSample() / 8) * sndtrack->getChannelCount() /*sndtrack->getSampleSize()*/);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TINT32 RIFFChunkLength = TFMTChunk::LENGTH + TWAVChunk::HDR_LENGTH + soundDataLenght;
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
	TFMTChunk fmtChunk(16);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	fmtChunk.m_encodingType = 1; // PCM
Toshihiro Shimizu 890ddd
	fmtChunk.m_chans = sndtrack->getChannelCount();
Toshihiro Shimizu 890ddd
	fmtChunk.m_sampleRate = sndtrack->getSampleRate();
Toshihiro Shimizu 890ddd
	fmtChunk.m_avgBytesPerSecond = (sndtrack->getBitPerSample() / 8) * fmtChunk.m_chans * sndtrack->getSampleRate();
Toshihiro Shimizu 890ddd
	//sndtrack->getSampleSize()*sndtrack->getSampleRate();
Toshihiro Shimizu 890ddd
	fmtChunk.m_bytesPerSample = (sndtrack->getBitPerSample() / 8) * fmtChunk.m_chans; //sndtrack->getSampleSize();
Toshihiro Shimizu 890ddd
	fmtChunk.m_bitPerSample = sndtrack->getBitPerSample();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TDATAChunk dataChunk(soundDataLenght);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 6a4e01
	std::unique_ptr<uchar[]> waveData(new UCHAR[soundDataLenght]);</uchar[]>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!TNZ_LITTLE_ENDIAN)
Toshihiro Shimizu 890ddd
		RIFFChunkLength = swapTINT32(RIFFChunkLength);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// era if defined(MACOSX)
Toshihiro Shimizu 890ddd
#if (!TNZ_LITTLE_ENDIAN)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (fmtChunk.m_bitPerSample == 8)
Toshihiro Shimizu 890ddd
			memcpy(
Toshihiro Shimizu 890ddd
				(void *)waveData,
Toshihiro Shimizu 890ddd
				(void *)sndtrack->getRawData(),
Toshihiro Shimizu 890ddd
				soundDataLenght);
Toshihiro Shimizu 890ddd
		else if (fmtChunk.m_bitPerSample == 16) {
Toshihiro Shimizu 890ddd
			swapAndCopySamples(
Toshihiro Shimizu 890ddd
				(short *)sndtrack->getRawData(),
Toshihiro Shimizu 890ddd
				(short *)waveData,
Toshihiro Shimizu 890ddd
				sndtrack->getSampleCount() * fmtChunk.m_chans);
Toshihiro Shimizu 890ddd
		} else if (fmtChunk.m_bitPerSample == 24) { //swap e togliere quarto byte
Toshihiro Shimizu 890ddd
			UCHAR *begin = (UCHAR *)sndtrack->getRawData();
Toshihiro Shimizu 890ddd
			for (int i = 0; i < (int)sndtrack->getSampleCount() * fmtChunk.m_chans; ++i) {
Toshihiro Shimizu 890ddd
				*(waveData + 3 * i) = *(begin + 4 * i + 3);
Toshihiro Shimizu 890ddd
				*(waveData + 3 * i + 1) = *(begin + 4 * i + 2);
Toshihiro Shimizu 890ddd
				*(waveData + 3 * i + 2) = *(begin + 4 * i + 1);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (fmtChunk.m_bitPerSample != 24)
Toshihiro Shimizu 890ddd
			memcpy(
Shinya Kitaoka 6a4e01
				(void *)waveData.get(),
Toshihiro Shimizu 890ddd
				(void *)sndtrack->getRawData(),
Toshihiro Shimizu 890ddd
				soundDataLenght);
Toshihiro Shimizu 890ddd
		else { //togliere quarto byte
Toshihiro Shimizu 890ddd
			UCHAR *begin = (UCHAR *)sndtrack->getRawData();
Toshihiro Shimizu 890ddd
			for (int i = 0; i < (int)sndtrack->getSampleCount() * fmtChunk.m_chans; ++i) {
Shinya Kitaoka 6a4e01
				*(waveData.get() + 3 * i) = *(begin + 4 * i);
Shinya Kitaoka 6a4e01
				*(waveData.get() + 3 * i + 1) = *(begin + 4 * i + 1);
Shinya Kitaoka 6a4e01
				*(waveData.get() + 3 * i + 2) = *(begin + 4 * i + 2);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 6a4e01
	dataChunk.m_samples = std::move(waveData);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	os.write("RIFF", 4);
Toshihiro Shimizu 890ddd
	os.write((char *)&RIFFChunkLength, sizeof(TINT32));
Toshihiro Shimizu 890ddd
	os.write("WAVE", 4);
Toshihiro Shimizu 890ddd
	fmtChunk.write(os);
Toshihiro Shimizu 890ddd
	dataChunk.write(os);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}