7676constexpr auto kFileTypeUInt16BE = 4 ;
7777constexpr auto kFileTypeSInt16LE = 5 ;
7878constexpr auto kFileTypeUInt16LE = 6 ;
79+ constexpr auto kFileType µLaw = 7 ;
80+ constexpr auto kFileTypeALaw = 10 ;
7981
8082constexpr auto kSeekTableRevision = 1 ;
8183
@@ -373,6 +375,30 @@ SeekTableEntry ParseSeekTableEntry(const void *buf)
373375 return it == begin ? end : --it;
374376}
375377
378+ // / Decodes a µ-law sample to a linear value.
379+ constexpr int16_t µLawToLinear(uint8_t µLaw) noexcept
380+ {
381+ const auto bias = 0x84 ;
382+
383+ µLaw = ~µLaw;
384+ int t = (((µLaw & 0x0F ) << 3 ) + bias) << (static_cast <int >(µLaw & 0x70 ) >> 4 );
385+ return static_cast <int16_t >((µLaw & 0x80 ) ? (bias - t) : (t - bias));
386+ }
387+
388+ // / Decodes a A-law sample to a linear value.
389+ constexpr int16_t ALawToLinear (uint8_t alaw) noexcept
390+ {
391+ const auto mask = 0x55 ;
392+
393+ alaw ^= mask;
394+ int i = (alaw & 0x0F ) << 4 ;
395+ if (auto seg = static_cast <int >(alaw & 0x70 ) >> 4 ; seg)
396+ i = (i + 0x108 ) << (seg - 1 );
397+ else
398+ i += 8 ;
399+ return static_cast <int16_t >((alaw & 0x80 ) ? i : -i);
400+ }
401+
376402} /* namespace */
377403
378404@interface SFBShortenDecoder ()
@@ -476,7 +502,7 @@ - (BOOL)openReturningError:(NSError **)error
476502 return NO ;
477503 }
478504
479- if ((_bitsPerSample == 8 && (_internalFileType != kFileTypeUInt8 && _internalFileType != kFileTypeSInt8 )) || (_bitsPerSample == 16 && (_internalFileType != kFileTypeUInt16BE && _internalFileType != kFileTypeUInt16LE && _internalFileType != kFileTypeSInt16BE && _internalFileType != kFileTypeSInt16LE ))) {
505+ if ((_bitsPerSample == 8 && (_internalFileType != kFileTypeUInt8 && _internalFileType != kFileTypeSInt8 && _internalFileType != kFileType µLaw && _internalFileType != kFileTypeALaw )) || (_bitsPerSample == 16 && (_internalFileType != kFileTypeUInt16BE && _internalFileType != kFileTypeUInt16LE && _internalFileType != kFileTypeSInt16BE && _internalFileType != kFileTypeSInt16LE ))) {
480506 os_log_error (gSFBAudioDecoderLog , " Unsupported bit depth/audio type combination: %u, %u" , _bitsPerSample, _internalFileType);
481507 if (error)
482508 *error = [NSError SFB_errorWithDomain: SFBAudioDecoderErrorDomain
@@ -502,6 +528,8 @@ - (BOOL)openReturningError:(NSError **)error
502528 processingStreamDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian ;
503529 if (_internalFileType == kFileTypeSInt8 || _internalFileType == kFileTypeSInt16BE || _internalFileType == kFileTypeSInt16LE )
504530 processingStreamDescription.mFormatFlags |= kAudioFormatFlagIsSignedInteger ;
531+ if (_internalFileType != kFileType µLaw || _internalFileType != kFileTypeALaw )
532+ processingStreamDescription.mFormatFlags |= kAudioFormatFlagIsSignedInteger ;
505533
506534 processingStreamDescription.mSampleRate = _sampleRate;
507535 processingStreamDescription.mChannelsPerFrame = static_cast <UInt32>(_channelCount);
@@ -569,6 +597,8 @@ - (BOOL)openReturningError:(NSError **)error
569597 case kFileTypeSInt8 :
570598 case kFileTypeSInt16BE :
571599 case kFileTypeSInt16LE :
600+ case kFileType µLaw:
601+ case kFileTypeALaw :
572602 mean = 0 ;
573603 break ;
574604 case kFileTypeUInt8 :
@@ -1247,12 +1277,11 @@ - (BOOL)decodeBlockReturningError:(NSError **)error
12471277 recoverySuggestion: NSLocalizedString(@" The file's extension may not match the file's type." , @" " )];
12481278 return NO ;
12491279 }
1250- /* this is a hack as version 0 differed in definition of var_get */
1280+ // Versions > 0 changed the behavior
12511281 if (_version == 0 )
12521282 resn--;
12531283 }
12541284
1255- /* find mean offset : N.B. this code duplicated */
12561285 if (_nmean == 0 )
12571286 coffset = _offset[chan][0 ];
12581287 else {
@@ -1390,7 +1419,6 @@ - (BOOL)decodeBlockReturningError:(NSError **)error
13901419 break ;
13911420 }
13921421
1393- /* store mean value if appropriate : N.B. Duplicated code */
13941422 if (_nmean > 0 ) {
13951423 int32_t sum = (_version < 2 ) ? 0 : _blocksize / 2 ;
13961424
@@ -1407,7 +1435,6 @@ - (BOOL)decodeBlockReturningError:(NSError **)error
14071435 _offset[chan][_nmean - 1 ] = (sum / _blocksize) << _bitshift;
14081436 }
14091437
1410- /* do the wrap */
14111438 for (auto i = -_nwrap; i < 0 ; i++) {
14121439 cbuffer[i] = cbuffer[i + _blocksize];
14131440 }
@@ -1419,56 +1446,62 @@ - (BOOL)decodeBlockReturningError:(NSError **)error
14191446 }
14201447
14211448 if (chan == _channelCount - 1 ) {
1449+ auto abl = _frameBuffer.audioBufferList ;
1450+
14221451 switch (_internalFileType) {
14231452 case kFileTypeUInt8 :
1424- {
1425- auto abl = _frameBuffer.audioBufferList ;
14261453 for (auto channel = 0 ; channel < _channelCount; ++channel) {
14271454 auto channel_buf = static_cast <uint8_t *>(abl->mBuffers [channel].mData );
14281455 for (auto sample = 0 ; sample < _blocksize; ++sample)
14291456 channel_buf[sample] = static_cast <uint8_t >(std::clamp (_buffer[channel][sample], 0 , UINT8_MAX));
14301457 }
1431- _frameBuffer.frameLength = (AVAudioFrameCount)_blocksize;
14321458 break ;
1433- }
14341459 case kFileTypeSInt8 :
1435- {
1436- auto abl = _frameBuffer.audioBufferList ;
14371460 for (auto channel = 0 ; channel < _channelCount; ++channel) {
14381461 auto channel_buf = static_cast <int8_t *>(abl->mBuffers [channel].mData );
14391462 for (auto sample = 0 ; sample < _blocksize; ++sample)
14401463 channel_buf[sample] = static_cast <int8_t >(std::clamp (_buffer[channel][sample], INT8_MIN, INT8_MAX));
14411464 }
1442- _frameBuffer.frameLength = (AVAudioFrameCount)_blocksize;
14431465 break ;
1444- }
1466+ case kFileType µLaw:
1467+ for (auto channel = 0 ; channel < _channelCount; ++channel) {
1468+ auto channel_buf = static_cast <int8_t *>(abl->mBuffers [channel].mData );
1469+ for (auto sample = 0 ; sample < _blocksize; ++sample) {
1470+ auto value = µLawToLinear (_buffer[channel][sample]);
1471+ channel_buf[sample] = static_cast <int8_t >(std::clamp (value >> 3 , INT8_MIN, INT8_MAX));
1472+ }
1473+ }
1474+ break ;
1475+ case kFileTypeALaw :
1476+ for (auto channel = 0 ; channel < _channelCount; ++channel) {
1477+ auto channel_buf = static_cast <int8_t *>(abl->mBuffers [channel].mData );
1478+ for (auto sample = 0 ; sample < _blocksize; ++sample) {
1479+ auto value = ALawToLinear (_buffer[channel][sample]);
1480+ channel_buf[sample] = static_cast <int8_t >(std::clamp (value >> 3 , INT8_MIN, INT8_MAX));
1481+ }
1482+ }
1483+ break ;
14451484 case kFileTypeUInt16BE :
14461485 case kFileTypeUInt16LE :
1447- {
1448- auto abl = _frameBuffer.audioBufferList ;
14491486 for (auto channel = 0 ; channel < _channelCount; ++channel) {
14501487 auto channel_buf = static_cast <uint16_t *>(abl->mBuffers [channel].mData );
14511488 for (auto sample = 0 ; sample < _blocksize; ++sample)
14521489 channel_buf[sample] = static_cast <uint16_t >(std::clamp (_buffer[channel][sample], 0 , UINT16_MAX));
14531490 }
1454- _frameBuffer.frameLength = (AVAudioFrameCount)_blocksize;
14551491 break ;
1456- }
14571492 case kFileTypeSInt16BE :
14581493 case kFileTypeSInt16LE :
1459- {
1460- auto abl = _frameBuffer.audioBufferList ;
14611494 for (auto channel = 0 ; channel < _channelCount; ++channel) {
14621495 auto channel_buf = static_cast <int16_t *>(abl->mBuffers [channel].mData );
14631496 for (auto sample = 0 ; sample < _blocksize; ++sample) {
14641497 channel_buf[sample] = static_cast <int16_t >(std::clamp (_buffer[channel][sample], INT16_MIN, INT16_MAX));
14651498 }
14661499 }
1467- _frameBuffer.frameLength = (AVAudioFrameCount)_blocksize;
14681500 break ;
1469- }
14701501 }
14711502
1503+ _frameBuffer.frameLength = static_cast <AVAudioFrameCount>(_blocksize);
1504+
14721505 ++_blocksDecoded;
14731506 return YES ;
14741507 }
0 commit comments