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__ |