7
7
@import os.log;
8
8
9
9
@import sndfile;
10
+ @import AVFAudioExtensions;
10
11
11
12
#import " SFBLibsndfileDecoder.h"
12
13
13
- #import " AVAudioChannelLayout+SFBChannelLabels.h"
14
14
#import " NSData+SFBExtensions.h"
15
15
#import " NSError+SFBURLPresentation.h"
16
+ #import " SFBLibsndfileUtilities.h"
16
17
17
18
SFBAudioDecoderName const SFBAudioDecoderNameLibsndfile = @" org.sbooth.AudioEngine.Decoder.Libsndfile" ;
18
19
@@ -21,7 +22,7 @@ static AudioFormatFlags CalculateLPCMFlags(UInt32 validBitsPerChannel, UInt32 to
21
22
return (isFloat ? kAudioFormatFlagIsFloat : kAudioFormatFlagIsSignedInteger ) | (isBigEndian ? kAudioFormatFlagIsBigEndian : 0 ) | ((validBitsPerChannel == totalBitsPerChannel) ? kAudioFormatFlagIsPacked : kAudioFormatFlagIsAlignedHigh ) | (isNonInterleaved ? kAudioFormatFlagIsNonInterleaved : 0 );
22
23
}
23
24
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)
25
26
{
26
27
NSCParameterAssert (asbd != NULL );
27
28
@@ -37,7 +38,8 @@ static void FillOutASBDForLPCM(AudioStreamBasicDescription *asbd, Float64 sample
37
38
asbd->mBytesPerFrame = (isNonInterleaved ? 1 : channelsPerFrame) * (totalBitsPerChannel / 8 );
38
39
}
39
40
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)
41
43
{
42
44
NSCParameterAssert (channel_map != NULL );
43
45
NSCParameterAssert (channels > 0 );
@@ -81,7 +83,7 @@ static void FillOutASBDForLPCM(AudioStreamBasicDescription *asbd, Float64 sample
81
83
case SF_CHANNEL_MAP_AMBISONIC_B_Z: labels[i] = kAudioChannelLabel_Ambisonic_Z ; break ;
82
84
83
85
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]);
85
87
labels[i] = kAudioChannelLabel_Unused ;
86
88
break ;
87
89
}
@@ -171,7 +173,7 @@ static sf_count_t my_sf_vio_tell(void *user_data)
171
173
@interface SFBLibsndfileDecoder ()
172
174
{
173
175
@private
174
- SNDFILE *_sndfile;;
176
+ SNDFILE *_sndfile;
175
177
SF_INFO _sfinfo;
176
178
enum ReadMethod _readMethod;
177
179
}
@@ -306,49 +308,49 @@ - (BOOL)openReturningError:(NSError **)error
306
308
}
307
309
308
310
// Generate interleaved native PCM output
309
- AudioStreamBasicDescription asbd = {0 };
311
+ AudioStreamBasicDescription processingStreamDescription = {0 };
310
312
311
313
int subtype = _sfinfo.format & SF_FORMAT_SUBMASK;
312
314
switch (subtype) {
313
315
// 8-bit PCM will be high-aligned in shorts
314
316
case SF_FORMAT_PCM_U8:
315
317
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 );
317
319
_readMethod = Short;
318
320
break ;
319
321
320
322
// 16-bit PCM
321
323
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 );
323
325
_readMethod = Short;
324
326
break ;
325
327
326
328
// 24-bit PCM will be high-aligned in ints
327
329
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 );
329
331
_readMethod = Int;
330
332
break ;
331
333
332
334
// 32-bit PCM
333
335
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 );
335
337
_readMethod = Int;
336
338
break ;
337
339
338
340
// Floating point formats
339
341
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 );
341
343
_readMethod = Float;
342
344
break ;
343
345
344
346
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 );
346
348
_readMethod = Double;
347
349
break ;
348
350
349
351
// Everything else will be converted to 32-bit float
350
352
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 );
352
354
_readMethod = Float;
353
355
break ;
354
356
}
@@ -359,7 +361,7 @@ - (BOOL)openReturningError:(NSError **)error
359
361
int channel_map [_sfinfo.channels];
360
362
int result = sf_command (_sndfile, SFC_GET_CHANNEL_MAP_INFO, channel_map, (int )sizeof (channel_map));
361
363
if (result == SF_TRUE)
362
- channelLayout = ChannelLayoutForSndfileChannelMap (channel_map, _sfinfo.channels );
364
+ channelLayout = ChannelLayoutFromSndfileChannelMap (channel_map, _sfinfo.channels );
363
365
364
366
if (!channelLayout) {
365
367
switch (_sfinfo.channels ) {
@@ -371,7 +373,7 @@ - (BOOL)openReturningError:(NSError **)error
371
373
}
372
374
}
373
375
374
- _processingFormat = [[AVAudioFormat alloc ] initWithStreamDescription: &asbd channelLayout: channelLayout];
376
+ _processingFormat = [[AVAudioFormat alloc ] initWithStreamDescription: &processingStreamDescription channelLayout: channelLayout];
375
377
376
378
// Set up the source format
377
379
AudioStreamBasicDescription sourceStreamDescription = {0 };
@@ -382,105 +384,7 @@ - (BOOL)openReturningError:(NSError **)error
382
384
sourceStreamDescription.mSampleRate = _sfinfo.samplerate ;
383
385
sourceStreamDescription.mChannelsPerFrame = (UInt32 )_sfinfo.channels ;
384
386
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 );
484
388
485
389
_sourceFormat = [[AVAudioFormat alloc ] initWithStreamDescription: &sourceStreamDescription channelLayout: channelLayout];
486
390
0 commit comments