Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 1 | /*************************************************************************** |
2 | * |
||
3 | * Copyright (c) Microsoft Corporation. All rights reserved. |
||
4 | * |
||
5 | * File: xma2defs.h |
||
6 | * Content: Constants, data types and functions for XMA2 compressed audio. |
||
7 | * |
||
8 | ***************************************************************************/ |
||
9 | |||
10 | #ifndef __XMA2DEFS_INCLUDED__ |
||
11 | #define __XMA2DEFS_INCLUDED__ |
||
12 | |||
13 | #include <sal.h> // Markers for documenting API semantics |
||
14 | #include <winerror.h> // For S_OK, E_FAIL |
||
15 | #include <audiodefs.h> // Basic data types and constants for audio work |
||
16 | |||
17 | |||
18 | /*************************************************************************** |
||
19 | * Overview |
||
20 | ***************************************************************************/ |
||
21 | |||
22 | // A typical XMA2 file contains these RIFF chunks: |
||
23 | // |
||
24 | // 'fmt' or 'XMA2' chunk (or both): A description of the XMA data's structure |
||
25 | // and characteristics (length, channels, sample rate, loops, block size, etc). |
||
26 | // |
||
27 | // 'seek' chunk: A seek table to help navigate the XMA data. |
||
28 | // |
||
29 | // 'data' chunk: The encoded XMA2 data. |
||
30 | // |
||
31 | // The encoded XMA2 data is structured as a set of BLOCKS, which contain PACKETS, |
||
32 | // which contain FRAMES, which contain SUBFRAMES (roughly speaking). The frames |
||
33 | // in a file may also be divided into several subsets, called STREAMS. |
||
34 | // |
||
35 | // FRAME: A variable-sized segment of XMA data that decodes to exactly 512 mono |
||
36 | // or stereo PCM samples. This is the smallest unit of XMA data that can |
||
37 | // be decoded in isolation. Frames are an arbitrary number of bits in |
||
38 | // length, and need not be byte-aligned. See "XMA frame structure" below. |
||
39 | // |
||
40 | // SUBFRAME: A region of bits in an XMA frame that decodes to 128 mono or stereo |
||
41 | // samples. The XMA decoder cannot decode a subframe in isolation; it needs |
||
42 | // a whole frame to work with. However, it can begin emitting the frame's |
||
43 | // decoded samples at any one of the four subframe boundaries. Subframes |
||
44 | // can be addressed for seeking and looping purposes. |
||
45 | // |
||
46 | // PACKET: A 2Kb region containing a 32-bit header and some XMA frames. Frames |
||
47 | // can (and usually do) span packets. A packet's header includes the offset |
||
48 | // in bits of the first frame that begins within that packet. All of the |
||
49 | // frames that begin in a given packet belong to the same "stream" (see the |
||
50 | // Multichannel Audio section below). |
||
51 | // |
||
52 | // STREAM: A set of packets within an XMA file that all contain data for the |
||
53 | // same mono or stereo component of a PCM file with more than two channels. |
||
54 | // The packets comprising a given stream may be interleaved with each other |
||
55 | // more or less arbitrarily; see Multichannel Audio. |
||
56 | // |
||
57 | // BLOCK: An array of XMA packets; or, to break it down differently, a series of |
||
58 | // consecutive XMA frames, padded at the end with reserved data. A block |
||
59 | // must contain at least one 2Kb packet per stream, and it can hold up to |
||
60 | // 4095 packets (8190Kb), but its size is typically in the 32Kb-128Kb range. |
||
61 | // (The size chosen involves a trade-off between memory use and efficiency |
||
62 | // of reading from permanent storage.) |
||
63 | // |
||
64 | // XMA frames do not span blocks, so a block is guaranteed to begin with a |
||
65 | // set of complete frames, one per stream. Also, a block in a multi-stream |
||
66 | // XMA2 file always contains the same number of samples for each stream; |
||
67 | // see Multichannel Audio. |
||
68 | // |
||
69 | // The 'data' chunk in an XMA2 file is an array of XMA2WAVEFORMAT.BlockCount XMA |
||
70 | // blocks, all the same size (as specified in XMA2WAVEFORMAT.BlockSizeInBytes) |
||
71 | // except for the last one, which may be shorter. |
||
72 | |||
73 | |||
74 | // MULTICHANNEL AUDIO: the XMA decoder can only decode raw XMA data into either |
||
75 | // mono or stereo PCM data. In order to encode a 6-channel file (say), the file |
||
76 | // must be deinterleaved into 3 stereo streams that are encoded independently, |
||
77 | // producing 3 encoded XMA data streams. Then the packets in these 3 streams |
||
78 | // are interleaved to produce a single XMA2 file, and some information is added |
||
79 | // to the file so that the original 6-channel audio can be reconstructed at |
||
80 | // decode time. This works using the concept of an XMA stream (see above). |
||
81 | // |
||
82 | // The frames for all the streams in an XMA file are interleaved in an arbitrary |
||
83 | // order. To locate a frame that belongs to a given stream in a given XMA block, |
||
84 | // you must examine the first few packets in the block. Here (and only here) the |
||
85 | // packets are guaranteed to be presented in stream order, so that all frames |
||
86 | // beginning in packet 0 belong to stream 0 (the first stereo pair), etc. |
||
87 | // |
||
88 | // (This means that when decoding multi-stream XMA files, only entire XMA blocks |
||
89 | // should be submitted to the decoder; otherwise it cannot know which frames |
||
90 | // belong to which stream.) |
||
91 | // |
||
92 | // Once you have one frame that belongs to a given stream, you can find the next |
||
93 | // one by looking at the frame's 'NextFrameOffsetBits' value (which is stored in |
||
94 | // its first 15 bits; see XMAFRAME below). The GetXmaFrameBitPosition function |
||
95 | // uses this technique. |
||
96 | |||
97 | |||
98 | // SEEKING IN XMA2 FILES: Here is some pseudocode to find the byte position and |
||
99 | // subframe in an XMA2 file which will contain sample S when decoded. |
||
100 | // |
||
101 | // 1. Traverse the seek table to find the XMA2 block containing sample S. The |
||
102 | // seek table is an array of big-endian DWORDs, one per block in the file. |
||
103 | // The Nth DWORD is the total number of PCM samples that would be obtained |
||
104 | // by decoding the entire XMA file up to the end of block N. Hence, the |
||
105 | // block we want is the first one whose seek table entry is greater than S. |
||
106 | // (See the GetXmaBlockContainingSample helper function.) |
||
107 | // |
||
108 | // 2. Calculate which frame F within the block found above contains sample S. |
||
109 | // Since each frame decodes to 512 samples, this is straightforward. The |
||
110 | // first frame in the block produces samples X to X + 512, where X is the |
||
111 | // seek table entry for the prior block. So F is (S - X) / 512. |
||
112 | // |
||
113 | // 3. Find the bit offset within the block where frame F starts. Since frames |
||
114 | // are variable-sized, this can only be done by traversing all the frames in |
||
115 | // the block until we reach frame F. (See GetXmaFrameBitPosition.) |
||
116 | // |
||
117 | // 4. Frame F has four 128-sample subframes. To find the subframe containing S, |
||
118 | // we can use the formula (S % 512) / 128. |
||
119 | // |
||
120 | // In the case of multi-stream XMA files, sample S is a multichannel sample with |
||
121 | // parts coming from several frames, one per stream. To find all these frames, |
||
122 | // steps 2-4 need to be repeated for each stream N, using the knowledge that the |
||
123 | // first packets in a block are presented in stream order. The frame traversal |
||
124 | // in step 3 must be started at the first frame in the Nth packet of the block, |
||
125 | // which will be the first frame for stream N. (And the packet header will tell |
||
126 | // you the first frame's start position within the packet.) |
||
127 | // |
||
128 | // Step 1 can be performed using the GetXmaBlockContainingSample function below, |
||
129 | // and steps 2-4 by calling GetXmaDecodePositionForSample once for each stream. |
||
130 | |||
131 | |||
132 | |||
133 | /*************************************************************************** |
||
134 | * XMA constants |
||
135 | ***************************************************************************/ |
||
136 | |||
137 | // Size of the PCM samples produced by the XMA decoder |
||
138 | #define XMA_OUTPUT_SAMPLE_BYTES 2u |
||
139 | #define XMA_OUTPUT_SAMPLE_BITS (XMA_OUTPUT_SAMPLE_BYTES * 8u) |
||
140 | |||
141 | // Size of an XMA packet |
||
142 | #define XMA_BYTES_PER_PACKET 2048u |
||
143 | #define XMA_BITS_PER_PACKET (XMA_BYTES_PER_PACKET * 8u) |
||
144 | |||
145 | // Size of an XMA packet header |
||
146 | #define XMA_PACKET_HEADER_BYTES 4u |
||
147 | #define XMA_PACKET_HEADER_BITS (XMA_PACKET_HEADER_BYTES * 8u) |
||
148 | |||
149 | // Sample blocks in a decoded XMA frame |
||
150 | #define XMA_SAMPLES_PER_FRAME 512u |
||
151 | |||
152 | // Sample blocks in a decoded XMA subframe |
||
153 | #define XMA_SAMPLES_PER_SUBFRAME 128u |
||
154 | |||
155 | // Maximum encoded data that can be submitted to the XMA decoder at a time |
||
156 | #define XMA_READBUFFER_MAX_PACKETS 4095u |
||
157 | #define XMA_READBUFFER_MAX_BYTES (XMA_READBUFFER_MAX_PACKETS * XMA_BYTES_PER_PACKET) |
||
158 | |||
159 | // Maximum size allowed for the XMA decoder's output buffers |
||
160 | #define XMA_WRITEBUFFER_MAX_BYTES (31u * 256u) |
||
161 | |||
162 | // Required byte alignment of the XMA decoder's output buffers |
||
163 | #define XMA_WRITEBUFFER_BYTE_ALIGNMENT 256u |
||
164 | |||
165 | // Decode chunk sizes for the XMA_PLAYBACK_INIT.subframesToDecode field |
||
166 | #define XMA_MIN_SUBFRAMES_TO_DECODE 1u |
||
167 | #define XMA_MAX_SUBFRAMES_TO_DECODE 8u |
||
168 | #define XMA_OPTIMAL_SUBFRAMES_TO_DECODE 4u |
||
169 | |||
170 | // LoopCount<255 means finite repetitions; LoopCount=255 means infinite looping |
||
171 | #define XMA_MAX_LOOPCOUNT 254u |
||
172 | #define XMA_INFINITE_LOOP 255u |
||
173 | |||
174 | |||
175 | |||
176 | /*************************************************************************** |
||
177 | * XMA format structures |
||
178 | ***************************************************************************/ |
||
179 | |||
180 | // The currently recommended way to express format information for XMA2 files |
||
181 | // is the XMA2WAVEFORMATEX structure. This structure is fully compliant with |
||
182 | // the WAVEFORMATEX standard and contains all the information needed to parse |
||
183 | // and manage XMA2 files in a compact way. |
||
184 | |||
185 | #define WAVE_FORMAT_XMA2 0x166 |
||
186 | |||
187 | typedef struct XMA2WAVEFORMATEX |
||
188 | { |
||
189 | WAVEFORMATEX wfx; |
||
190 | // Meaning of the WAVEFORMATEX fields here: |
||
191 | // wFormatTag; // Audio format type; always WAVE_FORMAT_XMA2 |
||
192 | // nChannels; // Channel count of the decoded audio |
||
193 | // nSamplesPerSec; // Sample rate of the decoded audio |
||
194 | // nAvgBytesPerSec; // Used internally by the XMA encoder |
||
195 | // nBlockAlign; // Decoded sample size; channels * wBitsPerSample / 8 |
||
196 | // wBitsPerSample; // Bits per decoded mono sample; always 16 for XMA |
||
197 | // cbSize; // Size in bytes of the rest of this structure (34) |
||
198 | |||
199 | WORD NumStreams; // Number of audio streams (1 or 2 channels each) |
||
200 | DWORD ChannelMask; // Spatial positions of the channels in this file, |
||
201 | // stored as SPEAKER_xxx values (see audiodefs.h) |
||
202 | DWORD SamplesEncoded; // Total number of PCM samples the file decodes to |
||
203 | DWORD BytesPerBlock; // XMA block size (but the last one may be shorter) |
||
204 | DWORD PlayBegin; // First valid sample in the decoded audio |
||
205 | DWORD PlayLength; // Length of the valid part of the decoded audio |
||
206 | DWORD LoopBegin; // Beginning of the loop region in decoded sample terms |
||
207 | DWORD LoopLength; // Length of the loop region in decoded sample terms |
||
208 | BYTE LoopCount; // Number of loop repetitions; 255 = infinite |
||
209 | BYTE EncoderVersion; // Version of XMA encoder that generated the file |
||
210 | WORD BlockCount; // XMA blocks in file (and entries in its seek table) |
||
211 | } XMA2WAVEFORMATEX, *PXMA2WAVEFORMATEX; |
||
212 | |||
213 | |||
214 | // The legacy XMA format structures are described here for reference, but they |
||
215 | // should not be used in new content. XMAWAVEFORMAT was the structure used in |
||
216 | // XMA version 1 files. XMA2WAVEFORMAT was used in early XMA2 files; it is not |
||
217 | // placed in the usual 'fmt' RIFF chunk but in its own 'XMA2' chunk. |
||
218 | |||
219 | #ifndef WAVE_FORMAT_XMA |
||
220 | #define WAVE_FORMAT_XMA 0x0165 |
||
221 | |||
222 | // Values used in the ChannelMask fields below. Similar to the SPEAKER_xxx |
||
223 | // values defined in audiodefs.h, but modified to fit in a single byte. |
||
224 | #ifndef XMA_SPEAKER_LEFT |
||
225 | #define XMA_SPEAKER_LEFT 0x01 |
||
226 | #define XMA_SPEAKER_RIGHT 0x02 |
||
227 | #define XMA_SPEAKER_CENTER 0x04 |
||
228 | #define XMA_SPEAKER_LFE 0x08 |
||
229 | #define XMA_SPEAKER_LEFT_SURROUND 0x10 |
||
230 | #define XMA_SPEAKER_RIGHT_SURROUND 0x20 |
||
231 | #define XMA_SPEAKER_LEFT_BACK 0x40 |
||
232 | #define XMA_SPEAKER_RIGHT_BACK 0x80 |
||
233 | #endif |
||
234 | |||
235 | |||
236 | // Used in XMAWAVEFORMAT for per-stream data |
||
237 | typedef struct XMASTREAMFORMAT |
||
238 | { |
||
239 | DWORD PsuedoBytesPerSec; // Used by the XMA encoder (typo preserved for legacy reasons) |
||
240 | DWORD SampleRate; // The stream's decoded sample rate (in XMA2 files, |
||
241 | // this is the same for all streams in the file). |
||
242 | DWORD LoopStart; // Bit offset of the frame containing the loop start |
||
243 | // point, relative to the beginning of the stream. |
||
244 | DWORD LoopEnd; // Bit offset of the frame containing the loop end. |
||
245 | BYTE SubframeData; // Two 4-bit numbers specifying the exact location of |
||
246 | // the loop points within the frames that contain them. |
||
247 | // SubframeEnd: Subframe of the loop end frame where |
||
248 | // the loop ends. Ranges from 0 to 3. |
||
249 | // SubframeSkip: Subframes to skip in the start frame to |
||
250 | // reach the loop. Ranges from 0 to 4. |
||
251 | BYTE Channels; // Number of channels in the stream (1 or 2) |
||
252 | WORD ChannelMask; // Spatial positions of the channels in the stream |
||
253 | } XMASTREAMFORMAT; |
||
254 | |||
255 | // Legacy XMA1 format structure |
||
256 | typedef struct XMAWAVEFORMAT |
||
257 | { |
||
258 | WORD FormatTag; // Audio format type (always WAVE_FORMAT_XMA) |
||
259 | WORD BitsPerSample; // Bit depth (currently required to be 16) |
||
260 | WORD EncodeOptions; // Options for XMA encoder/decoder |
||
261 | WORD LargestSkip; // Largest skip used in interleaving streams |
||
262 | WORD NumStreams; // Number of interleaved audio streams |
||
263 | BYTE LoopCount; // Number of loop repetitions; 255 = infinite |
||
264 | BYTE Version; // XMA encoder version that generated the file. |
||
265 | // Always 3 or higher for XMA2 files. |
||
266 | XMASTREAMFORMAT XmaStreams[1]; // Per-stream format information; the actual |
||
267 | // array length is in the NumStreams field. |
||
268 | } XMAWAVEFORMAT; |
||
269 | |||
270 | |||
271 | // Used in XMA2WAVEFORMAT for per-stream data |
||
272 | typedef struct XMA2STREAMFORMAT |
||
273 | { |
||
274 | BYTE Channels; // Number of channels in the stream (1 or 2) |
||
275 | BYTE RESERVED; // Reserved for future use |
||
276 | WORD ChannelMask; // Spatial positions of the channels in the stream |
||
277 | } XMA2STREAMFORMAT; |
||
278 | |||
279 | // Legacy XMA2 format structure (big-endian byte ordering) |
||
280 | typedef struct XMA2WAVEFORMAT |
||
281 | { |
||
282 | BYTE Version; // XMA encoder version that generated the file. |
||
283 | // Always 3 or higher for XMA2 files. |
||
284 | BYTE NumStreams; // Number of interleaved audio streams |
||
285 | BYTE RESERVED; // Reserved for future use |
||
286 | BYTE LoopCount; // Number of loop repetitions; 255 = infinite |
||
287 | DWORD LoopBegin; // Loop begin point, in samples |
||
288 | DWORD LoopEnd; // Loop end point, in samples |
||
289 | DWORD SampleRate; // The file's decoded sample rate |
||
290 | DWORD EncodeOptions; // Options for the XMA encoder/decoder |
||
291 | DWORD PsuedoBytesPerSec; // Used internally by the XMA encoder |
||
292 | DWORD BlockSizeInBytes; // Size in bytes of this file's XMA blocks (except |
||
293 | // possibly the last one). Always a multiple of |
||
294 | // 2Kb, since XMA blocks are arrays of 2Kb packets. |
||
295 | DWORD SamplesEncoded; // Total number of PCM samples encoded in this file |
||
296 | DWORD SamplesInSource; // Actual number of PCM samples in the source |
||
297 | // material used to generate this file |
||
298 | DWORD BlockCount; // Number of XMA blocks in this file (and hence |
||
299 | // also the number of entries in its seek table) |
||
300 | XMA2STREAMFORMAT Streams[1]; // Per-stream format information; the actual |
||
301 | // array length is in the NumStreams field. |
||
302 | } XMA2WAVEFORMAT; |
||
303 | |||
304 | #endif // #ifndef WAVE_FORMAT_XMA |
||
305 | |||
306 | |||
307 | |||
308 | /*************************************************************************** |
||
309 | * XMA packet structure (in big-endian form) |
||
310 | ***************************************************************************/ |
||
311 | |||
312 | typedef struct XMA2PACKET |
||
313 | { |
||
314 | int FrameCount : 6; // Number of XMA frames that begin in this packet |
||
315 | int FrameOffsetInBits : 15; // Bit of XmaData where the first complete frame begins |
||
316 | int PacketMetaData : 3; // Metadata stored in the packet (always 1 for XMA2) |
||
317 | int PacketSkipCount : 8; // How many packets belonging to other streams must be |
||
318 | // skipped to find the next packet belonging to this one |
||
319 | BYTE XmaData[XMA_BYTES_PER_PACKET - sizeof(DWORD)]; // XMA encoded data |
||
320 | } XMA2PACKET; |
||
321 | |||
322 | // E.g. if the first DWORD of a packet is 0x30107902: |
||
323 | // |
||
324 | // 001100 000001000001111 001 00000010 |
||
325 | // | | | |____ Skip 2 packets to find the next one for this stream |
||
326 | // | | |___________ XMA2 signature (always 001) |
||
327 | // | |_____________________ First frame starts 527 bits into packet |
||
328 | // |________________________________ Packet contains 12 frames |
||
329 | |||
330 | |||
331 | // Helper functions to extract the fields above from an XMA packet. (Note that |
||
332 | // the bitfields cannot be read directly on little-endian architectures such as |
||
333 | // the Intel x86, as they are laid out in big-endian form.) |
||
334 | |||
335 | __inline DWORD GetXmaPacketFrameCount(__in_bcount(1) const BYTE* pPacket) |
||
336 | { |
||
337 | return (DWORD)(pPacket[0] >> 2); |
||
338 | } |
||
339 | |||
340 | __inline DWORD GetXmaPacketFirstFrameOffsetInBits(__in_bcount(3) const BYTE* pPacket) |
||
341 | { |
||
342 | return ((DWORD)(pPacket[0] & 0x3) << 13) | |
||
343 | ((DWORD)(pPacket[1]) << 5) | |
||
344 | ((DWORD)(pPacket[2]) >> 3); |
||
345 | } |
||
346 | |||
347 | __inline DWORD GetXmaPacketMetadata(__in_bcount(3) const BYTE* pPacket) |
||
348 | { |
||
349 | return (DWORD)(pPacket[2] & 0x7); |
||
350 | } |
||
351 | |||
352 | __inline DWORD GetXmaPacketSkipCount(__in_bcount(4) const BYTE* pPacket) |
||
353 | { |
||
354 | return (DWORD)(pPacket[3]); |
||
355 | } |
||
356 | |||
357 | |||
358 | |||
359 | /*************************************************************************** |
||
360 | * XMA frame structure |
||
361 | ***************************************************************************/ |
||
362 | |||
363 | // There is no way to represent the XMA frame as a C struct, since it is a |
||
364 | // variable-sized string of bits that need not be stored at a byte-aligned |
||
365 | // position in memory. This is the layout: |
||
366 | // |
||
367 | // XMAFRAME |
||
368 | // { |
||
369 | // LengthInBits: A 15-bit number representing the length of this frame. |
||
370 | // XmaData: Encoded XMA data; its size in bits is (LengthInBits - 15). |
||
371 | // } |
||
372 | |||
373 | // Size in bits of the frame's initial LengthInBits field |
||
374 | #define XMA_BITS_IN_FRAME_LENGTH_FIELD 15 |
||
375 | |||
376 | // Special LengthInBits value that marks an invalid final frame |
||
377 | #define XMA_FINAL_FRAME_MARKER 0x7FFF |
||
378 | |||
379 | |||
380 | |||
381 | /*************************************************************************** |
||
382 | * XMA helper functions |
||
383 | ***************************************************************************/ |
||
384 | |||
385 | // We define a local ASSERT macro to equal the global one if it exists. |
||
386 | // You can define XMA2DEFS_ASSERT in advance to override this default. |
||
387 | #ifndef XMA2DEFS_ASSERT |
||
388 | #ifdef ASSERT |
||
389 | #define XMA2DEFS_ASSERT ASSERT |
||
390 | #else |
||
391 | #define XMA2DEFS_ASSERT(a) /* No-op by default */ |
||
392 | #endif |
||
393 | #endif |
||
394 | |||
395 | |||
396 | // GetXmaBlockContainingSample: Use a given seek table to find the XMA block |
||
397 | // containing a given decoded sample. Note that the seek table entries in an |
||
398 | // XMA file are stored in big-endian form and may need to be converted prior |
||
399 | // to calling this function. |
||
400 | |||
401 | __inline HRESULT GetXmaBlockContainingSample |
||
402 | ( |
||
403 | DWORD nBlockCount, // Blocks in the file (= seek table entries) |
||
404 | __in_ecount(nBlockCount) const DWORD* pSeekTable, // Pointer to the seek table data |
||
405 | DWORD nDesiredSample, // Decoded sample to locate |
||
406 | __out DWORD* pnBlockContainingSample, // Index of the block containing the sample |
||
407 | __out DWORD* pnSampleOffsetWithinBlock // Position of the sample in this block |
||
408 | ) |
||
409 | { |
||
410 | DWORD nPreviousTotalSamples = 0; |
||
411 | DWORD nBlock; |
||
412 | DWORD nTotalSamplesSoFar; |
||
413 | |||
414 | XMA2DEFS_ASSERT(pSeekTable); |
||
415 | XMA2DEFS_ASSERT(pnBlockContainingSample); |
||
416 | XMA2DEFS_ASSERT(pnSampleOffsetWithinBlock); |
||
417 | |||
418 | for (nBlock = 0; nBlock < nBlockCount; ++nBlock) |
||
419 | { |
||
420 | nTotalSamplesSoFar = pSeekTable[nBlock]; |
||
421 | if (nTotalSamplesSoFar > nDesiredSample) |
||
422 | { |
||
423 | *pnBlockContainingSample = nBlock; |
||
424 | *pnSampleOffsetWithinBlock = nDesiredSample - nPreviousTotalSamples; |
||
425 | return S_OK; |
||
426 | } |
||
427 | nPreviousTotalSamples = nTotalSamplesSoFar; |
||
428 | } |
||
429 | |||
430 | return E_FAIL; |
||
431 | } |
||
432 | |||
433 | |||
434 | // GetXmaFrameLengthInBits: Reads a given frame's LengthInBits field. |
||
435 | |||
436 | __inline DWORD GetXmaFrameLengthInBits |
||
437 | ( |
||
438 | __in_bcount(nBitPosition / 8 + 3) |
||
439 | __in const BYTE* pPacket, // Pointer to XMA packet[s] containing the frame |
||
440 | DWORD nBitPosition // Bit offset of the frame within this packet |
||
441 | ) |
||
442 | { |
||
443 | DWORD nRegion; |
||
444 | DWORD nBytePosition = nBitPosition / 8; |
||
445 | DWORD nBitOffset = nBitPosition % 8; |
||
446 | |||
447 | if (nBitOffset < 2) // Only need to read 2 bytes (and might not be safe to read more) |
||
448 | { |
||
449 | nRegion = (DWORD)(pPacket[nBytePosition+0]) << 8 | |
||
450 | (DWORD)(pPacket[nBytePosition+1]); |
||
451 | return (nRegion >> (1 - nBitOffset)) & 0x7FFF; // Last 15 bits |
||
452 | } |
||
453 | else // Need to read 3 bytes |
||
454 | { |
||
455 | nRegion = (DWORD)(pPacket[nBytePosition+0]) << 16 | |
||
456 | (DWORD)(pPacket[nBytePosition+1]) << 8 | |
||
457 | (DWORD)(pPacket[nBytePosition+2]); |
||
458 | return (nRegion >> (9 - nBitOffset)) & 0x7FFF; // Last 15 bits |
||
459 | } |
||
460 | } |
||
461 | |||
462 | |||
463 | // GetXmaFrameBitPosition: Calculates the bit offset of a given frame within |
||
464 | // an XMA block or set of blocks. Returns 0 on failure. |
||
465 | |||
466 | __inline DWORD GetXmaFrameBitPosition |
||
467 | ( |
||
468 | __in_bcount(nXmaDataBytes) const BYTE* pXmaData, // Pointer to XMA block[s] |
||
469 | DWORD nXmaDataBytes, // Size of pXmaData in bytes |
||
470 | DWORD nStreamIndex, // Stream within which to seek |
||
471 | DWORD nDesiredFrame // Frame sought |
||
472 | ) |
||
473 | { |
||
474 | const BYTE* pCurrentPacket; |
||
475 | DWORD nPacketsExamined = 0; |
||
476 | DWORD nFrameCountSoFar = 0; |
||
477 | DWORD nFramesToSkip; |
||
478 | DWORD nFrameBitOffset; |
||
479 | |||
480 | XMA2DEFS_ASSERT(pXmaData); |
||
481 | XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0); |
||
482 | |||
483 | // Get the first XMA packet belonging to the desired stream, relying on the |
||
484 | // fact that the first packets for each stream are in consecutive order at |
||
485 | // the beginning of an XMA block. |
||
486 | |||
487 | pCurrentPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET; |
||
488 | for (;;) |
||
489 | { |
||
490 | // If we have exceeded the size of the XMA data, return failure |
||
491 | if (pCurrentPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes) |
||
492 | { |
||
493 | return 0; |
||
494 | } |
||
495 | |||
496 | // If the current packet contains the frame we are looking for... |
||
497 | if (nFrameCountSoFar + GetXmaPacketFrameCount(pCurrentPacket) > nDesiredFrame) |
||
498 | { |
||
499 | // See how many frames in this packet we need to skip to get to it |
||
500 | XMA2DEFS_ASSERT(nDesiredFrame >= nFrameCountSoFar); |
||
501 | nFramesToSkip = nDesiredFrame - nFrameCountSoFar; |
||
502 | |||
503 | // Get the bit offset of the first frame in this packet |
||
504 | nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pCurrentPacket); |
||
505 | |||
506 | // Advance nFrameBitOffset to the frame of interest |
||
507 | while (nFramesToSkip--) |
||
508 | { |
||
509 | nFrameBitOffset += GetXmaFrameLengthInBits(pCurrentPacket, nFrameBitOffset); |
||
510 | } |
||
511 | |||
512 | // The bit offset to return is the number of bits from pXmaData to |
||
513 | // pCurrentPacket plus the bit offset of the frame of interest |
||
514 | return (DWORD)(pCurrentPacket - pXmaData) * 8 + nFrameBitOffset; |
||
515 | } |
||
516 | |||
517 | // If we haven't found the right packet yet, advance our counters |
||
518 | ++nPacketsExamined; |
||
519 | nFrameCountSoFar += GetXmaPacketFrameCount(pCurrentPacket); |
||
520 | |||
521 | // And skip to the next packet belonging to the same stream |
||
522 | pCurrentPacket += XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pCurrentPacket) + 1); |
||
523 | } |
||
524 | } |
||
525 | |||
526 | |||
527 | // GetLastXmaFrameBitPosition: Calculates the bit offset of the last complete |
||
528 | // frame in an XMA block or set of blocks. |
||
529 | |||
530 | __inline DWORD GetLastXmaFrameBitPosition |
||
531 | ( |
||
532 | __in_bcount(nXmaDataBytes) const BYTE* pXmaData, // Pointer to XMA block[s] |
||
533 | DWORD nXmaDataBytes, // Size of pXmaData in bytes |
||
534 | DWORD nStreamIndex // Stream within which to seek |
||
535 | ) |
||
536 | { |
||
537 | const BYTE* pLastPacket; |
||
538 | DWORD nBytesToNextPacket; |
||
539 | DWORD nFrameBitOffset; |
||
540 | DWORD nFramesInLastPacket; |
||
541 | |||
542 | XMA2DEFS_ASSERT(pXmaData); |
||
543 | XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0); |
||
544 | XMA2DEFS_ASSERT(nXmaDataBytes >= XMA_BYTES_PER_PACKET * (nStreamIndex + 1)); |
||
545 | |||
546 | // Get the first XMA packet belonging to the desired stream, relying on the |
||
547 | // fact that the first packets for each stream are in consecutive order at |
||
548 | // the beginning of an XMA block. |
||
549 | pLastPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET; |
||
550 | |||
551 | // Search for the last packet belonging to the desired stream |
||
552 | for (;;) |
||
553 | { |
||
554 | nBytesToNextPacket = XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pLastPacket) + 1); |
||
555 | XMA2DEFS_ASSERT(nBytesToNextPacket); |
||
556 | if (pLastPacket + nBytesToNextPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes) |
||
557 | { |
||
558 | break; // The next packet would extend beyond the end of pXmaData |
||
559 | } |
||
560 | pLastPacket += nBytesToNextPacket; |
||
561 | } |
||
562 | |||
563 | // The last packet can sometimes have no seekable frames, in which case we |
||
564 | // have to use the previous one |
||
565 | if (GetXmaPacketFrameCount(pLastPacket) == 0) |
||
566 | { |
||
567 | pLastPacket -= nBytesToNextPacket; |
||
568 | } |
||
569 | |||
570 | // Found the last packet. Get the bit offset of its first frame. |
||
571 | nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pLastPacket); |
||
572 | |||
573 | // Traverse frames until we reach the last one |
||
574 | nFramesInLastPacket = GetXmaPacketFrameCount(pLastPacket); |
||
575 | while (--nFramesInLastPacket) |
||
576 | { |
||
577 | nFrameBitOffset += GetXmaFrameLengthInBits(pLastPacket, nFrameBitOffset); |
||
578 | } |
||
579 | |||
580 | // The bit offset to return is the number of bits from pXmaData to |
||
581 | // pLastPacket plus the offset of the last frame in this packet. |
||
582 | return (DWORD)(pLastPacket - pXmaData) * 8 + nFrameBitOffset; |
||
583 | } |
||
584 | |||
585 | |||
586 | // GetXmaDecodePositionForSample: Obtains the information needed to make the |
||
587 | // decoder generate audio starting at a given sample position relative to the |
||
588 | // beginning of the given XMA block: the bit offset of the appropriate frame, |
||
589 | // and the right subframe within that frame. This data can be passed directly |
||
590 | // to the XMAPlaybackSetDecodePosition function. |
||
591 | |||
592 | __inline HRESULT GetXmaDecodePositionForSample |
||
593 | ( |
||
594 | __in_bcount(nXmaDataBytes) const BYTE* pXmaData, // Pointer to XMA block[s] |
||
595 | DWORD nXmaDataBytes, // Size of pXmaData in bytes |
||
596 | DWORD nStreamIndex, // Stream within which to seek |
||
597 | DWORD nDesiredSample, // Sample sought |
||
598 | __out DWORD* pnBitOffset, // Returns the bit offset within pXmaData of |
||
599 | // the frame containing the sample sought |
||
600 | __out DWORD* pnSubFrame // Returns the subframe containing the sample |
||
601 | ) |
||
602 | { |
||
603 | DWORD nDesiredFrame = nDesiredSample / XMA_SAMPLES_PER_FRAME; |
||
604 | DWORD nSubFrame = (nDesiredSample % XMA_SAMPLES_PER_FRAME) / XMA_SAMPLES_PER_SUBFRAME; |
||
605 | DWORD nBitOffset = GetXmaFrameBitPosition(pXmaData, nXmaDataBytes, nStreamIndex, nDesiredFrame); |
||
606 | |||
607 | XMA2DEFS_ASSERT(pnBitOffset); |
||
608 | XMA2DEFS_ASSERT(pnSubFrame); |
||
609 | |||
610 | if (nBitOffset) |
||
611 | { |
||
612 | *pnBitOffset = nBitOffset; |
||
613 | *pnSubFrame = nSubFrame; |
||
614 | return S_OK; |
||
615 | } |
||
616 | else |
||
617 | { |
||
618 | return E_FAIL; |
||
619 | } |
||
620 | } |
||
621 | |||
622 | |||
623 | // GetXmaSampleRate: Obtains the legal XMA sample rate (24, 32, 44.1 or 48Khz) |
||
624 | // corresponding to a generic sample rate. |
||
625 | |||
626 | __inline DWORD GetXmaSampleRate(DWORD dwGeneralRate) |
||
627 | { |
||
628 | DWORD dwXmaRate = 48000; // Default XMA rate for all rates above 44100Hz |
||
629 | |||
630 | if (dwGeneralRate <= 24000) dwXmaRate = 24000; |
||
631 | else if (dwGeneralRate <= 32000) dwXmaRate = 32000; |
||
632 | else if (dwGeneralRate <= 44100) dwXmaRate = 44100; |
||
633 | |||
634 | return dwXmaRate; |
||
635 | } |
||
636 | |||
637 | |||
638 | // Functions to convert between WAVEFORMATEXTENSIBLE channel masks (combinations |
||
639 | // of the SPEAKER_xxx flags defined in audiodefs.h) and XMA channel masks (which |
||
640 | // are limited to eight possible speaker positions: left, right, center, low |
||
641 | // frequency, side left, side right, back left and back right). |
||
642 | |||
643 | __inline DWORD GetStandardChannelMaskFromXmaMask(BYTE bXmaMask) |
||
644 | { |
||
645 | DWORD dwStandardMask = 0; |
||
646 | |||
647 | if (bXmaMask & XMA_SPEAKER_LEFT) dwStandardMask |= SPEAKER_FRONT_LEFT; |
||
648 | if (bXmaMask & XMA_SPEAKER_RIGHT) dwStandardMask |= SPEAKER_FRONT_RIGHT; |
||
649 | if (bXmaMask & XMA_SPEAKER_CENTER) dwStandardMask |= SPEAKER_FRONT_CENTER; |
||
650 | if (bXmaMask & XMA_SPEAKER_LFE) dwStandardMask |= SPEAKER_LOW_FREQUENCY; |
||
651 | if (bXmaMask & XMA_SPEAKER_LEFT_SURROUND) dwStandardMask |= SPEAKER_SIDE_LEFT; |
||
652 | if (bXmaMask & XMA_SPEAKER_RIGHT_SURROUND) dwStandardMask |= SPEAKER_SIDE_RIGHT; |
||
653 | if (bXmaMask & XMA_SPEAKER_LEFT_BACK) dwStandardMask |= SPEAKER_BACK_LEFT; |
||
654 | if (bXmaMask & XMA_SPEAKER_RIGHT_BACK) dwStandardMask |= SPEAKER_BACK_RIGHT; |
||
655 | |||
656 | return dwStandardMask; |
||
657 | } |
||
658 | |||
659 | __inline BYTE GetXmaChannelMaskFromStandardMask(DWORD dwStandardMask) |
||
660 | { |
||
661 | BYTE bXmaMask = 0; |
||
662 | |||
663 | if (dwStandardMask & SPEAKER_FRONT_LEFT) bXmaMask |= XMA_SPEAKER_LEFT; |
||
664 | if (dwStandardMask & SPEAKER_FRONT_RIGHT) bXmaMask |= XMA_SPEAKER_RIGHT; |
||
665 | if (dwStandardMask & SPEAKER_FRONT_CENTER) bXmaMask |= XMA_SPEAKER_CENTER; |
||
666 | if (dwStandardMask & SPEAKER_LOW_FREQUENCY) bXmaMask |= XMA_SPEAKER_LFE; |
||
667 | if (dwStandardMask & SPEAKER_SIDE_LEFT) bXmaMask |= XMA_SPEAKER_LEFT_SURROUND; |
||
668 | if (dwStandardMask & SPEAKER_SIDE_RIGHT) bXmaMask |= XMA_SPEAKER_RIGHT_SURROUND; |
||
669 | if (dwStandardMask & SPEAKER_BACK_LEFT) bXmaMask |= XMA_SPEAKER_LEFT_BACK; |
||
670 | if (dwStandardMask & SPEAKER_BACK_RIGHT) bXmaMask |= XMA_SPEAKER_RIGHT_BACK; |
||
671 | |||
672 | return bXmaMask; |
||
673 | } |
||
674 | |||
675 | |||
676 | // LocalizeXma2Format: Modifies a XMA2WAVEFORMATEX structure in place to comply |
||
677 | // with the current platform's byte-ordering rules (little- or big-endian). |
||
678 | |||
679 | __inline HRESULT LocalizeXma2Format(__inout XMA2WAVEFORMATEX* pXma2Format) |
||
680 | { |
||
681 | #define XMASWAP2BYTES(n) ((WORD)(((n) >> 8) | (((n) & 0xff) << 8))) |
||
682 | #define XMASWAP4BYTES(n) ((DWORD)((n) >> 24 | (n) << 24 | ((n) & 0xff00) << 8 | ((n) & 0xff0000) >> 8)) |
||
683 | |||
684 | if (pXma2Format->wfx.wFormatTag == WAVE_FORMAT_XMA2) |
||
685 | { |
||
686 | return S_OK; |
||
687 | } |
||
688 | else if (XMASWAP2BYTES(pXma2Format->wfx.wFormatTag) == WAVE_FORMAT_XMA2) |
||
689 | { |
||
690 | pXma2Format->wfx.wFormatTag = XMASWAP2BYTES(pXma2Format->wfx.wFormatTag); |
||
691 | pXma2Format->wfx.nChannels = XMASWAP2BYTES(pXma2Format->wfx.nChannels); |
||
692 | pXma2Format->wfx.nSamplesPerSec = XMASWAP4BYTES(pXma2Format->wfx.nSamplesPerSec); |
||
693 | pXma2Format->wfx.nAvgBytesPerSec = XMASWAP4BYTES(pXma2Format->wfx.nAvgBytesPerSec); |
||
694 | pXma2Format->wfx.nBlockAlign = XMASWAP2BYTES(pXma2Format->wfx.nBlockAlign); |
||
695 | pXma2Format->wfx.wBitsPerSample = XMASWAP2BYTES(pXma2Format->wfx.wBitsPerSample); |
||
696 | pXma2Format->wfx.cbSize = XMASWAP2BYTES(pXma2Format->wfx.cbSize); |
||
697 | pXma2Format->NumStreams = XMASWAP2BYTES(pXma2Format->NumStreams); |
||
698 | pXma2Format->ChannelMask = XMASWAP4BYTES(pXma2Format->ChannelMask); |
||
699 | pXma2Format->SamplesEncoded = XMASWAP4BYTES(pXma2Format->SamplesEncoded); |
||
700 | pXma2Format->BytesPerBlock = XMASWAP4BYTES(pXma2Format->BytesPerBlock); |
||
701 | pXma2Format->PlayBegin = XMASWAP4BYTES(pXma2Format->PlayBegin); |
||
702 | pXma2Format->PlayLength = XMASWAP4BYTES(pXma2Format->PlayLength); |
||
703 | pXma2Format->LoopBegin = XMASWAP4BYTES(pXma2Format->LoopBegin); |
||
704 | pXma2Format->LoopLength = XMASWAP4BYTES(pXma2Format->LoopLength); |
||
705 | pXma2Format->BlockCount = XMASWAP2BYTES(pXma2Format->BlockCount); |
||
706 | return S_OK; |
||
707 | } |
||
708 | else |
||
709 | { |
||
710 | return E_FAIL; // Not a recognizable XMA2 format |
||
711 | } |
||
712 | |||
713 | #undef XMASWAP2BYTES |
||
714 | #undef XMASWAP4BYTES |
||
715 | } |
||
716 | |||
717 | |||
718 | #endif // #ifndef __XMA2DEFS_INCLUDED__ |