| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737 | /* * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_APACHE_LICENSE_HEADER_START@ *  * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *  *     http://www.apache.org/licenses/LICENSE-2.0 *  * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *  * @APPLE_APACHE_LICENSE_HEADER_END@ *//*	File:		ALACDecoder.cpp*/#include <stdlib.h>#include <string.h>#include "ALACDecoder.h"#include "dplib.h"#include "aglib.h"#include "matrixlib.h"#include "ALACBitUtilities.h"#include "EndianPortable.h"#if (__GNUC__) > 4 || defined (__APPLE__)#pragma GCC diagnostic ignored "-Wunused-const-variable"#endif#if !defined(__APPLE__) #pragma GCC diagnostic ignored "-Wunused-but-set-variable"#endif// constants/dataconst uint32_t kMaxBitDepth = 32;			// max allowed bit depth is 32// prototypesstatic void Zero16( int16_t * buffer, uint32_t numItems, uint32_t stride );static void Zero24( uint8_t * buffer, uint32_t numItems, uint32_t stride );static void Zero32( int32_t * buffer, uint32_t numItems, uint32_t stride );/*	Constructor*/ALACDecoder::ALACDecoder() :	mMixBufferU( nil ),	mMixBufferV( nil ),	mPredictor( nil ),	mShiftBuffer( nil ){	memset( &mConfig, 0, sizeof(mConfig) );}/*	Destructor*/ALACDecoder::~ALACDecoder(){	// delete the matrix mixing buffers	if ( mMixBufferU )    {		free(mMixBufferU);        mMixBufferU = NULL;    }	if ( mMixBufferV )    {		free(mMixBufferV);        mMixBufferV = NULL;    }		// delete the dynamic predictor's "corrector" buffer	// - note: mShiftBuffer shares memory with this buffer	if ( mPredictor )    {		free(mPredictor);        mPredictor = NULL;    }}/*	Init()	- initialize the decoder with the given configuration*/int32_t ALACDecoder::Init( void * inMagicCookie, uint32_t inMagicCookieSize ){	int32_t		status = ALAC_noErr;    ALACSpecificConfig theConfig;    uint8_t * theActualCookie = (uint8_t *)inMagicCookie;    uint32_t theCookieBytesRemaining = inMagicCookieSize;    // For historical reasons the decoder needs to be resilient to magic cookies vended by older encoders.    // As specified in the ALACMagicCookieDescription.txt document, there may be additional data encapsulating     // the ALACSpecificConfig. This would consist of format ('frma') and 'alac' atoms which precede the    // ALACSpecificConfig.     // See ALACMagicCookieDescription.txt for additional documentation concerning the 'magic cookie'        // skip format ('frma') atom if present    if (theActualCookie[4] == 'f' && theActualCookie[5] == 'r' && theActualCookie[6] == 'm' && theActualCookie[7] == 'a')    {        theActualCookie += 12;        theCookieBytesRemaining -= 12;    }        // skip 'alac' atom header if present    if (theActualCookie[4] == 'a' && theActualCookie[5] == 'l' && theActualCookie[6] == 'a' && theActualCookie[7] == 'c')    {        theActualCookie += 12;        theCookieBytesRemaining -= 12;    }    // read the ALACSpecificConfig    if (theCookieBytesRemaining >= sizeof(ALACSpecificConfig))    {        theConfig.frameLength = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->frameLength);        theConfig.compatibleVersion = ((ALACSpecificConfig *)theActualCookie)->compatibleVersion;        theConfig.bitDepth = ((ALACSpecificConfig *)theActualCookie)->bitDepth;        theConfig.pb = ((ALACSpecificConfig *)theActualCookie)->pb;        theConfig.mb = ((ALACSpecificConfig *)theActualCookie)->mb;        theConfig.kb = ((ALACSpecificConfig *)theActualCookie)->kb;        theConfig.numChannels = ((ALACSpecificConfig *)theActualCookie)->numChannels;        theConfig.maxRun = Swap16BtoN(((ALACSpecificConfig *)theActualCookie)->maxRun);        theConfig.maxFrameBytes = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->maxFrameBytes);        theConfig.avgBitRate = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->avgBitRate);        theConfig.sampleRate = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->sampleRate);        mConfig = theConfig;                RequireAction( mConfig.compatibleVersion <= kALACVersion, return kALAC_ParamError; );        // allocate mix buffers        mMixBufferU = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );        mMixBufferV = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );        // allocate dynamic predictor buffer        mPredictor = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );        // "shift off" buffer shares memory with predictor buffer        mShiftBuffer = (uint16_t *) mPredictor;                RequireAction( (mMixBufferU != nil) && (mMixBufferV != nil) && (mPredictor != nil),                        status = kALAC_MemFullError; goto Exit; );     }    else    {        status = kALAC_ParamError;    }    // skip to Channel Layout Info    // theActualCookie += sizeof(ALACSpecificConfig);        // Currently, the Channel Layout Info portion of the magic cookie (as defined in the     // ALACMagicCookieDescription.txt document) is unused by the decoder.     Exit:	return status;}/*	Decode()	- the decoded samples are interleaved into the output buffer in the order they arrive in	  the bitstream*/int32_t ALACDecoder::Decode( BitBuffer * bits, uint8_t * sampleBuffer, uint32_t numSamples, uint32_t numChannels, uint32_t * outNumSamples ){	BitBuffer			shiftBits;	uint32_t            bits1, bits2;	uint8_t				tag;	uint8_t				elementInstanceTag;	AGParamRec			agParams;	uint32_t				channelIndex;	int16_t				coefsU[32];		// max possible size is 32 although NUMCOEPAIRS is the current limit	int16_t				coefsV[32];	uint8_t				numU, numV;	uint8_t				mixBits;	int8_t				mixRes;	uint16_t			unusedHeader;	uint8_t				escapeFlag;	uint32_t			chanBits;	uint8_t				bytesShifted;	uint32_t			shift;	uint8_t				modeU, modeV;	uint32_t			denShiftU, denShiftV;	uint16_t			pbFactorU, pbFactorV;	uint16_t			pb;	int16_t *			samples;	int16_t *			out16;	uint8_t *			out20;	uint8_t *			out24;	int32_t *			out32;	uint8_t				headerByte;	uint8_t				partialFrame;	uint32_t			extraBits;	int32_t				val;	uint32_t			i, j;	int32_t             status;		RequireAction( (bits != nil) && (sampleBuffer != nil) && (outNumSamples != nil), return kALAC_ParamError; );	RequireAction( numChannels > 0, return kALAC_ParamError; );	mActiveElements = 0;	channelIndex	= 0;		samples = (int16_t *) sampleBuffer;	status = ALAC_noErr;	*outNumSamples = numSamples;	while ( status == ALAC_noErr )	{		// bail if we ran off the end of the buffer    	RequireAction( bits->cur < bits->end, status = kALAC_ParamError; goto Exit; );		// copy global decode params for this element		pb = mConfig.pb;		// read element tag		tag = BitBufferReadSmall( bits, 3 );		switch ( tag )		{			case ID_SCE:			case ID_LFE:			{				// mono/LFE channel				elementInstanceTag = BitBufferReadSmall( bits, 4 );				mActiveElements |= (1u << elementInstanceTag);				// read the 12 unused header bits				unusedHeader = (uint16_t) BitBufferRead( bits, 12 );				RequireAction( unusedHeader == 0, status = kALAC_ParamError; goto Exit; );				// read the 1-bit "partial frame" flag, 2-bit "shift-off" flag & 1-bit "escape" flag				headerByte = (uint8_t) BitBufferRead( bits, 4 );								partialFrame = headerByte >> 3;								bytesShifted = (headerByte >> 1) & 0x3u;				RequireAction( bytesShifted != 3, status = kALAC_ParamError; goto Exit; );				shift = bytesShifted * 8;				escapeFlag = headerByte & 0x1;				chanBits = mConfig.bitDepth - (bytesShifted * 8);								// check for partial frame to override requested numSamples				if ( partialFrame != 0 )				{					numSamples  = BitBufferRead( bits, 16 ) << 16;					numSamples |= BitBufferRead( bits, 16 );				}				if ( escapeFlag == 0 )				{					// compressed frame, read rest of parameters					mixBits	= (uint8_t) BitBufferRead( bits, 8 );					mixRes	= (int8_t) BitBufferRead( bits, 8 );					//Assert( (mixBits == 0) && (mixRes == 0) );		// no mixing for mono					headerByte	= (uint8_t) BitBufferRead( bits, 8 );					modeU		= headerByte >> 4;					denShiftU	= headerByte & 0xfu;										headerByte	= (uint8_t) BitBufferRead( bits, 8 );					pbFactorU	= headerByte >> 5;					numU		= headerByte & 0x1fu;					for ( i = 0; i < numU; i++ )						coefsU[i] = (int16_t) BitBufferRead( bits, 16 );										// if shift active, skip the the shift buffer but remember where it starts					if ( bytesShifted != 0 )					{						shiftBits = *bits;						BitBufferAdvance( bits, (bytesShifted * 8) * numSamples ); 					}					// decompress					set_ag_params( &agParams, mConfig.mb, (pb * pbFactorU) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );					status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits1 );					RequireNoErr( status, goto Exit; );					if ( modeU == 0 )					{						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );					}					else					{						// the special "numActive == 31" mode can be done in-place						unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );					}				}				else				{					//Assert( bytesShifted == 0 );					// uncompressed frame, copy data into the mix buffer to use common output code					shift = 32 - chanBits;					if ( chanBits <= 16 )					{						for ( i = 0; i < numSamples; i++ )						{							val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );							val = (val << shift) >> shift;							mMixBufferU[i] = val;						}					}					else					{						// BitBufferRead() can't read more than 16 bits at a time so break up the reads						extraBits = chanBits - 16;						for ( i = 0; i < numSamples; i++ )						{							val = (int32_t) BitBufferRead( bits, 16 );							val = (val << 16) >> shift;							mMixBufferU[i] = val | BitBufferRead( bits, (uint8_t) extraBits );						}					}					mixBits = mixRes = 0;					bits1 = chanBits * numSamples;					bytesShifted = 0;				}				// now read the shifted values into the shift buffer				if ( bytesShifted != 0 )				{					shift = bytesShifted * 8;					//Assert( shift <= 16 );					for ( i = 0; i < numSamples; i++ )						mShiftBuffer[i] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );				}				// convert 32-bit integers into output buffer				switch ( mConfig.bitDepth )				{					case 16:						out16 = &((int16_t *)sampleBuffer)[channelIndex];						for ( i = 0, j = 0; i < numSamples; i++, j += numChannels )							out16[j] = (int16_t) mMixBufferU[i];						break;					case 20:						out20 = (uint8_t *)sampleBuffer + (channelIndex * 3);						copyPredictorTo20( mMixBufferU, out20, numChannels, numSamples );						break;					case 24:						out24 = (uint8_t *)sampleBuffer + (channelIndex * 3);						if ( bytesShifted != 0 )							copyPredictorTo24Shift( mMixBufferU, mShiftBuffer, out24, numChannels, numSamples, bytesShifted );						else							copyPredictorTo24( mMixBufferU, out24, numChannels, numSamples );													break;					case 32:						out32 = &((int32_t *)sampleBuffer)[channelIndex];						if ( bytesShifted != 0 )							copyPredictorTo32Shift( mMixBufferU, mShiftBuffer, out32, numChannels, numSamples, bytesShifted );						else							copyPredictorTo32( mMixBufferU, out32, numChannels, numSamples);						break;				}				channelIndex += 1;				*outNumSamples = numSamples;				break;			}			case ID_CPE:			{				// if decoding this pair would take us over the max channels limit, bail				if ( (channelIndex + 2) > numChannels )					goto NoMoreChannels;				// stereo channel pair				elementInstanceTag = BitBufferReadSmall( bits, 4 );				mActiveElements |= (1u << elementInstanceTag);				// read the 12 unused header bits				unusedHeader = (uint16_t) BitBufferRead( bits, 12 );				RequireAction( unusedHeader == 0, status = kALAC_ParamError; goto Exit; );				// read the 1-bit "partial frame" flag, 2-bit "shift-off" flag & 1-bit "escape" flag				headerByte = (uint8_t) BitBufferRead( bits, 4 );								partialFrame = headerByte >> 3;								bytesShifted = (headerByte >> 1) & 0x3u;				RequireAction( bytesShifted != 3, status = kALAC_ParamError; goto Exit; );				shift = bytesShifted * 8;				escapeFlag = headerByte & 0x1;				chanBits = mConfig.bitDepth - (bytesShifted * 8) + 1;								// check for partial frame length to override requested numSamples				if ( partialFrame != 0 )				{					numSamples  = BitBufferRead( bits, 16 ) << 16;					numSamples |= BitBufferRead( bits, 16 );				}				if ( escapeFlag == 0 )				{					// compressed frame, read rest of parameters					mixBits		= (uint8_t) BitBufferRead( bits, 8 );					mixRes		= (int8_t) BitBufferRead( bits, 8 );					headerByte	= (uint8_t) BitBufferRead( bits, 8 );					modeU		= headerByte >> 4;					denShiftU	= headerByte & 0xfu;										headerByte	= (uint8_t) BitBufferRead( bits, 8 );					pbFactorU	= headerByte >> 5;					numU		= headerByte & 0x1fu;					for ( i = 0; i < numU; i++ )						coefsU[i] = (int16_t) BitBufferRead( bits, 16 );					headerByte	= (uint8_t) BitBufferRead( bits, 8 );					modeV		= headerByte >> 4;					denShiftV	= headerByte & 0xfu;										headerByte	= (uint8_t) BitBufferRead( bits, 8 );					pbFactorV	= headerByte >> 5;					numV		= headerByte & 0x1fu;					for ( i = 0; i < numV; i++ )						coefsV[i] = (int16_t) BitBufferRead( bits, 16 );					// if shift active, skip the interleaved shifted values but remember where they start					if ( bytesShifted != 0 )					{						shiftBits = *bits;						BitBufferAdvance( bits, (bytesShifted * 8) * 2 * numSamples );					}					// decompress and run predictor for "left" channel					set_ag_params( &agParams, mConfig.mb, (pb * pbFactorU) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );					status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits1 );					RequireNoErr( status, goto Exit; );					if ( modeU == 0 )					{						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );					}					else					{						// the special "numActive == 31" mode can be done in-place						unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );					}					// decompress and run predictor for "right" channel					set_ag_params( &agParams, mConfig.mb, (pb * pbFactorV) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );					status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits2 );					RequireNoErr( status, goto Exit; );					if ( modeV == 0 )					{						unpc_block( mPredictor, mMixBufferV, numSamples, &coefsV[0], numV, chanBits, denShiftV );					}					else					{						// the special "numActive == 31" mode can be done in-place						unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );						unpc_block( mPredictor, mMixBufferV, numSamples, &coefsV[0], numV, chanBits, denShiftV );					}				}				else				{					//Assert( bytesShifted == 0 );					// uncompressed frame, copy data into the mix buffers to use common output code					chanBits = mConfig.bitDepth;					shift = 32 - chanBits;					if ( chanBits <= 16 )					{						for ( i = 0; i < numSamples; i++ )						{							val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );							val = (val << shift) >> shift;							mMixBufferU[i] = val;							val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );							val = (val << shift) >> shift;							mMixBufferV[i] = val;						}					}					else					{						// BitBufferRead() can't read more than 16 bits at a time so break up the reads						extraBits = chanBits - 16;						for ( i = 0; i < numSamples; i++ )						{							val = (int32_t) BitBufferRead( bits, 16 );							val = (val << 16) >> shift;							mMixBufferU[i] = val | BitBufferRead( bits, (uint8_t)extraBits );							val = (int32_t) BitBufferRead( bits, 16 );							val = (val << 16) >> shift;							mMixBufferV[i] = val | BitBufferRead( bits, (uint8_t)extraBits );						}					}					bits1 = chanBits * numSamples;					bits2 = chanBits * numSamples;					mixBits = mixRes = 0;					bytesShifted = 0;				}				// now read the shifted values into the shift buffer				if ( bytesShifted != 0 )				{					shift = bytesShifted * 8;					//Assert( shift <= 16 );					for ( i = 0; i < (numSamples * 2); i += 2 )					{						mShiftBuffer[i + 0] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );						mShiftBuffer[i + 1] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );					}				}				// un-mix the data and convert to output format				// - note that mixRes = 0 means just interleave so we use that path for uncompressed frames				switch ( mConfig.bitDepth )				{					case 16:						out16 = &((int16_t *)sampleBuffer)[channelIndex];						unmix16( mMixBufferU, mMixBufferV, out16, numChannels, numSamples, mixBits, mixRes );						break;					case 20:						out20 = (uint8_t *)sampleBuffer + (channelIndex * 3);						unmix20( mMixBufferU, mMixBufferV, out20, numChannels, numSamples, mixBits, mixRes );						break;					case 24:						out24 = (uint8_t *)sampleBuffer + (channelIndex * 3);						unmix24( mMixBufferU, mMixBufferV, out24, numChannels, numSamples,									mixBits, mixRes, mShiftBuffer, bytesShifted );						break;					case 32:						out32 = &((int32_t *)sampleBuffer)[channelIndex];						unmix32( mMixBufferU, mMixBufferV, out32, numChannels, numSamples,									mixBits, mixRes, mShiftBuffer, bytesShifted );						break;				}				channelIndex += 2;				*outNumSamples = numSamples;				break;			}			case ID_CCE:			case ID_PCE:			{				// unsupported element, bail				//AssertNoErr( tag );				status = kALAC_ParamError;				break;			}			case ID_DSE:			{				// data stream element -- parse but ignore				status = this->DataStreamElement( bits );				break;			}						case ID_FIL:			{				// fill element -- parse but ignore				status = this->FillElement( bits );				break;			}			case ID_END:			{				// frame end, all done so byte align the frame and check for overruns				BitBufferByteAlign( bits, false );				//Assert( bits->cur == bits->end );				goto Exit;			}		}#if ! DEBUG		// if we've decoded all of our channels, bail (but not in debug b/c we want to know if we're seeing bad bits)		// - this also protects us if the config does not match the bitstream or crap data bits follow the audio bits		if ( channelIndex >= numChannels )			break;#endif	}NoMoreChannels:	// if we get here and haven't decoded all of the requested channels, fill the remaining channels with zeros	for ( ; channelIndex < numChannels; channelIndex++ )	{		switch ( mConfig.bitDepth )		{			case 16:			{				int16_t *	fill16 = &((int16_t *)sampleBuffer)[channelIndex];				Zero16( fill16, numSamples, numChannels );				break;			}			case 24:			{				uint8_t *	fill24 = (uint8_t *)sampleBuffer + (channelIndex * 3);				Zero24( fill24, numSamples, numChannels );				break;			}			case 32:			{				int32_t *	fill32 = &((int32_t *)sampleBuffer)[channelIndex];				Zero32( fill32, numSamples, numChannels );				break;			}		}	}Exit:	return status;}#if PRAGMA_MARK#pragma mark -#endif/*	FillElement()	- they're just filler so we don't need 'em*/int32_t ALACDecoder::FillElement( BitBuffer * bits ){	int16_t		count;		// 4-bit count or (4-bit + 8-bit count) if 4-bit count == 15	// - plus this weird -1 thing I still don't fully understand	count = BitBufferReadSmall( bits, 4 );	if ( count == 15 )		count += (int16_t) BitBufferReadSmall( bits, 8 ) - 1;	BitBufferAdvance( bits, count * 8 );	RequireAction( bits->cur <= bits->end, return kALAC_ParamError; );	return ALAC_noErr;	}/*	DataStreamElement()	- we don't care about data stream elements so just skip them*/int32_t ALACDecoder::DataStreamElement( BitBuffer * bits ){	uint8_t		element_instance_tag;	int32_t		data_byte_align_flag;	uint16_t		count;		// the tag associates this data stream element with a given audio element	element_instance_tag = BitBufferReadSmall( bits, 4 );		data_byte_align_flag = BitBufferReadOne( bits );	// 8-bit count or (8-bit + 8-bit count) if 8-bit count == 255	count = BitBufferReadSmall( bits, 8 );	if ( count == 255 )		count += BitBufferReadSmall( bits, 8 );	// the align flag means the bitstream should be byte-aligned before reading the following data bytes	if ( data_byte_align_flag )		BitBufferByteAlign( bits, false );	// skip the data bytes	BitBufferAdvance( bits, count * 8 );	RequireAction( bits->cur <= bits->end, return kALAC_ParamError; );	return ALAC_noErr;}/*	ZeroN()	- helper routines to clear out output channel buffers when decoding fewer channels than requested*/static void Zero16( int16_t * buffer, uint32_t numItems, uint32_t stride ){	if ( stride == 1 )	{		memset( buffer, 0, numItems * sizeof(int16_t) );	}	else	{		for ( uint32_t index = 0; index < (numItems * stride); index += stride )			buffer[index] = 0;	}}static void Zero24( uint8_t * buffer, uint32_t numItems, uint32_t stride ){	if ( stride == 1 )	{		memset( buffer, 0, numItems * 3 );	}	else	{		for ( uint32_t index = 0; index < (numItems * stride * 3); index += (stride * 3) )		{			buffer[index + 0] = 0;			buffer[index + 1] = 0;			buffer[index + 2] = 0;		}	}}static void Zero32( int32_t * buffer, uint32_t numItems, uint32_t stride ){	if ( stride == 1 )	{		memset( buffer, 0, numItems * sizeof(int32_t) );	}	else	{		for ( uint32_t index = 0; index < (numItems * stride); index += stride )			buffer[index] = 0;	}}
 |