|
|
/***************************************************************************
* * Copyright (c) Microsoft Corporation. All rights reserved. * * File: xact3wb.h * Content: XACT 3 wave bank definitions. * ****************************************************************************/
#ifndef __XACT3WB_H__
#define __XACT3WB_H__
#ifdef _XBOX
# include <xtl.h>
#else
# include <math.h>
#endif
#include <audiodefs.h>
#include <xma2defs.h>
#pragma warning(push)
#pragma warning(disable:4201)
#pragma warning(disable:4214) // nonstandard extension used : bit field types other than int
#pragma pack(push, 1)
#if !defined(_X86_)
#define XACTUNALIGNED __unaligned
#else
#define XACTUNALIGNED
#endif
#ifdef _M_PPCBE
#pragma bitfield_order(push, lsb_to_msb)
#endif
#define WAVEBANK_HEADER_SIGNATURE 'DNBW' // WaveBank RIFF chunk signature
#define WAVEBANK_HEADER_VERSION 44 // Current wavebank file version
#define WAVEBANK_BANKNAME_LENGTH 64 // Wave bank friendly name length, in characters
#define WAVEBANK_ENTRYNAME_LENGTH 64 // Wave bank entry friendly name length, in characters
#define WAVEBANK_MAX_DATA_SEGMENT_SIZE 0xFFFFFFFF // Maximum wave bank data segment size, in bytes
#define WAVEBANK_MAX_COMPACT_DATA_SEGMENT_SIZE 0x001FFFFF // Maximum compact wave bank data segment size, in bytes
typedef DWORD WAVEBANKOFFSET;
//
// Bank flags
//
#define WAVEBANK_TYPE_BUFFER 0x00000000 // In-memory buffer
#define WAVEBANK_TYPE_STREAMING 0x00000001 // Streaming
#define WAVEBANK_TYPE_MASK 0x00000001
#define WAVEBANK_FLAGS_ENTRYNAMES 0x00010000 // Bank includes entry names
#define WAVEBANK_FLAGS_COMPACT 0x00020000 // Bank uses compact format
#define WAVEBANK_FLAGS_SYNC_DISABLED 0x00040000 // Bank is disabled for audition sync
#define WAVEBANK_FLAGS_SEEKTABLES 0x00080000 // Bank includes seek tables.
#define WAVEBANK_FLAGS_MASK 0x000F0000
//
// Entry flags
//
#define WAVEBANKENTRY_FLAGS_READAHEAD 0x00000001 // Enable stream read-ahead
#define WAVEBANKENTRY_FLAGS_LOOPCACHE 0x00000002 // One or more looping sounds use this wave
#define WAVEBANKENTRY_FLAGS_REMOVELOOPTAIL 0x00000004 // Remove data after the end of the loop region
#define WAVEBANKENTRY_FLAGS_IGNORELOOP 0x00000008 // Used internally when the loop region can't be used
#define WAVEBANKENTRY_FLAGS_MASK 0x00000008
//
// Entry wave format identifiers
//
#define WAVEBANKMINIFORMAT_TAG_PCM 0x0 // PCM data
#define WAVEBANKMINIFORMAT_TAG_XMA 0x1 // XMA data
#define WAVEBANKMINIFORMAT_TAG_ADPCM 0x2 // ADPCM data
#define WAVEBANKMINIFORMAT_TAG_WMA 0x3 // WMA data
#define WAVEBANKMINIFORMAT_BITDEPTH_8 0x0 // 8-bit data (PCM only)
#define WAVEBANKMINIFORMAT_BITDEPTH_16 0x1 // 16-bit data (PCM only)
//
// Arbitrary fixed sizes
//
#define WAVEBANKENTRY_XMASTREAMS_MAX 3 // enough for 5.1 channel audio
#define WAVEBANKENTRY_XMACHANNELS_MAX 6 // enough for 5.1 channel audio (cf. XAUDIOCHANNEL_SOURCEMAX)
//
// DVD data sizes
//
#define WAVEBANK_DVD_SECTOR_SIZE 2048
#define WAVEBANK_DVD_BLOCK_SIZE (WAVEBANK_DVD_SECTOR_SIZE * 16)
//
// Bank alignment presets
//
#define WAVEBANK_ALIGNMENT_MIN 4 // Minimum alignment
#define WAVEBANK_ALIGNMENT_DVD WAVEBANK_DVD_SECTOR_SIZE // DVD-optimized alignment
//
// Wave bank segment identifiers
//
typedef enum WAVEBANKSEGIDX { WAVEBANK_SEGIDX_BANKDATA = 0, // Bank data
WAVEBANK_SEGIDX_ENTRYMETADATA, // Entry meta-data
WAVEBANK_SEGIDX_SEEKTABLES, // Storage for seek tables for the encoded waves.
WAVEBANK_SEGIDX_ENTRYNAMES, // Entry friendly names
WAVEBANK_SEGIDX_ENTRYWAVEDATA, // Entry wave data
WAVEBANK_SEGIDX_COUNT } WAVEBANKSEGIDX, *LPWAVEBANKSEGIDX;
typedef const WAVEBANKSEGIDX *LPCWAVEBANKSEGIDX;
//
// Endianness
//
#ifdef __cplusplus
namespace XACTWaveBank { __inline void SwapBytes(XACTUNALIGNED DWORD &dw) {
#ifdef _X86_
__asm { mov edi, dw mov eax, [edi] bswap eax mov [edi], eax }
#else // _X86_
dw = _byteswap_ulong(dw);
#endif // _X86_
}
__inline void SwapBytes(XACTUNALIGNED WORD &w) {
#ifdef _X86_
__asm { mov edi, w mov ax, [edi] xchg ah, al mov [edi], ax }
#else // _X86_
w = _byteswap_ushort(w);
#endif // _X86_
}
}
#endif // __cplusplus
//
// Wave bank region in bytes.
//
typedef struct WAVEBANKREGION { DWORD dwOffset; // Region offset, in bytes.
DWORD dwLength; // Region length, in bytes.
#ifdef __cplusplus
void SwapBytes(void) { XACTWaveBank::SwapBytes(dwOffset); XACTWaveBank::SwapBytes(dwLength); }
#endif // __cplusplus
} WAVEBANKREGION, *LPWAVEBANKREGION;
typedef const WAVEBANKREGION *LPCWAVEBANKREGION;
//
// Wave bank region in samples.
//
typedef struct WAVEBANKSAMPLEREGION { DWORD dwStartSample; // Start sample for the region.
DWORD dwTotalSamples; // Region length in samples.
#ifdef __cplusplus
void SwapBytes(void) { XACTWaveBank::SwapBytes(dwStartSample); XACTWaveBank::SwapBytes(dwTotalSamples); }
#endif // __cplusplus
} WAVEBANKSAMPLEREGION, *LPWAVEBANKSAMPLEREGION;
typedef const WAVEBANKSAMPLEREGION *LPCWAVEBANKSAMPLEREGION;
//
// Wave bank file header
//
typedef struct WAVEBANKHEADER { DWORD dwSignature; // File signature
DWORD dwVersion; // Version of the tool that created the file
DWORD dwHeaderVersion; // Version of the file format
WAVEBANKREGION Segments[WAVEBANK_SEGIDX_COUNT]; // Segment lookup table
#ifdef __cplusplus
void SwapBytes(void) { XACTWaveBank::SwapBytes(dwSignature); XACTWaveBank::SwapBytes(dwVersion); XACTWaveBank::SwapBytes(dwHeaderVersion);
for(int i = 0; i < WAVEBANK_SEGIDX_COUNT; i++) { Segments[i].SwapBytes(); } }
#endif // __cplusplus
} WAVEBANKHEADER, *LPWAVEBANKHEADER;
typedef const WAVEBANKHEADER *LPCWAVEBANKHEADER;
//
// Table for converting WMA Average Bytes per Second values to the WAVEBANKMINIWAVEFORMAT wBlockAlign field
// NOTE: There can be a max of 8 values in the table.
//
#define MAX_WMA_AVG_BYTES_PER_SEC_ENTRIES 7
static const DWORD aWMAAvgBytesPerSec[] = { 12000, 24000, 4000, 6000, 8000, 20000, 2500 }; // bitrate = entry * 8
//
// Table for converting WMA Block Align values to the WAVEBANKMINIWAVEFORMAT wBlockAlign field
// NOTE: There can be a max of 32 values in the table.
//
#define MAX_WMA_BLOCK_ALIGN_ENTRIES 17
static const DWORD aWMABlockAlign[] = { 929, 1487, 1280, 2230, 8917, 8192, 4459, 5945, 2304, 1536, 1485, 1008, 2731, 4096, 6827, 5462, 1280 };
struct WAVEBANKENTRY;
//
// Entry compressed data format
//
typedef union WAVEBANKMINIWAVEFORMAT { struct { DWORD wFormatTag : 2; // Format tag
DWORD nChannels : 3; // Channel count (1 - 6)
DWORD nSamplesPerSec : 18; // Sampling rate
DWORD wBlockAlign : 8; // Block alignment. For WMA, lower 6 bits block alignment index, upper 2 bits bytes-per-second index.
DWORD wBitsPerSample : 1; // Bits per sample (8 vs. 16, PCM only); WMAudio2/WMAudio3 (for WMA)
};
DWORD dwValue;
#ifdef __cplusplus
void SwapBytes(void) { XACTWaveBank::SwapBytes(dwValue); }
WORD BitsPerSample() const { if (wFormatTag == WAVEBANKMINIFORMAT_TAG_XMA) return XMA_OUTPUT_SAMPLE_BITS; // First, because most common on Xbox 360
if (wFormatTag == WAVEBANKMINIFORMAT_TAG_WMA) return 16; if (wFormatTag == WAVEBANKMINIFORMAT_TAG_ADPCM) return 4; // MSADPCM_BITS_PER_SAMPLE == 4
// wFormatTag must be WAVEBANKMINIFORMAT_TAG_PCM (2 bits can only represent 4 different values)
return (wBitsPerSample == WAVEBANKMINIFORMAT_BITDEPTH_16) ? 16 : 8; }
#define ADPCM_MINIWAVEFORMAT_BLOCKALIGN_CONVERSION_OFFSET 22
DWORD BlockAlign() const { DWORD dwReturn = 0;
switch (wFormatTag) { case WAVEBANKMINIFORMAT_TAG_PCM: dwReturn = wBlockAlign; break;
case WAVEBANKMINIFORMAT_TAG_XMA: dwReturn = nChannels * XMA_OUTPUT_SAMPLE_BITS / 8; break;
case WAVEBANKMINIFORMAT_TAG_ADPCM: dwReturn = (wBlockAlign + ADPCM_MINIWAVEFORMAT_BLOCKALIGN_CONVERSION_OFFSET) * nChannels; break;
case WAVEBANKMINIFORMAT_TAG_WMA: { DWORD dwBlockAlignIndex = wBlockAlign & 0x1F; if (dwBlockAlignIndex < MAX_WMA_BLOCK_ALIGN_ENTRIES) dwReturn = aWMABlockAlign[dwBlockAlignIndex]; } break; }
return dwReturn; }
DWORD AvgBytesPerSec() const { DWORD dwReturn = 0;
switch (wFormatTag) { case WAVEBANKMINIFORMAT_TAG_PCM: case WAVEBANKMINIFORMAT_TAG_XMA: dwReturn = nSamplesPerSec * wBlockAlign; break;
case WAVEBANKMINIFORMAT_TAG_ADPCM: { DWORD blockAlign = BlockAlign(); DWORD samplesPerAdpcmBlock = AdpcmSamplesPerBlock(); dwReturn = blockAlign * nSamplesPerSec / samplesPerAdpcmBlock; } break;
case WAVEBANKMINIFORMAT_TAG_WMA: { DWORD dwBytesPerSecIndex = wBlockAlign >> 5; if (dwBytesPerSecIndex < MAX_WMA_AVG_BYTES_PER_SEC_ENTRIES) dwReturn = aWMAAvgBytesPerSec[dwBytesPerSecIndex]; } break; }
return dwReturn; }
DWORD EncodeWMABlockAlign(DWORD dwBlockAlign, DWORD dwAvgBytesPerSec) const { DWORD dwReturn = 0; DWORD dwBlockAlignIndex = 0; DWORD dwBytesPerSecIndex = 0;
for (; dwBlockAlignIndex < MAX_WMA_BLOCK_ALIGN_ENTRIES && dwBlockAlign != aWMABlockAlign[dwBlockAlignIndex]; dwBlockAlignIndex++);
if (dwBlockAlignIndex < MAX_WMA_BLOCK_ALIGN_ENTRIES) { for (; dwBytesPerSecIndex < MAX_WMA_AVG_BYTES_PER_SEC_ENTRIES && dwAvgBytesPerSec != aWMAAvgBytesPerSec[dwBytesPerSecIndex]; dwBytesPerSecIndex++);
if (dwBytesPerSecIndex < MAX_WMA_AVG_BYTES_PER_SEC_ENTRIES) { dwReturn = dwBlockAlignIndex | (dwBytesPerSecIndex << 5); } }
return dwReturn; }
void XMA2FillFormatEx(XMA2WAVEFORMATEX *fmt, WORD blockCount, const struct WAVEBANKENTRY* entry) const;
DWORD AdpcmSamplesPerBlock() const { DWORD nBlockAlign = (wBlockAlign + ADPCM_MINIWAVEFORMAT_BLOCKALIGN_CONVERSION_OFFSET) * nChannels; return nBlockAlign * 2 / (DWORD)nChannels - 12; }
void AdpcmFillCoefficientTable(ADPCMWAVEFORMAT *fmt) const { // These are fixed since we are always using MS ADPCM
fmt->wNumCoef = 7; /* MSADPCM_NUM_COEFFICIENTS */
static ADPCMCOEFSET aCoef[7] = { { 256, 0}, {512, -256}, {0,0}, {192,64}, {240,0}, {460, -208}, {392,-232} }; memcpy( &fmt->aCoef, aCoef, sizeof(aCoef) ); }
#endif // __cplusplus
} WAVEBANKMINIWAVEFORMAT, *LPWAVEBANKMINIWAVEFORMAT;
typedef const WAVEBANKMINIWAVEFORMAT *LPCWAVEBANKMINIWAVEFORMAT;
//
// Entry meta-data
//
typedef struct WAVEBANKENTRY { union { struct { // Entry flags
DWORD dwFlags : 4;
// Duration of the wave, in units of one sample.
// For instance, a ten second long wave sampled
// at 48KHz would have a duration of 480,000.
// This value is not affected by the number of
// channels, the number of bits per sample, or the
// compression format of the wave.
DWORD Duration : 28; }; DWORD dwFlagsAndDuration; };
WAVEBANKMINIWAVEFORMAT Format; // Entry format.
WAVEBANKREGION PlayRegion; // Region within the wave data segment that contains this entry.
WAVEBANKSAMPLEREGION LoopRegion; // Region within the wave data (in samples) that should loop.
#ifdef __cplusplus
void SwapBytes(void) { XACTWaveBank::SwapBytes(dwFlagsAndDuration); Format.SwapBytes(); PlayRegion.SwapBytes(); LoopRegion.SwapBytes(); }
#endif // __cplusplus
} WAVEBANKENTRY, *LPWAVEBANKENTRY;
typedef const WAVEBANKENTRY *LPCWAVEBANKENTRY;
//
// Compact entry meta-data
//
typedef struct WAVEBANKENTRYCOMPACT { DWORD dwOffset : 21; // Data offset, in sectors
DWORD dwLengthDeviation : 11; // Data length deviation, in bytes
#ifdef __cplusplus
void SwapBytes(void) { XACTWaveBank::SwapBytes(*(LPDWORD)this); }
#endif // __cplusplus
} WAVEBANKENTRYCOMPACT, *LPWAVEBANKENTRYCOMPACT;
typedef const WAVEBANKENTRYCOMPACT *LPCWAVEBANKENTRYCOMPACT;
//
// Bank data segment
//
typedef struct WAVEBANKDATA { DWORD dwFlags; // Bank flags
DWORD dwEntryCount; // Number of entries in the bank
CHAR szBankName[WAVEBANK_BANKNAME_LENGTH]; // Bank friendly name
DWORD dwEntryMetaDataElementSize; // Size of each entry meta-data element, in bytes
DWORD dwEntryNameElementSize; // Size of each entry name element, in bytes
DWORD dwAlignment; // Entry alignment, in bytes
WAVEBANKMINIWAVEFORMAT CompactFormat; // Format data for compact bank
FILETIME BuildTime; // Build timestamp
#ifdef __cplusplus
void SwapBytes(void) { XACTWaveBank::SwapBytes(dwFlags); XACTWaveBank::SwapBytes(dwEntryCount); XACTWaveBank::SwapBytes(dwEntryMetaDataElementSize); XACTWaveBank::SwapBytes(dwEntryNameElementSize); XACTWaveBank::SwapBytes(dwAlignment); CompactFormat.SwapBytes(); XACTWaveBank::SwapBytes(BuildTime.dwLowDateTime); XACTWaveBank::SwapBytes(BuildTime.dwHighDateTime); }
#endif // __cplusplus
} WAVEBANKDATA, *LPWAVEBANKDATA;
typedef const WAVEBANKDATA *LPCWAVEBANKDATA;
inline void WAVEBANKMINIWAVEFORMAT::XMA2FillFormatEx(XMA2WAVEFORMATEX *fmt, WORD blockCount, const WAVEBANKENTRY* entry) const { // Note caller is responsbile for filling out fmt->wfx with other helper functions.
fmt->NumStreams = (WORD)( (nChannels + 1) / 2 );
switch (nChannels) { case 1: fmt->ChannelMask = SPEAKER_MONO; break; case 2: fmt->ChannelMask = SPEAKER_STEREO; break; case 3: fmt->ChannelMask = SPEAKER_2POINT1; break; case 4: fmt->ChannelMask = SPEAKER_QUAD; break; case 5: fmt->ChannelMask = SPEAKER_4POINT1; break; case 6: fmt->ChannelMask = SPEAKER_5POINT1; break; case 7: fmt->ChannelMask = SPEAKER_5POINT1 | SPEAKER_BACK_CENTER; break; case 8: fmt->ChannelMask = SPEAKER_7POINT1; break; default: fmt->ChannelMask = 0; break; }
fmt->SamplesEncoded = entry->Duration; fmt->BytesPerBlock = 65536; /* XACT_FIXED_XMA_BLOCK_SIZE */
fmt->PlayBegin = entry->PlayRegion.dwOffset; fmt->PlayLength = entry->PlayRegion.dwLength;
if (entry->LoopRegion.dwTotalSamples > 0) { fmt->LoopBegin = entry->LoopRegion.dwStartSample; fmt->LoopLength = entry->LoopRegion.dwTotalSamples; fmt->LoopCount = 0xff; /* XACTLOOPCOUNT_INFINITE */ } else { fmt->LoopBegin = 0; fmt->LoopLength = 0; fmt->LoopCount = 0; }
fmt->EncoderVersion = 4; // XMAENCODER_VERSION_XMA2
fmt->BlockCount = blockCount; }
#ifdef _M_PPCBE
#pragma bitfield_order(pop)
#endif
#pragma warning(pop)
#pragma pack(pop)
#endif // __XACTWB_H__
|