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;
|
int bitsPerSample;
|
||||||
BOOL floatingPoint;
|
BOOL floatingPoint;
|
||||||
int channels;
|
int channels;
|
||||||
|
uint32_t channelConfig;
|
||||||
float frequency;
|
float frequency;
|
||||||
long totalFrames;
|
long totalFrames;
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,33 @@
|
||||||
- (BOOL)readInfoFromExtAudioFileRef;
|
- (BOOL)readInfoFromExtAudioFileRef;
|
||||||
@end
|
@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,
|
static OSStatus readProc(void *clientData,
|
||||||
SInt64 position,
|
SInt64 position,
|
||||||
UInt32 requestCount,
|
UInt32 requestCount,
|
||||||
|
@ -177,6 +204,28 @@ static SInt64 getSizeProc(void *clientData) {
|
||||||
return NO;
|
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;
|
bitrate = (_bitrate + 500) / 1000;
|
||||||
|
|
||||||
CFStringRef formatName;
|
CFStringRef formatName;
|
||||||
|
@ -330,6 +379,7 @@ static SInt64 getSizeProc(void *clientData) {
|
||||||
- (NSDictionary *)properties {
|
- (NSDictionary *)properties {
|
||||||
return [NSDictionary dictionaryWithObjectsAndKeys:
|
return [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
[NSNumber numberWithInt:channels], @"channels",
|
[NSNumber numberWithInt:channels], @"channels",
|
||||||
|
[NSNumber numberWithInt:channelConfig], @"channelConfig",
|
||||||
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
|
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
|
||||||
[NSNumber numberWithBool:floatingPoint], @"floatingPoint",
|
[NSNumber numberWithBool:floatingPoint], @"floatingPoint",
|
||||||
[NSNumber numberWithInt:bitrate], @"bitrate",
|
[NSNumber numberWithInt:bitrate], @"bitrate",
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
id<CogSource> source;
|
id<CogSource> source;
|
||||||
BOOL seekable;
|
BOOL seekable;
|
||||||
int channels;
|
int channels;
|
||||||
|
uint32_t channelConfig;
|
||||||
int bitsPerSample;
|
int bitsPerSample;
|
||||||
BOOL floatingPoint;
|
BOOL floatingPoint;
|
||||||
BOOL lossy;
|
BOOL lossy;
|
||||||
|
|
|
@ -249,6 +249,7 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
|
||||||
|
|
||||||
frequency = codecCtx->sample_rate;
|
frequency = codecCtx->sample_rate;
|
||||||
channels = codecCtx->channels;
|
channels = codecCtx->channels;
|
||||||
|
channelConfig = (uint32_t)codecCtx->channel_layout;
|
||||||
floatingPoint = NO;
|
floatingPoint = NO;
|
||||||
|
|
||||||
switch(codecCtx->sample_fmt) {
|
switch(codecCtx->sample_fmt) {
|
||||||
|
@ -616,6 +617,7 @@ int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
|
||||||
- (NSDictionary *)properties {
|
- (NSDictionary *)properties {
|
||||||
return [NSDictionary dictionaryWithObjectsAndKeys:
|
return [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
[NSNumber numberWithInt:channels], @"channels",
|
[NSNumber numberWithInt:channels], @"channels",
|
||||||
|
[NSNumber numberWithInt:channelConfig], @"channelConfig",
|
||||||
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
|
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
|
||||||
[NSNumber numberWithBool:(bitsPerSample == 8)], @"Unsigned",
|
[NSNumber numberWithBool:(bitsPerSample == 8)], @"Unsigned",
|
||||||
[NSNumber numberWithFloat:frequency], @"sampleRate",
|
[NSNumber numberWithFloat:frequency], @"sampleRate",
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
int bitsPerSample;
|
int bitsPerSample;
|
||||||
int channels;
|
int channels;
|
||||||
|
uint32_t channelConfig;
|
||||||
float frequency;
|
float frequency;
|
||||||
long totalFrames;
|
long totalFrames;
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,28 @@
|
||||||
|
|
||||||
@implementation FlacDecoder
|
@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) {
|
FLAC__StreamDecoderReadStatus ReadCallback(const FLAC__StreamDecoder *decoder, FLAC__byte blockBuffer[], size_t *bytes, void *client_data) {
|
||||||
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
FlacDecoder *flacDecoder = (__bridge FlacDecoder *)client_data;
|
||||||
long bytesRead = [[flacDecoder source] read:blockBuffer amount:*bytes];
|
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->totalFrames = metadata->data.stream_info.total_samples;
|
||||||
|
|
||||||
[flacDecoder willChangeValueForKey:@"properties"];
|
|
||||||
[flacDecoder didChangeValueForKey:@"properties"];
|
|
||||||
|
|
||||||
flacDecoder->hasStreamInfo = YES;
|
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) {
|
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);
|
FLAC__stream_decoder_process_until_end_of_metadata(decoder);
|
||||||
|
|
||||||
|
if(hasStreamInfo) {
|
||||||
|
[self willChangeValueForKey:@"properties"];
|
||||||
|
[self didChangeValueForKey:@"properties"];
|
||||||
|
}
|
||||||
|
|
||||||
blockBuffer = malloc(SAMPLE_blockBuffer_SIZE);
|
blockBuffer = malloc(SAMPLE_blockBuffer_SIZE);
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
|
@ -305,6 +333,7 @@ void ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorS
|
||||||
- (NSDictionary *)properties {
|
- (NSDictionary *)properties {
|
||||||
return [NSDictionary dictionaryWithObjectsAndKeys:
|
return [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
[NSNumber numberWithInt:channels], @"channels",
|
[NSNumber numberWithInt:channels], @"channels",
|
||||||
|
[NSNumber numberWithInt:channelConfig], @"channelConfig",
|
||||||
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
|
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
|
||||||
[NSNumber numberWithFloat:frequency], @"sampleRate",
|
[NSNumber numberWithFloat:frequency], @"sampleRate",
|
||||||
[NSNumber numberWithDouble:totalFrames], @"totalFrames",
|
[NSNumber numberWithDouble:totalFrames], @"totalFrames",
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
int bitsPerSample;
|
int bitsPerSample;
|
||||||
int channels;
|
int channels;
|
||||||
|
uint32_t channelConfig;
|
||||||
BOOL floatingPoint;
|
BOOL floatingPoint;
|
||||||
int bitrate;
|
int bitrate;
|
||||||
float frequency;
|
float frequency;
|
||||||
|
|
|
@ -144,6 +144,7 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) {
|
||||||
}
|
}
|
||||||
|
|
||||||
channels = WavpackGetNumChannels(wpc);
|
channels = WavpackGetNumChannels(wpc);
|
||||||
|
channelConfig = WavpackGetChannelMask(wpc);
|
||||||
bitsPerSample = WavpackGetBitsPerSample(wpc);
|
bitsPerSample = WavpackGetBitsPerSample(wpc);
|
||||||
|
|
||||||
frequency = WavpackGetSampleRate(wpc);
|
frequency = WavpackGetSampleRate(wpc);
|
||||||
|
@ -282,6 +283,7 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) {
|
||||||
- (NSDictionary *)properties {
|
- (NSDictionary *)properties {
|
||||||
return [NSDictionary dictionaryWithObjectsAndKeys:
|
return [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
[NSNumber numberWithInt:channels], @"channels",
|
[NSNumber numberWithInt:channels], @"channels",
|
||||||
|
[NSNumber numberWithInt:channelConfig], @"channelConfig",
|
||||||
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
|
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
|
||||||
[NSNumber numberWithInt:bitrate], @"bitrate",
|
[NSNumber numberWithInt:bitrate], @"bitrate",
|
||||||
[NSNumber numberWithFloat:frequency], @"sampleRate",
|
[NSNumber numberWithFloat:frequency], @"sampleRate",
|
||||||
|
|
Loading…
Reference in New Issue