Initial commit.
[libsalac.git] / src / lib / alac / codec / ALACDecoder.cpp
blobce3340dad3699283b5f92d04b91e11d61797f55b
1 /*
2 * Copyright (c) 2011 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
22 File: ALACDecoder.cpp
25 #include <stdlib.h>
26 #include <string.h>
28 #include "ALACDecoder.h"
30 #include "dplib.h"
31 #include "aglib.h"
32 #include "matrixlib.h"
34 #include "ALACBitUtilities.h"
35 #include "EndianPortable.h"
37 // constants/data
38 const uint32_t kMaxBitDepth = 32; // max allowed bit depth is 32
41 // prototypes
42 static void Zero16( int16_t * buffer, uint32_t numItems, uint32_t stride );
43 static void Zero24( uint8_t * buffer, uint32_t numItems, uint32_t stride );
44 static void Zero32( int32_t * buffer, uint32_t numItems, uint32_t stride );
47 Constructor
49 ALACDecoder::ALACDecoder() :
50 mMixBufferU( nil ),
51 mMixBufferV( nil ),
52 mPredictor( nil ),
53 mShiftBuffer( nil )
55 memset( &mConfig, 0, sizeof(mConfig) );
59 Destructor
61 ALACDecoder::~ALACDecoder()
63 // delete the matrix mixing buffers
64 if ( mMixBufferU )
66 free(mMixBufferU);
67 mMixBufferU = NULL;
69 if ( mMixBufferV )
71 free(mMixBufferV);
72 mMixBufferV = NULL;
75 // delete the dynamic predictor's "corrector" buffer
76 // - note: mShiftBuffer shares memory with this buffer
77 if ( mPredictor )
79 free(mPredictor);
80 mPredictor = NULL;
85 Init()
86 - initialize the decoder with the given configuration
88 int32_t ALACDecoder::Init( void * inMagicCookie, uint32_t inMagicCookieSize )
90 int32_t status = ALAC_noErr;
91 ALACSpecificConfig theConfig;
92 uint8_t * theActualCookie = (uint8_t *)inMagicCookie;
93 uint32_t theCookieBytesRemaining = inMagicCookieSize;
95 // For historical reasons the decoder needs to be resilient to magic cookies vended by older encoders.
96 // As specified in the ALACMagicCookieDescription.txt document, there may be additional data encapsulating
97 // the ALACSpecificConfig. This would consist of format ('frma') and 'alac' atoms which precede the
98 // ALACSpecificConfig.
99 // See ALACMagicCookieDescription.txt for additional documentation concerning the 'magic cookie'
101 // skip format ('frma') atom if present
102 if (theActualCookie[4] == 'f' && theActualCookie[5] == 'r' && theActualCookie[6] == 'm' && theActualCookie[7] == 'a')
104 theActualCookie += 12;
105 theCookieBytesRemaining -= 12;
108 // skip 'alac' atom header if present
109 if (theActualCookie[4] == 'a' && theActualCookie[5] == 'l' && theActualCookie[6] == 'a' && theActualCookie[7] == 'c')
111 theActualCookie += 12;
112 theCookieBytesRemaining -= 12;
115 // read the ALACSpecificConfig
116 if (theCookieBytesRemaining >= sizeof(ALACSpecificConfig))
118 theConfig.frameLength = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->frameLength);
119 theConfig.compatibleVersion = ((ALACSpecificConfig *)theActualCookie)->compatibleVersion;
120 theConfig.bitDepth = ((ALACSpecificConfig *)theActualCookie)->bitDepth;
121 theConfig.pb = ((ALACSpecificConfig *)theActualCookie)->pb;
122 theConfig.mb = ((ALACSpecificConfig *)theActualCookie)->mb;
123 theConfig.kb = ((ALACSpecificConfig *)theActualCookie)->kb;
124 theConfig.numChannels = ((ALACSpecificConfig *)theActualCookie)->numChannels;
125 theConfig.maxRun = Swap16BtoN(((ALACSpecificConfig *)theActualCookie)->maxRun);
126 theConfig.maxFrameBytes = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->maxFrameBytes);
127 theConfig.avgBitRate = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->avgBitRate);
128 theConfig.sampleRate = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->sampleRate);
130 mConfig = theConfig;
132 RequireAction( mConfig.compatibleVersion <= kALACVersion, return kALAC_ParamError; );
134 // allocate mix buffers
135 mMixBufferU = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );
136 mMixBufferV = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );
138 // allocate dynamic predictor buffer
139 mPredictor = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );
141 // "shift off" buffer shares memory with predictor buffer
142 mShiftBuffer = (uint16_t *) mPredictor;
144 RequireAction( (mMixBufferU != nil) && (mMixBufferV != nil) && (mPredictor != nil),
145 status = kALAC_MemFullError; goto Exit; );
147 else
149 status = kALAC_ParamError;
152 // skip to Channel Layout Info
153 // theActualCookie += sizeof(ALACSpecificConfig);
155 // Currently, the Channel Layout Info portion of the magic cookie (as defined in the
156 // ALACMagicCookieDescription.txt document) is unused by the decoder.
158 Exit:
159 return status;
163 Decode()
164 - the decoded samples are interleaved into the output buffer in the order they arrive in
165 the bitstream
167 int32_t ALACDecoder::Decode( BitBuffer * bits, uint8_t * sampleBuffer, uint32_t numSamples, uint32_t numChannels, uint32_t * outNumSamples )
169 BitBuffer shiftBits;
170 uint32_t bits1, bits2;
171 uint8_t tag;
172 uint8_t elementInstanceTag;
173 AGParamRec agParams;
174 uint32_t channelIndex;
175 int16_t coefsU[32]; // max possible size is 32 although NUMCOEPAIRS is the current limit
176 int16_t coefsV[32];
177 uint8_t numU, numV;
178 uint8_t mixBits;
179 int8_t mixRes;
180 uint16_t unusedHeader;
181 uint8_t escapeFlag;
182 uint32_t chanBits;
183 uint8_t bytesShifted;
184 uint32_t shift;
185 uint8_t modeU, modeV;
186 uint32_t denShiftU, denShiftV;
187 uint16_t pbFactorU, pbFactorV;
188 uint16_t pb;
189 int16_t * samples;
190 int16_t * out16;
191 uint8_t * out20;
192 uint8_t * out24;
193 int32_t * out32;
194 uint8_t headerByte;
195 uint8_t partialFrame;
196 uint32_t extraBits;
197 int32_t val;
198 uint32_t i, j;
199 int32_t status;
201 RequireAction( (bits != nil) && (sampleBuffer != nil) && (outNumSamples != nil), return kALAC_ParamError; );
202 RequireAction( numChannels > 0, return kALAC_ParamError; );
204 mActiveElements = 0;
205 channelIndex = 0;
207 samples = (int16_t *) sampleBuffer;
209 status = ALAC_noErr;
210 *outNumSamples = numSamples;
212 while ( status == ALAC_noErr )
214 // bail if we ran off the end of the buffer
215 RequireAction( bits->cur < bits->end, status = kALAC_ParamError; goto Exit; );
217 // copy global decode params for this element
218 pb = mConfig.pb;
220 // read element tag
221 tag = BitBufferReadSmall( bits, 3 );
222 switch ( tag )
224 case ID_SCE:
225 case ID_LFE:
227 // mono/LFE channel
228 elementInstanceTag = BitBufferReadSmall( bits, 4 );
229 mActiveElements |= (1u << elementInstanceTag);
231 // read the 12 unused header bits
232 unusedHeader = (uint16_t) BitBufferRead( bits, 12 );
233 RequireAction( unusedHeader == 0, status = kALAC_ParamError; goto Exit; );
235 // read the 1-bit "partial frame" flag, 2-bit "shift-off" flag & 1-bit "escape" flag
236 headerByte = (uint8_t) BitBufferRead( bits, 4 );
238 partialFrame = headerByte >> 3;
240 bytesShifted = (headerByte >> 1) & 0x3u;
241 RequireAction( bytesShifted != 3, status = kALAC_ParamError; goto Exit; );
243 shift = bytesShifted * 8;
245 escapeFlag = headerByte & 0x1;
247 chanBits = mConfig.bitDepth - (bytesShifted * 8);
249 // check for partial frame to override requested numSamples
250 if ( partialFrame != 0 )
252 numSamples = BitBufferRead( bits, 16 ) << 16;
253 numSamples |= BitBufferRead( bits, 16 );
256 if ( escapeFlag == 0 )
258 // compressed frame, read rest of parameters
259 mixBits = (uint8_t) BitBufferRead( bits, 8 );
260 mixRes = (int8_t) BitBufferRead( bits, 8 );
261 //Assert( (mixBits == 0) && (mixRes == 0) ); // no mixing for mono
263 headerByte = (uint8_t) BitBufferRead( bits, 8 );
264 modeU = headerByte >> 4;
265 denShiftU = headerByte & 0xfu;
267 headerByte = (uint8_t) BitBufferRead( bits, 8 );
268 pbFactorU = headerByte >> 5;
269 numU = headerByte & 0x1fu;
271 for ( i = 0; i < numU; i++ )
272 coefsU[i] = (int16_t) BitBufferRead( bits, 16 );
274 // if shift active, skip the the shift buffer but remember where it starts
275 if ( bytesShifted != 0 )
277 shiftBits = *bits;
278 BitBufferAdvance( bits, (bytesShifted * 8) * numSamples );
281 // decompress
282 set_ag_params( &agParams, mConfig.mb, (pb * pbFactorU) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );
283 status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits1 );
284 RequireNoErr( status, goto Exit; );
286 if ( modeU == 0 )
288 unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
290 else
292 // the special "numActive == 31" mode can be done in-place
293 unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );
294 unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
297 else
299 //Assert( bytesShifted == 0 );
301 // uncompressed frame, copy data into the mix buffer to use common output code
302 shift = 32 - chanBits;
303 if ( chanBits <= 16 )
305 for ( i = 0; i < numSamples; i++ )
307 val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );
308 val = (val << shift) >> shift;
309 mMixBufferU[i] = val;
312 else
314 // BitBufferRead() can't read more than 16 bits at a time so break up the reads
315 extraBits = chanBits - 16;
316 for ( i = 0; i < numSamples; i++ )
318 val = (int32_t) BitBufferRead( bits, 16 );
319 val = (val << 16) >> shift;
320 mMixBufferU[i] = val | BitBufferRead( bits, (uint8_t) extraBits );
324 mixBits = mixRes = 0;
325 bits1 = chanBits * numSamples;
326 bytesShifted = 0;
329 // now read the shifted values into the shift buffer
330 if ( bytesShifted != 0 )
332 shift = bytesShifted * 8;
333 //Assert( shift <= 16 );
335 for ( i = 0; i < numSamples; i++ )
336 mShiftBuffer[i] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );
339 // convert 32-bit integers into output buffer
340 switch ( mConfig.bitDepth )
342 case 16:
343 out16 = &((int16_t *)sampleBuffer)[channelIndex];
344 for ( i = 0, j = 0; i < numSamples; i++, j += numChannels )
345 out16[j] = (int16_t) mMixBufferU[i];
346 break;
347 case 20:
348 out20 = (uint8_t *)sampleBuffer + (channelIndex * 3);
349 copyPredictorTo20( mMixBufferU, out20, numChannels, numSamples );
350 break;
351 case 24:
352 out24 = (uint8_t *)sampleBuffer + (channelIndex * 3);
353 if ( bytesShifted != 0 )
354 copyPredictorTo24Shift( mMixBufferU, mShiftBuffer, out24, numChannels, numSamples, bytesShifted );
355 else
356 copyPredictorTo24( mMixBufferU, out24, numChannels, numSamples );
357 break;
358 case 32:
359 out32 = &((int32_t *)sampleBuffer)[channelIndex];
360 if ( bytesShifted != 0 )
361 copyPredictorTo32Shift( mMixBufferU, mShiftBuffer, out32, numChannels, numSamples, bytesShifted );
362 else
363 copyPredictorTo32( mMixBufferU, out32, numChannels, numSamples);
364 break;
367 channelIndex += 1;
368 *outNumSamples = numSamples;
369 break;
372 case ID_CPE:
374 // if decoding this pair would take us over the max channels limit, bail
375 if ( (channelIndex + 2) > numChannels )
376 goto NoMoreChannels;
378 // stereo channel pair
379 elementInstanceTag = BitBufferReadSmall( bits, 4 );
380 mActiveElements |= (1u << elementInstanceTag);
382 // read the 12 unused header bits
383 unusedHeader = (uint16_t) BitBufferRead( bits, 12 );
384 RequireAction( unusedHeader == 0, status = kALAC_ParamError; goto Exit; );
386 // read the 1-bit "partial frame" flag, 2-bit "shift-off" flag & 1-bit "escape" flag
387 headerByte = (uint8_t) BitBufferRead( bits, 4 );
389 partialFrame = headerByte >> 3;
391 bytesShifted = (headerByte >> 1) & 0x3u;
392 RequireAction( bytesShifted != 3, status = kALAC_ParamError; goto Exit; );
394 shift = bytesShifted * 8;
396 escapeFlag = headerByte & 0x1;
398 chanBits = mConfig.bitDepth - (bytesShifted * 8) + 1;
400 // check for partial frame length to override requested numSamples
401 if ( partialFrame != 0 )
403 numSamples = BitBufferRead( bits, 16 ) << 16;
404 numSamples |= BitBufferRead( bits, 16 );
407 if ( escapeFlag == 0 )
409 // compressed frame, read rest of parameters
410 mixBits = (uint8_t) BitBufferRead( bits, 8 );
411 mixRes = (int8_t) BitBufferRead( bits, 8 );
413 headerByte = (uint8_t) BitBufferRead( bits, 8 );
414 modeU = headerByte >> 4;
415 denShiftU = headerByte & 0xfu;
417 headerByte = (uint8_t) BitBufferRead( bits, 8 );
418 pbFactorU = headerByte >> 5;
419 numU = headerByte & 0x1fu;
420 for ( i = 0; i < numU; i++ )
421 coefsU[i] = (int16_t) BitBufferRead( bits, 16 );
423 headerByte = (uint8_t) BitBufferRead( bits, 8 );
424 modeV = headerByte >> 4;
425 denShiftV = headerByte & 0xfu;
427 headerByte = (uint8_t) BitBufferRead( bits, 8 );
428 pbFactorV = headerByte >> 5;
429 numV = headerByte & 0x1fu;
430 for ( i = 0; i < numV; i++ )
431 coefsV[i] = (int16_t) BitBufferRead( bits, 16 );
433 // if shift active, skip the interleaved shifted values but remember where they start
434 if ( bytesShifted != 0 )
436 shiftBits = *bits;
437 BitBufferAdvance( bits, (bytesShifted * 8) * 2 * numSamples );
440 // decompress and run predictor for "left" channel
441 set_ag_params( &agParams, mConfig.mb, (pb * pbFactorU) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );
442 status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits1 );
443 RequireNoErr( status, goto Exit; );
445 if ( modeU == 0 )
447 unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
449 else
451 // the special "numActive == 31" mode can be done in-place
452 unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );
453 unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
456 // decompress and run predictor for "right" channel
457 set_ag_params( &agParams, mConfig.mb, (pb * pbFactorV) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );
458 status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits2 );
459 RequireNoErr( status, goto Exit; );
461 if ( modeV == 0 )
463 unpc_block( mPredictor, mMixBufferV, numSamples, &coefsV[0], numV, chanBits, denShiftV );
465 else
467 // the special "numActive == 31" mode can be done in-place
468 unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );
469 unpc_block( mPredictor, mMixBufferV, numSamples, &coefsV[0], numV, chanBits, denShiftV );
472 else
474 //Assert( bytesShifted == 0 );
476 // uncompressed frame, copy data into the mix buffers to use common output code
477 chanBits = mConfig.bitDepth;
478 shift = 32 - chanBits;
479 if ( chanBits <= 16 )
481 for ( i = 0; i < numSamples; i++ )
483 val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );
484 val = (val << shift) >> shift;
485 mMixBufferU[i] = val;
487 val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );
488 val = (val << shift) >> shift;
489 mMixBufferV[i] = val;
492 else
494 // BitBufferRead() can't read more than 16 bits at a time so break up the reads
495 extraBits = chanBits - 16;
496 for ( i = 0; i < numSamples; i++ )
498 val = (int32_t) BitBufferRead( bits, 16 );
499 val = (val << 16) >> shift;
500 mMixBufferU[i] = val | BitBufferRead( bits, (uint8_t)extraBits );
502 val = (int32_t) BitBufferRead( bits, 16 );
503 val = (val << 16) >> shift;
504 mMixBufferV[i] = val | BitBufferRead( bits, (uint8_t)extraBits );
508 bits1 = chanBits * numSamples;
509 bits2 = chanBits * numSamples;
510 mixBits = mixRes = 0;
511 bytesShifted = 0;
514 // now read the shifted values into the shift buffer
515 if ( bytesShifted != 0 )
517 shift = bytesShifted * 8;
518 //Assert( shift <= 16 );
520 for ( i = 0; i < (numSamples * 2); i += 2 )
522 mShiftBuffer[i + 0] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );
523 mShiftBuffer[i + 1] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );
527 // un-mix the data and convert to output format
528 // - note that mixRes = 0 means just interleave so we use that path for uncompressed frames
529 switch ( mConfig.bitDepth )
531 case 16:
532 out16 = &((int16_t *)sampleBuffer)[channelIndex];
533 unmix16( mMixBufferU, mMixBufferV, out16, numChannels, numSamples, mixBits, mixRes );
534 break;
535 case 20:
536 out20 = (uint8_t *)sampleBuffer + (channelIndex * 3);
537 unmix20( mMixBufferU, mMixBufferV, out20, numChannels, numSamples, mixBits, mixRes );
538 break;
539 case 24:
540 out24 = (uint8_t *)sampleBuffer + (channelIndex * 3);
541 unmix24( mMixBufferU, mMixBufferV, out24, numChannels, numSamples,
542 mixBits, mixRes, mShiftBuffer, bytesShifted );
543 break;
544 case 32:
545 out32 = &((int32_t *)sampleBuffer)[channelIndex];
546 unmix32( mMixBufferU, mMixBufferV, out32, numChannels, numSamples,
547 mixBits, mixRes, mShiftBuffer, bytesShifted );
548 break;
551 channelIndex += 2;
552 *outNumSamples = numSamples;
553 break;
556 case ID_CCE:
557 case ID_PCE:
559 // unsupported element, bail
560 //AssertNoErr( tag );
561 status = kALAC_ParamError;
562 break;
565 case ID_DSE:
567 // data stream element -- parse but ignore
568 status = this->DataStreamElement( bits );
569 break;
572 case ID_FIL:
574 // fill element -- parse but ignore
575 status = this->FillElement( bits );
576 break;
579 case ID_END:
581 // frame end, all done so byte align the frame and check for overruns
582 BitBufferByteAlign( bits, false );
583 //Assert( bits->cur == bits->end );
584 goto Exit;
588 #if ! DEBUG
589 // 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)
590 // - this also protects us if the config does not match the bitstream or crap data bits follow the audio bits
591 if ( channelIndex >= numChannels )
592 break;
593 #endif
596 NoMoreChannels:
598 // if we get here and haven't decoded all of the requested channels, fill the remaining channels with zeros
599 for ( ; channelIndex < numChannels; channelIndex++ )
601 switch ( mConfig.bitDepth )
603 case 16:
605 int16_t * fill16 = &((int16_t *)sampleBuffer)[channelIndex];
606 Zero16( fill16, numSamples, numChannels );
607 break;
609 case 24:
611 uint8_t * fill24 = (uint8_t *)sampleBuffer + (channelIndex * 3);
612 Zero24( fill24, numSamples, numChannels );
613 break;
615 case 32:
617 int32_t * fill32 = &((int32_t *)sampleBuffer)[channelIndex];
618 Zero32( fill32, numSamples, numChannels );
619 break;
624 Exit:
625 return status;
628 #if PRAGMA_MARK
629 #pragma mark -
630 #endif
633 FillElement()
634 - they're just filler so we don't need 'em
636 int32_t ALACDecoder::FillElement( BitBuffer * bits )
638 int16_t count;
640 // 4-bit count or (4-bit + 8-bit count) if 4-bit count == 15
641 // - plus this weird -1 thing I still don't fully understand
642 count = BitBufferReadSmall( bits, 4 );
643 if ( count == 15 )
644 count += (int16_t) BitBufferReadSmall( bits, 8 ) - 1;
646 BitBufferAdvance( bits, count * 8 );
648 RequireAction( bits->cur <= bits->end, return kALAC_ParamError; );
650 return ALAC_noErr;
654 DataStreamElement()
655 - we don't care about data stream elements so just skip them
657 int32_t ALACDecoder::DataStreamElement( BitBuffer * bits )
659 uint8_t element_instance_tag;
660 int32_t data_byte_align_flag;
661 uint16_t count;
663 // the tag associates this data stream element with a given audio element
664 element_instance_tag = BitBufferReadSmall( bits, 4 );
666 data_byte_align_flag = BitBufferReadOne( bits );
668 // 8-bit count or (8-bit + 8-bit count) if 8-bit count == 255
669 count = BitBufferReadSmall( bits, 8 );
670 if ( count == 255 )
671 count += BitBufferReadSmall( bits, 8 );
673 // the align flag means the bitstream should be byte-aligned before reading the following data bytes
674 if ( data_byte_align_flag )
675 BitBufferByteAlign( bits, false );
677 // skip the data bytes
678 BitBufferAdvance( bits, count * 8 );
680 RequireAction( bits->cur <= bits->end, return kALAC_ParamError; );
682 return ALAC_noErr;
686 ZeroN()
687 - helper routines to clear out output channel buffers when decoding fewer channels than requested
689 static void Zero16( int16_t * buffer, uint32_t numItems, uint32_t stride )
691 if ( stride == 1 )
693 memset( buffer, 0, numItems * sizeof(int16_t) );
695 else
697 for ( uint32_t index = 0; index < (numItems * stride); index += stride )
698 buffer[index] = 0;
702 static void Zero24( uint8_t * buffer, uint32_t numItems, uint32_t stride )
704 if ( stride == 1 )
706 memset( buffer, 0, numItems * 3 );
708 else
710 for ( uint32_t index = 0; index < (numItems * stride * 3); index += (stride * 3) )
712 buffer[index + 0] = 0;
713 buffer[index + 1] = 0;
714 buffer[index + 2] = 0;
719 static void Zero32( int32_t * buffer, uint32_t numItems, uint32_t stride )
721 if ( stride == 1 )
723 memset( buffer, 0, numItems * sizeof(int32_t) );
725 else
727 for ( uint32_t index = 0; index < (numItems * stride); index += stride )
728 buffer[index] = 0;