File: SampleIO.h

package info (click to toggle)
libopenmpt 0.4.3-1%2Bdeb10u1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 7,724 kB
  • sloc: cpp: 99,820; sh: 4,503; ansic: 3,449; makefile: 480
file content (259 lines) | stat: -rw-r--r-- 6,909 bytes parent folder | download | duplicates (2)
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