1
0

SampleIO.h 6.6 KB

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