diff options
Diffstat (limited to 'macosx/HBAudioTrack.m')
-rw-r--r-- | macosx/HBAudioTrack.m | 761 |
1 files changed, 291 insertions, 470 deletions
diff --git a/macosx/HBAudioTrack.m b/macosx/HBAudioTrack.m index 1c998cc4f..9e93eab5d 100644 --- a/macosx/HBAudioTrack.m +++ b/macosx/HBAudioTrack.m @@ -19,339 +19,95 @@ NSString *keyAudioInputCodecParam = @"keyAudioInputCodecParam"; NSString *keyAudioInputChannelLayout = @"keyAudioInputChannelLayout"; NSString *keyAudioTrackLanguageIsoCode = @"keyAudioTrackLanguageIsoCode"; -NSString *keyAudioCodecName = @"keyAudioCodecName"; -NSString *keyAudioSupportedMuxers = @"keyAudioSupportedMuxers"; -NSString *keyAudioSampleRateName = @"keyAudioSampleRateName"; -NSString *keyAudioBitrateName = @"keyAudioBitrateName"; -NSString *keyAudioMustMatchTrack = @"keyAudioMustMatchTrack"; -NSString *keyAudioMixdownName = @"keyAudioMixdownName"; - -NSString *keyAudioCodec = @"codec"; -NSString *keyAudioMixdown = @"mixdown"; -NSString *keyAudioSamplerate = @"samplerate"; -NSString *keyAudioBitrate = @"bitrate"; - -static NSMutableArray *masterCodecArray = nil; -static NSMutableArray *masterMixdownArray = nil; -static NSMutableArray *masterBitRateArray = nil; - -@interface NSArray (HBAudioSupport) -- (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey; -- (NSDictionary *) lastDictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey; -@end -@implementation NSArray (HBAudioSupport) -- (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey reverse: (BOOL) reverse -{ - NSDictionary *retval = nil; - NSEnumerator *enumerator = reverse ? [self reverseObjectEnumerator] : [self objectEnumerator]; - NSDictionary *dict; - id aValue; - - while (nil != (dict = [enumerator nextObject]) && !retval) - { - if (nil != (aValue = dict[aKey]) && [aValue isEqual: anObject]) - { - retval = dict; - } - } - return retval; -} -- (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey -{ - return [self dictionaryWithObject: anObject matchingKey: aKey reverse: NO]; -} -- (NSDictionary *) lastDictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey -{ - return [self dictionaryWithObject: anObject matchingKey: aKey reverse: YES]; -} - -@end +#define DEFAULT_SAMPLERATE 48000 @interface HBAudioTrack () - -@property (nonatomic, readwrite) NSArray *codecs; -@property (nonatomic, readwrite) NSArray *mixdowns; -@property (nonatomic, readwrite) NSArray *bitRates; - +@property (nonatomic, readwrite) BOOL validating; @end @implementation HBAudioTrack -#pragma mark - -#pragma mark Object Setup - -+ (void)initialize +- (instancetype)init { - if ([HBAudioTrack class] == self) + self = [super init]; + if (self) { - masterCodecArray = [[NSMutableArray alloc] init]; // knowingly leaked - for (const hb_encoder_t *audio_encoder = hb_audio_encoder_get_next(NULL); - audio_encoder != NULL; - audio_encoder = hb_audio_encoder_get_next(audio_encoder)) - { - id audioMustMatchTrack; - if ((audio_encoder->codec & HB_ACODEC_PASS_FLAG) && - (audio_encoder->codec != HB_ACODEC_AUTO_PASS)) - { - audioMustMatchTrack = @(audio_encoder->codec & - ~HB_ACODEC_PASS_FLAG); - } - else - { - audioMustMatchTrack = @NO; - } - [masterCodecArray addObject:@{keyAudioCodecName: @(audio_encoder->name), - keyAudioCodec: @(audio_encoder->codec), - keyAudioSupportedMuxers: @(audio_encoder->muxers), - keyAudioMustMatchTrack: audioMustMatchTrack}]; - } - - masterMixdownArray = [[NSMutableArray alloc] init]; // knowingly leaked - for (const hb_mixdown_t *mixdown = hb_mixdown_get_next(NULL); - mixdown != NULL; - mixdown = hb_mixdown_get_next(mixdown)) - { - [masterMixdownArray addObject:@{keyAudioMixdownName: @(mixdown->name), - keyAudioMixdown: @(mixdown->amixdown)}]; - } - - masterBitRateArray = [[NSMutableArray alloc] init]; // knowingly leaked - for (const hb_rate_t *audio_bitrate = hb_audio_bitrate_get_next(NULL); - audio_bitrate != NULL; - audio_bitrate = hb_audio_bitrate_get_next(audio_bitrate)) - { - [masterBitRateArray addObject:@{keyAudioBitrateName: @(audio_bitrate->name), - keyAudioBitrate: @(audio_bitrate->rate)}]; - } + // Defaults settings + _encoder = HB_ACODEC_CA_AAC; + _container = HB_MUX_MKV; + _sampleRate = 0; + _bitRate = 160; + _mixdown = HB_AMIXDOWN_DOLBYPLII; } + return self; } -// Ensure the list of codecs is accurate -// Update the current value of codec based on the revised list -- (void) updateCodecs +- (instancetype)initWithTrackIdx:(NSUInteger)index + container:(int)container + dataSource:(id<HBAudioTrackDataSource>)dataSource + delegate:(id<HBAudioTrackDelegate>)delegate; { - NSMutableArray *permittedCodecs = [NSMutableArray array]; - NSUInteger count = [masterCodecArray count]; - NSDictionary *dict; - - // First get a list of the permitted codecs based on the internal rules - if (nil != self.track && self.enabled) + self = [super init]; + if (self) { - BOOL goodToAdd; - - for (unsigned int i = 0; i < count; i++) - { - dict = masterCodecArray[i]; - - // First make sure only codecs permitted by the container are here - goodToAdd = !!([dict[keyAudioSupportedMuxers] intValue] & self.container); + _dataSource = dataSource; + _sourceTrackIdx = index; + _container = container; - // Now we make sure if DTS or AC3 is not available in the track it is not put in the codec list, but in a general way - if ([dict[keyAudioMustMatchTrack] boolValue]) - { - if ([dict[keyAudioMustMatchTrack] intValue] != [self.track[keyAudioInputCodec] intValue]) - { - goodToAdd = NO; - } - } + [self validateSettings]; - if (goodToAdd) - { - [permittedCodecs addObject: dict]; - } - } + _delegate = delegate; } - // Now make sure the permitted list and the actual ones matches - [self setCodecs: permittedCodecs]; + return self; +} - // Ensure our codec is on the list of permitted codecs - if (!self.codec || ![permittedCodecs containsObject: self.codec]) +- (void)validateSettings +{ + if (_sourceTrackIdx) { - if (0 < [permittedCodecs count]) + if (self.encoder == 0) { - self.codec = permittedCodecs[0]; // This should be defaulting to Core Audio + self.encoder = HB_ACODEC_CA_AAC; + self.bitRate = 160; } else { - self.codec = nil; + self.encoder = [self sanatizeEncoderValue:self.encoder]; } } -} - -- (void)updateMixdowns:(BOOL)shouldSetDefault -{ - NSMutableArray *permittedMixdowns = [NSMutableArray array]; - NSDictionary *dict; - int currentMixdown; - - unsigned long long channelLayout = [self.track[keyAudioInputChannelLayout] unsignedLongLongValue]; - NSUInteger count = [masterMixdownArray count]; - int codecCodec = [self.codec[keyAudioCodec] intValue]; - int theDefaultMixdown = hb_mixdown_get_default(codecCodec, channelLayout); - - for (unsigned int i = 0; i < count; i++) - { - dict = masterMixdownArray[i]; - currentMixdown = [dict[keyAudioMixdown] intValue]; - - if (hb_mixdown_is_supported(currentMixdown, codecCodec, channelLayout)) - { - [permittedMixdowns addObject: dict]; - } - } - - if (!self.enabled) - { - permittedMixdowns = nil; - } - - // Now make sure the permitted list and the actual ones matches - self.mixdowns = permittedMixdowns; - - // Select the proper one - if (shouldSetDefault) - { - self.mixdown = [permittedMixdowns dictionaryWithObject: @(theDefaultMixdown) - matchingKey: keyAudioMixdown]; - } - - if (!self.mixdown || ![permittedMixdowns containsObject: self.mixdown]) + else { - self.mixdown = [permittedMixdowns lastObject]; + self.encoder = 0; + self.mixdown = 0; + self.sampleRate = 0; + self.bitRate = -1; } } -- (void)validateSamplerate -{ - int codec = [self.codec[keyAudioCodec] intValue]; - int samplerate = [self.sampleRate[keyAudioSamplerate] intValue]; +#pragma mark - Track properties - if (codec & HB_ACODEC_PASS_FLAG) - { - [self setSampleRateFromName:@"Auto"]; - } - else if (samplerate) - { - samplerate = hb_audio_samplerate_find_closest(samplerate, codec); - [self setSampleRateFromName:@(hb_audio_samplerate_get_name(samplerate))]; - } -} - -- (void)updateBitRates:(BOOL)shouldSetDefault +- (void)setSourceTrackIdx:(NSUInteger)sourceTrackIdx { - NSMutableArray *permittedBitRates = [NSMutableArray array]; - NSDictionary *dict; - int minBitRate; - int maxBitRate; - int currentBitRate; - BOOL shouldAdd; - - NSUInteger count = [masterBitRateArray count]; - int trackInputBitRate = [self.track[keyAudioInputBitrate] intValue]; - int theSampleRate = [self.sampleRate[keyAudioSamplerate] intValue]; - - if (0 == theSampleRate) // this means Auto + if (sourceTrackIdx != _sourceTrackIdx) { - theSampleRate = [self.track[keyAudioInputSampleRate] intValue]; + [[self.undo prepareWithInvocationTarget:self] setSourceTrackIdx:_sourceTrackIdx]; } - int ourCodec = [self.codec[keyAudioCodec] intValue]; - int ourMixdown = [self.mixdown[keyAudioMixdown] intValue]; - int theDefaultBitRate = hb_audio_bitrate_get_default(ourCodec, theSampleRate, ourMixdown); - hb_audio_bitrate_get_limits(ourCodec, theSampleRate, ourMixdown, &minBitRate, &maxBitRate); - - BOOL codecIsPassthru = ([self.codec[keyAudioCodec] intValue] & HB_ACODEC_PASS_FLAG) ? YES : NO; - BOOL codecIsLossless = (theDefaultBitRate == -1) ? YES : NO; - - if (codecIsPassthru) - { - NSDictionary *sourceBitRate = [masterBitRateArray dictionaryWithObject: @(trackInputBitRate) - matchingKey: keyAudioBitrate]; - if (!sourceBitRate) - { - // the source bitrate isn't in the master array - create it - sourceBitRate = @{keyAudioBitrateName: [NSString stringWithFormat: @"%d", trackInputBitRate], - keyAudioBitrate: @(trackInputBitRate)}; - } - [permittedBitRates addObject: sourceBitRate]; - } - else if (codecIsLossless) - { - NSDictionary *bitRateNotApplicable = @{keyAudioBitrateName: @"N/A", - keyAudioBitrate: @-1}; - [permittedBitRates addObject: bitRateNotApplicable]; - } - else - { - for (unsigned int i = 0; i < count; i++) - { - dict = masterBitRateArray[i]; - currentBitRate = [dict[keyAudioBitrate] intValue]; - - // First ensure the bitrate falls within range of the codec - shouldAdd = (currentBitRate >= minBitRate && currentBitRate <= maxBitRate); - - if (shouldAdd) - { - [permittedBitRates addObject: dict]; - } - } - } - - if (!self.enabled) - { - permittedBitRates = nil; - } - - // Make sure we are updated with the permitted list - self.bitRates = permittedBitRates; - - // Select the proper one - if (shouldSetDefault) - { - [self setBitRateFromName: [NSString stringWithFormat:@"%d", theDefaultBitRate]]; - } + NSUInteger oldIdx = _sourceTrackIdx; + _sourceTrackIdx = sourceTrackIdx; - if (!self.bitRate || ![permittedBitRates containsObject: self.bitRate]) + if (!(self.undo.isUndoing || self.undo.isRedoing)) { - self.bitRate = [permittedBitRates lastObject]; - } -} - -#pragma mark - -#pragma mark Accessors + [self validateSettings]; -- (NSArray *)sampleRates -{ - NSMutableArray *samplerates = [[NSMutableArray alloc] init]; - - /* - * Note that for the Auto value we use 0 for the sample rate because our controller will give back the track's - * input sample rate when it finds this 0 value as the selected sample rate. We do this because the input - * sample rate depends on the track, which means it depends on the title, so cannot be nicely set up here. - */ - [samplerates addObject:@{keyAudioSampleRateName: @"Auto", - keyAudioSamplerate: @0}]; - - int codec = [self.codec[keyAudioCodec] intValue]; - for (const hb_rate_t *audio_samplerate = hb_audio_samplerate_get_next(NULL); - audio_samplerate != NULL; - audio_samplerate = hb_audio_samplerate_get_next(audio_samplerate)) - { - int rate = audio_samplerate->rate; - if (rate == hb_audio_samplerate_find_closest(rate, codec)) + if (oldIdx != sourceTrackIdx) { - [samplerates addObject:@{keyAudioSampleRateName: @(audio_samplerate->name), - keyAudioSamplerate: @(rate)}]; + [self.delegate track:self didChangeSourceFrom:oldIdx]; } } - return samplerates; } -#pragma mark - -#pragma mark Setters - - (void)setContainer:(int)container { if (container != _container) @@ -362,54 +118,33 @@ static NSMutableArray *masterBitRateArray = nil; if (!(self.undo.isUndoing || self.undo.isRedoing)) { - [self updateCodecs]; - } -} - -- (void)setTrack:(NSDictionary *)track -{ - if (track != _track) - { - [[self.undo prepareWithInvocationTarget:self] setTrack:_track]; - } - NSDictionary *oldValue = _track; - _track = track; - if (nil != _track && !(self.undo.isUndoing || self.undo.isRedoing)) - { - [self updateCodecs]; - [self updateMixdowns: YES]; - if (self.enabled) - { - self.sampleRate = self.sampleRates[0]; // default to Auto - } - if ([self.dataSource.noneTrack isEqual: oldValue]) - { - [self.delegate switchingTrackFromNone: self]; - } - if ([self.dataSource.noneTrack isEqual: self.track]) + if (self.encoder) { - [self.delegate settingTrackToNone: self]; + self.encoder = [self sanatizeEncoderValue:self.encoder]; } } } -- (void)setCodec:(NSDictionary *)codec +- (void)setEncoder:(int)encoder { - if (codec != _codec) + if (encoder != _encoder) { - [[self.undo prepareWithInvocationTarget:self] setCodec:_codec]; + [[self.undo prepareWithInvocationTarget:self] setEncoder:_encoder]; } - _codec = codec; + _encoder = encoder; - if (!(self.undo.isUndoing || self.undo.isRedoing)) + if (!(self.undo.isUndoing || self.undo.isRedoing) && !self.validating) { - [self validateSamplerate]; - [self updateMixdowns:YES]; - [self updateBitRates:YES]; + self.validating = YES; + [self.delegate encoderChanged]; + self.mixdown = [self sanatizeMixdownValue:self.mixdown]; + self.sampleRate = [self sanatizeSamplerateValue:self.sampleRate]; + self.bitRate = [self sanatizeBitrateValue:self.bitRate]; + self.validating = NO; } } -- (void)setMixdown:(NSDictionary *)mixdown +- (void)setMixdown:(int)mixdown { if (mixdown != _mixdown) { @@ -417,14 +152,15 @@ static NSMutableArray *masterBitRateArray = nil; } _mixdown = mixdown; - if (!(self.undo.isUndoing || self.undo.isRedoing)) + if (!(self.undo.isUndoing || self.undo.isRedoing) && !self.validating) { - [self updateBitRates:YES]; - [self.delegate mixdownChanged]; + self.validating = YES; + self.bitRate = [self sanatizeBitrateValue:self.bitRate]; + self.validating = NO; } } -- (void)setSampleRate:(NSDictionary *)sampleRate +- (void)setSampleRate:(int)sampleRate { if (sampleRate != _sampleRate) { @@ -432,13 +168,15 @@ static NSMutableArray *masterBitRateArray = nil; } _sampleRate = sampleRate; - if (!(self.undo.isUndoing || self.undo.isRedoing)) + if (!(self.undo.isUndoing || self.undo.isRedoing) && !self.validating) { - [self updateBitRates: NO]; + self.validating = YES; + self.bitRate = [self sanatizeBitrateValue:self.bitRate]; + self.validating = NO; } } -- (void)setBitRate:(NSDictionary *)bitRate +- (void)setBitRate:(int)bitRate { if (bitRate != _bitRate) { @@ -447,15 +185,6 @@ static NSMutableArray *masterBitRateArray = nil; _bitRate = bitRate; } -- (void)setDrc:(double)drc -{ - if (drc != _drc) - { - [[self.undo prepareWithInvocationTarget:self] setDrc:_drc]; - } - _drc = drc; -} - - (void)setGain:(double)gain { if (gain != _gain) @@ -465,140 +194,235 @@ static NSMutableArray *masterBitRateArray = nil; _gain = gain; } -#pragma mark - -#pragma mark Special Setters - -- (void)setTrackFromIndex:(int)aValue +// Because we have indicated that the binding for the gain validates immediately we can implement the +// key value binding method to ensure the gain stays in our accepted range. +- (BOOL)validateGain:(id *)ioValue error:(NSError * __autoreleasing *)outError { - self.track = [self.dataSource.masterTrackArray dictionaryWithObject: @(aValue) - matchingKey: keyAudioTrackIndex]; + BOOL retval = YES; + + if (nil != *ioValue) + { + if ([*ioValue intValue] < -20) + { + *ioValue = @(-20); + } + else if ([*ioValue intValue] > 20) + { + *ioValue = @20; + } + } + + return retval; } -// This returns whether it is able to set the actual codec desired. -- (BOOL)setCodecFromName:(NSString *)aValue +- (void)setDrc:(double)drc { - NSDictionary *dict = [self.codecs dictionaryWithObject: aValue matchingKey: keyAudioCodecName]; - if (nil != dict) + if (drc != _drc) { - self.codec = dict; + [[self.undo prepareWithInvocationTarget:self] setDrc:_drc]; } - return (nil != dict); + _drc = drc; } -- (void)setMixdownFromName:(NSString *)aValue +#pragma mark - Validation + +- (int)sanatizeEncoderValue:(int)proposedEncoder { - NSDictionary *dict = [self.mixdowns dictionaryWithObject: aValue matchingKey: keyAudioMixdownName]; - if (nil != dict) + if (proposedEncoder) + { + NSDictionary *sourceTrack = [_dataSource sourceTrackAtIndex:_sourceTrackIdx]; + int inputCodec = [sourceTrack[keyAudioInputCodec] intValue]; + + hb_encoder_t *proposedEncoderInfo = hb_audio_encoder_get_from_codec(proposedEncoder); + + if (proposedEncoderInfo && proposedEncoderInfo->muxers & self.container) + { + // If the codec is passthru, see if the new source supports it. + if (proposedEncoderInfo->codec & HB_ACODEC_PASS_FLAG) + { + if ((proposedEncoderInfo->codec & inputCodec & HB_ACODEC_PASS_MASK)) + { + return proposedEncoder; + } + } + else + { + return proposedEncoder; + } + } + + return HB_ACODEC_CA_AAC; + } + else { - self.mixdown = dict; + return proposedEncoder; } } -- (void)setSampleRateFromName:(NSString *)aValue +- (int)sanatizeMixdownValue:(int)proposedMixdown { - NSDictionary *dict = [self.sampleRates dictionaryWithObject: aValue matchingKey: keyAudioSampleRateName]; - if (nil != dict) + NSDictionary *sourceTrack = [_dataSource sourceTrackAtIndex:_sourceTrackIdx]; + unsigned long long channelLayout = [sourceTrack[keyAudioInputChannelLayout] unsignedLongLongValue]; + + if (!hb_mixdown_is_supported(proposedMixdown, self.encoder, channelLayout)) { - self.sampleRate = dict; + return hb_mixdown_get_default(self.encoder, channelLayout); } + return proposedMixdown; } -- (void)setBitRateFromName:(NSString *)aValue +- (int)sanatizeSamplerateValue:(int)proposedSamplerate { - NSDictionary *dict = [self.bitRates dictionaryWithObject: aValue matchingKey: keyAudioBitrateName]; - if (nil != dict) + if (self.encoder & HB_ACODEC_PASS_FLAG) + { + return 0; // Auto (same as source) + } + else if (proposedSamplerate) { - self.bitRate = dict; + return hb_audio_samplerate_find_closest(proposedSamplerate, self.encoder); } + return proposedSamplerate; } -- (void)setCodecs:(NSArray *)codecs +- (int)sanatizeBitrateValue:(int)proposedBitrate { - if (codecs != _codecs) + if (self.encoder & HB_ACODEC_PASS_FLAG) { - [[self.undo prepareWithInvocationTarget:self] setCodecs:_codecs]; + return -1; + } + else if (proposedBitrate == -1) // switching from passthru + { + return hb_audio_bitrate_get_default(self.encoder, + self.sampleRate ? self.sampleRate : DEFAULT_SAMPLERATE, + self.mixdown); + } + else + { + return hb_audio_bitrate_get_best(self.encoder, proposedBitrate, self.sampleRate, self.mixdown); } - _codecs = codecs; } -- (void)setMixdowns:(NSArray *)mixdowns +#pragma mark - Options + +- (NSArray<NSString *> *)encoders { - if (mixdowns != _mixdowns) + NSMutableArray<NSString *> *encoders = [[NSMutableArray alloc] init]; + + NSDictionary *sourceTrack = [_dataSource sourceTrackAtIndex:_sourceTrackIdx]; + int inputCodec = [sourceTrack[keyAudioInputCodec] intValue]; + + for (const hb_encoder_t *audio_encoder = hb_audio_encoder_get_next(NULL); + audio_encoder != NULL; + audio_encoder = hb_audio_encoder_get_next(audio_encoder)) { - [[self.undo prepareWithInvocationTarget:self] setMixdowns:_mixdowns]; + if (audio_encoder->muxers & self.container) + { + if (audio_encoder->codec & HB_ACODEC_PASS_FLAG) + { + // If the codec is passthru, show only the supported ones. + if ((audio_encoder->codec & inputCodec & HB_ACODEC_PASS_MASK)) + { + [encoders addObject:@(audio_encoder->name)]; + } + } + else + { + [encoders addObject:@(audio_encoder->name)]; + } + } } - _mixdowns = mixdowns; + return encoders; } -- (void)setBitRates:(NSArray *)bitRates +- (NSArray<NSString *> *)mixdowns { - if (bitRates != _bitRates) + NSMutableArray<NSString *> *mixdowns = [[NSMutableArray alloc] init]; + + NSDictionary *sourceTrack = [_dataSource sourceTrackAtIndex:_sourceTrackIdx]; + unsigned long long channelLayout = [sourceTrack[keyAudioInputChannelLayout] unsignedLongLongValue]; + + for (const hb_mixdown_t *mixdown = hb_mixdown_get_next(NULL); + mixdown != NULL; + mixdown = hb_mixdown_get_next(mixdown)) { - [[self.undo prepareWithInvocationTarget:self] setBitRates:_bitRates]; + if (hb_mixdown_is_supported(mixdown->amixdown, self.encoder, channelLayout)) + { + [mixdowns addObject:@(mixdown->name)]; + } } - _bitRates = bitRates; + return mixdowns; } -#pragma mark - -#pragma mark Validation - -// Because we have indicated that the binding for the gain validates immediately we can implement the -// key value binding method to ensure the gain stays in our accepted range. -- (BOOL)validateGain:(id *)ioValue error:(NSError * __autoreleasing *)outError +- (NSArray<NSString *> *)sampleRates { - BOOL retval = YES; + NSMutableArray<NSString *> *sampleRates = [[NSMutableArray alloc] init]; + [sampleRates addObject:@"Auto"]; - if (nil != *ioValue) + for (const hb_rate_t *audio_samplerate = hb_audio_samplerate_get_next(NULL); + audio_samplerate != NULL; + audio_samplerate = hb_audio_samplerate_get_next(audio_samplerate)) { - if ([*ioValue intValue] < -20) + int rate = audio_samplerate->rate; + if (rate == hb_audio_samplerate_find_closest(rate, self.encoder)) { - *ioValue = @(-20); + [sampleRates addObject:@(audio_samplerate->name)]; } - else if ([*ioValue intValue] > 20) + } + return sampleRates; +} + +- (NSArray<NSString *> *)bitRates +{ + int minBitRate = 0; + int maxBitRate = 0; + + hb_audio_bitrate_get_limits(self.encoder, self.sampleRate, self.mixdown, &minBitRate, &maxBitRate); + + NSMutableArray<NSString *> *bitRates = [[NSMutableArray alloc] init]; + for (const hb_rate_t *audio_bitrate = hb_audio_bitrate_get_next(NULL); + audio_bitrate != NULL; + audio_bitrate = hb_audio_bitrate_get_next(audio_bitrate)) + { + if (audio_bitrate->rate >= minBitRate && audio_bitrate->rate <= maxBitRate) { - *ioValue = @20; + [bitRates addObject:@(audio_bitrate->name)]; } } - - return retval; + return bitRates; } -#pragma mark - Bindings Support +#pragma mark - KVO UI Additions -- (NSArray *)masterTrackArray +- (NSArray *)sourceTracksArray { - return self.dataSource.masterTrackArray; + return [self.dataSource sourceTracksArray]; } -- (BOOL)enabled +- (BOOL)isEnabled { - return (nil != self.track) ? (![self.track isEqual: self.dataSource.noneTrack]) : NO; + return self.sourceTrackIdx != 0; } - (BOOL)mixdownEnabled { - BOOL retval = self.enabled; + BOOL retval = self.isEnabled; - if (retval) + if (retval && self.mixdown == HB_AMIXDOWN_NONE) { - int myMixdown = [self.mixdown[keyAudioMixdown] intValue]; - if (myMixdown == HB_AMIXDOWN_NONE) - { - // "None" mixdown (passthru) - retval = NO; - } + // "None" mixdown (passthru) + retval = NO; } + return retval; } - (BOOL)bitrateEnabled { - BOOL retval = self.enabled; + BOOL retval = self.isEnabled; if (retval) { - int myCodecCodec = [self.codec[keyAudioCodec] intValue]; - int myCodecDefaultBitrate = hb_audio_bitrate_get_default(myCodecCodec, 0, 0); + int myCodecDefaultBitrate = hb_audio_bitrate_get_default(self.encoder, 0, 0); if (myCodecDefaultBitrate < 0) { retval = NO; @@ -607,16 +431,17 @@ static NSMutableArray *masterBitRateArray = nil; return retval; } -- (BOOL)DRCEnabled +- (BOOL)drcEnabled { - BOOL retval = self.enabled; + BOOL retval = self.isEnabled; if (retval) { - int myTrackParam = [self.track[keyAudioInputCodecParam] intValue]; - int myTrackCodec = [self.track[keyAudioInputCodec] intValue]; - int myCodecCodec = [self.codec[keyAudioCodec] intValue]; - if (!hb_audio_can_apply_drc(myTrackCodec, myTrackParam, myCodecCodec)) + NSDictionary *sourceTrack = [_dataSource sourceTrackAtIndex:_sourceTrackIdx]; + + int inputCodec = [sourceTrack[keyAudioInputCodec] intValue]; + int inputCodecParam = [sourceTrack[keyAudioInputCodecParam] intValue]; + if (!hb_audio_can_apply_drc(inputCodec, inputCodecParam, self.encoder)) { retval = NO; } @@ -624,52 +449,46 @@ static NSMutableArray *masterBitRateArray = nil; return retval; } -- (BOOL)PassThruDisabled +- (BOOL)passThruDisabled { - BOOL retval = self.enabled; + BOOL retval = YES; - if (retval) + if (self.encoder & HB_ACODEC_PASS_FLAG) { - int myCodecCodec = [self.codec[keyAudioCodec] intValue]; - if (myCodecCodec & HB_ACODEC_PASS_FLAG) - { - retval = NO; - } + retval = NO; } + return retval; } -- (void)setNilValueForKey:(NSString *)key -{ - if ([key isEqualToString:@"drc"] || [key isEqualToString:@"gain"]) - { - [self setValue:@0 forKey:key]; - } -} +#pragma mark - KVO + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { NSSet *retval = nil; - if ([key isEqualToString:@"enabled"]) + if ([key isEqualToString:@"bitrateEnabled"] || + [key isEqualToString:@"passThruDisabled"] || + [key isEqualToString:@"mixdownEnabled"]) { - retval = [NSSet setWithObjects:@"track", nil]; + retval = [NSSet setWithObjects:@"encoder", nil]; } - else if ([key isEqualToString:@"PassThruDisabled"]) + else if ([key isEqualToString:@"mixdowns"] || + [key isEqualToString:@"drcEnabled"]) { - retval = [NSSet setWithObjects:@"track", @"codec", nil]; + retval = [NSSet setWithObjects:@"sourceTrackIdx", @"encoder", nil]; } - else if ([key isEqualToString:@"DRCEnabled"]) + else if ([key isEqualToString:@"sampleRates"]) { - retval = [NSSet setWithObjects:@"track", @"codec", nil]; + retval = [NSSet setWithObjects:@"encoder", @"mixdown", nil]; } - else if ([key isEqualToString:@"bitrateEnabled"]) + else if ([key isEqualToString:@"bitRates"]) { - retval = [NSSet setWithObjects:@"track", @"codec", nil]; + retval = [NSSet setWithObjects:@"encoder", @"mixdown", @"sampleRate", nil]; } - else if ([key isEqualToString:@"mixdownEnabled"]) + else if ([key isEqualToString:@"encoders"]) { - retval = [NSSet setWithObjects:@"track", @"mixdown", nil]; + retval = [NSSet setWithObjects:@"container", @"sourceTrackIdx", nil]; } else { @@ -679,6 +498,14 @@ static NSMutableArray *masterBitRateArray = nil; return retval; } +- (void)setNilValueForKey:(NSString *)key +{ + if ([key isEqualToString:@"drc"] || [key isEqualToString:@"gain"]) + { + [self setValue:@0 forKey:key]; + } +} + #pragma mark - NSCopying - (instancetype)copyWithZone:(NSZone *)zone @@ -687,18 +514,16 @@ static NSMutableArray *masterBitRateArray = nil; if (copy) { - copy->_track = [_track copy]; - copy->_codec = [_codec copy]; - copy->_mixdown = [_mixdown copy]; - copy->_sampleRate = [_sampleRate copy]; - copy->_bitRate = [_bitRate copy]; - copy->_drc = _drc; - copy->_gain = _gain; + copy->_sourceTrackIdx = _sourceTrackIdx; copy->_container = _container; - copy->_codecs = [_codecs copy]; - copy->_mixdowns = [_mixdowns copy]; - copy->_bitRates = [_bitRates copy]; + copy->_encoder = _encoder; + copy->_mixdown = _mixdown; + copy->_sampleRate = _sampleRate; + copy->_bitRate = _bitRate; + + copy->_gain = _gain; + copy->_drc = _drc; } return copy; @@ -713,38 +538,34 @@ static NSMutableArray *masterBitRateArray = nil; - (void)encodeWithCoder:(NSCoder *)coder { - [coder encodeInt:2 forKey:@"HBAudioTrackVersion"]; + [coder encodeInt:3 forKey:@"HBAudioTrackVersion"]; - encodeObject(_track); - encodeObject(_codec); - encodeObject(_mixdown); - encodeObject(_sampleRate); - encodeObject(_bitRate); - encodeDouble(_drc); - encodeDouble(_gain); + encodeInteger(_sourceTrackIdx); encodeInt(_container); - encodeObject(_codecs); - encodeObject(_mixdowns); - encodeObject(_bitRates); + encodeInt(_encoder); + encodeInt(_mixdown); + encodeInt(_sampleRate); + encodeInt(_bitRate); + + encodeDouble(_gain); + encodeDouble(_drc); } - (instancetype)initWithCoder:(NSCoder *)decoder { self = [super init]; - decodeObject(_track, NSDictionary); - decodeObject(_codec, NSDictionary); - decodeObject(_mixdown, NSDictionary); - decodeObject(_sampleRate, NSDictionary); - decodeObject(_bitRate, NSDictionary); - decodeDouble(_drc); - decodeDouble(_gain); + decodeInteger(_sourceTrackIdx); decodeInt(_container); - decodeObject(_codecs, NSMutableArray); - decodeObject(_mixdowns, NSMutableArray); - decodeObject(_bitRates, NSArray); + decodeInt(_encoder); + decodeInt(_mixdown); + decodeInt(_sampleRate); + decodeInt(_bitRate); + + decodeDouble(_gain); + decodeDouble(_drc); return self; } |