Skip to content

Commit 82d3223

Browse files
authored
Refactor libsndfile decoder and encoder (sbooth#478)
Closes sbooth#457
1 parent ca61d19 commit 82d3223

File tree

4 files changed

+180
-135
lines changed

4 files changed

+180
-135
lines changed

Sources/CSFBAudioEngine/Decoders/SFBLibsndfileDecoder.m

+18-114
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
@import os.log;
88

99
@import sndfile;
10+
@import AVFAudioExtensions;
1011

1112
#import "SFBLibsndfileDecoder.h"
1213

13-
#import "AVAudioChannelLayout+SFBChannelLabels.h"
1414
#import "NSData+SFBExtensions.h"
1515
#import "NSError+SFBURLPresentation.h"
16+
#import "SFBLibsndfileUtilities.h"
1617

1718
SFBAudioDecoderName const SFBAudioDecoderNameLibsndfile = @"org.sbooth.AudioEngine.Decoder.Libsndfile";
1819

@@ -21,7 +22,7 @@ static AudioFormatFlags CalculateLPCMFlags(UInt32 validBitsPerChannel, UInt32 to
2122
return (isFloat ? kAudioFormatFlagIsFloat : kAudioFormatFlagIsSignedInteger) | (isBigEndian ? kAudioFormatFlagIsBigEndian : 0) | ((validBitsPerChannel == totalBitsPerChannel) ? kAudioFormatFlagIsPacked : kAudioFormatFlagIsAlignedHigh) | (isNonInterleaved ? kAudioFormatFlagIsNonInterleaved : 0);
2223
}
2324

24-
static void FillOutASBDForLPCM(AudioStreamBasicDescription *asbd, Float64 sampleRate, UInt32 channelsPerFrame, UInt32 validBitsPerChannel, UInt32 totalBitsPerChannel, BOOL isFloat, BOOL isBigEndian, BOOL isNonInterleaved)
25+
static void FillOutASBDForLPCM(AudioStreamBasicDescription * _Nonnull asbd, Float64 sampleRate, UInt32 channelsPerFrame, UInt32 validBitsPerChannel, UInt32 totalBitsPerChannel, BOOL isFloat, BOOL isBigEndian, BOOL isNonInterleaved)
2526
{
2627
NSCParameterAssert(asbd != NULL);
2728

@@ -37,7 +38,8 @@ static void FillOutASBDForLPCM(AudioStreamBasicDescription *asbd, Float64 sample
3738
asbd->mBytesPerFrame = (isNonInterleaved ? 1 : channelsPerFrame) * (totalBitsPerChannel / 8);
3839
}
3940

40-
static AVAudioChannelLayout * ChannelLayoutForSndfileChannelMap(int * _Nonnull channel_map, int channels)
41+
/// Returns an `AVAudioChannelLayout` object initialized with the channels from a sndfile channel map
42+
static AVAudioChannelLayout * _Nullable ChannelLayoutFromSndfileChannelMap(int * _Nonnull channel_map, int channels)
4143
{
4244
NSCParameterAssert(channel_map != NULL);
4345
NSCParameterAssert(channels > 0);
@@ -81,7 +83,7 @@ static void FillOutASBDForLPCM(AudioStreamBasicDescription *asbd, Float64 sample
8183
case SF_CHANNEL_MAP_AMBISONIC_B_Z: labels[i] = kAudioChannelLabel_Ambisonic_Z; break;
8284

8385
default:
84-
os_log_error(gSFBAudioDecoderLog, "Invalid sndfile channel: %d", channel_map[i]);
86+
os_log_error(gSFBAudioDecoderLog, "Invalid libsndfile channel: %d", channel_map[i]);
8587
labels[i] = kAudioChannelLabel_Unused;
8688
break;
8789
}
@@ -171,7 +173,7 @@ static sf_count_t my_sf_vio_tell(void *user_data)
171173
@interface SFBLibsndfileDecoder ()
172174
{
173175
@private
174-
SNDFILE *_sndfile;;
176+
SNDFILE *_sndfile;
175177
SF_INFO _sfinfo;
176178
enum ReadMethod _readMethod;
177179
}
@@ -306,49 +308,49 @@ - (BOOL)openReturningError:(NSError **)error
306308
}
307309

308310
// Generate interleaved native PCM output
309-
AudioStreamBasicDescription asbd = {0};
311+
AudioStreamBasicDescription processingStreamDescription = {0};
310312

311313
int subtype = _sfinfo.format & SF_FORMAT_SUBMASK;
312314
switch(subtype) {
313315
// 8-bit PCM will be high-aligned in shorts
314316
case SF_FORMAT_PCM_U8:
315317
case SF_FORMAT_PCM_S8:
316-
FillOutASBDForLPCM(&asbd, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 8, 16, NO, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
318+
FillOutASBDForLPCM(&processingStreamDescription, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 8, 16, NO, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
317319
_readMethod = Short;
318320
break;
319321

320322
// 16-bit PCM
321323
case SF_FORMAT_PCM_16:
322-
FillOutASBDForLPCM(&asbd, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 16, 16, NO, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
324+
FillOutASBDForLPCM(&processingStreamDescription, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 16, 16, NO, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
323325
_readMethod = Short;
324326
break;
325327

326328
// 24-bit PCM will be high-aligned in ints
327329
case SF_FORMAT_PCM_24:
328-
FillOutASBDForLPCM(&asbd, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 24, 32, NO, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
330+
FillOutASBDForLPCM(&processingStreamDescription, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 24, 32, NO, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
329331
_readMethod = Int;
330332
break;
331333

332334
// 32-bit PCM
333335
case SF_FORMAT_PCM_32:
334-
FillOutASBDForLPCM(&asbd, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 32, 32, NO, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
336+
FillOutASBDForLPCM(&processingStreamDescription, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 32, 32, NO, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
335337
_readMethod = Int;
336338
break;
337339

338340
// Floating point formats
339341
case SF_FORMAT_FLOAT:
340-
FillOutASBDForLPCM(&asbd, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 32, 32, YES, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
342+
FillOutASBDForLPCM(&processingStreamDescription, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 32, 32, YES, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
341343
_readMethod = Float;
342344
break;
343345

344346
case SF_FORMAT_DOUBLE:
345-
FillOutASBDForLPCM(&asbd, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 64, 64, YES, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
347+
FillOutASBDForLPCM(&processingStreamDescription, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 64, 64, YES, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
346348
_readMethod = Double;
347349
break;
348350

349351
// Everything else will be converted to 32-bit float
350352
default:
351-
FillOutASBDForLPCM(&asbd, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 32, 32, YES, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
353+
FillOutASBDForLPCM(&processingStreamDescription, _sfinfo.samplerate, (UInt32)_sfinfo.channels, 32, 32, YES, kAudioFormatFlagsNativeEndian == kAudioFormatFlagIsBigEndian, NO);
352354
_readMethod = Float;
353355
break;
354356
}
@@ -359,7 +361,7 @@ - (BOOL)openReturningError:(NSError **)error
359361
int channel_map [_sfinfo.channels];
360362
int result = sf_command(_sndfile, SFC_GET_CHANNEL_MAP_INFO, channel_map, (int)sizeof(channel_map));
361363
if(result == SF_TRUE)
362-
channelLayout = ChannelLayoutForSndfileChannelMap(channel_map, _sfinfo.channels);
364+
channelLayout = ChannelLayoutFromSndfileChannelMap(channel_map, _sfinfo.channels);
363365

364366
if(!channelLayout) {
365367
switch(_sfinfo.channels) {
@@ -371,7 +373,7 @@ - (BOOL)openReturningError:(NSError **)error
371373
}
372374
}
373375

374-
_processingFormat = [[AVAudioFormat alloc] initWithStreamDescription:&asbd channelLayout:channelLayout];
376+
_processingFormat = [[AVAudioFormat alloc] initWithStreamDescription:&processingStreamDescription channelLayout:channelLayout];
375377

376378
// Set up the source format
377379
AudioStreamBasicDescription sourceStreamDescription = {0};
@@ -382,105 +384,7 @@ - (BOOL)openReturningError:(NSError **)error
382384
sourceStreamDescription.mSampleRate = _sfinfo.samplerate;
383385
sourceStreamDescription.mChannelsPerFrame = (UInt32)_sfinfo.channels;
384386

385-
int majorFormat = _sfinfo.format & SF_FORMAT_TYPEMASK;
386-
387-
switch(subtype) {
388-
case SF_FORMAT_PCM_U8:
389-
sourceStreamDescription.mFormatID = kAudioFormatLinearPCM;
390-
sourceStreamDescription.mBitsPerChannel = 8;
391-
break;
392-
393-
case SF_FORMAT_PCM_S8:
394-
if(majorFormat == SF_FORMAT_FLAC) {
395-
sourceStreamDescription.mFormatID = kAudioFormatFLAC;
396-
}
397-
else {
398-
sourceStreamDescription.mFormatID = kAudioFormatLinearPCM;
399-
sourceStreamDescription.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
400-
sourceStreamDescription.mBitsPerChannel = 8;
401-
}
402-
break;
403-
404-
case SF_FORMAT_PCM_16:
405-
if(majorFormat == SF_FORMAT_FLAC) {
406-
sourceStreamDescription.mFormatID = kAudioFormatFLAC;
407-
sourceStreamDescription.mFormatFlags = kAppleLosslessFormatFlag_16BitSourceData;
408-
}
409-
else {
410-
sourceStreamDescription.mFormatID = kAudioFormatLinearPCM;
411-
sourceStreamDescription.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
412-
sourceStreamDescription.mBitsPerChannel = 16;
413-
}
414-
break;
415-
416-
case SF_FORMAT_PCM_24:
417-
if(majorFormat == SF_FORMAT_FLAC) {
418-
sourceStreamDescription.mFormatID = kAudioFormatFLAC;
419-
sourceStreamDescription.mFormatFlags = kAppleLosslessFormatFlag_24BitSourceData;
420-
}
421-
else {
422-
sourceStreamDescription.mFormatID = kAudioFormatLinearPCM;
423-
sourceStreamDescription.mFormatFlags = kAudioFormatFlagIsSignedInteger;
424-
sourceStreamDescription.mBitsPerChannel = 24;
425-
}
426-
break;
427-
428-
case SF_FORMAT_PCM_32:
429-
sourceStreamDescription.mFormatID = kAudioFormatLinearPCM;
430-
sourceStreamDescription.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
431-
sourceStreamDescription.mBitsPerChannel = 32;
432-
break;
433-
434-
case SF_FORMAT_FLOAT:
435-
// sourceStreamDescription.mFormatID = kAudioFormatLinearPCM;
436-
sourceStreamDescription.mFormatFlags = kAudioFormatFlagIsFloat;
437-
sourceStreamDescription.mBitsPerChannel = 32;
438-
break;
439-
440-
case SF_FORMAT_DOUBLE:
441-
// sourceStreamDescription.mFormatID = kAudioFormatLinearPCM;
442-
sourceStreamDescription.mFormatFlags = kAudioFormatFlagIsFloat;
443-
sourceStreamDescription.mBitsPerChannel = 64;
444-
break;
445-
446-
case SF_FORMAT_VORBIS:
447-
sourceStreamDescription.mFormatID = kSFBAudioFormatVorbis;
448-
break;
449-
450-
case SF_FORMAT_OPUS:
451-
sourceStreamDescription.mFormatID = kAudioFormatOpus;
452-
break;
453-
454-
case SF_FORMAT_ALAC_16:
455-
sourceStreamDescription.mFormatID = kAudioFormatAppleLossless;
456-
sourceStreamDescription.mFormatFlags = kAppleLosslessFormatFlag_16BitSourceData;
457-
break;
458-
459-
case SF_FORMAT_ALAC_20:
460-
sourceStreamDescription.mFormatID = kAudioFormatAppleLossless;
461-
sourceStreamDescription.mFormatFlags = kAppleLosslessFormatFlag_20BitSourceData;
462-
break;
463-
464-
case SF_FORMAT_ALAC_24:
465-
sourceStreamDescription.mFormatID = kAudioFormatAppleLossless;
466-
sourceStreamDescription.mFormatFlags = kAppleLosslessFormatFlag_24BitSourceData;
467-
break;
468-
469-
case SF_FORMAT_ALAC_32:
470-
sourceStreamDescription.mFormatID = kAudioFormatAppleLossless;
471-
sourceStreamDescription.mFormatFlags = kAppleLosslessFormatFlag_32BitSourceData;
472-
break;
473-
474-
case SF_FORMAT_ULAW:
475-
sourceStreamDescription.mFormatID = kAudioFormatULaw;
476-
sourceStreamDescription.mBitsPerChannel = 8;
477-
break;
478-
479-
case SF_FORMAT_ALAW:
480-
sourceStreamDescription.mFormatID = kAudioFormatALaw;
481-
sourceStreamDescription.mBitsPerChannel = 8;
482-
break;
483-
}
387+
FillASBDWithSndfileFormat(&sourceStreamDescription, _sfinfo.format);
484388

485389
_sourceFormat = [[AVAudioFormat alloc] initWithStreamDescription:&sourceStreamDescription channelLayout:channelLayout];
486390

Sources/CSFBAudioEngine/Encoders/SFBLibsndfileEncoder.m

+33-21
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#import "SFBLibsndfileEncoder.h"
1515

1616
#import "NSError+SFBURLPresentation.h"
17+
#import "SFBLibsndfileUtilities.h"
1718

1819
SFBAudioEncoderName const SFBAudioEncoderNameLibsndfile = @"org.sbooth.AudioEngine.Encoder.Libsndfile";
1920

@@ -146,8 +147,8 @@ static int InferSubtypeFromFormat(AVAudioFormat *format)
146147
return 0;
147148
}
148149

149-
/// Converts an array of Core Audio channel descriptions to a sndfile channel map
150-
static void ChannelMapFromCAChannelDescriptions(int * _Nonnull channel_map, int channels, const AudioChannelDescription * _Nonnull channelDescriptions)
150+
/// Fills a sndfile channel map with the corresponding channels from `channelDescriptions`
151+
static void SndfileChannelMapWithChannelDescriptions(int * _Nonnull channel_map, int channels, const AudioChannelDescription *channelDescriptions)
151152
{
152153
NSCParameterAssert(channel_map != NULL);
153154
NSCParameterAssert(channels > 0);
@@ -188,13 +189,15 @@ static void ChannelMapFromCAChannelDescriptions(int * _Nonnull channel_map, int
188189
case kAudioChannelLabel_Ambisonic_Z: channel_map[i] = SF_CHANNEL_MAP_AMBISONIC_B_Z; break;
189190

190191
default:
192+
os_log_error(gSFBAudioEncoderLog, "Unable to map channel label: %d", channelDescriptions[i].mChannelLabel);
191193
channel_map[i] = SF_CHANNEL_MAP_INVALID;
192194
break;
193195
}
194196
}
195197
}
196198

197-
static BOOL ChannelMapFromCAChannelBitmap(int * _Nonnull channel_map, int channels, AudioChannelBitmap channelBitmap, NSError **error)
199+
/// Fills a sndfile channel map with the corresponding channels from `channelBitmap`
200+
static BOOL SndfileChannelMapWithChannelBitmap(int * _Nonnull channel_map, int channels, AudioChannelBitmap channelBitmap, NSError **error)
198201
{
199202
NSCParameterAssert(channel_map != NULL);
200203
NSCParameterAssert(channels > 0);
@@ -222,14 +225,15 @@ static BOOL ChannelMapFromCAChannelBitmap(int * _Nonnull channel_map, int channe
222225
return NO;
223226
}
224227

225-
ChannelMapFromCAChannelDescriptions(channel_map, channels, channelLayout->mChannelDescriptions);
228+
SndfileChannelMapWithChannelDescriptions(channel_map, channels, channelLayout->mChannelDescriptions);
226229

227230
free(channelLayout);
228231

229232
return YES;
230233
}
231234

232-
static BOOL ChannelMapFromCAChannelLayoutTag(int * _Nonnull channel_map, int channels, AudioChannelLayoutTag layoutTag, NSError **error)
235+
/// Fills a sndfile channel map with the corresponding channels from `layoutTag`
236+
static BOOL SndfileChannelMapWithChannelLayoutTag(int * _Nonnull channel_map, int channels, AudioChannelLayoutTag layoutTag, NSError **error)
233237
{
234238
NSCParameterAssert(channel_map != NULL);
235239
NSCParameterAssert(channels > 0);
@@ -257,29 +261,30 @@ static BOOL ChannelMapFromCAChannelLayoutTag(int * _Nonnull channel_map, int cha
257261
return NO;
258262
}
259263

260-
ChannelMapFromCAChannelDescriptions(channel_map, channels, channelLayout->mChannelDescriptions);
264+
SndfileChannelMapWithChannelDescriptions(channel_map, channels, channelLayout->mChannelDescriptions);
261265

262266
free(channelLayout);
263267

264268
return YES;
265269
}
266270

267-
static BOOL ChannelMapFromCAChannelLayout(int * _Nonnull channel_map, int channels, const AudioChannelLayout * _Nonnull channelLayout, NSError **error)
271+
/// Fills a sndfile channel map with the corresponding channels from `channelLayout`
272+
static BOOL SndfileChannelMapFromChannelLayout(int * _Nonnull channel_map, int channels, AVAudioChannelLayout * _Nonnull channelLayout, NSError **error)
268273
{
269274
NSCParameterAssert(channel_map != NULL);
270275
NSCParameterAssert(channels > 0);
271-
NSCParameterAssert(channelLayout != NULL);
276+
NSCParameterAssert(channelLayout != nil);
272277

273-
AudioChannelLayoutTag layoutTag = channelLayout->mChannelLayoutTag;
278+
AudioChannelLayoutTag layoutTag = channelLayout.layoutTag;
274279

275280
if(layoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
276-
ChannelMapFromCAChannelDescriptions(channel_map, channels, channelLayout->mChannelDescriptions);
281+
SndfileChannelMapWithChannelDescriptions(channel_map, channels, channelLayout.layout->mChannelDescriptions);
277282
return YES;
278283
}
279284
else if(layoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
280-
return ChannelMapFromCAChannelBitmap(channel_map, channels, channelLayout->mChannelBitmap, error);
285+
return SndfileChannelMapWithChannelBitmap(channel_map, channels, channelLayout.layout->mChannelBitmap, error);
281286
else
282-
return ChannelMapFromCAChannelLayoutTag(channel_map, channels, layoutTag, error);
287+
return SndfileChannelMapWithChannelLayoutTag(channel_map, channels, layoutTag, error);
283288
}
284289

285290
enum WriteMethod {
@@ -376,7 +381,7 @@ static sf_count_t my_sf_vio_tell(void *user_data)
376381
@interface SFBLibsndfileEncoder ()
377382
{
378383
@private
379-
SNDFILE *_sndfile;;
384+
SNDFILE *_sndfile;
380385
SF_INFO _sfinfo;
381386
enum WriteMethod _writeMethod;
382387
}
@@ -532,7 +537,7 @@ - (BOOL)openReturningError:(NSError **)error
532537
else if(majorFormatSetting == SFBAudioEncodingSettingsValueLibsndfileMajorFormatMPC2K) majorFormat = SF_FORMAT_MPC2K;
533538
else if(majorFormatSetting == SFBAudioEncodingSettingsValueLibsndfileMajorFormatRF64) majorFormat = SF_FORMAT_RF64;
534539
else
535-
os_log_error(gSFBAudioEncoderLog, "Ignoring unknown Libsndfile major format: %{public}@", majorFormatSetting);
540+
os_log_error(gSFBAudioEncoderLog, "Ignoring unknown libsndfile major format: %{public}@", majorFormatSetting);
536541
}
537542
else {
538543
majorFormat = MajorFormatForExtension(_outputSource.url.pathExtension);
@@ -574,7 +579,7 @@ - (BOOL)openReturningError:(NSError **)error
574579
else if(subtypeSetting == SFBAudioEncodingSettingsValueLibsndfileSubtypeALAC_24) subtype = SF_FORMAT_ALAC_24;
575580
else if(subtypeSetting == SFBAudioEncodingSettingsValueLibsndfileSubtypeALAC_32) subtype = SF_FORMAT_ALAC_32;
576581
else
577-
os_log_error(gSFBAudioEncoderLog, "Ignoring unknown Libsndfile subtype: %{public}@", subtypeSetting);
582+
os_log_error(gSFBAudioEncoderLog, "Ignoring unknown libsndfile subtype: %{public}@", subtypeSetting);
578583
}
579584
else {
580585
subtype = InferSubtypeFromFormat(_processingFormat);
@@ -589,7 +594,7 @@ - (BOOL)openReturningError:(NSError **)error
589594
else if(fileEndianSetting == SFBAudioEncodingSettingsValueLibsndfileFileEndianBig) endian = SF_ENDIAN_BIG;
590595
else if(fileEndianSetting == SFBAudioEncodingSettingsValueLibsndfileFileEndianCPU) endian = SF_ENDIAN_CPU;
591596
else
592-
os_log_error(gSFBAudioEncoderLog, "Ignoring unknown Libsndfile file endian-ness: %{public}@", fileEndianSetting);
597+
os_log_error(gSFBAudioEncoderLog, "Ignoring unknown libsndfile file endian-ness: %{public}@", fileEndianSetting);
593598
}
594599

595600
_sfinfo.samplerate = (int)_processingFormat.sampleRate;
@@ -648,8 +653,8 @@ - (BOOL)openReturningError:(NSError **)error
648653
if(processingFormatChannelLayout) {
649654
int channel_map [_sfinfo.channels];
650655

651-
if(!ChannelMapFromCAChannelLayout(channel_map, _sfinfo.channels, processingFormatChannelLayout.layout, error)) {
652-
os_log_error(gSFBAudioEncoderLog, "Unable to determine Libsndfile channel map for %{public}@", processingFormatChannelLayout.layoutName);
656+
if(!SndfileChannelMapFromChannelLayout(channel_map, _sfinfo.channels, processingFormatChannelLayout, error)) {
657+
os_log_error(gSFBAudioEncoderLog, "Unable to determine libsndfile channel map for %{public}@", processingFormatChannelLayout.layoutName);
653658
return NO;
654659
}
655660

@@ -669,9 +674,16 @@ - (BOOL)openReturningError:(NSError **)error
669674
}
670675

671676
AudioStreamBasicDescription outputStreamDescription = {0};
672-
outputStreamDescription.mSampleRate = _processingFormat.sampleRate;
673-
outputStreamDescription.mChannelsPerFrame = _processingFormat.channelCount;
674-
_outputFormat = [[AVAudioFormat alloc] initWithStreamDescription:&outputStreamDescription];
677+
678+
// Generic libsndfile format ID, will be set to something more specific if known
679+
outputStreamDescription.mFormatID = 'SNDF';
680+
681+
outputStreamDescription.mSampleRate = _processingFormat.sampleRate;
682+
outputStreamDescription.mChannelsPerFrame = _processingFormat.channelCount;
683+
684+
FillASBDWithSndfileFormat(&outputStreamDescription, _sfinfo.format);
685+
686+
_outputFormat = [[AVAudioFormat alloc] initWithStreamDescription:&outputStreamDescription channelLayout:processingFormatChannelLayout];
675687

676688
return YES;
677689
}

0 commit comments

Comments
 (0)