Skip to content

Commit 0287258

Browse files
authored
Add µ-law and A-law decoding (#399)
1 parent 4cce8e2 commit 0287258

File tree

1 file changed

+54
-21
lines changed

1 file changed

+54
-21
lines changed

Sources/CSFBAudioEngine/Decoders/SFBShortenDecoder.mm

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@
7676
constexpr auto kFileTypeUInt16BE = 4;
7777
constexpr auto kFileTypeSInt16LE = 5;
7878
constexpr auto kFileTypeUInt16LE = 6;
79+
constexpr auto kFileTypeµLaw = 7;
80+
constexpr auto kFileTypeALaw = 10;
7981

8082
constexpr 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

Comments
 (0)