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
Shinya Kitaoka 120a6e
    //------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    void
Shinya Kitaoka 120a6e
    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
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;
Shinya Kitaoka 120a6e
    bool signedSample  = (fmtChunk->m_bitPerSample != 8);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    track = TSoundTrack::create((int)fmtChunk->m_sampleRate,
Shinya Kitaoka 120a6e
                                fmtChunk->m_bitPerSample, fmtChunk->m_chans,
Shinya Kitaoka 120a6e
                                sampleCount, signedSample);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (track) {
Shinya Kitaoka 120a6e
      switch (fmtChunk->m_bitPerSample) {
Shinya Kitaoka 120a6e
      case 8:
Shinya Kitaoka 120a6e
        memcpy((void *)track->getRawData(),
Shinya Kitaoka 120a6e
               (void *)(dataChunk->m_samples.get()),
Shinya Kitaoka 120a6e
               sampleCount * fmtChunk->m_bytesPerSample);
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case 16:
Shinya Kitaoka 120a6e
        if (!TNZ_LITTLE_ENDIAN)
Shinya Kitaoka 120a6e
          swapAndCopySamples((short *)dataChunk->m_samples.get(),
Shinya Kitaoka 120a6e
                             (short *)track->getRawData(),
Shinya Kitaoka 120a6e
                             sampleCount * fmtChunk->m_chans);
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          memcpy((void *)track->getRawData(),
Shinya Kitaoka 120a6e
                 (void *)(dataChunk->m_samples.get()),
Shinya Kitaoka 120a6e
                 sampleCount * fmtChunk->m_bytesPerSample);
Shinya Kitaoka 120a6e
        //#endif
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case 24:
Shinya Kitaoka 120a6e
        if (!TNZ_LITTLE_ENDIAN) {
Shinya Kitaoka 120a6e
          UCHAR *begin = (UCHAR *)track->getRawData();
Shinya Kitaoka 120a6e
          for (int i = 0; i < (int)(sampleCount * fmtChunk->m_chans); ++i) {
Shinya Kitaoka 120a6e
            *(begin + 4 * i)     = 0;
Shinya Kitaoka 120a6e
            *(begin + 4 * i + 1) = *(dataChunk->m_samples.get() + 3 * i + 2);
Shinya Kitaoka 120a6e
            *(begin + 4 * i + 2) = *(dataChunk->m_samples.get() + 3 * i + 1);
Shinya Kitaoka 120a6e
            *(begin + 4 * i + 3) = *(dataChunk->m_samples.get() + 3 * i);
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          UCHAR *begin = (UCHAR *)track->getRawData();
Shinya Kitaoka 120a6e
          for (int i = 0; i < (int)(sampleCount * fmtChunk->m_chans); ++i) {
Shinya Kitaoka 120a6e
            memcpy((void *)(begin + 4 * i),
Shinya Kitaoka 120a6e
                   (void *)(dataChunk->m_samples.get() + 3 * i), 3);
Shinya Kitaoka 120a6e
            *(begin + 4 * i + 3) = 0;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        //#endif
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Toshihiro Shimizu 890ddd
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    /*if (!TNZ_LITTLE_ENDIAN)
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
if (fmtChunk->m_bitPerSample > 8)
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
assert(fmtChunk->m_bitPerSample <= 16);
Shinya Kitaoka 120a6e
swapAndCopySamples(
Shinya Kitaoka 120a6e
(short*)dataChunk->m_samples,
Shinya Kitaoka 120a6e
(short*)track->getRawData(),
Shinya Kitaoka 120a6e
sampleCount*fmtChunk->m_chans);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
else
Shinya Kitaoka 120a6e
memcpy(
Shinya Kitaoka 120a6e
    (void*)track->getRawData(),
Shinya Kitaoka 120a6e
(void*)(dataChunk->m_samples),
Shinya Kitaoka 120a6e
sampleCount*fmtChunk->m_bytesPerSample);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
else
Shinya Kitaoka 120a6e
memcpy(
Shinya Kitaoka 120a6e
(void*)track->getRawData(),
Shinya Kitaoka 120a6e
(void*)(dataChunk->m_samples),
Shinya Kitaoka 120a6e
sampleCount*fmtChunk->m_bytesPerSample);*/
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
Shinya Kitaoka 120a6e
  fmtChunk.m_encodingType      = 1;  // PCM
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
Toshihiro Shimizu 890ddd
// era if defined(MACOSX)
Toshihiro Shimizu 890ddd
#if (!TNZ_LITTLE_ENDIAN)
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    if (fmtChunk.m_bitPerSample == 8)
MCCCS a0ce32
      memcpy((void *)waveData, (void *)sndtrack->getRawData(), soundDataLength);
Shinya Kitaoka 120a6e
    else if (fmtChunk.m_bitPerSample == 16) {
Shinya Kitaoka 120a6e
      swapAndCopySamples((short *)sndtrack->getRawData(), (short *)waveData,
Shinya Kitaoka 120a6e
                         sndtrack->getSampleCount() * fmtChunk.m_chans);
Shinya Kitaoka 120a6e
    } else if (fmtChunk.m_bitPerSample == 24) {  // swap e togliere quarto byte
Shinya Kitaoka 120a6e
      UCHAR *begin = (UCHAR *)sndtrack->getRawData();
Shinya Kitaoka 120a6e
      for (int i = 0; i < (int)sndtrack->getSampleCount() * fmtChunk.m_chans;
Shinya Kitaoka 120a6e
           ++i) {
Shinya Kitaoka 120a6e
        *(waveData + 3 * i)     = *(begin + 4 * i + 3);
Shinya Kitaoka 120a6e
        *(waveData + 3 * i + 1) = *(begin + 4 * i + 2);
Shinya Kitaoka 120a6e
        *(waveData + 3 * i + 2) = *(begin + 4 * i + 1);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    if (fmtChunk.m_bitPerSample != 24)
Shinya Kitaoka 120a6e
      memcpy((void *)waveData.get(), (void *)sndtrack->getRawData(),
MCCCS a0ce32
             soundDataLength);
Shinya Kitaoka 120a6e
    else {  // togliere quarto byte
Shinya Kitaoka 120a6e
      UCHAR *begin = (UCHAR *)sndtrack->getRawData();
Shinya Kitaoka 120a6e
      for (int i = 0; i < (int)sndtrack->getSampleCount() * fmtChunk.m_chans;
Shinya Kitaoka 120a6e
           ++i) {
Shinya Kitaoka 120a6e
        *(waveData.get() + 3 * i)     = *(begin + 4 * i);
Shinya Kitaoka 120a6e
        *(waveData.get() + 3 * i + 1) = *(begin + 4 * i + 1);
Shinya Kitaoka 120a6e
        *(waveData.get() + 3 * i + 2) = *(begin + 4 * i + 2);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
#endif
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
}