|
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 |
}
|