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
parent
95fb65527f
commit
22d8b8c132
|
@ -43,6 +43,7 @@
|
|||
int bitsPerSample;
|
||||
BOOL floatingPoint;
|
||||
int channels;
|
||||
uint32_t channelConfig;
|
||||
float frequency;
|
||||
long totalFrames;
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
id<CogSource> source;
|
||||
BOOL seekable;
|
||||
int channels;
|
||||
uint32_t channelConfig;
|
||||
int bitsPerSample;
|
||||
BOOL floatingPoint;
|
||||
BOOL lossy;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
int bitsPerSample;
|
||||
int channels;
|
||||
uint32_t channelConfig;
|
||||
float frequency;
|
||||
long totalFrames;
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
int bitsPerSample;
|
||||
int channels;
|
||||
uint32_t channelConfig;
|
||||
BOOL floatingPoint;
|
||||
int bitrate;
|
||||
float frequency;
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue