/***************************************************************************
 
 *
 
 * 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 <sal.h>        // Markers for documenting API semantics
 
#include <winerror.h>   // For S_OK, E_FAIL
 
#include <audiodefs.h>  // Basic data types and constants for audio work
 
 
 
 
 
/***************************************************************************
 
 *  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 XMA2WAVEFORMATEX 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.
 
                             //   SubframeEnd: Subframe of the loop end frame where
 
                             //                the loop ends.  Ranges from 0 to 3.
 
                             //   SubframeSkip: Subframes to skip in the start frame to
 
                             //                 reach the loop.  Ranges from 0 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(__in_bcount(1) const BYTE* pPacket)
 
{
 
    return (DWORD)(pPacket[0] >> 2);
 
}
 
 
 
__inline DWORD GetXmaPacketFirstFrameOffsetInBits(__in_bcount(3) const BYTE* pPacket)
 
{
 
    return ((DWORD)(pPacket[0] & 0x3) << 13) |
 
           ((DWORD)(pPacket[1]) << 5) |
 
           ((DWORD)(pPacket[2]) >> 3);
 
}
 
 
 
__inline DWORD GetXmaPacketMetadata(__in_bcount(3) const BYTE* pPacket)
 
{
 
    return (DWORD)(pPacket[2] & 0x7);
 
}
 
 
 
__inline DWORD GetXmaPacketSkipCount(__in_bcount(4) 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
 
 ***************************************************************************/
 
 
 
// We define a local ASSERT macro to equal the global one if it exists.
 
// You can define XMA2DEFS_ASSERT in advance to override this default.
 
#ifndef XMA2DEFS_ASSERT
 
    #ifdef ASSERT
 
        #define XMA2DEFS_ASSERT ASSERT
 
    #else
 
        #define XMA2DEFS_ASSERT(a) /* No-op by default */
 
    #endif
 
#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)
 
    __in_ecount(nBlockCount) const DWORD* pSeekTable,  // Pointer to the seek table data
 
    DWORD nDesiredSample,                   // Decoded sample to locate
 
    __out DWORD* pnBlockContainingSample,   // Index of the block containing the sample
 
    __out 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)
 
    {
 
        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
 
(
 
    __in_bcount(nBitPosition / 8 + 3)
 
    __in const BYTE* pPacket,  // Pointer to 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
 
(
 
    __in_bcount(nXmaDataBytes) const BYTE* pXmaData,  // Pointer to 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
 
(
 
    __in_bcount(nXmaDataBytes) const BYTE* pXmaData,  // Pointer to 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
 
(
 
    __in_bcount(nXmaDataBytes) const BYTE* pXmaData,  // Pointer to XMA block[s]
 
    DWORD nXmaDataBytes,                              // Size of pXmaData in bytes
 
    DWORD nStreamIndex,                               // Stream within which to seek
 
    DWORD nDesiredSample,                             // Sample sought
 
    __out DWORD* pnBitOffset,                         // Returns the bit offset within pXmaData of
 
                                                      // the frame containing the sample sought
 
    __out 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(__inout 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__