1
0

ITCompression.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /*
  2. * ITCompression.cpp
  3. * -----------------
  4. * Purpose: Code for IT sample compression and decompression.
  5. * Notes : The original Python compression code was written by GreaseMonkey and has been released into the public domain.
  6. * Authors: OpenMPT Devs
  7. * Ben "GreaseMonkey" Russell
  8. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  9. */
  10. #include "stdafx.h"
  11. #include <ostream>
  12. #include "ITCompression.h"
  13. #include "mpt/io/base.hpp"
  14. #include "mpt/io/io.hpp"
  15. #include "mpt/io/io_stdstream.hpp"
  16. #include "../common/misc_util.h"
  17. #include "ModSample.h"
  18. #include "SampleCopy.h"
  19. OPENMPT_NAMESPACE_BEGIN
  20. // Algorithm parameters for 16-Bit samples
  21. struct IT16BitParams
  22. {
  23. using sample_t = int16;
  24. static constexpr int16 lowerTab[] = {0, -1, -3, -7, -15, -31, -56, -120, -248, -504, -1016, -2040, -4088, -8184, -16376, -32760, -32768};
  25. static constexpr int16 upperTab[] = {0, 1, 3, 7, 15, 31, 55, 119, 247, 503, 1015, 2039, 4087, 8183, 16375, 32759, 32767};
  26. static constexpr int8 fetchA = 4;
  27. static constexpr int8 lowerB = -8;
  28. static constexpr int8 upperB = 7;
  29. static constexpr int8 defWidth = 17;
  30. static constexpr int mask = 0xFFFF;
  31. };
  32. // Algorithm parameters for 8-Bit samples
  33. struct IT8BitParams
  34. {
  35. using sample_t = int8;
  36. static constexpr int8 lowerTab[] = {0, -1, -3, -7, -15, -31, -60, -124, -128};
  37. static constexpr int8 upperTab[] = {0, 1, 3, 7, 15, 31, 59, 123, 127};
  38. static constexpr int8 fetchA = 3;
  39. static constexpr int8 lowerB = -4;
  40. static constexpr int8 upperB = 3;
  41. static constexpr int8 defWidth = 9;
  42. static constexpr int mask = 0xFF;
  43. };
  44. static constexpr int8 ITWidthChangeSize[] = { 4, 5, 6, 7, 8, 9, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };
  45. //////////////////////////////////////////////////////////////////////////////
  46. // IT 2.14 compression
  47. ITCompression::ITCompression(const ModSample &sample, bool it215, std::ostream *f, SmpLength maxLength)
  48. : file(f)
  49. , mptSample(sample)
  50. , is215(it215)
  51. {
  52. if(mptSample.GetElementarySampleSize() > 1)
  53. Compress<IT16BitParams>(mptSample.sample16(), maxLength);
  54. else
  55. Compress<IT8BitParams>(mptSample.sample8(), maxLength);
  56. }
  57. template<typename Properties>
  58. void ITCompression::Compress(const typename Properties::sample_t *mptSampleData, SmpLength maxLength)
  59. {
  60. packedData.resize(bufferSize);
  61. std::vector<typename Properties::sample_t> sampleData;
  62. sampleData.resize(blockSize / sizeof(typename Properties::sample_t));
  63. if(maxLength == 0 || maxLength > mptSample.nLength)
  64. maxLength = mptSample.nLength;
  65. for(uint8 chn = 0; chn < mptSample.GetNumChannels(); chn++)
  66. {
  67. SmpLength offset = 0;
  68. SmpLength remain = maxLength;
  69. while(remain > 0)
  70. {
  71. // Initialise output buffer and bit writer positions
  72. packedLength = 2;
  73. bitPos = 0;
  74. remBits = 8;
  75. byteVal = 0;
  76. CompressBlock<Properties>(mptSampleData + chn, offset, remain, sampleData.data());
  77. if(file) mpt::IO::WriteRaw(*file, packedData.data(), packedLength);
  78. packedTotalLength += packedLength;
  79. offset += baseLength;
  80. remain -= baseLength;
  81. }
  82. }
  83. packedData.resize(0);
  84. packedData.shrink_to_fit();
  85. }
  86. template<typename T>
  87. void ITCompression::CopySample(T *target, const T *source, SmpLength offset, SmpLength length, SmpLength skip)
  88. {
  89. T *out = target;
  90. const T *in = source + offset * skip;
  91. for(SmpLength i = 0, j = 0; j < length; i += skip, j++)
  92. {
  93. out[j] = in[i];
  94. }
  95. }
  96. // Convert sample to delta values.
  97. template<typename T>
  98. void ITCompression::Deltafy(T *sampleData)
  99. {
  100. T *p = sampleData;
  101. int oldVal = 0;
  102. for(SmpLength i = 0; i < baseLength; i++)
  103. {
  104. int newVal = p[i];
  105. p[i] = static_cast<T>(newVal - oldVal);
  106. oldVal = newVal;
  107. }
  108. }
  109. template<typename Properties>
  110. void ITCompression::CompressBlock(const typename Properties::sample_t *data, SmpLength offset, SmpLength actualLength, typename Properties::sample_t *sampleData)
  111. {
  112. baseLength = std::min(actualLength, SmpLength(blockSize / sizeof(typename Properties::sample_t)));
  113. CopySample<typename Properties::sample_t>(sampleData, data, offset, baseLength, mptSample.GetNumChannels());
  114. Deltafy(sampleData);
  115. if(is215)
  116. {
  117. Deltafy(sampleData);
  118. }
  119. // Initialise bit width table with initial values
  120. bwt.assign(baseLength, Properties::defWidth);
  121. // Recurse!
  122. SquishRecurse<Properties>(Properties::defWidth, Properties::defWidth, Properties::defWidth, Properties::defWidth - 2, 0, baseLength, sampleData);
  123. // Write those bits!
  124. const typename Properties::sample_t *p = sampleData;
  125. int8 width = Properties::defWidth;
  126. for(size_t i = 0; i < baseLength; i++)
  127. {
  128. if(bwt[i] != width)
  129. {
  130. if(width <= 6)
  131. {
  132. // Mode A: 1 to 6 bits
  133. MPT_ASSERT(width);
  134. WriteBits(width, (1 << (width - 1)));
  135. WriteBits(Properties::fetchA, ConvertWidth(width, bwt[i]));
  136. } else if(width < Properties::defWidth)
  137. {
  138. // Mode B: 7 to 8 / 16 bits
  139. int xv = (1 << (width - 1)) + Properties::lowerB + ConvertWidth(width, bwt[i]);
  140. WriteBits(width, xv);
  141. } else
  142. {
  143. // Mode C: 9 / 17 bits
  144. MPT_ASSERT((bwt[i] - 1) >= 0);
  145. WriteBits(width, (1 << (width - 1)) + bwt[i] - 1);
  146. }
  147. width = bwt[i];
  148. }
  149. WriteBits(width, static_cast<int>(p[i]) & Properties::mask);
  150. }
  151. // Write last byte and update block length
  152. WriteByte(byteVal);
  153. packedData[0] = static_cast<uint8>((packedLength - 2) & 0xFF);
  154. packedData[1] = static_cast<uint8>((packedLength - 2) >> 8);
  155. }
  156. int8 ITCompression::GetWidthChangeSize(int8 w, bool is16)
  157. {
  158. MPT_ASSERT(w > 0 && static_cast<unsigned int>(w) <= std::size(ITWidthChangeSize));
  159. int8 wcs = ITWidthChangeSize[w - 1];
  160. if(w <= 6 && is16)
  161. wcs++;
  162. return wcs;
  163. }
  164. template<typename Properties>
  165. void ITCompression::SquishRecurse(int8 sWidth, int8 lWidth, int8 rWidth, int8 width, SmpLength offset, SmpLength length, const typename Properties::sample_t *sampleData)
  166. {
  167. if(width + 1 < 1)
  168. {
  169. for(SmpLength i = offset; i < offset + length; i++)
  170. bwt[i] = sWidth;
  171. return;
  172. }
  173. MPT_ASSERT(width >= 0 && static_cast<unsigned int>(width) < std::size(Properties::lowerTab));
  174. SmpLength i = offset;
  175. SmpLength end = offset + length;
  176. const typename Properties::sample_t *p = sampleData;
  177. while(i < end)
  178. {
  179. if(p[i] >= Properties::lowerTab[width] && p[i] <= Properties::upperTab[width])
  180. {
  181. SmpLength start = i;
  182. // Check for how long we can keep this bit width
  183. while(i < end && p[i] >= Properties::lowerTab[width] && p[i] <= Properties::upperTab[width])
  184. {
  185. i++;
  186. }
  187. const SmpLength blockLength = i - start;
  188. const int8 xlwidth = start == offset ? lWidth : sWidth;
  189. const int8 xrwidth = i == end ? rWidth : sWidth;
  190. const bool is16 = sizeof(typename Properties::sample_t) > 1;
  191. const int8 wcsl = GetWidthChangeSize(xlwidth, is16);
  192. const int8 wcss = GetWidthChangeSize(sWidth, is16);
  193. const int8 wcsw = GetWidthChangeSize(width + 1, is16);
  194. bool comparison;
  195. if(i == baseLength)
  196. {
  197. SmpLength keepDown = wcsl + (width + 1) * blockLength;
  198. SmpLength levelLeft = wcsl + sWidth * blockLength;
  199. if(xlwidth == sWidth)
  200. levelLeft -= wcsl;
  201. comparison = (keepDown <= levelLeft);
  202. } else
  203. {
  204. SmpLength keepDown = wcsl + (width + 1) * blockLength + wcsw;
  205. SmpLength levelLeft = wcsl + sWidth * blockLength + wcss;
  206. if(xlwidth == sWidth)
  207. levelLeft -= wcsl;
  208. if(xrwidth == sWidth)
  209. levelLeft -= wcss;
  210. comparison = (keepDown <= levelLeft);
  211. }
  212. SquishRecurse<Properties>(comparison ? (width + 1) : sWidth, xlwidth, xrwidth, width - 1, start, blockLength, sampleData);
  213. } else
  214. {
  215. bwt[i] = sWidth;
  216. i++;
  217. }
  218. }
  219. }
  220. int8 ITCompression::ConvertWidth(int8 curWidth, int8 newWidth)
  221. {
  222. curWidth--;
  223. newWidth--;
  224. MPT_ASSERT(newWidth != curWidth);
  225. if(newWidth > curWidth)
  226. newWidth--;
  227. return newWidth;
  228. }
  229. void ITCompression::WriteBits(int8 width, int v)
  230. {
  231. while(width > remBits)
  232. {
  233. byteVal |= (v << bitPos);
  234. width -= remBits;
  235. v >>= remBits;
  236. bitPos = 0;
  237. remBits = 8;
  238. WriteByte(byteVal);
  239. byteVal = 0;
  240. }
  241. if(width > 0)
  242. {
  243. byteVal |= (v & ((1 << width) - 1)) << bitPos;
  244. remBits -= width;
  245. bitPos += width;
  246. }
  247. }
  248. void ITCompression::WriteByte(uint8 v)
  249. {
  250. if(packedLength < bufferSize)
  251. {
  252. packedData[packedLength++] = v;
  253. } else
  254. {
  255. // How could this happen, anyway?
  256. MPT_ASSERT_NOTREACHED();
  257. }
  258. }
  259. //////////////////////////////////////////////////////////////////////////////
  260. // IT 2.14 decompression
  261. ITDecompression::ITDecompression(FileReader &file, ModSample &sample, bool it215)
  262. : mptSample(sample)
  263. , is215(it215)
  264. {
  265. for(uint8 chn = 0; chn < mptSample.GetNumChannels(); chn++)
  266. {
  267. writtenSamples = writePos = 0;
  268. while(writtenSamples < sample.nLength && file.CanRead(sizeof(uint16)))
  269. {
  270. uint16 compressedSize = file.ReadUint16LE();
  271. if(!compressedSize)
  272. continue; // Malformed sample?
  273. bitFile = file.ReadChunk(compressedSize);
  274. // Initialise bit reader
  275. mem1 = mem2 = 0;
  276. try
  277. {
  278. if(mptSample.GetElementarySampleSize() > 1)
  279. Uncompress<IT16BitParams>(mptSample.sample16() + chn);
  280. else
  281. Uncompress<IT8BitParams>(mptSample.sample8() + chn);
  282. } catch(const BitReader::eof &)
  283. {
  284. // Data is not sufficient to decode the block
  285. //AddToLog(LogWarning, "Truncated IT sample block");
  286. }
  287. }
  288. }
  289. }
  290. template<typename Properties>
  291. void ITDecompression::Uncompress(typename Properties::sample_t *target)
  292. {
  293. curLength = std::min(mptSample.nLength - writtenSamples, SmpLength(ITCompression::blockSize / sizeof(typename Properties::sample_t)));
  294. int width = Properties::defWidth;
  295. while(curLength > 0)
  296. {
  297. if(width > Properties::defWidth)
  298. {
  299. // Error!
  300. return;
  301. }
  302. int v = bitFile.ReadBits(width);
  303. const int topBit = (1 << (width - 1));
  304. if(width <= 6)
  305. {
  306. // Mode A: 1 to 6 bits
  307. if(v == topBit)
  308. ChangeWidth(width, bitFile.ReadBits(Properties::fetchA));
  309. else
  310. Write<Properties>(v, topBit, target);
  311. } else if(width < Properties::defWidth)
  312. {
  313. // Mode B: 7 to 8 / 16 bits
  314. if(v >= topBit + Properties::lowerB && v <= topBit + Properties::upperB)
  315. ChangeWidth(width, v - (topBit + Properties::lowerB));
  316. else
  317. Write<Properties>(v, topBit, target);
  318. } else
  319. {
  320. // Mode C: 9 / 17 bits
  321. if(v & topBit)
  322. width = (v & ~topBit) + 1;
  323. else
  324. Write<Properties>((v & ~topBit), 0, target);
  325. }
  326. }
  327. }
  328. void ITDecompression::ChangeWidth(int &curWidth, int width)
  329. {
  330. width++;
  331. if(width >= curWidth)
  332. width++;
  333. curWidth = width;
  334. }
  335. template<typename Properties>
  336. void ITDecompression::Write(int v, int topBit, typename Properties::sample_t *target)
  337. {
  338. if(v & topBit)
  339. v -= (topBit << 1);
  340. mem1 += v;
  341. mem2 += mem1;
  342. target[writePos] = static_cast<typename Properties::sample_t>(static_cast<int>(is215 ? mem2 : mem1));
  343. writtenSamples++;
  344. writePos += mptSample.GetNumChannels();
  345. curLength--;
  346. }
  347. OPENMPT_NAMESPACE_END