|
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"
|
|
justburner |
9369f1 |
#include "tsioutils.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 |
// TWAVChunk: classe base per i vari chunk WAV
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
class TWAVChunk {
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
static TINT32 HDR_LENGTH;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
string m_name;
|
|
Shinya Kitaoka |
120a6e |
TINT32 m_length; // lunghezza del chunk in byte
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TWAVChunk(string name, TINT32 length) : m_name(name), m_length(length) {}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
virtual ~TWAVChunk() {}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
virtual bool read(Tifstream &is) {
|
|
Shinya Kitaoka |
120a6e |
skip(is);
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void skip(Tifstream &is) { is.seekg(m_length, ios::cur); }
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
static bool readHeader(Tifstream &is, string &name, TINT32 &length) {
|
|
Shinya Kitaoka |
120a6e |
char cName[5];
|
|
Shinya Kitaoka |
120a6e |
TINT32 len = 0;
|
|
Shinya Kitaoka |
120a6e |
memset(cName, 0, sizeof(cName));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
is.read(cName, 4);
|
|
Shinya Kitaoka |
120a6e |
if (is.fail()) return false;
|
|
Shinya Kitaoka |
120a6e |
cName[4] = '\0';
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
is.read((char *)&len, sizeof(len));
|
|
Shinya Kitaoka |
120a6e |
if (is.fail()) return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// il formato WAV memorizza i dati come little-endian
|
|
Shinya Kitaoka |
120a6e |
// se la piattaforma non e' little-endian bisogna scambiare i byte
|
|
Shinya Kitaoka |
120a6e |
if (!TNZ_LITTLE_ENDIAN) len = swapTINT32(len);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
name = string(cName);
|
|
Shinya Kitaoka |
120a6e |
length = len;
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
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 |
|
|
Shinya Kitaoka |
d1f6c4 |
class TFMTChunk final : public TWAVChunk {
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
static TINT32 LENGTH;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
USHORT m_encodingType; // PCM, ...
|
|
Shinya Kitaoka |
120a6e |
USHORT m_chans; // numero di canali
|
|
Shinya Kitaoka |
120a6e |
TUINT32 m_sampleRate;
|
|
Shinya Kitaoka |
120a6e |
TUINT32 m_avgBytesPerSecond;
|
|
Shinya Kitaoka |
120a6e |
USHORT m_bytesPerSample;
|
|
Shinya Kitaoka |
120a6e |
USHORT m_bitPerSample;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TFMTChunk(TINT32 length) : TWAVChunk("fmt ", length) {}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
473e70 |
bool read(Tifstream &is) override {
|
|
Shinya Kitaoka |
120a6e |
is.read((char *)&m_encodingType, sizeof(m_encodingType));
|
|
Shinya Kitaoka |
120a6e |
is.read((char *)&m_chans, sizeof(m_chans));
|
|
Shinya Kitaoka |
120a6e |
is.read((char *)&m_sampleRate, sizeof(m_sampleRate));
|
|
Shinya Kitaoka |
120a6e |
is.read((char *)&m_avgBytesPerSecond, sizeof(m_avgBytesPerSecond));
|
|
Shinya Kitaoka |
120a6e |
is.read((char *)&m_bytesPerSample, sizeof(m_bytesPerSample));
|
|
Shinya Kitaoka |
120a6e |
is.read((char *)&m_bitPerSample, sizeof(m_bitPerSample));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!TNZ_LITTLE_ENDIAN) {
|
|
Shinya Kitaoka |
120a6e |
m_encodingType = swapUshort(m_encodingType);
|
|
Shinya Kitaoka |
120a6e |
m_chans = swapUshort(m_chans);
|
|
Shinya Kitaoka |
120a6e |
m_sampleRate = swapTINT32(m_sampleRate);
|
|
Shinya Kitaoka |
120a6e |
m_avgBytesPerSecond = swapTINT32(m_avgBytesPerSecond);
|
|
Shinya Kitaoka |
120a6e |
m_bytesPerSample = swapUshort(m_bytesPerSample);
|
|
Shinya Kitaoka |
120a6e |
m_bitPerSample = swapUshort(m_bitPerSample);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
assert(m_length >= 16);
|
|
Shinya Kitaoka |
120a6e |
if (m_length > 16) is.seekg((long)is.tellg() + m_length - 16);
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
bool write(ofstream &os) {
|
|
Shinya Kitaoka |
120a6e |
TUINT32 length = m_length;
|
|
Shinya Kitaoka |
120a6e |
USHORT type = m_encodingType;
|
|
Shinya Kitaoka |
120a6e |
USHORT chans = m_chans;
|
|
Shinya Kitaoka |
120a6e |
TUINT32 sampleRate = m_sampleRate;
|
|
Shinya Kitaoka |
120a6e |
TUINT32 bytesPerSecond = m_avgBytesPerSecond;
|
|
Shinya Kitaoka |
120a6e |
USHORT bytesPerSample = m_bytesPerSample;
|
|
Shinya Kitaoka |
120a6e |
USHORT bitPerSample = m_bitPerSample;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!TNZ_LITTLE_ENDIAN) {
|
|
Shinya Kitaoka |
120a6e |
length = swapTINT32(length);
|
|
Shinya Kitaoka |
120a6e |
type = swapUshort(type);
|
|
Shinya Kitaoka |
120a6e |
chans = swapUshort(chans);
|
|
Shinya Kitaoka |
120a6e |
sampleRate = swapTINT32(sampleRate);
|
|
Shinya Kitaoka |
120a6e |
bytesPerSecond = swapTINT32(bytesPerSecond);
|
|
Shinya Kitaoka |
120a6e |
bytesPerSample = swapUshort(bytesPerSample);
|
|
Shinya Kitaoka |
120a6e |
bitPerSample = swapUshort(bitPerSample);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
os.write((char *)"fmt ", 4);
|
|
Shinya Kitaoka |
120a6e |
os.write((char *)&length, sizeof(length));
|
|
Shinya Kitaoka |
120a6e |
os.write((char *)&type, sizeof(type));
|
|
Shinya Kitaoka |
120a6e |
os.write((char *)&chans, sizeof(chans));
|
|
Shinya Kitaoka |
120a6e |
os.write((char *)&sampleRate, sizeof(sampleRate));
|
|
Shinya Kitaoka |
120a6e |
os.write((char *)&bytesPerSecond, sizeof(bytesPerSecond));
|
|
Shinya Kitaoka |
120a6e |
os.write((char *)&bytesPerSample, sizeof(bytesPerSample));
|
|
Shinya Kitaoka |
120a6e |
os.write((char *)&bitPerSample, sizeof(bitPerSample));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
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 |
|
|
Shinya Kitaoka |
d1f6c4 |
class TDATAChunk final : public TWAVChunk {
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
std::unique_ptr<uchar[]> m_samples;</uchar[]>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TDATAChunk(TINT32 length) : TWAVChunk("data", length) {}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
473e70 |
bool read(Tifstream &is) override {
|
|
Shinya Kitaoka |
120a6e |
// alloca il buffer dei campioni
|
|
Shinya Kitaoka |
120a6e |
m_samples.reset(new UCHAR[m_length]);
|
|
Shinya Kitaoka |
120a6e |
if (!m_samples) return false;
|
|
Shinya Kitaoka |
120a6e |
is.read((char *)m_samples.get(), m_length);
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
bool write(ofstream &os) {
|
|
Shinya Kitaoka |
120a6e |
TINT32 length = m_length;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (!TNZ_LITTLE_ENDIAN) {
|
|
Shinya Kitaoka |
120a6e |
length = swapTINT32(length);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
os.write((char *)"data", 4);
|
|
Shinya Kitaoka |
120a6e |
os.write((char *)&length, sizeof(length));
|
|
Shinya Kitaoka |
120a6e |
os.write((char *)m_samples.get(), m_length);
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackReaderWav::TSoundTrackReaderWav(const TFilePath &fp)
|
|
Shinya Kitaoka |
120a6e |
: TSoundTrackReader(fp) {}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TSoundTrackP TSoundTrackReaderWav::load() {
|
|
Shinya Kitaoka |
120a6e |
char chunkName[5];
|
|
Shinya Kitaoka |
120a6e |
char RIFFType[5];
|
|
Shinya Kitaoka |
120a6e |
TINT32 chunkLength;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
Tifstream is(m_path);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!is) throw TException(m_path.getWideString() + L" : File doesn't exist");
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// legge il nome del chunk
|
|
Shinya Kitaoka |
120a6e |
is.read((char *)&chunkName, sizeof(chunkName) - 1);
|
|
Shinya Kitaoka |
120a6e |
chunkName[4] = '\0';
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// legge la lunghezza del chunk
|
|
Shinya Kitaoka |
120a6e |
is.read((char *)&chunkLength, sizeof(chunkLength));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!TNZ_LITTLE_ENDIAN) chunkLength = swapTINT32(chunkLength);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// legge il RIFFType
|
|
Shinya Kitaoka |
120a6e |
is.read((char *)&RIFFType, sizeof(RIFFType) - 1);
|
|
Shinya Kitaoka |
120a6e |
RIFFType[4] = '\0';
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// per i .wav il RIFFType DEVE essere uguale a "WAVE"
|
|
Shinya Kitaoka |
120a6e |
if ((string(RIFFType, 4) != "WAVE"))
|
|
Shinya Kitaoka |
120a6e |
throw TException("The WAV file doesn't contain the WAVE form");
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TFMTChunk *fmtChunk = 0;
|
|
Shinya Kitaoka |
120a6e |
TDATAChunk *dataChunk = 0;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
while (!is.eof()) {
|
|
Shinya Kitaoka |
120a6e |
string name = "";
|
|
Shinya Kitaoka |
120a6e |
TINT32 length = 0;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
bool ret = TWAVChunk::readHeader(is, name, length);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!ret) break;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// legge solo i chunk che ci interessano, ossia FMT e DATA
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (name == "fmt ") {
|
|
Shinya Kitaoka |
120a6e |
// legge i dati del chunk FMT
|
|
Shinya Kitaoka |
120a6e |
fmtChunk = new TFMTChunk(length);
|
|
Shinya Kitaoka |
120a6e |
fmtChunk->read(is);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// considera il byte di pad alla fine del chunk nel caso
|
|
Shinya Kitaoka |
120a6e |
// in cui la lunghezza di questi e' dispari
|
|
Shinya Kitaoka |
120a6e |
if (length & 1) {
|
|
Shinya Kitaoka |
120a6e |
is.seekg((long)is.tellg() + 1);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Shinya Kitaoka |
120a6e |
} else if (name == "data") {
|
|
Shinya Kitaoka |
120a6e |
// legge i dati del chunk DATA
|
|
Shinya Kitaoka |
120a6e |
dataChunk = new TDATAChunk(length);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
dataChunk->read(is);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// considera il byte di pad alla fine del chunk nel caso
|
|
Shinya Kitaoka |
120a6e |
// in cui la lunghezza di questi e' dispari
|
|
Shinya Kitaoka |
120a6e |
if (length & 1) {
|
|
Shinya Kitaoka |
120a6e |
is.seekg((long)is.tellg() + 1);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
// spostati nello stream di un numero di byte pari a length
|
|
Shinya Kitaoka |
120a6e |
if (length & 1)
|
|
Shinya Kitaoka |
120a6e |
is.seekg((long)is.tellg() + (long)length + 1);
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Shinya Kitaoka |
120a6e |
is.seekg((long)is.tellg() + (long)length);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TSoundTrackP track = 0;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (fmtChunk && dataChunk) {
|
|
Shinya Kitaoka |
120a6e |
TINT32 sampleCount = dataChunk->m_length / fmtChunk->m_bytesPerSample;
|
|
justburner |
9369f1 |
int sampleType = 0;
|
|
justburner |
9369f1 |
|
|
justburner |
9369f1 |
if (fmtChunk->m_encodingType == 1) // WAVE_FORMAT_PCM
|
|
justburner |
9369f1 |
sampleType = (fmtChunk->m_bitPerSample == 8) ? TSound::UINT : TSound::INT;
|
|
justburner |
9369f1 |
else if (fmtChunk->m_encodingType == 3) // WAVE_FORMAT_IEEE_FLOAT
|
|
justburner |
9369f1 |
sampleType = TSound::FLOAT;
|
|
Shinya Kitaoka |
120a6e |
|
|
justburner |
9369f1 |
if (sampleType) // valid sample type
|
|
justburner |
9369f1 |
track = TSoundTrack::create((int)fmtChunk->m_sampleRate,
|
|
justburner |
9369f1 |
fmtChunk->m_bitPerSample, fmtChunk->m_chans,
|
|
justburner |
9369f1 |
sampleCount, sampleType);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (track) {
|
|
justburner |
9369f1 |
if (!TNZ_LITTLE_ENDIAN) {
|
|
justburner |
9369f1 |
switch (fmtChunk->m_bitPerSample) {
|
|
justburner |
9369f1 |
case 16:
|
|
justburner |
9369f1 |
swapAndCopy16Bits((short *)dataChunk->m_samples.get(),
|
|
justburner |
9369f1 |
(short *)track->getRawData(),
|
|
justburner |
9369f1 |
sampleCount * fmtChunk->m_chans);
|
|
justburner |
9369f1 |
break;
|
|
justburner |
9369f1 |
case 24:
|
|
justburner |
9369f1 |
swapAndCopy24Bits((short *)dataChunk->m_samples.get(),
|
|
justburner |
9369f1 |
(short *)track->getRawData(),
|
|
justburner |
9369f1 |
sampleCount * fmtChunk->m_chans);
|
|
justburner |
9369f1 |
break;
|
|
justburner |
9369f1 |
case 32:
|
|
justburner |
9369f1 |
swapAndCopy32Bits((TINT32 *)dataChunk->m_samples.get(),
|
|
justburner |
9369f1 |
(TINT32 *)track->getRawData(),
|
|
justburner |
9369f1 |
sampleCount * fmtChunk->m_chans);
|
|
justburner |
9369f1 |
break;
|
|
justburner |
9369f1 |
default:
|
|
Shinya Kitaoka |
120a6e |
memcpy((void *)track->getRawData(),
|
|
Shinya Kitaoka |
120a6e |
(void *)(dataChunk->m_samples.get()),
|
|
Shinya Kitaoka |
120a6e |
sampleCount * fmtChunk->m_bytesPerSample);
|
|
justburner |
9369f1 |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
justburner |
9369f1 |
} else {
|
|
justburner |
9369f1 |
memcpy((void *)track->getRawData(),
|
|
justburner |
9369f1 |
(void *)(dataChunk->m_samples.get()),
|
|
justburner |
9369f1 |
sampleCount * fmtChunk->m_bytesPerSample);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (fmtChunk) delete fmtChunk;
|
|
Shinya Kitaoka |
120a6e |
if (dataChunk) delete dataChunk;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
return track;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackWriterWav::TSoundTrackWriterWav(const TFilePath &fp)
|
|
Shinya Kitaoka |
120a6e |
: TSoundTrackWriter(fp) {}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
bool TSoundTrackWriterWav::save(const TSoundTrackP &sndtrack) {
|
|
Shinya Kitaoka |
120a6e |
if (!sndtrack)
|
|
Shinya Kitaoka |
120a6e |
throw TException(L"Unable to save the soundtrack: " +
|
|
Shinya Kitaoka |
120a6e |
m_path.getWideString());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (sndtrack->getBitPerSample() == 8 && sndtrack->isSampleSigned())
|
|
Shinya Kitaoka |
120a6e |
throw TException("The format (8 bit signed) is incompatible with WAV file");
|
|
Toshihiro Shimizu |
890ddd |
|
|
MCCCS |
a0ce32 |
TINT32 soundDataLength =
|
|
Shinya Kitaoka |
120a6e |
(TINT32)(sndtrack->getSampleCount() * (sndtrack->getBitPerSample() / 8) *
|
|
Shinya Kitaoka |
120a6e |
sndtrack->getChannelCount() /*sndtrack->getSampleSize()*/);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TINT32 RIFFChunkLength =
|
|
MCCCS |
a0ce32 |
TFMTChunk::LENGTH + TWAVChunk::HDR_LENGTH + soundDataLength;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TFileStatus fs(m_path);
|
|
Shinya Kitaoka |
120a6e |
if (fs.doesExist() && !fs.isWritable())
|
|
Shinya Kitaoka |
120a6e |
throw TException(L"Unable to save the soundtrack: " +
|
|
Shinya Kitaoka |
120a6e |
m_path.getWideString() + L" is read-only");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
Tofstream os(m_path);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TFMTChunk fmtChunk(16);
|
|
Toshihiro Shimizu |
890ddd |
|
|
justburner |
9369f1 |
fmtChunk.m_encodingType = sndtrack->getSampleType() & TSound::WMASK;
|
|
Shinya Kitaoka |
120a6e |
fmtChunk.m_chans = sndtrack->getChannelCount();
|
|
Shinya Kitaoka |
120a6e |
fmtChunk.m_sampleRate = sndtrack->getSampleRate();
|
|
Shinya Kitaoka |
120a6e |
fmtChunk.m_avgBytesPerSecond = (sndtrack->getBitPerSample() / 8) *
|
|
Shinya Kitaoka |
120a6e |
fmtChunk.m_chans * sndtrack->getSampleRate();
|
|
Shinya Kitaoka |
120a6e |
// sndtrack->getSampleSize()*sndtrack->getSampleRate();
|
|
Shinya Kitaoka |
120a6e |
fmtChunk.m_bytesPerSample = (sndtrack->getBitPerSample() / 8) *
|
|
Shinya Kitaoka |
120a6e |
fmtChunk.m_chans; // sndtrack->getSampleSize();
|
|
Shinya Kitaoka |
120a6e |
fmtChunk.m_bitPerSample = sndtrack->getBitPerSample();
|
|
Toshihiro Shimizu |
890ddd |
|
|
MCCCS |
a0ce32 |
TDATAChunk dataChunk(soundDataLength);
|
|
Toshihiro Shimizu |
890ddd |
|
|
MCCCS |
a0ce32 |
std::unique_ptr<uchar[]> waveData(new UCHAR[soundDataLength]);</uchar[]>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (!TNZ_LITTLE_ENDIAN) RIFFChunkLength = swapTINT32(RIFFChunkLength);
|
|
Toshihiro Shimizu |
890ddd |
|
|
justburner |
9369f1 |
if (!TNZ_LITTLE_ENDIAN) {
|
|
justburner |
9369f1 |
switch (fmtChunk.m_bitPerSample) {
|
|
justburner |
9369f1 |
case 16:
|
|
justburner |
9369f1 |
swapAndCopy16Bits((short *)sndtrack->getRawData(),
|
|
justburner |
9369f1 |
(short *)waveData.get(),
|
|
justburner |
9369f1 |
sndtrack->getSampleCount() * fmtChunk.m_chans);
|
|
justburner |
9369f1 |
break;
|
|
justburner |
9369f1 |
case 24:
|
|
justburner |
9369f1 |
swapAndCopy24Bits((void *)sndtrack->getRawData(), (void *)waveData.get(),
|
|
justburner |
9369f1 |
sndtrack->getSampleCount() * fmtChunk.m_chans);
|
|
justburner |
9369f1 |
break;
|
|
justburner |
9369f1 |
case 32:
|
|
justburner |
9369f1 |
swapAndCopy32Bits((TINT32 *)sndtrack->getRawData(),
|
|
justburner |
9369f1 |
(TINT32 *)waveData.get(),
|
|
justburner |
9369f1 |
sndtrack->getSampleCount() * fmtChunk.m_chans);
|
|
justburner |
9369f1 |
break;
|
|
justburner |
9369f1 |
default:
|
|
Shinya Kitaoka |
120a6e |
memcpy((void *)waveData.get(), (void *)sndtrack->getRawData(),
|
|
MCCCS |
a0ce32 |
soundDataLength);
|
|
justburner |
9369f1 |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
justburner |
9369f1 |
} else {
|
|
justburner |
9369f1 |
memcpy((void *)waveData.get(), (void *)sndtrack->getRawData(),
|
|
justburner |
9369f1 |
soundDataLength);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
justburner |
9369f1 |
|
|
Shinya Kitaoka |
120a6e |
dataChunk.m_samples = std::move(waveData);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
os.write("RIFF", 4);
|
|
Shinya Kitaoka |
120a6e |
os.write((char *)&RIFFChunkLength, sizeof(TINT32));
|
|
Shinya Kitaoka |
120a6e |
os.write("WAVE", 4);
|
|
Shinya Kitaoka |
120a6e |
fmtChunk.write(os);
|
|
Shinya Kitaoka |
120a6e |
dataChunk.write(os);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|