Implement channel config fields for inputs

This implements channel masks for inputs where applicable, namely the
CoreAudio decoder, FFmpeg, FLAC, and WavPack. All others will still use
guessing from the channel number.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
CQTexperiment
Christopher Snowhill 2022-02-07 02:06:51 -08:00
parent 95fb65527f
commit 22d8b8c132
8 changed files with 90 additions and 3 deletions

View File

@ -43,6 +43,7 @@
int bitsPerSample;
BOOL floatingPoint;
int channels;
uint32_t channelConfig;
float frequency;
long totalFrames;

View File

@ -28,6 +28,33 @@
- (BOOL)readInfoFromExtAudioFileRef;
@end
static int ffat_get_channel_id(AudioChannelLabel label) {
if(label == 0)
return -1;
else if(label <= kAudioChannelLabel_LFEScreen)
return label - 1;
else if(label <= kAudioChannelLabel_RightSurround)
return label + 4;
else if(label <= kAudioChannelLabel_CenterSurround)
return label + 1;
else if(label <= kAudioChannelLabel_RightSurroundDirect)
return label + 23;
else if(label <= kAudioChannelLabel_TopBackRight)
return label - 1;
else if(label < kAudioChannelLabel_RearSurroundLeft)
return -1;
else if(label <= kAudioChannelLabel_RearSurroundRight)
return label - 29;
else if(label <= kAudioChannelLabel_RightWide)
return label - 4;
else if(label == kAudioChannelLabel_LFE2)
return -1;
else if(label == kAudioChannelLabel_Mono)
return 2; // Front center
else
return -1;
}
static OSStatus readProc(void *clientData,
SInt64 position,
UInt32 requestCount,
@ -177,6 +204,28 @@ static SInt64 getSizeProc(void *clientData) {
return NO;
}
err = AudioFileGetPropertyInfo(afi, kAudioFilePropertyChannelLayout, &size, NULL);
if(err != noErr || size == 0) {
err = ExtAudioFileDispose(_in);
return NO;
}
AudioChannelLayout *acl = malloc(size);
err = AudioFileGetProperty(afi, kAudioFilePropertyChannelLayout, &size, acl);
if(err != noErr) {
free(acl);
err = ExtAudioFileDispose(_in);
return NO;
}
uint32_t config = 0;
for(uint32_t i = 0; i < acl->mNumberChannelDescriptions; ++i) {
int channelNumber = ffat_get_channel_id(acl->mChannelDescriptions[i].mChannelLabel);
if(channelNumber >= 0)
config |= 1 << channelNumber;
}
channelConfig = config;
bitrate = (_bitrate + 500) / 1000;
CFStringRef formatName;
@ -330,6 +379,7 @@ static SInt64 getSizeProc(void *clientData) {
- (NSDictionary *)properties {
return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:channels], @"channels",
[NSNumber numberWithInt:channelConfig], @"channelConfig",
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
[NSNumber numberWithBool:floatingPoint], @"floatingPoint",
[NSNumber numberWithInt:bitrate], @"bitrate",

View File

@ -17,6 +17,7 @@
id<CogSource> source;
BOOL seekable;
int channels;
uint32_t channelConfig;
int bitsPerSample;
BOOL floatingPoint;
BOOL lossy;

View File

@ -249,6 +249,7 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
frequency = codecCtx->sample_rate;
channels = codecCtx->channels;
channelConfig = (uint32_t)codecCtx->channel_layout;
floatingPoint = NO;
switch(codecCtx->sample_fmt) {
@ -616,6 +617,7 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
- (NSDictionary *)properties {
return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:channels], @"channels",
[NSNumber numberWithInt:channelConfig], @"channelConfig",
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
[NSNumber numberWithBool:(bitsPerSample == 8)], @"Unsigned",
[NSNumber numberWithFloat:frequency], @"sampleRate",

View File

@ -26,6 +26,7 @@
int bitsPerSample;
int channels;
uint32_t channelConfig;
float frequency;
long totalFrames;

View File

@ -12,6 +12,28 @@
@implementation FlacDecoder
static const char *CHANNEL_MASK_TAG = "WAVEFORMATEXTENSIBLE_CHANNEL_MASK";
static FLAC__bool flac__utils_get_channel_mask_tag(const FLAC__StreamMetadata *object, FLAC__uint32 *channel_mask) {
int offset;
uint32_t val;
char *p;
FLAC__ASSERT(object);
FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
if(0 > (offset = FLAC__metadata_object_vorbiscomment_find_entry_from(object, /*offset=*/0, CHANNEL_MASK_TAG)))
return false;
if(object->data.vorbis_comment.comments[offset].length < strlen(CHANNEL_MASK_TAG) + 4)
return false;
if(0 == (p = strchr((const char *)object->data.vorbis_comment.comments[offset].entry, '='))) /* should never happen, but just in case */
return false;
if(strncasecmp(p, "=0x", 3))
return false;
if(sscanf(p + 3, "%x", &val) != 1)
return false;
*channel_mask = val;
return true;
}
FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder *decoder, FLAC__byte blockBuffer[], size_t *bytes, void *client_data) {
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
long bytesRead = [[flacDecoder source] read:blockBuffer amount:*bytes];
@ -168,11 +190,12 @@ void MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMeta
flacDecoder->totalFrames = metadata->data.stream_info.total_samples;
[flacDecoder willChangeValueForKey:@"properties"];
[flacDecoder didChangeValueForKey:@"properties"];
flacDecoder->hasStreamInfo = YES;
}
if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
(void)flac__utils_get_channel_mask_tag(metadata, &flacDecoder->channelConfig);
}
}
void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) {
@ -208,6 +231,11 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS
FLAC__stream_decoder_process_until_end_of_metadata(decoder);
if(hasStreamInfo) {
[self willChangeValueForKey:@"properties"];
[self didChangeValueForKey:@"properties"];
}
blockBuffer = malloc(SAMPLE_blockBuffer_SIZE);
return YES;
@ -305,6 +333,7 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS
- (NSDictionary *)properties {
return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:channels], @"channels",
[NSNumber numberWithInt:channelConfig], @"channelConfig",
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
[NSNumber numberWithFloat:frequency], @"sampleRate",
[NSNumber numberWithDouble:totalFrames], @"totalFrames",

View File

@ -39,6 +39,7 @@
int bitsPerSample;
int channels;
uint32_t channelConfig;
BOOL floatingPoint;
int bitrate;
float frequency;

View File

@ -144,6 +144,7 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) {
}
channels = WavpackGetNumChannels(wpc);
channelConfig = WavpackGetChannelMask(wpc);
bitsPerSample = WavpackGetBitsPerSample(wpc);
frequency = WavpackGetSampleRate(wpc);
@ -282,6 +283,7 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) {
- (NSDictionary *)properties {
return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:channels], @"channels",
[NSNumber numberWithInt:channelConfig], @"channelConfig",
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
[NSNumber numberWithInt:bitrate], @"bitrate",
[NSNumber numberWithFloat:frequency], @"sampleRate",