1 /*
2  * ITCompression.h
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 
11 #pragma once
12 
13 #include "openmpt/all/BuildSettings.hpp"
14 
15 #include <vector>
16 #include <iosfwd>
17 #include "Snd_defs.h"
18 #include "BitReader.h"
19 
20 
21 OPENMPT_NAMESPACE_BEGIN
22 
23 struct ModSample;
24 
25 class ITCompression
26 {
27 public:
28 	ITCompression(const ModSample &sample, bool it215, std::ostream *f, SmpLength maxLength = 0);
GetCompressedSize()29 	size_t GetCompressedSize() const { return packedTotalLength; }
30 
31 	static constexpr size_t bufferSize = 2 + 0xFFFF;  // Our output buffer can't be longer than this.
32 	static constexpr size_t blockSize = 0x8000;       // Block size (in bytes) in which samples are being processed
33 
34 protected:
35 	std::vector<int8> bwt;           // Bit width table for each sampling point
36 	std::vector<uint8> packedData;   // Compressed data for current sample block
37 	std::ostream *file = nullptr;    // File to which compressed data will be written (can be nullptr if you only want to find out the sample size)
38 	std::vector<int8> sampleData8;   // Pre-processed sample data for currently compressed sample block
39 	std::vector<int16> sampleData16; // Pre-processed sample data for currently compressed sample block
40 	const ModSample &mptSample;      // Sample that is being processed
41 	size_t packedLength = 0;         // Size of currently compressed sample block
42 	size_t packedTotalLength = 0;    // Size of all compressed data so far
43 	SmpLength baseLength = 0;        // Length of the currently compressed sample block (in samples)
44 
45 	// Bit writer
46 	int8 bitPos = 0;    // Current bit position in this byte
47 	int8 remBits = 0;   // Remaining bits in this byte
48 	uint8 byteVal = 0;  // Current byte value to be written
49 
50 	const bool is215;  // Use IT2.15 compression (double deltas)
51 
52 	template<typename Properties>
53 	void Compress(const typename Properties::sample_t *mptSampleData, SmpLength maxLength);
54 
55 	template<typename T>
56 	static void CopySample(T *target, const T *source, SmpLength offset, SmpLength length, SmpLength skip);
57 
58 	template<typename T>
59 	void Deltafy(T *sampleData);
60 
61 	template<typename Properties>
62 	void CompressBlock(const typename Properties::sample_t *data, SmpLength offset, SmpLength actualLength, typename Properties::sample_t *sampleData);
63 
64 	static int8 GetWidthChangeSize(int8 w, bool is16);
65 
66 	template<typename Properties>
67 	void SquishRecurse(int8 sWidth, int8 lWidth, int8 rWidth, int8 width, SmpLength offset, SmpLength length, const typename Properties::sample_t *sampleData);
68 
69 	static int8 ConvertWidth(int8 curWidth, int8 newWidth);
70 	void WriteBits(int8 width, int v);
71 
72 	void WriteByte(uint8 v);
73 };
74 
75 
76 class ITDecompression
77 {
78 public:
79 	ITDecompression(FileReader &file, ModSample &sample, bool it215);
80 
81 protected:
82 	BitReader bitFile;
83 	ModSample &mptSample;  // Sample that is being processed
84 
85 	SmpLength writtenSamples = 0;     // Number of samples so far written on this channel
86 	SmpLength writePos = 0;           // Absolut write position in sample (for stereo samples)
87 	SmpLength curLength = 0;          // Length of currently processed block
88 	unsigned int mem1 = 0, mem2 = 0;  // Integrator memory
89 
90 	const bool is215;  // Use IT2.15 compression (double deltas)
91 
92 	template<typename Properties>
93 	void Uncompress(typename Properties::sample_t *target);
94 	static void ChangeWidth(int &curWidth, int width);
95 
96 	template<typename Properties>
97 	void Write(int v, int topbit, typename Properties::sample_t *target);
98 };
99 
100 
101 OPENMPT_NAMESPACE_END
102