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
|
/*
* 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 "openmpt/all/BuildSettings.hpp"
#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
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)
{
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_CONSTEXPRINLINE 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 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_CONSTEXPRINLINE 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_CONSTEXPRINLINE 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 GetPinnedView()
MPT_CONSTEXPRINLINE 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
|