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