text: /***************************************************************************
   *
   * Copyright (c) Microsoft Corporation.  All rights reserved.
   *
   * File:     xma2defs.h
   * Content:  Constants, data types and functions for XMA2 compressed audio.
   *
   ***************************************************************************/
  
  #ifndef __XMA2DEFS_INCLUDED__
  #define __XMA2DEFS_INCLUDED__
  
  #include "audiodefs.h"  // Basic data types and constants for audio work
  #include <winerror.h>   // For S_OK, E_FAIL
  
  
  /***************************************************************************
   *  Overview
   ***************************************************************************/
  
  // A typical XMA2 file contains these RIFF chunks:
  //
  // 'fmt' or 'XMA2' chunk (or both): A description of the XMA data's structure
  // and characteristics (length, channels, sample rate, loops, block size, etc).
  //
  // 'seek' chunk: A seek table to help navigate the XMA data.
  //
  // 'data' chunk: The encoded XMA2 data.
  //
  // The encoded XMA2 data is structured as a set of BLOCKS, which contain PACKETS,
  // which contain FRAMES, which contain SUBFRAMES (roughly speaking).  The frames
  // in a file may also be divided into several subsets, called STREAMS.
  //
  // FRAME: A variable-sized segment of XMA data that decodes to exactly 512 mono
  //      or stereo PCM samples.  This is the smallest unit of XMA data that can
  //      be decoded in isolation.  Frames are an arbitrary number of bits in
  //      length, and need not be byte-aligned.  See "XMA frame structure" below.
  //
  // SUBFRAME: A region of bits in an XMA frame that decodes to 128 mono or stereo
  //      samples.  The XMA decoder cannot decode a subframe in isolation; it needs
  //      a whole frame to work with.  However, it can begin emitting the frame's
  //      decoded samples at any one of the four subframe boundaries.  Subframes
  //      can be addressed for seeking and looping purposes.
  //
  // PACKET: A 2Kb region containing a 32-bit header and some XMA frames.  Frames
  //      can (and usually do) span packets.  A packet's header includes the offset
  //      in bits of the first frame that begins within that packet.  All of the
  //      frames that begin in a given packet belong to the same "stream" (see the
  //      Multichannel Audio section below).
  //
  // STREAM: A set of packets within an XMA file that all contain data for the
  //      same mono or stereo component of a PCM file with more than two channels.
  //      The packets comprising a given stream may be interleaved with each other
  //      more or less arbitrarily; see Multichannel Audio.
  //
  // BLOCK: An array of XMA packets; or, to break it down differently, a series of
  //      consecutive XMA frames, padded at the end with reserved data.  A block
  //      must contain at least one 2Kb packet per stream, and it can hold up to
  //      4095 packets (8190Kb), but its size is typically in the 32Kb-128Kb range.
  //      (The size chosen involves a trade-off between memory use and efficiency
  //      of reading from permanent storage.)
  //
  //      XMA frames do not span blocks, so a block is guaranteed to begin with a
  //      set of complete frames, one per stream.  Also, a block in a multi-stream
  //      XMA2 file always contains the same number of samples for each stream;
  //      see Multichannel Audio.
  //
  // The 'data' chunk in an XMA2 file is an array of XMA2WAVEFORMAT.BlockCount XMA
  // blocks, all the same size (as specified in XMA2WAVEFORMAT.BlockSizeInBytes)
  // except for the last one, which may be shorter.
  
  
  // MULTICHANNEL AUDIO: the XMA decoder can only decode raw XMA data into either
  // mono or stereo PCM data.  In order to encode a 6-channel file (say), the file
  // must be deinterleaved into 3 stereo streams that are encoded independently,
  // producing 3 encoded XMA data streams.  Then the packets in these 3 streams
  // are interleaved to produce a single XMA2 file, and some information is added
  // to the file so that the original 6-channel audio can be reconstructed at
  // decode time.  This works using the concept of an XMA stream (see above).
  //
  // The frames for all the streams in an XMA file are interleaved in an arbitrary
  // order.  To locate a frame that belongs to a given stream in a given XMA block,
  // you must examine the first few packets in the block.  Here (and only here) the
  // packets are guaranteed to be presented in stream order, so that all frames
  // beginning in packet 0 belong to stream 0 (the first stereo pair), etc.
  //
  // (This means that when decoding multi-stream XMA files, only entire XMA blocks
  // should be submitted to the decoder; otherwise it cannot know which frames
  // belong to which stream.)
  //
  // Once you have one frame that belongs to a given stream, you can find the next
  // one by looking at the frame's 'NextFrameOffsetBits' value (which is stored in
  // its first 15 bits; see XMAFRAME below).  The GetXmaFrameBitPosition function
  // uses this technique.
  
  
  // SEEKING IN XMA2 FILES: Here is some pseudocode to find the byte position and
  // subframe in an XMA2 file which will contain sample S when decoded.
  //
  // 1. Traverse the seek table to find the XMA2 block containing sample S. The
  //    seek table is an array of big-endian DWORDs, one per block in the file.
  //    The Nth DWORD is the total number of PCM samples that would be obtained
  //    by decoding the entire XMA file up to the end of block N.  Hence, the
  //    block we want is the first one whose seek table entry is greater than S.
  //    (See the GetXmaBlockContainingSample helper function.)
  //
  // 2. Calculate which frame F within the block found above contains sample S.
  //    Since each frame decodes to 512 samples, this is straightforward.  The
  //    first frame in the block produces samples X to X + 512, where X is the
  //    seek table entry for the prior block.  So F is (S - X) / 512.
  //
  // 3. Find the bit offset within the block where frame F starts.  Since frames
  //    are variable-sized, this can only be done by traversing all the frames in
  //    the block until we reach frame F.  (See GetXmaFrameBitPosition.)
  //
  // 4. Frame F has four 128-sample subframes.  To find the subframe containing S,
  //    we can use the formula (S % 512) / 128.
  //
  // In the case of multi-stream XMA files, sample S is a multichannel sample with
  // parts coming from several frames, one per stream.  To find all these frames,
  // steps 2-4 need to be repeated for each stream N, using the knowledge that the
  // first packets in a block are presented in stream order.  The frame traversal
  // in step 3 must be started at the first frame in the Nth packet of the block,
  // which will be the first frame for stream N.  (And the packet header will tell
  // you the first frame's start position within the packet.)
  //
  // Step 1 can be performed using the GetXmaBlockContainingSample function below,
  // and steps 2-4 by calling GetXmaDecodePositionForSample once for each stream.
  
  
  
  /***************************************************************************
   *  XMA constants
   ***************************************************************************/
  
  // Size of the PCM samples produced by the XMA decoder
  #define XMA_OUTPUT_SAMPLE_BYTES         2u
  #define XMA_OUTPUT_SAMPLE_BITS          (XMA_OUTPUT_SAMPLE_BYTES * 8u)
  
  // Size of an XMA packet
  #define XMA_BYTES_PER_PACKET            2048u
  #define XMA_BITS_PER_PACKET             (XMA_BYTES_PER_PACKET * 8u)
  
  // Size of an XMA packet header
  #define XMA_PACKET_HEADER_BYTES         4u
  #define XMA_PACKET_HEADER_BITS          (XMA_PACKET_HEADER_BYTES * 8u)
  
  // Sample blocks in a decoded XMA frame
  #define XMA_SAMPLES_PER_FRAME           512u
  
  // Sample blocks in a decoded XMA subframe
  #define XMA_SAMPLES_PER_SUBFRAME        128u
  
  // Maximum encoded data that can be submitted to the XMA decoder at a time
  #define XMA_READBUFFER_MAX_PACKETS      4095u
  #define XMA_READBUFFER_MAX_BYTES        (XMA_READBUFFER_MAX_PACKETS * XMA_BYTES_PER_PACKET)
  
  // Maximum size allowed for the XMA decoder's output buffers
  #define XMA_WRITEBUFFER_MAX_BYTES       (31u * 256u)
  
  // Required byte alignment of the XMA decoder's output buffers
  #define XMA_WRITEBUFFER_BYTE_ALIGNMENT  256u
  
  // Decode chunk sizes for the XMA_PLAYBACK_INIT.subframesToDecode field
  #define XMA_MIN_SUBFRAMES_TO_DECODE     1u
  #define XMA_MAX_SUBFRAMES_TO_DECODE     8u
  #define XMA_OPTIMAL_SUBFRAMES_TO_DECODE 4u
  
  // LoopCount<255 means finite repetitions; LoopCount=255 means infinite looping
  #define XMA_MAX_LOOPCOUNT               254u
  #define XMA_INFINITE_LOOP               255u
  
  
  
  /***************************************************************************
   *  XMA format structures
   ***************************************************************************/
  
  // The currently recommended way to express format information for XMA2 files
  // is the XMAWAVEFORMATEX structure.  This structure is fully compliant with
  // the WAVEFORMATEX standard and contains all the information needed to parse
  // and manage XMA2 files in a compact way.
  
  #define WAVE_FORMAT_XMA2 0x166
  
  typedef struct XMA2WAVEFORMATEX
  {
      WAVEFORMATEX wfx;
      // Meaning of the WAVEFORMATEX fields here:
      //    wFormatTag;        // Audio format type; always WAVE_FORMAT_XMA2
      //    nChannels;         // Channel count of the decoded audio
      //    nSamplesPerSec;    // Sample rate of the decoded audio
      //    nAvgBytesPerSec;   // Used internally by the XMA encoder
      //    nBlockAlign;       // Decoded sample size; channels * wBitsPerSample / 8
      //    wBitsPerSample;    // Bits per decoded mono sample; always 16 for XMA
      //    cbSize;            // Size in bytes of the rest of this structure (34)
  
      WORD  NumStreams;        // Number of audio streams (1 or 2 channels each)
      DWORD ChannelMask;       // Spatial positions of the channels in this file,
                               // stored as SPEAKER_xxx values (see audiodefs.h)
      DWORD SamplesEncoded;    // Total number of PCM samples the file decodes to
      DWORD BytesPerBlock;     // XMA block size (but the last one may be shorter)
      DWORD PlayBegin;         // First valid sample in the decoded audio
      DWORD PlayLength;        // Length of the valid part of the decoded audio
      DWORD LoopBegin;         // Beginning of the loop region in decoded sample terms
      DWORD LoopLength;        // Length of the loop region in decoded sample terms
      BYTE  LoopCount;         // Number of loop repetitions; 255 = infinite
      BYTE  EncoderVersion;    // Version of XMA encoder that generated the file
      WORD  BlockCount;        // XMA blocks in file (and entries in its seek table)
  } XMA2WAVEFORMATEX, *PXMA2WAVEFORMATEX;
  
  
  // The legacy XMA format structures are described here for reference, but they
  // should not be used in new content.  XMAWAVEFORMAT was the structure used in
  // XMA version 1 files.  XMA2WAVEFORMAT was used in early XMA2 files; it is not
  // placed in the usual 'fmt' RIFF chunk but in its own 'XMA2' chunk.
  
  #ifndef WAVE_FORMAT_XMA
  #define WAVE_FORMAT_XMA 0x0165
  
  // Values used in the ChannelMask fields below.  Similar to the SPEAKER_xxx
  // values defined in audiodefs.h, but modified to fit in a single byte.
  #ifndef XMA_SPEAKER_LEFT
      #define XMA_SPEAKER_LEFT            0x01
      #define XMA_SPEAKER_RIGHT           0x02
      #define XMA_SPEAKER_CENTER          0x04
      #define XMA_SPEAKER_LFE             0x08
      #define XMA_SPEAKER_LEFT_SURROUND   0x10
      #define XMA_SPEAKER_RIGHT_SURROUND  0x20
      #define XMA_SPEAKER_LEFT_BACK       0x40
      #define XMA_SPEAKER_RIGHT_BACK      0x80
  #endif
  
  
  // Used in XMAWAVEFORMAT for per-stream data
  typedef struct XMASTREAMFORMAT
  {
      DWORD PsuedoBytesPerSec; // Used by the XMA encoder (typo preserved for legacy reasons)
      DWORD SampleRate;        // The stream's decoded sample rate (in XMA2 files,
                               // this is the same for all streams in the file).
      DWORD LoopStart;         // Bit offset of the frame containing the loop start
                               // point, relative to the beginning of the stream.
      DWORD LoopEnd;           // Bit offset of the frame containing the loop end.
      BYTE  SubframeData;      // Two 4-bit numbers specifying the exact location of
                               // the loop points within the frames that contain them.
                               //  1st 4 bits: Which subframe of the end frame does
                               //              the loop end at.  Ranges from 0 to 3.
                               //  2nd 4 bits: Which subframe of the start frame does
                               //              the loop begin at.  Ranges from 1 to 4.
      BYTE  Channels;          // Number of channels in the stream (1 or 2)
      WORD  ChannelMask;       // Spatial positions of the channels in the stream
  } XMASTREAMFORMAT;
  
  // Legacy XMA1 format structure
  typedef struct XMAWAVEFORMAT
  {
      WORD FormatTag;          // Audio format type (always WAVE_FORMAT_XMA)
      WORD BitsPerSample;      // Bit depth (currently required to be 16)
      WORD EncodeOptions;      // Options for XMA encoder/decoder
      WORD LargestSkip;        // Largest skip used in interleaving streams
      WORD NumStreams;         // Number of interleaved audio streams
      BYTE LoopCount;          // Number of loop repetitions; 255 = infinite
      BYTE Version;            // XMA encoder version that generated the file.
                               // Always 3 or higher for XMA2 files.
      XMASTREAMFORMAT XmaStreams[1]; // Per-stream format information; the actual
                                     // array length is in the NumStreams field.
  } XMAWAVEFORMAT;
  
  
  // Used in XMA2WAVEFORMAT for per-stream data
  typedef struct XMA2STREAMFORMAT
  {
      BYTE Channels;           // Number of channels in the stream (1 or 2)
      BYTE RESERVED;           // Reserved for future use
      WORD ChannelMask;        // Spatial positions of the channels in the stream
  } XMA2STREAMFORMAT;
  
  // Legacy XMA2 format structure (big-endian byte ordering)
  typedef struct XMA2WAVEFORMAT
  {
      BYTE  Version;           // XMA encoder version that generated the file.
                               // Always 3 or higher for XMA2 files.
      BYTE  NumStreams;        // Number of interleaved audio streams
      BYTE  RESERVED;          // Reserved for future use
      BYTE  LoopCount;         // Number of loop repetitions; 255 = infinite
      DWORD LoopBegin;         // Loop begin point, in samples
      DWORD LoopEnd;           // Loop end point, in samples
      DWORD SampleRate;        // The file's decoded sample rate
      DWORD EncodeOptions;     // Options for the XMA encoder/decoder
      DWORD PsuedoBytesPerSec; // Used internally by the XMA encoder
      DWORD BlockSizeInBytes;  // Size in bytes of this file's XMA blocks (except
                               // possibly the last one).  Always a multiple of
                               // 2Kb, since XMA blocks are arrays of 2Kb packets.
      DWORD SamplesEncoded;    // Total number of PCM samples encoded in this file
      DWORD SamplesInSource;   // Actual number of PCM samples in the source
                               // material used to generate this file
      DWORD BlockCount;        // Number of XMA blocks in this file (and hence
                               // also the number of entries in its seek table)
      XMA2STREAMFORMAT Streams[1]; // Per-stream format information; the actual
                                   // array length is in the NumStreams field.
  } XMA2WAVEFORMAT;
  
  #endif // #ifndef WAVE_FORMAT_XMA
  
  
  
  /***************************************************************************
   *  XMA packet structure (in big-endian form)
   ***************************************************************************/
  
  typedef struct XMA2PACKET
  {
      int FrameCount        :  6;  // Number of XMA frames that begin in this packet
      int FrameOffsetInBits : 15;  // Bit of XmaData where the first complete frame begins
      int PacketMetaData    :  3;  // Metadata stored in the packet (always 1 for XMA2)
      int PacketSkipCount   :  8;  // How many packets belonging to other streams must be
                                   // skipped to find the next packet belonging to this one
      BYTE XmaData[XMA_BYTES_PER_PACKET - sizeof(DWORD)];  // XMA encoded data
  } XMA2PACKET;
  
  // E.g. if the first DWORD of a packet is 0x30107902:
  //
  // 001100 000001000001111 001 00000010
  //    |          |         |      |____ Skip 2 packets to find the next one for this stream
  //    |          |         |___________ XMA2 signature (always 001)
  //    |          |_____________________ First frame starts 527 bits into packet
  //    |________________________________ Packet contains 12 frames
  
  
  // Helper functions to extract the fields above from an XMA packet.  (Note that
  // the bitfields cannot be read directly on little-endian architectures such as
  // the Intel x86, as they are laid out in big-endian form.)
  
  __inline DWORD GetXmaPacketFrameCount(const BYTE* pPacket)
  {
      return (DWORD)(pPacket[0] >> 2);
  }
  
  __inline DWORD GetXmaPacketFirstFrameOffsetInBits(const BYTE* pPacket)
  {
      return ((DWORD)(pPacket[0] & 0x3) << 13) |
             ((DWORD)(pPacket[1]) << 5) |
             ((DWORD)(pPacket[2]) >> 3);
  }
  
  __inline DWORD GetXmaPacketMetadata(const BYTE* pPacket)
  {
      return (DWORD)(pPacket[2] & 0x7);
  }
  
  __inline DWORD GetXmaPacketSkipCount(const BYTE* pPacket)
  {
      return (DWORD)(pPacket[3]);
  }
  
  
  
  /***************************************************************************
   *  XMA frame structure
   ***************************************************************************/
  
  // There is no way to represent the XMA frame as a C struct, since it is a
  // variable-sized string of bits that need not be stored at a byte-aligned
  // position in memory.  This is the layout:
  //
  // XMAFRAME
  // {
  //    LengthInBits: A 15-bit number representing the length of this frame.
  //    XmaData: Encoded XMA data; its size in bits is (LengthInBits - 15).
  // }
  
  // Size in bits of the frame's initial LengthInBits field
  #define XMA_BITS_IN_FRAME_LENGTH_FIELD 15
  
  // Special LengthInBits value that marks an invalid final frame
  #define XMA_FINAL_FRAME_MARKER 0x7FFF
  
  
  
  /***************************************************************************
   *  XMA helper functions
   ***************************************************************************/
  
  // Try to use ASSERT and TRACE macros if available
  #ifdef ASSERT
      #define XMA2DEFS_ASSERT ASSERT
  #else
      #define XMA2DEFS_ASSERT(a)
  #endif
  
  
  // GetXmaBlockContainingSample: Use a given seek table to find the XMA block
  // containing a given decoded sample.  Note that the seek table entries in an
  // XMA file are stored in big-endian form and may need to be converted prior
  // to calling this function.
  
  __inline HRESULT GetXmaBlockContainingSample
  (
      DWORD nBlockCount,               // Blocks in the file (= seek table entries)
      const DWORD* pSeekTable,         // Pointer to data from the seek table chunk
      DWORD nDesiredSample,            // Decoder sample to locate
      DWORD* pnBlockContainingSample,  // Index of the block containing the sample
      DWORD* pnSampleOffsetWithinBlock // Position of the sample in this block
  )
  {
      DWORD nPreviousTotalSamples = 0;
      DWORD nBlock;
      DWORD nTotalSamplesSoFar;
  
      XMA2DEFS_ASSERT(pSeekTable);
      XMA2DEFS_ASSERT(pnBlockContainingSample);
      XMA2DEFS_ASSERT(pnSampleOffsetWithinBlock);
  
      for (nBlock = 0; nBlock < nBlockCount; ++nBlock)
      {
          // REVISE: Is byte-swapping required?
          nTotalSamplesSoFar = pSeekTable[nBlock];
          if (nTotalSamplesSoFar > nDesiredSample)
          {
              *pnBlockContainingSample = nBlock;
              *pnSampleOffsetWithinBlock = nDesiredSample - nPreviousTotalSamples;
              return S_OK;
          }
          nPreviousTotalSamples = nTotalSamplesSoFar;
      }
  
      return E_FAIL;
  }
  
  
  // GetXmaFrameLengthInBits: Reads a given frame's LengthInBits field.
  
  __inline DWORD GetXmaFrameLengthInBits
  (
      const BYTE* pPacket, // Beginning of the XMA packet[s] containing the frame
      DWORD nBitPosition   // Bit offset of the frame within this packet
  )
  {
      DWORD nRegion;
      DWORD nBytePosition = nBitPosition / 8;
      DWORD nBitOffset = nBitPosition % 8;
  
      if (nBitOffset < 2) // Only need to read 2 bytes (and might not be safe to read more)
      {
          nRegion = (DWORD)(pPacket[nBytePosition+0]) << 8 |
                    (DWORD)(pPacket[nBytePosition+1]);
          return (nRegion >> (1 - nBitOffset)) & 0x7FFF;  // Last 15 bits
      }
      else // Need to read 3 bytes
      {
          nRegion = (DWORD)(pPacket[nBytePosition+0]) << 16 |
                    (DWORD)(pPacket[nBytePosition+1]) << 8 |
                    (DWORD)(pPacket[nBytePosition+2]);
          return (nRegion >> (9 - nBitOffset)) & 0x7FFF;  // Last 15 bits
      }
  }
  
  
  // GetXmaFrameBitPosition: Calculates the bit offset of a given frame within
  // an XMA block or set of blocks.  Returns 0 on failure.
  
  __inline DWORD GetXmaFrameBitPosition
  (
      const BYTE* pXmaData,  // Pointer to beginning of the XMA block[s]
      DWORD nXmaDataBytes,   // Size of pXmaData in bytes
      DWORD nStreamIndex,    // Stream within which to seek
      DWORD nDesiredFrame    // Frame sought
  )
  {
      const BYTE* pCurrentPacket;
      DWORD nPacketsExamined = 0;
      DWORD nFrameCountSoFar = 0;
      DWORD nFramesToSkip;
      DWORD nFrameBitOffset;
  
      XMA2DEFS_ASSERT(pXmaData);
      XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0);
  
      // Get the first XMA packet belonging to the desired stream, relying on the
      // fact that the first packets for each stream are in consecutive order at
      // the beginning of an XMA block.
  
      pCurrentPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET;
      for (;;)
      {
          // If we have exceeded the size of the XMA data, return failure
          if (pCurrentPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes)
          {
              return 0;
          }
  
          // If the current packet contains the frame we are looking for...
          if (nFrameCountSoFar + GetXmaPacketFrameCount(pCurrentPacket) > nDesiredFrame)
          {
              // See how many frames in this packet we need to skip to get to it
              XMA2DEFS_ASSERT(nDesiredFrame >= nFrameCountSoFar);
              nFramesToSkip = nDesiredFrame - nFrameCountSoFar;
  
              // Get the bit offset of the first frame in this packet
              nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pCurrentPacket);
  
              // Advance nFrameBitOffset to the frame of interest
              while (nFramesToSkip--)
              {
                  nFrameBitOffset += GetXmaFrameLengthInBits(pCurrentPacket, nFrameBitOffset);
              }
  
              // The bit offset to return is the number of bits from pXmaData to
              // pCurrentPacket plus the bit offset of the frame of interest
              return (DWORD)(pCurrentPacket - pXmaData) * 8 + nFrameBitOffset;
          }
  
          // If we haven't found the right packet yet, advance our counters
          ++nPacketsExamined;
          nFrameCountSoFar += GetXmaPacketFrameCount(pCurrentPacket);
  
          // And skip to the next packet belonging to the same stream
          pCurrentPacket += XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pCurrentPacket) + 1);
      }
  }
  
  
  // GetLastXmaFrameBitPosition: Calculates the bit offset of the last complete
  // frame in an XMA block or set of blocks.
  
  __inline DWORD GetLastXmaFrameBitPosition
  (
      const BYTE* pXmaData,  // Pointer to beginning of the XMA block[s]
      DWORD nXmaDataBytes,   // Size of pXmaData in bytes
      DWORD nStreamIndex     // Stream within which to seek
  )
  {
      const BYTE* pLastPacket;
      DWORD nBytesToNextPacket;
      DWORD nFrameBitOffset;
      DWORD nFramesInLastPacket;
  
      XMA2DEFS_ASSERT(pXmaData);
      XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0);
      XMA2DEFS_ASSERT(nXmaDataBytes >= XMA_BYTES_PER_PACKET * (nStreamIndex + 1));
  
      // Get the first XMA packet belonging to the desired stream, relying on the
      // fact that the first packets for each stream are in consecutive order at
      // the beginning of an XMA block.
      pLastPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET;
  
      // Search for the last packet belonging to the desired stream
      for (;;)
      {
          nBytesToNextPacket = XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pLastPacket) + 1);
          XMA2DEFS_ASSERT(nBytesToNextPacket);
          if (pLastPacket + nBytesToNextPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes)
          {
              break;  // The next packet would extend beyond the end of pXmaData
          }
          pLastPacket += nBytesToNextPacket;
      }
  
      // The last packet can sometimes have no seekable frames, in which case we
      // have to use the previous one
      if (GetXmaPacketFrameCount(pLastPacket) == 0)
      {
          pLastPacket -= nBytesToNextPacket;
      }
  
      // Found the last packet.  Get the bit offset of its first frame.
      nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pLastPacket);
  
      // Traverse frames until we reach the last one
      nFramesInLastPacket = GetXmaPacketFrameCount(pLastPacket);
      while (--nFramesInLastPacket)
      {
          nFrameBitOffset += GetXmaFrameLengthInBits(pLastPacket, nFrameBitOffset);
      }
  
      // The bit offset to return is the number of bits from pXmaData to
      // pLastPacket plus the offset of the last frame in this packet.
      return (DWORD)(pLastPacket - pXmaData) * 8 + nFrameBitOffset;
  }
  
  
  // GetXmaDecodePositionForSample: Obtains the information needed to make the
  // decoder generate audio starting at a given sample position relative to the
  // beginning of the given XMA block: the bit offset of the appropriate frame,
  // and the right subframe within that frame.  This data can be passed directly
  // to the XMAPlaybackSetDecodePosition function.
  
  __inline HRESULT GetXmaDecodePositionForSample
  (
      const BYTE* pXmaData,  // Pointer to beginning of the XMA block[s]
      DWORD nXmaDataBytes,   // Size of pXmaData in bytes
      DWORD nStreamIndex,    // Stream within which to seek
      DWORD nDesiredSample,  // Sample sought
      DWORD* pnBitOffset,    // Returns the bit offset within pXmaData of
                             // the frame containing the sample sought
      DWORD* pnSubFrame      // Returns the subframe containing the sample
  )
  {
      DWORD nDesiredFrame = nDesiredSample / XMA_SAMPLES_PER_FRAME;
      DWORD nSubFrame = (nDesiredSample % XMA_SAMPLES_PER_FRAME) / XMA_SAMPLES_PER_SUBFRAME;
      DWORD nBitOffset = GetXmaFrameBitPosition(pXmaData, nXmaDataBytes, nStreamIndex, nDesiredFrame);
  
      XMA2DEFS_ASSERT(pnBitOffset);
      XMA2DEFS_ASSERT(pnSubFrame);
  
      if (nBitOffset)
      {
          *pnBitOffset = nBitOffset;
          *pnSubFrame = nSubFrame;
          return S_OK;
      }
      else
      {
          return E_FAIL;
      }
  }
  
  
  // GetXmaSampleRate: Obtains the legal XMA sample rate (24, 32, 44.1 or 48Khz)
  // corresponding to a generic sample rate.
  
  __inline DWORD GetXmaSampleRate(DWORD dwGeneralRate)
  {
      DWORD dwXmaRate = 48000; // Default XMA rate for all rates above 44100Hz
  
      if (dwGeneralRate <= 24000)      dwXmaRate = 24000;
      else if (dwGeneralRate <= 32000) dwXmaRate = 32000;
      else if (dwGeneralRate <= 44100) dwXmaRate = 44100;
  
      return dwXmaRate;
  }
  
  
  // Functions to convert between WAVEFORMATEXTENSIBLE channel masks (combinations
  // of the SPEAKER_xxx flags defined in audiodefs.h) and XMA channel masks (which
  // are limited to eight possible speaker positions: left, right, center, low
  // frequency, side left, side right, back left and back right).
  
  __inline DWORD GetStandardChannelMaskFromXmaMask(BYTE bXmaMask)
  {
      DWORD dwStandardMask = 0;
  
      if (bXmaMask & XMA_SPEAKER_LEFT)           dwStandardMask |= SPEAKER_FRONT_LEFT;
      if (bXmaMask & XMA_SPEAKER_RIGHT)          dwStandardMask |= SPEAKER_FRONT_RIGHT;
      if (bXmaMask & XMA_SPEAKER_CENTER)         dwStandardMask |= SPEAKER_FRONT_CENTER;
      if (bXmaMask & XMA_SPEAKER_LFE)            dwStandardMask |= SPEAKER_LOW_FREQUENCY;
      if (bXmaMask & XMA_SPEAKER_LEFT_SURROUND)  dwStandardMask |= SPEAKER_SIDE_LEFT;
      if (bXmaMask & XMA_SPEAKER_RIGHT_SURROUND) dwStandardMask |= SPEAKER_SIDE_RIGHT;
      if (bXmaMask & XMA_SPEAKER_LEFT_BACK)      dwStandardMask |= SPEAKER_BACK_LEFT;
      if (bXmaMask & XMA_SPEAKER_RIGHT_BACK)     dwStandardMask |= SPEAKER_BACK_RIGHT;
  
      return dwStandardMask;
  }
  
  __inline BYTE GetXmaChannelMaskFromStandardMask(DWORD dwStandardMask)
  {
      BYTE bXmaMask = 0;
  
      if (dwStandardMask & SPEAKER_FRONT_LEFT)    bXmaMask |= XMA_SPEAKER_LEFT;
      if (dwStandardMask & SPEAKER_FRONT_RIGHT)   bXmaMask |= XMA_SPEAKER_RIGHT;
      if (dwStandardMask & SPEAKER_FRONT_CENTER)  bXmaMask |= XMA_SPEAKER_CENTER;
      if (dwStandardMask & SPEAKER_LOW_FREQUENCY) bXmaMask |= XMA_SPEAKER_LFE;
      if (dwStandardMask & SPEAKER_SIDE_LEFT)     bXmaMask |= XMA_SPEAKER_LEFT_SURROUND;
      if (dwStandardMask & SPEAKER_SIDE_RIGHT)    bXmaMask |= XMA_SPEAKER_RIGHT_SURROUND;
      if (dwStandardMask & SPEAKER_BACK_LEFT)     bXmaMask |= XMA_SPEAKER_LEFT_BACK;
      if (dwStandardMask & SPEAKER_BACK_RIGHT)    bXmaMask |= XMA_SPEAKER_RIGHT_BACK;
  
      return bXmaMask;
  }
  
  
  // LocalizeXma2Format: Modifies a XMA2WAVEFORMATEX structure in place to comply
  // with the current platform's byte-ordering rules (little- or big-endian).
  
  __inline HRESULT LocalizeXma2Format(XMA2WAVEFORMATEX* pXma2Format)
  {
      #define XMASWAP2BYTES(n) ((WORD)(((n) >> 8) | (((n) & 0xff) << 8)))
      #define XMASWAP4BYTES(n) ((DWORD)((n) >> 24 | (n) << 24 | ((n) & 0xff00) << 8 | ((n) & 0xff0000) >> 8))
  
      if (pXma2Format->wfx.wFormatTag == WAVE_FORMAT_XMA2)
      {
          return S_OK;
      }
      else if (XMASWAP2BYTES(pXma2Format->wfx.wFormatTag) == WAVE_FORMAT_XMA2)
      {
          pXma2Format->wfx.wFormatTag      = XMASWAP2BYTES(pXma2Format->wfx.wFormatTag);
          pXma2Format->wfx.nChannels       = XMASWAP2BYTES(pXma2Format->wfx.nChannels);
          pXma2Format->wfx.nSamplesPerSec  = XMASWAP4BYTES(pXma2Format->wfx.nSamplesPerSec);
          pXma2Format->wfx.nAvgBytesPerSec = XMASWAP4BYTES(pXma2Format->wfx.nAvgBytesPerSec);
          pXma2Format->wfx.nBlockAlign     = XMASWAP2BYTES(pXma2Format->wfx.nBlockAlign);
          pXma2Format->wfx.wBitsPerSample  = XMASWAP2BYTES(pXma2Format->wfx.wBitsPerSample);
          pXma2Format->wfx.cbSize          = XMASWAP2BYTES(pXma2Format->wfx.cbSize);
          pXma2Format->NumStreams          = XMASWAP2BYTES(pXma2Format->NumStreams);
          pXma2Format->ChannelMask         = XMASWAP4BYTES(pXma2Format->ChannelMask);
          pXma2Format->SamplesEncoded      = XMASWAP4BYTES(pXma2Format->SamplesEncoded);
          pXma2Format->BytesPerBlock       = XMASWAP4BYTES(pXma2Format->BytesPerBlock);
          pXma2Format->PlayBegin           = XMASWAP4BYTES(pXma2Format->PlayBegin);
          pXma2Format->PlayLength          = XMASWAP4BYTES(pXma2Format->PlayLength);
          pXma2Format->LoopBegin           = XMASWAP4BYTES(pXma2Format->LoopBegin);
          pXma2Format->LoopLength          = XMASWAP4BYTES(pXma2Format->LoopLength);
          pXma2Format->BlockCount          = XMASWAP2BYTES(pXma2Format->BlockCount);
          return S_OK;
      }
      else
      {
          return E_FAIL; // Not a recognizable XMA2 format
      }
  
      #undef XMASWAP2BYTES
      #undef XMASWAP4BYTES
  }
  
  
  #endif // #ifndef __XMA2DEFS_INCLUDED__
  