1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
|
/*
* SampleIO.h
* ----------
* Purpose: Central code for reading and writing samples. Create your SampleIO object and have a go at the ReadSample and WriteSample functions!
* Notes : Not all combinations of possible sample format combinations are implemented, especially for WriteSample.
* Using the existing generic sample conversion functors in SampleFormatConverters.h, it should be quite easy to extend the code, though.
* Authors: Olivier Lapicque
* OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
*/
#pragma once
#include "BuildSettings.h"
#include "../common/FileReaderFwd.h"
OPENMPT_NAMESPACE_BEGIN
struct ModSample;
// Sample import / export formats
class SampleIO
{
public:
// Bits per sample
enum Bitdepth : uint8
{
_8bit = 8,
_16bit = 16,
_24bit = 24,
_32bit = 32,
_64bit = 64,
};
// Number of channels + channel format
enum Channels : uint8
{
mono = 1,
stereoInterleaved, // LRLRLR...
stereoSplit, // LLL...RRR...
};
// Sample byte order
enum Endianness : uint8
{
littleEndian = 0,
bigEndian = 1,
};
// Sample encoding
enum Encoding : uint8
{
signedPCM = 0, // Integer PCM, signed
unsignedPCM, // Integer PCM, unsigned
deltaPCM, // Integer PCM, delta-encoded
floatPCM, // Floating point PCM
IT214, // Impulse Tracker 2.14 compressed
IT215, // Impulse Tracker 2.15 compressed
AMS, // AMS / Velvet Studio packed
DMF, // DMF Huffman compression
MDL, // MDL Huffman compression
PTM8Dto16, // PTM 8-Bit delta value -> 16-Bit sample
PCM7to8, // 8-Bit sample data with unused high bit
ADPCM, // 4-Bit ADPCM-packed
MT2, // MadTracker 2 stereo delta encoding
floatPCM15, // Floating point PCM with 2^15 full scale
floatPCM23, // Floating point PCM with 2^23 full scale
floatPCMnormalize, // Floating point PCM and data will be normalized while reading
signedPCMnormalize, // Integer PCM and data will be normalized while reading
uLaw, // 8-to-16 bit G.711 u-law compression
aLaw, // 8-to-16 bit G.711 a-law compression
};
protected:
Bitdepth m_bitdepth;
Channels m_channels;
Endianness m_endianness;
Encoding m_encoding;
public:
constexpr SampleIO(Bitdepth bits = _8bit, Channels channels = mono, Endianness endianness = littleEndian, Encoding encoding = signedPCM)
: m_bitdepth(bits), m_channels(channels), m_endianness(endianness), m_encoding(encoding)
{ }
bool operator== (const SampleIO &other) const
{
return memcmp(this, &other, sizeof(*this)) == 0;
}
bool operator!= (const SampleIO &other) const
{
return memcmp(this, &other, sizeof(*this)) != 0;
}
void operator|= (Bitdepth bits)
{
m_bitdepth = bits;
}
void operator|= (Channels channels)
{
m_channels = channels;
}
void operator|= (Endianness endianness)
{
m_endianness = endianness;
}
void operator|= (Encoding encoding)
{
m_encoding = encoding;
}
void MayNormalize()
{
if(GetBitDepth() == 24 || GetBitDepth() == 32)
{
if(GetEncoding() == SampleIO::signedPCM)
{
m_encoding = SampleIO::signedPCMnormalize;
} else if(GetEncoding() == SampleIO::floatPCM)
{
m_encoding = SampleIO::floatPCMnormalize;
}
}
}
// Return 0 in case of variable-length encoded samples.
MPT_CONSTEXPR14_FUN uint8 GetEncodedBitsPerSample() const
{
switch(GetEncoding())
{
case signedPCM: // Integer PCM, signed
case unsignedPCM: //Integer PCM, unsigned
case deltaPCM: // Integer PCM, delta-encoded
case floatPCM: // Floating point PCM
case MT2: // MadTracker 2 stereo delta encoding
case floatPCM15: // Floating point PCM with 2^15 full scale
case floatPCM23: // Floating point PCM with 2^23 full scale
case floatPCMnormalize: // Floating point PCM and data will be normalized while reading
case signedPCMnormalize: // Integer PCM and data will be normalized while reading
return GetBitDepth();
case IT214: // Impulse Tracker 2.14 compressed
case IT215: // Impulse Tracker 2.15 compressed
case AMS: // AMS / Velvet Studio packed
case DMF: // DMF Huffman compression
case MDL: // MDL Huffman compression
return 0; // variable-length compressed
case PTM8Dto16: // PTM 8-Bit delta value -> 16-Bit sample
return 16;
case PCM7to8: // 8-Bit sample data with unused high bit
return 8;
case ADPCM: // 4-Bit ADPCM-packed
return 4;
case uLaw: // G.711 u-law
return 8;
case aLaw: // G.711 a-law
return 8;
default:
return 0;
}
}
// Return the static header size additional to the raw encoded sample data.
MPT_CONSTEXPR14_FUN std::size_t GetEncodedHeaderSize() const
{
switch(GetEncoding())
{
case ADPCM:
return 16;
default:
return 0;
}
}
// Returns true if the encoded size cannot be calculated apriori from the encoding format and the sample length.
MPT_CONSTEXPR14_FUN bool IsVariableLengthEncoded() const
{
return GetEncodedBitsPerSample() == 0;
}
// Returns true if the decoder for a given format uses FileReader interface and thus do not need to call GetPinnedRawDataView()
MPT_CONSTEXPR14_FUN bool UsesFileReaderForDecoding() const
{
switch(GetEncoding())
{
case IT214:
case IT215:
case AMS:
case DMF:
case MDL:
return true;
default:
return false;
}
}
// Get bits per sample
constexpr uint8 GetBitDepth() const
{
return static_cast<uint8>(m_bitdepth);
}
// Get channel layout
constexpr Channels GetChannelFormat() const
{
return m_channels;
}
// Get number of channels
constexpr uint8 GetNumChannels() const
{
return GetChannelFormat() == mono ? 1u : 2u;
}
// Get sample byte order
constexpr Endianness GetEndianness() const
{
return m_endianness;
}
// Get sample format / encoding
constexpr Encoding GetEncoding() const
{
return m_encoding;
}
// Returns the encoded size of the sample. In case of variable-length encoding returns 0.
std::size_t CalculateEncodedSize(SmpLength length) const
{
if(IsVariableLengthEncoded())
{
return 0;
}
uint8 bps = GetEncodedBitsPerSample();
if(bps % 8u != 0)
{
MPT_ASSERT(GetEncoding() == ADPCM && bps == 4);
return GetEncodedHeaderSize() + (((length + 1) / 2) * GetNumChannels()); // round up
}
return GetEncodedHeaderSize() + (length * (bps / 8) * GetNumChannels());
}
// Read a sample from memory
size_t ReadSample(ModSample &sample, FileReader &file) const;
#ifndef MODPLUG_NO_FILESAVE
// Write a sample to file
size_t WriteSample(std::ostream &f, const ModSample &sample, SmpLength maxSamples = 0) const;
#endif // MODPLUG_NO_FILESAVE
};
OPENMPT_NAMESPACE_END
|