171 lines
		
	
	
	
		
			5.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			171 lines
		
	
	
	
		
			5.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "riff.h"
 | 
						|
 | 
						|
namespace RIFF{
 | 
						|
 | 
						|
  Chunk::Chunk(const void *_p, uint32_t len){
 | 
						|
    p = (const char *)_p;
 | 
						|
    if (len && len < getPayloadSize() + 8){
 | 
						|
      FAIL_MSG("Chunk %s (%" PRIu32 "b) does not fit in %" PRIu32 " bytes length!",
 | 
						|
               getType().c_str(), getPayloadSize() + 8, len);
 | 
						|
      p = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Chunk::Chunk(void *_p, const char *t, uint32_t len){
 | 
						|
    p = (const char *)_p;
 | 
						|
    memcpy((void *)p, t, 4);
 | 
						|
    Bit::htobl_le((char *)p + 4, len);
 | 
						|
  }
 | 
						|
 | 
						|
  void Chunk::toPrettyString(std::ostream &o, size_t indent) const{
 | 
						|
    if (!p){
 | 
						|
      o << std::string(indent, ' ') << "INVALID CHUNK" << std::endl;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    switch (Bit::btohl(p)){
 | 
						|
    case 0x52494646lu: // RIFF
 | 
						|
    case 0x4C495354lu: // LIST
 | 
						|
      return ListChunk(p).toPrettyString(o, indent);
 | 
						|
    case 0x666D7420: // "fmt "
 | 
						|
      return fmt(p).toPrettyString(o, indent);
 | 
						|
    case 0x66616374: // fact
 | 
						|
      return fact(p).toPrettyString(o, indent);
 | 
						|
    case 0x49534654: // ISFT
 | 
						|
      return ISFT(p).toPrettyString(o, indent);
 | 
						|
    default:
 | 
						|
      o << std::string(indent, ' ') << "[" << getType() << "] UNIMPLEMENTED ("
 | 
						|
        << (getPayloadSize() + 8) << "b)" << std::endl;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  void ListChunk::toPrettyString(std::ostream &o, size_t indent) const{
 | 
						|
    o << std::string(indent, ' ') << "[" << getType() << "] " << getIdentifier() << " ("
 | 
						|
      << (getPayloadSize() + 8) << "b):" << std::endl;
 | 
						|
    indent += 2;
 | 
						|
    uint32_t i = 12;
 | 
						|
    uint32_t len = getPayloadSize() + 8;
 | 
						|
    while (i + 8 <= len){
 | 
						|
      const Chunk C(p + i);
 | 
						|
      C.toPrettyString(o, indent);
 | 
						|
      i += C.getPayloadSize() + 8;
 | 
						|
      if (!C){return;}
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  uint16_t fmt::getFormat() const{
 | 
						|
    if (!p){return 0;}
 | 
						|
    return Bit::btohs_le(p + 8);
 | 
						|
  }
 | 
						|
  std::string fmt::getCodec() const{
 | 
						|
    switch (getFormat()){
 | 
						|
    case 0x1: return "PCM";
 | 
						|
    case 0x2: return "ADPCM";
 | 
						|
    case 0x3: return "FLOAT";
 | 
						|
    case 0x102:
 | 
						|
    case 0x172:
 | 
						|
    case 0x6: return "PCMA";
 | 
						|
    case 0x101:
 | 
						|
    case 0x171:
 | 
						|
    case 0x7: return "PCMU";
 | 
						|
    case 0x55: return "MP3";
 | 
						|
    case 0xFFFE: // Extended, not implemented
 | 
						|
    default: return "?";
 | 
						|
    }
 | 
						|
  }
 | 
						|
  uint16_t fmt::getChannels() const{
 | 
						|
    if (!p){return 0;}
 | 
						|
    return Bit::btohs_le(p + 10);
 | 
						|
  }
 | 
						|
  uint32_t fmt::getHz() const{
 | 
						|
    if (!p){return 0;}
 | 
						|
    return Bit::btohl_le(p + 12);
 | 
						|
  }
 | 
						|
  uint32_t fmt::getBPS() const{
 | 
						|
    if (!p){return 0;}
 | 
						|
    return Bit::btohl_le(p + 16);
 | 
						|
  }
 | 
						|
  uint16_t fmt::getBlockSize() const{
 | 
						|
    if (!p){return 0;}
 | 
						|
    return Bit::btohs_le(p + 20);
 | 
						|
  }
 | 
						|
  uint16_t fmt::getSize() const{
 | 
						|
    if (!p){return 0;}
 | 
						|
    return Bit::btohs_le(p + 22);
 | 
						|
  }
 | 
						|
  uint16_t fmt::getExtLen() const{
 | 
						|
    if (getPayloadSize() < 18){return 0;}
 | 
						|
    return Bit::btohs_le(p + 24);
 | 
						|
  }
 | 
						|
  uint16_t fmt::getValidBits() const{
 | 
						|
    if (getPayloadSize() < 20 || getExtLen() < 2){return 0;}
 | 
						|
    return Bit::btohs_le(p + 26);
 | 
						|
  }
 | 
						|
  uint32_t fmt::getChannelMask() const{
 | 
						|
    if (getPayloadSize() < 24 || getExtLen() < 6){return 0;}
 | 
						|
    return Bit::btohl_le(p + 28);
 | 
						|
  }
 | 
						|
  std::string fmt::getGUID() const{
 | 
						|
    if (getPayloadSize() < 40 || getExtLen() < 22){return "";}
 | 
						|
    return std::string(p + 32, 16);
 | 
						|
  }
 | 
						|
  void fmt::toPrettyString(std::ostream &o, size_t indent) const{
 | 
						|
    o << std::string(indent, ' ') << "[" << getType() << "] (" << (getPayloadSize() + 8) << "b):" << std::endl;
 | 
						|
    indent += 1;
 | 
						|
    o << std::string(indent, ' ') << "Codec: " << getCodec() << " (" << getFormat() << ")" << std::endl;
 | 
						|
    o << std::string(indent, ' ') << "Channels: " << getChannels() << std::endl;
 | 
						|
    o << std::string(indent, ' ') << "Sample rate: " << getHz() << "Hz" << std::endl;
 | 
						|
    o << std::string(indent, ' ') << "Bytes/s: " << getBPS() << std::endl;
 | 
						|
    o << std::string(indent, ' ') << "Block size: " << getBlockSize() << " bytes" << std::endl;
 | 
						|
    o << std::string(indent, ' ') << "Sample size: " << getSize() << " bits" << std::endl;
 | 
						|
    if (getExtLen()){
 | 
						|
      o << std::string(indent, ' ') << "-- extended " << getExtLen() << "bytes --" << std::endl;
 | 
						|
      if (getExtLen() >= 2){
 | 
						|
        o << std::string(indent, ' ') << "Valid bits: " << getValidBits() << std::endl;
 | 
						|
      }
 | 
						|
      if (getExtLen() >= 6){
 | 
						|
        o << std::string(indent, ' ') << "Channel mask: " << getChannelMask() << std::endl;
 | 
						|
      }
 | 
						|
      if (getExtLen() >= 22){
 | 
						|
        o << std::string(indent, ' ') << "GUID: " << getGUID() << std::endl;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  std::string fmt::generate(uint16_t format, uint16_t channels, uint32_t hz, uint32_t bps,
 | 
						|
                            uint16_t blocksize, uint16_t size){
 | 
						|
    std::string ret("fmt \022\000\000\000", 8);
 | 
						|
    ret.append(std::string((size_t)18, '\000'));
 | 
						|
    Bit::htobs_le((char *)ret.data() + 8, format);
 | 
						|
    Bit::htobs_le((char *)ret.data() + 10, channels);
 | 
						|
    Bit::htobl_le((char *)ret.data() + 12, hz);
 | 
						|
    Bit::htobl_le((char *)ret.data() + 16, bps);
 | 
						|
    Bit::htobs_le((char *)ret.data() + 20, blocksize);
 | 
						|
    Bit::htobs_le((char *)ret.data() + 22, size);
 | 
						|
    Bit::htobs_le((char *)ret.data() + 24, 0);
 | 
						|
    return ret;
 | 
						|
  }
 | 
						|
 | 
						|
  uint32_t fact::getSamplesPerChannel() const{
 | 
						|
    if (!p){return 0;}
 | 
						|
    return Bit::btohl_le(p + 8);
 | 
						|
  }
 | 
						|
  void fact::toPrettyString(std::ostream &o, size_t indent) const{
 | 
						|
    o << std::string(indent, ' ') << "[" << getType() << "] (" << (getPayloadSize() + 8) << "b):" << std::endl;
 | 
						|
    indent += 1;
 | 
						|
    o << std::string(indent, ' ') << "Samples per channel: " << getSamplesPerChannel() << std::endl;
 | 
						|
  }
 | 
						|
  std::string fact::generate(uint32_t samples){
 | 
						|
    std::string ret("fact\004\000\000\000\000\000\000\000", 12);
 | 
						|
    Bit::htobl_le((char *)ret.data() + 8, samples);
 | 
						|
    return ret;
 | 
						|
  }
 | 
						|
 | 
						|
  std::string ISFT::getSoftware() const{
 | 
						|
    if (!p){return 0;}
 | 
						|
    return std::string(p + 8, getPayloadSize());
 | 
						|
  }
 | 
						|
  void ISFT::toPrettyString(std::ostream &o, size_t indent) const{
 | 
						|
    o << std::string(indent, ' ') << "[" << getType() << "] (" << (getPayloadSize() + 8) << "b):" << std::endl;
 | 
						|
    indent += 1;
 | 
						|
    o << std::string(indent, ' ') << "Software: " << getSoftware() << std::endl;
 | 
						|
  }
 | 
						|
}// namespace RIFF
 |